| /*------------------------------------------------------------------------- |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2023 The Khronos Group Inc. |
| * Copyright (c) 2023 Google Inc. |
| * Copyright (c) 2023 LunarG Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Vulkan external memory utilities for Android Hardware Buffer |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktExternalMemoryAndroidHardwareBufferUtil.hpp" |
| |
| #ifndef CTS_USES_VULKANSC |
| |
| #if (DE_OS == DE_OS_ANDROID) |
| #include <sys/system_properties.h> |
| |
| #if defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__) |
| #include <android/hardware_buffer.h> |
| #include "deDynamicLibrary.hpp" |
| #define BUILT_WITH_ANDROID_HARDWARE_BUFFER 1 |
| #endif // defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__) |
| |
| #if defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__) |
| #define BUILT_WITH_ANDROID_P_HARDWARE_BUFFER 1 |
| #endif // defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__) |
| |
| #if defined(__ANDROID_API_T__) && (DE_ANDROID_API >= __ANDROID_API_T__) |
| #define BUILT_WITH_ANDROID_T_HARDWARE_BUFFER 1 |
| #endif // defined(__ANDROID_API_T__) && (DE_ANDROID_API >= __ANDROID_API_T__) |
| |
| #if defined(__ANDROID_API_U__) && (DE_ANDROID_API >= __ANDROID_API_U__) |
| #define BUILT_WITH_ANDROID_U_HARDWARE_BUFFER 1 |
| #endif // defined(__ANDROID_API_U__) && (DE_ANDROID_API >= __ANDROID_API_U__) |
| |
| #endif // (DE_OS == DE_OS_ANDROID) |
| |
| namespace vkt |
| { |
| |
| namespace ExternalMemoryUtil |
| { |
| |
| #if (DE_OS == DE_OS_ANDROID) |
| |
| static int32_t androidGetSdkVersion() |
| { |
| static int32_t sdkVersion = -1; |
| if (sdkVersion < 0) |
| { |
| char value[128] = {0}; |
| __system_property_get("ro.build.version.sdk", value); |
| sdkVersion = static_cast<int32_t>(strtol(value, nullptr, 10)); |
| printf("SDK Version is %d\n", sdkVersion); |
| } |
| return sdkVersion; |
| } |
| |
| static int32_t checkAnbApiBuild() |
| { |
| int32_t sdkVersion = androidGetSdkVersion(); |
| #if !defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| // When testing AHB on Android-O and newer the CTS must be compiled against API26 or newer. |
| DE_TEST_ASSERT(!(sdkVersion >= 26)); /* __ANDROID_API_O__ */ |
| #endif // !defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| #if !defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| // When testing AHB on Android-P and newer the CTS must be compiled against API28 or newer. |
| DE_TEST_ASSERT(!(sdkVersion >= 28)); /*__ANDROID_API_P__ */ |
| #endif // !defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| #if !defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| // When testing AHB on Android-T and newer the CTS must be compiled against API33 or newer. |
| DE_TEST_ASSERT(!(sdkVersion >= 33)); /*__ANDROID_API_T__ */ |
| #endif // !defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| #if !defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| // When testing AHB on Android-U and newer the CTS must be compiled against API34 or newer. |
| DE_TEST_ASSERT(!(sdkVersion >= 34)); /*__ANDROID_API_U__ */ |
| #endif // !defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| return sdkVersion; |
| } |
| |
| bool AndroidHardwareBufferExternalApi::supportsAhb() |
| { |
| return (checkAnbApiBuild() >= __ANDROID_API_O__); |
| } |
| |
| bool AndroidHardwareBufferExternalApi::supportsCubeMap() |
| { |
| return (checkAnbApiBuild() >= 28); |
| } |
| |
| AndroidHardwareBufferExternalApi::AndroidHardwareBufferExternalApi() |
| { |
| int32_t sdkVersion = checkAnbApiBuild(); |
| if (sdkVersion >= __ANDROID_API_O__) |
| { |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| if (!loadAhbDynamicApis(sdkVersion)) |
| { |
| // Couldn't load Android AHB system APIs. |
| DE_TEST_ASSERT(false); |
| } |
| #else |
| // Invalid Android AHB APIs configuration. Please check the instructions on how to build NDK for Android. |
| DE_TEST_ASSERT(false); |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| } |
| } |
| |
| AndroidHardwareBufferExternalApi::~AndroidHardwareBufferExternalApi() |
| { |
| } |
| |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| typedef int (*pfn_system_property_get)(const char *, char *); |
| typedef int (*pfnAHardwareBuffer_allocate)(const AHardwareBuffer_Desc *desc, AHardwareBuffer **outBuffer); |
| typedef void (*pfnAHardwareBuffer_describe)(const AHardwareBuffer *buffer, AHardwareBuffer_Desc *outDesc); |
| typedef void (*pfnAHardwareBuffer_acquire)(AHardwareBuffer *buffer); |
| typedef void (*pfnAHardwareBuffer_release)(AHardwareBuffer *buffer); |
| typedef int (*pfnAHardwareBuffer_lock)(AHardwareBuffer *buffer, uint64_t usage, int32_t fence, const ARect *rect, |
| void **outVirtualAddress); |
| typedef int (*pfnAHardwareBuffer_unlock)(AHardwareBuffer *buffer, int32_t *fence); |
| |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| typedef int (*pfnAHardwareBuffer_lockPlanes)(AHardwareBuffer *buffer, uint64_t usage, int32_t fence, const ARect *rect, |
| AHardwareBuffer_Planes *outPlanes); |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| |
| struct AhbFunctions |
| { |
| pfnAHardwareBuffer_allocate allocate; |
| pfnAHardwareBuffer_describe describe; |
| pfnAHardwareBuffer_acquire acquire; |
| pfnAHardwareBuffer_release release; |
| pfnAHardwareBuffer_lock lock; |
| pfnAHardwareBuffer_unlock unlock; |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| pfnAHardwareBuffer_lockPlanes lockPlanes; // Introduced in SDK 29 |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| }; |
| |
| static AhbFunctions ahbFunctions; |
| |
| static bool ahbFunctionsLoaded(AhbFunctions *pAhbFunctions) |
| { |
| static bool ahbApiLoaded = false; |
| if (ahbApiLoaded || ((pAhbFunctions->allocate != nullptr) && (pAhbFunctions->describe != nullptr) && |
| (pAhbFunctions->acquire != nullptr) && (pAhbFunctions->release != nullptr) && |
| (pAhbFunctions->lock != nullptr) && (pAhbFunctions->unlock != nullptr) |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| && (pAhbFunctions->lockPlanes != nullptr) |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| )) |
| { |
| ahbApiLoaded = true; |
| return true; |
| } |
| return false; |
| } |
| |
| bool AndroidHardwareBufferExternalApi::loadAhbDynamicApis(int32_t sdkVersion) |
| { |
| if (sdkVersion >= __ANDROID_API_O__) |
| { |
| if (!ahbFunctionsLoaded(&ahbFunctions)) |
| { |
| static de::DynamicLibrary libnativewindow("libnativewindow.so"); |
| ahbFunctions.allocate = |
| reinterpret_cast<pfnAHardwareBuffer_allocate>(libnativewindow.getFunction("AHardwareBuffer_allocate")); |
| ahbFunctions.describe = |
| reinterpret_cast<pfnAHardwareBuffer_describe>(libnativewindow.getFunction("AHardwareBuffer_describe")); |
| ahbFunctions.acquire = |
| reinterpret_cast<pfnAHardwareBuffer_acquire>(libnativewindow.getFunction("AHardwareBuffer_acquire")); |
| ahbFunctions.release = |
| reinterpret_cast<pfnAHardwareBuffer_release>(libnativewindow.getFunction("AHardwareBuffer_release")); |
| ahbFunctions.lock = |
| reinterpret_cast<pfnAHardwareBuffer_lock>(libnativewindow.getFunction("AHardwareBuffer_lock")); |
| ahbFunctions.unlock = |
| reinterpret_cast<pfnAHardwareBuffer_unlock>(libnativewindow.getFunction("AHardwareBuffer_unlock")); |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| ahbFunctions.lockPlanes = reinterpret_cast<pfnAHardwareBuffer_lockPlanes>( |
| libnativewindow.getFunction("AHardwareBuffer_lockPlanes")); |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| |
| return ahbFunctionsLoaded(&ahbFunctions); |
| } |
| else |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| class AndroidHardwareBufferExternalApi26 : public AndroidHardwareBufferExternalApi |
| { |
| public: |
| vk::pt::AndroidHardwareBufferPtr allocate(uint32_t width, uint32_t height, uint32_t layers, uint32_t format, |
| uint64_t usage) override; |
| void acquire(vk::pt::AndroidHardwareBufferPtr buffer) override; |
| void release(vk::pt::AndroidHardwareBufferPtr buffer) override; |
| void describe(const vk::pt::AndroidHardwareBufferPtr buffer, uint32_t *width, uint32_t *height, uint32_t *layers, |
| uint32_t *format, uint64_t *usage, uint32_t *stride) override; |
| void *lock(vk::pt::AndroidHardwareBufferPtr buffer, uint64_t usage) override; |
| bool lockPlanes(vk::pt::AndroidHardwareBufferPtr buffer, uint64_t usage, uint32_t &planeCount, void *planeData[4], |
| uint32_t planeStride[4], uint32_t planeRowStride[4]) override; |
| bool unlock(vk::pt::AndroidHardwareBufferPtr buffer) override; |
| uint64_t vkUsageToAhbUsage(vk::VkImageUsageFlagBits vkFlag) override; |
| uint64_t vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlag) override; |
| uint32_t vkFormatToAhbFormat(vk::VkFormat vkFormat) override; |
| uint64_t mustSupportAhbUsageFlags() override; |
| bool ahbFormatIsBlob(uint32_t ahbFormat) override |
| { |
| return (ahbFormat == AHARDWAREBUFFER_FORMAT_BLOB); |
| }; |
| bool ahbFormatIsYuv(uint32_t) override |
| { |
| return false; |
| }; |
| std::vector<uint32_t> getAllSupportedFormats() override; |
| const char *getFormatAsString(uint32_t format) override; |
| |
| AndroidHardwareBufferExternalApi26() : AndroidHardwareBufferExternalApi(){}; |
| virtual ~AndroidHardwareBufferExternalApi26(){}; |
| |
| private: |
| // Stop the compiler generating methods of copy the object |
| AndroidHardwareBufferExternalApi26(AndroidHardwareBufferExternalApi26 const ©); // Not Implemented |
| AndroidHardwareBufferExternalApi26 &operator=(AndroidHardwareBufferExternalApi26 const ©); // Not Implemented |
| }; |
| |
| vk::pt::AndroidHardwareBufferPtr AndroidHardwareBufferExternalApi26::allocate(uint32_t width, uint32_t height, |
| uint32_t layers, uint32_t format, |
| uint64_t usage) |
| { |
| AHardwareBuffer_Desc hbufferdesc = { |
| width, height, |
| layers, // number of images |
| format, usage, |
| 0u, // Stride in pixels, ignored for AHardwareBuffer_allocate() |
| 0u, // Initialize to zero, reserved for future use |
| 0u // Initialize to zero, reserved for future use |
| }; |
| |
| AHardwareBuffer *hbuffer = nullptr; |
| ahbFunctions.allocate(&hbufferdesc, &hbuffer); |
| |
| return vk::pt::AndroidHardwareBufferPtr(hbuffer); |
| } |
| |
| void AndroidHardwareBufferExternalApi26::acquire(vk::pt::AndroidHardwareBufferPtr buffer) |
| { |
| ahbFunctions.acquire(static_cast<AHardwareBuffer *>(buffer.internal)); |
| } |
| |
| void AndroidHardwareBufferExternalApi26::release(vk::pt::AndroidHardwareBufferPtr buffer) |
| { |
| ahbFunctions.release(static_cast<AHardwareBuffer *>(buffer.internal)); |
| } |
| |
| void AndroidHardwareBufferExternalApi26::describe(const vk::pt::AndroidHardwareBufferPtr buffer, uint32_t *width, |
| uint32_t *height, uint32_t *layers, uint32_t *format, uint64_t *usage, |
| uint32_t *stride) |
| { |
| AHardwareBuffer_Desc desc; |
| ahbFunctions.describe(static_cast<const AHardwareBuffer *>(buffer.internal), &desc); |
| if (width) |
| *width = desc.width; |
| if (height) |
| *height = desc.height; |
| if (layers) |
| *layers = desc.layers; |
| if (format) |
| *format = desc.format; |
| if (usage) |
| *usage = desc.usage; |
| if (stride) |
| *stride = desc.stride; |
| } |
| |
| void *AndroidHardwareBufferExternalApi26::lock(vk::pt::AndroidHardwareBufferPtr buffer, uint64_t usage) |
| { |
| void *data = nullptr; |
| int32_t fence = -1; // No fence |
| const ARect *rect = nullptr; // NULL rect means all buffer access |
| int result = ahbFunctions.lock(static_cast<AHardwareBuffer *>(buffer.internal), usage, fence, rect, &data); |
| return result == 0 ? data : nullptr; |
| } |
| |
| bool AndroidHardwareBufferExternalApi26::lockPlanes(vk::pt::AndroidHardwareBufferPtr, uint64_t, uint32_t &, void *[4], |
| uint32_t[4], uint32_t[4]) |
| { |
| // SDK 26 does not support locking planes |
| return false; |
| } |
| |
| bool AndroidHardwareBufferExternalApi26::unlock(vk::pt::AndroidHardwareBufferPtr buffer) |
| { |
| int32_t *fence = nullptr; // No fence |
| |
| // 0 is the success code for the unlock function |
| return (ahbFunctions.unlock(static_cast<AHardwareBuffer *>(buffer.internal), fence) == 0u); |
| } |
| |
| uint64_t AndroidHardwareBufferExternalApi26::vkUsageToAhbUsage(vk::VkImageUsageFlagBits vkFlags) |
| { |
| switch (vkFlags) |
| { |
| case vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT: |
| case vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT: |
| // No AHB equivalent. |
| return 0u; |
| case vk::VK_IMAGE_USAGE_SAMPLED_BIT: |
| return AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| case vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT: |
| return AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| case vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT: |
| case vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT: |
| // Alias of AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER which is defined in later Android API versions. |
| return AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; |
| default: |
| return 0u; |
| } |
| } |
| |
| uint64_t AndroidHardwareBufferExternalApi26::vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlags) |
| { |
| switch (vkFlags) |
| { |
| case vk::VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT: |
| case vk::VK_IMAGE_CREATE_EXTENDED_USAGE_BIT: |
| // No AHB equivalent. |
| return 0u; |
| case vk::VK_IMAGE_CREATE_PROTECTED_BIT: |
| return AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT; |
| default: |
| return 0u; |
| } |
| } |
| |
| uint32_t AndroidHardwareBufferExternalApi26::vkFormatToAhbFormat(vk::VkFormat vkFormat) |
| { |
| switch (vkFormat) |
| { |
| case vk::VK_FORMAT_R8G8B8A8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; |
| case vk::VK_FORMAT_R8G8B8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM; |
| case vk::VK_FORMAT_R5G6B5_UNORM_PACK16: |
| return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; |
| case vk::VK_FORMAT_R16G16B16A16_SFLOAT: |
| return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; |
| case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32: |
| return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; |
| default: |
| return 0u; |
| } |
| } |
| |
| uint64_t AndroidHardwareBufferExternalApi26::mustSupportAhbUsageFlags() |
| { |
| return (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT); |
| } |
| |
| std::vector<uint32_t> AndroidHardwareBufferExternalApi26::getAllSupportedFormats() |
| { |
| std::vector<uint32_t> formats = { |
| AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, |
| AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, |
| AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, |
| AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, |
| AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, |
| AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, |
| AHARDWAREBUFFER_FORMAT_BLOB, |
| }; |
| |
| return formats; |
| } |
| |
| const char *AndroidHardwareBufferExternalApi26::getFormatAsString(uint32_t format) |
| { |
| switch (format) |
| { |
| case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: |
| return "AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT"; |
| case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_BLOB: |
| return "AHARDWAREBUFFER_FORMAT_BLOB"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| #if defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| class AndroidHardwareBufferExternalApi28 : public AndroidHardwareBufferExternalApi26 |
| { |
| public: |
| uint64_t vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlag) override; |
| uint32_t vkFormatToAhbFormat(vk::VkFormat vkFormat) override; |
| uint64_t mustSupportAhbUsageFlags() override; |
| std::vector<uint32_t> getAllSupportedFormats() override; |
| const char *getFormatAsString(uint32_t format) override; |
| |
| AndroidHardwareBufferExternalApi28() : AndroidHardwareBufferExternalApi26(){}; |
| virtual ~AndroidHardwareBufferExternalApi28(){}; |
| |
| private: |
| // Stop the compiler generating methods of copy the object |
| AndroidHardwareBufferExternalApi28(AndroidHardwareBufferExternalApi28 const ©); // Not Implemented |
| AndroidHardwareBufferExternalApi28 &operator=(AndroidHardwareBufferExternalApi28 const ©); // Not Implemented |
| }; |
| |
| uint64_t AndroidHardwareBufferExternalApi28::vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlags) |
| { |
| switch (vkFlags) |
| { |
| case vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT: |
| return AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP; |
| default: |
| return AndroidHardwareBufferExternalApi26::vkCreateToAhbUsage(vkFlags); |
| } |
| } |
| |
| uint32_t AndroidHardwareBufferExternalApi28::vkFormatToAhbFormat(vk::VkFormat vkFormat) |
| { |
| switch (vkFormat) |
| { |
| case vk::VK_FORMAT_D16_UNORM: |
| return AHARDWAREBUFFER_FORMAT_D16_UNORM; |
| case vk::VK_FORMAT_X8_D24_UNORM_PACK32: |
| return AHARDWAREBUFFER_FORMAT_D24_UNORM; |
| case vk::VK_FORMAT_D24_UNORM_S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT; |
| case vk::VK_FORMAT_D32_SFLOAT: |
| return AHARDWAREBUFFER_FORMAT_D32_FLOAT; |
| case vk::VK_FORMAT_D32_SFLOAT_S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT; |
| case vk::VK_FORMAT_S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_S8_UINT; |
| default: |
| return AndroidHardwareBufferExternalApi26::vkFormatToAhbFormat(vkFormat); |
| } |
| } |
| |
| uint64_t AndroidHardwareBufferExternalApi28::mustSupportAhbUsageFlags() |
| { |
| return AndroidHardwareBufferExternalApi26::mustSupportAhbUsageFlags() | AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | |
| AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE; |
| } |
| |
| std::vector<uint32_t> AndroidHardwareBufferExternalApi28::getAllSupportedFormats() |
| { |
| std::vector<uint32_t> formats = AndroidHardwareBufferExternalApi26::getAllSupportedFormats(); |
| |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_D16_UNORM); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_D24_UNORM); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_D32_FLOAT); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_S8_UINT); |
| |
| return formats; |
| } |
| |
| const char *AndroidHardwareBufferExternalApi28::getFormatAsString(uint32_t format) |
| { |
| switch (format) |
| { |
| case AHARDWAREBUFFER_FORMAT_D16_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_D16_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_D24_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_D24_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT"; |
| case AHARDWAREBUFFER_FORMAT_D32_FLOAT: |
| return "AHARDWAREBUFFER_FORMAT_D32_FLOAT"; |
| case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT"; |
| case AHARDWAREBUFFER_FORMAT_S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_S8_UINT"; |
| default: |
| return AndroidHardwareBufferExternalApi26::getFormatAsString(format); |
| } |
| } |
| |
| #endif // defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| class AndroidHardwareBufferExternalApi33 : public AndroidHardwareBufferExternalApi28 |
| { |
| public: |
| bool lockPlanes(vk::pt::AndroidHardwareBufferPtr buffer, uint64_t usage, uint32_t &planeCount, void *planeData[4], |
| uint32_t planeStride[4], uint32_t planeRowStride[4]) override; |
| |
| uint32_t vkFormatToAhbFormat(vk::VkFormat vkFormat) override; |
| std::vector<uint32_t> getAllSupportedFormats() override; |
| const char *getFormatAsString(uint32_t format) override; |
| bool ahbFormatIsYuv(uint32_t format) override |
| { |
| return (format == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) || (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010); |
| } |
| |
| AndroidHardwareBufferExternalApi33() : AndroidHardwareBufferExternalApi28(){}; |
| virtual ~AndroidHardwareBufferExternalApi33(){}; |
| |
| private: |
| // Stop the compiler generating methods of copy the object |
| AndroidHardwareBufferExternalApi33(AndroidHardwareBufferExternalApi33 const ©); // Not Implemented |
| AndroidHardwareBufferExternalApi33 &operator=(AndroidHardwareBufferExternalApi33 const ©); // Not Implemented |
| }; |
| |
| bool AndroidHardwareBufferExternalApi33::lockPlanes(vk::pt::AndroidHardwareBufferPtr buffer, uint64_t usage, |
| uint32_t &planeCountOut, void *planeDataOut[4], |
| uint32_t planePixelStrideOut[4], uint32_t planeRowStrideOut[4]) |
| { |
| AHardwareBuffer_Planes planes; |
| int32_t fence = -1; // No fence |
| const ARect *rect = nullptr; // NULL rect means all buffer access |
| const int lockResult = |
| ahbFunctions.lockPlanes(static_cast<AHardwareBuffer *>(buffer.internal), usage, fence, rect, &planes); |
| const bool succeeded = (lockResult == 0); |
| |
| if (succeeded) |
| { |
| planeCountOut = planes.planeCount; |
| for (uint32_t i = 0; i < planeCountOut; ++i) |
| { |
| planeDataOut[i] = planes.planes[i].data; |
| planePixelStrideOut[i] = planes.planes[i].pixelStride; |
| planeRowStrideOut[i] = planes.planes[i].rowStride; |
| } |
| } |
| |
| return succeeded; |
| } |
| |
| uint32_t AndroidHardwareBufferExternalApi33::vkFormatToAhbFormat(vk::VkFormat vkFormat) |
| { |
| switch (vkFormat) |
| { |
| case vk::VK_FORMAT_R8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8_UNORM; |
| default: |
| return AndroidHardwareBufferExternalApi28::vkFormatToAhbFormat(vkFormat); |
| } |
| } |
| |
| std::vector<uint32_t> AndroidHardwareBufferExternalApi33::getAllSupportedFormats() |
| { |
| std::vector<uint32_t> formats = AndroidHardwareBufferExternalApi28::getAllSupportedFormats(); |
| |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_R8_UNORM); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420); // Unsure if this was added in SDK 30 |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_YCbCr_P010); |
| |
| return formats; |
| } |
| |
| const char *AndroidHardwareBufferExternalApi33::getFormatAsString(uint32_t format) |
| { |
| switch (format) |
| { |
| case AHARDWAREBUFFER_FORMAT_R8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8_UNORM"; |
| case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: |
| return "AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420"; |
| case AHARDWAREBUFFER_FORMAT_YCbCr_P010: |
| return "AHARDWAREBUFFER_FORMAT_YCbCr_P010"; |
| default: |
| return AndroidHardwareBufferExternalApi28::getFormatAsString(format); |
| } |
| } |
| |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| class AndroidHardwareBufferExternalApi34 : public AndroidHardwareBufferExternalApi33 |
| { |
| public: |
| uint32_t vkFormatToAhbFormat(vk::VkFormat vkFormat) override; |
| std::vector<uint32_t> getAllSupportedFormats() override; |
| const char *getFormatAsString(uint32_t format) override; |
| |
| AndroidHardwareBufferExternalApi34() : AndroidHardwareBufferExternalApi33(){}; |
| virtual ~AndroidHardwareBufferExternalApi34(){}; |
| |
| private: |
| // Stop the compiler generating methods of copy the object |
| AndroidHardwareBufferExternalApi34(AndroidHardwareBufferExternalApi34 const ©); // Not Implemented |
| AndroidHardwareBufferExternalApi34 &operator=(AndroidHardwareBufferExternalApi34 const ©); // Not Implemented |
| }; |
| |
| uint32_t AndroidHardwareBufferExternalApi34::vkFormatToAhbFormat(vk::VkFormat vkFormat) |
| { |
| switch (vkFormat) |
| { |
| case vk::VK_FORMAT_R16_UINT: |
| return AHARDWAREBUFFER_FORMAT_R16_UINT; |
| case vk::VK_FORMAT_R16G16_UINT: |
| return AHARDWAREBUFFER_FORMAT_R16G16_UINT; |
| case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: |
| return AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM; |
| default: |
| return AndroidHardwareBufferExternalApi33::vkFormatToAhbFormat(vkFormat); |
| } |
| } |
| |
| std::vector<uint32_t> AndroidHardwareBufferExternalApi34::getAllSupportedFormats() |
| { |
| std::vector<uint32_t> formats = AndroidHardwareBufferExternalApi33::getAllSupportedFormats(); |
| |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_R16_UINT); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_R16G16_UINT); |
| formats.emplace_back(AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM); |
| |
| return formats; |
| } |
| |
| const char *AndroidHardwareBufferExternalApi34::getFormatAsString(uint32_t format) |
| { |
| switch (format) |
| { |
| case AHARDWAREBUFFER_FORMAT_R16_UINT: |
| return "AHARDWAREBUFFER_FORMAT_R16_UINT"; |
| case AHARDWAREBUFFER_FORMAT_R16G16_UINT: |
| return "AHARDWAREBUFFER_FORMAT_R16G16_UINT"; |
| case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM"; |
| default: |
| return AndroidHardwareBufferExternalApi33::getFormatAsString(format); |
| } |
| } |
| |
| #endif // defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| #endif // (DE_OS == DE_OS_ANDROID) |
| |
| AndroidHardwareBufferExternalApi *AndroidHardwareBufferExternalApi::getInstance() |
| { |
| #if (DE_OS == DE_OS_ANDROID) |
| int32_t sdkVersion = checkAnbApiBuild(); |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| #if defined(__ANDROID_API_U__) && (DE_ANDROID_API >= __ANDROID_API_U__) |
| if (sdkVersion >= __ANDROID_API_U__) |
| { |
| static AndroidHardwareBufferExternalApi34 api34Instance; |
| return &api34Instance; |
| } |
| #endif // defined(__ANDROID_API_U__) && (DE_ANDROID_API >= __ANDROID_API_U__) |
| |
| #if defined(__ANDROID_API_T__) && (DE_ANDROID_API >= __ANDROID_API_T__) |
| if (sdkVersion >= __ANDROID_API_T__) |
| { |
| static AndroidHardwareBufferExternalApi33 api33Instance; |
| return &api33Instance; |
| } |
| #endif // defined(__ANDROID_API_T__) && (DE_ANDROID_API >= __ANDROID_API_T__) |
| |
| #if defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__) |
| if (sdkVersion >= __ANDROID_API_P__) |
| { |
| static AndroidHardwareBufferExternalApi28 api28Instance; |
| return &api28Instance; |
| } |
| #endif // defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__) |
| |
| #if defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__) |
| if (sdkVersion >= __ANDROID_API_O__) |
| { |
| static AndroidHardwareBufferExternalApi26 api26Instance; |
| return &api26Instance; |
| } |
| #endif // defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__) |
| |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| DE_UNREF(sdkVersion); |
| #endif // DE_OS == DE_OS_ANDROID |
| return nullptr; |
| } |
| |
| int32_t AndroidHardwareBufferInstance::getSdkVersion() |
| { |
| #if (DE_OS == DE_OS_ANDROID) |
| return androidGetSdkVersion(); |
| #endif // (DE_OS == DE_OS_ANDROID) |
| return 0u; |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatSupported(Format format) |
| { |
| switch (format) |
| { |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| case Format::R8G8B8A8_UNORM: |
| case Format::R8G8B8X8_UNORM: |
| case Format::R8G8B8_UNORM: |
| case Format::R5G6B5_UNORM: |
| case Format::R16G16B16A16_FLOAT: |
| case Format::R10G10B10A2_UNORM: |
| case Format::BLOB: |
| |
| #if defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| case Format::D16_UNORM: |
| case Format::D24_UNORM: |
| case Format::D24_UNORM_S8_UINT: |
| case Format::D32_FLOAT: |
| case Format::D32_FLOAT_S8_UINT: |
| case Format::S8_UINT: |
| #endif // defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| case Format::Y8Cb8Cr8_420: |
| case Format::YCbCr_P010: |
| case Format::R8_UNORM: |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| case Format::R16_UINT: |
| case Format::R16G16_UINT: |
| case Format::R10G10B10A10_UNORM: |
| #endif // defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| |
| case Format::B8G8R8A8_UNORM: |
| case Format::YV12: |
| case Format::Y8: |
| case Format::Y16: |
| case Format::RAW16: |
| case Format::RAW10: |
| case Format::RAW12: |
| case Format::RAW_OPAQUE: |
| case Format::IMPLEMENTATION_DEFINED: |
| case Format::NV16: |
| case Format::NV21: |
| case Format::YUY2: |
| return true; |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatYuv(Format format) |
| { |
| switch (format) |
| { |
| case Format::Y8Cb8Cr8_420: |
| case Format::YCbCr_P010: |
| case Format::YV12: |
| case Format::Y8: |
| case Format::Y16: |
| case Format::NV16: |
| case Format::NV21: |
| case Format::YUY2: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatRaw(Format format) |
| { |
| switch (format) |
| { |
| case Format::RAW10: |
| case Format::RAW12: |
| case Format::RAW16: |
| case Format::RAW_OPAQUE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatColor(Format format) |
| { |
| switch (format) |
| { |
| case Format::R8G8B8A8_UNORM: |
| case Format::R8G8B8X8_UNORM: |
| case Format::R8G8B8_UNORM: |
| case Format::R5G6B5_UNORM: |
| case Format::R16G16B16A16_FLOAT: |
| case Format::R10G10B10A2_UNORM: |
| case Format::Y8Cb8Cr8_420: |
| case Format::YCbCr_P010: |
| case Format::R8_UNORM: |
| case Format::R16_UINT: |
| case Format::R16G16_UINT: |
| case Format::R10G10B10A10_UNORM: |
| case Format::B8G8R8A8_UNORM: |
| case Format::YV12: |
| case Format::Y8: |
| case Format::Y16: |
| case Format::IMPLEMENTATION_DEFINED: |
| case Format::NV16: |
| case Format::NV21: |
| case Format::YUY2: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatDepth(Format format) |
| { |
| switch (format) |
| { |
| case Format::D16_UNORM: |
| case Format::D24_UNORM: |
| case Format::D24_UNORM_S8_UINT: |
| case Format::D32_FLOAT: |
| case Format::D32_FLOAT_S8_UINT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isFormatStencil(Format format) |
| { |
| switch (format) |
| { |
| case Format::D24_UNORM_S8_UINT: |
| case Format::D32_FLOAT_S8_UINT: |
| case Format::S8_UINT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::hasFormatAlpha(Format format) |
| { |
| switch (format) |
| { |
| case Format::R8G8B8A8_UNORM: |
| case Format::R16G16B16A16_FLOAT: |
| case Format::R10G10B10A2_UNORM: |
| case Format::R10G10B10A10_UNORM: |
| case Format::B8G8R8A8_UNORM: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| const char *AndroidHardwareBufferInstance::getFormatName(Format format) |
| { |
| switch (format) |
| { |
| case Format::R8G8B8A8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM"; |
| case Format::R8G8B8X8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM"; |
| case Format::R8G8B8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM"; |
| case Format::R5G6B5_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM"; |
| case Format::R16G16B16A16_FLOAT: |
| return "AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT"; |
| case Format::R10G10B10A2_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM"; |
| case Format::BLOB: |
| return "AHARDWAREBUFFER_FORMAT_BLOB"; |
| case Format::D16_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_D16_UNORM"; |
| case Format::D24_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_D24_UNORM"; |
| case Format::D24_UNORM_S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT"; |
| case Format::D32_FLOAT: |
| return "AHARDWAREBUFFER_FORMAT_D32_FLOAT"; |
| case Format::D32_FLOAT_S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT"; |
| case Format::S8_UINT: |
| return "AHARDWAREBUFFER_FORMAT_S8_UINT"; |
| case Format::Y8Cb8Cr8_420: |
| return "AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420"; |
| case Format::YCbCr_P010: |
| return "AHARDWAREBUFFER_FORMAT_YCbCr_P010"; |
| case Format::R8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R8_UNORM"; |
| case Format::R16_UINT: |
| return "AHARDWAREBUFFER_FORMAT_R16_UINT"; |
| case Format::R16G16_UINT: |
| return "AHARDWAREBUFFER_FORMAT_R16G16_UINT"; |
| case Format::R10G10B10A10_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM"; |
| case Format::B8G8R8A8_UNORM: |
| return "AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM"; |
| case Format::YV12: |
| return "AHARDWAREBUFFER_FORMAT_YV12"; |
| case Format::Y8: |
| return "AHARDWAREBUFFER_FORMAT_Y8"; |
| case Format::Y16: |
| return "AHARDWAREBUFFER_FORMAT_Y16"; |
| case Format::RAW16: |
| return "AHARDWAREBUFFER_FORMAT_RAW16"; |
| case Format::RAW10: |
| return "AHARDWAREBUFFER_FORMAT_RAW10"; |
| case Format::RAW12: |
| return "AHARDWAREBUFFER_FORMAT_RAW12"; |
| case Format::RAW_OPAQUE: |
| return "AHARDWAREBUFFER_FORMAT_RAW_OPAQUE"; |
| case Format::IMPLEMENTATION_DEFINED: |
| return "AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED"; |
| case Format::NV16: |
| return "AHARDWAREBUFFER_FORMAT_YCbCr_422_SP"; |
| case Format::NV21: |
| return "AHARDWAREBUFFER_FORMAT_YCrCb_420_SP"; |
| case Format::YUY2: |
| return "AHARDWAREBUFFER_FORMAT_YCbCr_422_I"; |
| |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| uint32_t AndroidHardwareBufferInstance::formatToInternalFormat(Format format) |
| { |
| switch (format) |
| { |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| case Format::R8G8B8A8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; |
| case Format::R8G8B8X8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; |
| case Format::R8G8B8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM; |
| case Format::R5G6B5_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; |
| case Format::R16G16B16A16_FLOAT: |
| return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; |
| case Format::R10G10B10A2_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; |
| case Format::BLOB: |
| return AHARDWAREBUFFER_FORMAT_BLOB; |
| |
| #if defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| case Format::D16_UNORM: |
| return AHARDWAREBUFFER_FORMAT_D16_UNORM; |
| case Format::D24_UNORM: |
| return AHARDWAREBUFFER_FORMAT_D24_UNORM; |
| case Format::D24_UNORM_S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT; |
| case Format::D32_FLOAT: |
| return AHARDWAREBUFFER_FORMAT_D32_FLOAT; |
| case Format::D32_FLOAT_S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT; |
| case Format::S8_UINT: |
| return AHARDWAREBUFFER_FORMAT_S8_UINT; |
| #endif // defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| case Format::Y8Cb8Cr8_420: |
| return AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420; |
| case Format::YCbCr_P010: |
| return AHARDWAREBUFFER_FORMAT_YCbCr_P010; |
| case Format::R8_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R8_UNORM; |
| #endif // defined(BUILT_WITH_ANDROID_T_HARDWARE_BUFFER) |
| |
| #if defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| case Format::R16_UINT: |
| return AHARDWAREBUFFER_FORMAT_R16_UINT; |
| case Format::R16G16_UINT: |
| return AHARDWAREBUFFER_FORMAT_R16G16_UINT; |
| case Format::R10G10B10A10_UNORM: |
| return AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM; |
| #endif // defined(BUILT_WITH_ANDROID_U_HARDWARE_BUFFER) |
| |
| // Values obtained AOSP header (nativewindow/include/vndk/hardware_buffer.h) |
| case B8G8R8A8_UNORM: |
| return 5; |
| case YV12: |
| return 0x32315659; |
| case Y8: |
| return 0x20203859; |
| case Y16: |
| return 0x20363159; |
| case RAW16: |
| return 0x20; |
| case RAW10: |
| return 0x25; |
| case RAW12: |
| return 0x26; |
| case RAW_OPAQUE: |
| return 0x24; |
| case IMPLEMENTATION_DEFINED: |
| return 0x22; |
| case NV16: |
| return 0x10; |
| case NV21: |
| return 0x11; |
| case YUY2: |
| return 0x14; |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| |
| default: |
| return 0u; |
| } |
| } |
| |
| tcu::TextureFormat AndroidHardwareBufferInstance::formatToTextureFormat(Format format) |
| { |
| switch (format) |
| { |
| case Format::R8G8B8A8_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGBA, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::R8G8B8X8_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGBA, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::R8G8B8_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGB, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::R5G6B5_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGB, |
| tcu::TextureFormat::ChannelType::UNORM_SHORT_565); |
| case Format::R16G16B16A16_FLOAT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGBA, tcu::TextureFormat::ChannelType::HALF_FLOAT); |
| case Format::R10G10B10A2_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGBA, |
| tcu::TextureFormat::ChannelType::UNORM_INT_1010102_REV); |
| case Format::D16_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::D, tcu::TextureFormat::ChannelType::UNORM_INT16); |
| case Format::D24_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::D, tcu::TextureFormat::ChannelType::UNORM_INT24); |
| case Format::D24_UNORM_S8_UINT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::DS, |
| tcu::TextureFormat::ChannelType::UNSIGNED_INT_24_8_REV); |
| case Format::D32_FLOAT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::D, tcu::TextureFormat::ChannelType::FLOAT); |
| case Format::S8_UINT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::S, tcu::TextureFormat::ChannelType::UNSIGNED_INT8); |
| case Format::Y8Cb8Cr8_420: |
| case Format::YV12: |
| case Format::NV16: |
| case Format::NV21: |
| case Format::YUY2: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGB, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::YCbCr_P010: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGB, |
| tcu::TextureFormat::ChannelType::UNORM_INT_101010); |
| case Format::R8_UNORM: |
| case Format::Y8: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::R, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::Y16: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::R, tcu::TextureFormat::ChannelType::UNORM_INT16); |
| case Format::RAW16: |
| case Format::R16_UINT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::R, tcu::TextureFormat::ChannelType::UNSIGNED_INT16); |
| case Format::R16G16_UINT: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RG, |
| tcu::TextureFormat::ChannelType::UNSIGNED_INT16); |
| case Format::R10G10B10A10_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::RGBA, |
| tcu::TextureFormat::ChannelType::UNORM_SHORT_10); |
| |
| case Format::B8G8R8A8_UNORM: |
| return tcu::TextureFormat(tcu::TextureFormat::ChannelOrder::BGRA, tcu::TextureFormat::ChannelType::UNORM_INT8); |
| case Format::RAW10: |
| return tcu::getUncompressedFormat(tcu::COMPRESSEDTEXFORMAT_AHB_RAW10); |
| case Format::RAW12: |
| return tcu::getUncompressedFormat(tcu::COMPRESSEDTEXFORMAT_AHB_RAW12); |
| |
| // Format::IMPLEMENTATION_DEFINED |
| // Format::RAW_OPAQUE |
| // Format::D32_FLOAT_S8_UINT |
| // Format::BLOB |
| default: |
| return tcu::TextureFormat(); // Unassigned |
| } |
| } |
| |
| AndroidHardwareBufferInstance::ChromaLocation AndroidHardwareBufferInstance::vkChromaLocationToChromaLocation( |
| vk::VkChromaLocation location) |
| { |
| switch (location) |
| { |
| case vk::VK_CHROMA_LOCATION_COSITED_EVEN: |
| return ChromaLocation::COSITED_EVEN; |
| case vk::VK_CHROMA_LOCATION_MIDPOINT: |
| return ChromaLocation::MIDPOINT; |
| default: |
| DE_ASSERT(false); // Should never reach this |
| return ChromaLocation::COSITED_EVEN; |
| break; |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::reduceYuvTexture(tcu::TextureLevel &texture, Format format, ChromaLocation xChroma, |
| ChromaLocation yChroma) |
| { |
| switch (format) |
| { |
| // YUV 4:2:0 |
| case Y8Cb8Cr8_420: |
| case YCbCr_P010: |
| case YV12: |
| case NV21: |
| reduceYuv420Texture(texture, xChroma, yChroma); |
| break; |
| |
| // YUV 4:2:2 |
| case NV16: |
| case YUY2: |
| reduceYuv422Texture(texture, xChroma); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::reduceYuv420Texture(tcu::TextureLevel &texture, ChromaLocation xChroma, |
| ChromaLocation yChroma) |
| { |
| tcu::PixelBufferAccess access = texture.getAccess(); |
| |
| for (int32_t y = 0; y < texture.getHeight(); y += 2) |
| { |
| for (int32_t x = 0; x < texture.getWidth(); x += 2) |
| { |
| tcu::Vec4 colors[4] = {access.getPixel(x, y), access.getPixel(x, y + 1), access.getPixel(x + 1, y), |
| access.getPixel(x + 1, y + 1)}; |
| tcu::Vec2 chroma = colors[0].xz(); |
| float texelCount = 1.0f; |
| |
| if (yChroma == ChromaLocation::MIDPOINT) |
| { |
| chroma += colors[1].xz(); |
| texelCount += 1.0f; |
| |
| if (xChroma == ChromaLocation::MIDPOINT) |
| { |
| chroma += colors[3].xz(); |
| texelCount += 1.0f; |
| } |
| } |
| |
| if (xChroma == ChromaLocation::MIDPOINT) |
| { |
| chroma += colors[2].xz(); |
| texelCount += 1.0f; |
| } |
| |
| chroma = chroma / texelCount; |
| |
| colors[0].xz() = chroma; |
| access.setPixel(colors[0], x, y); |
| colors[1].xz() = chroma; |
| access.setPixel(colors[1], x, y + 1); |
| colors[2].xz() = chroma; |
| access.setPixel(colors[2], x + 1, y); |
| colors[3].xz() = chroma; |
| access.setPixel(colors[3], x + 1, y + 1); |
| } |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::reduceYuv422Texture(tcu::TextureLevel &texture, ChromaLocation xChroma) |
| { |
| tcu::PixelBufferAccess access = texture.getAccess(); |
| |
| for (int32_t y = 0; y < texture.getHeight(); ++y) |
| { |
| for (int32_t x = 0; x < texture.getWidth(); x += 2) |
| { |
| tcu::Vec4 colors[2] = {access.getPixel(x, y), access.getPixel(x + 1, y)}; |
| tcu::Vec2 chroma = colors[0].xz(); |
| |
| if (xChroma == ChromaLocation::MIDPOINT) |
| { |
| chroma += colors[1].xz(); |
| chroma = chroma / 2.0f; |
| } |
| |
| colors[0].xz() = chroma; |
| access.setPixel(colors[0], x, y); |
| colors[1].xz() = chroma; |
| access.setPixel(colors[1], x + 1, y); |
| } |
| } |
| } |
| |
| uint64_t AndroidHardwareBufferInstance::usageToInternalUsage(Usage usage) |
| { |
| uint64_t internalUsage = 0u; |
| |
| #if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| |
| // AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT used instead of AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
| // due to the latter requiring higher SDK versions than the former |
| if (usage & Usage::GPU_FRAMEBUFFER) |
| internalUsage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; |
| |
| if (usage & Usage::GPU_SAMPLED) |
| internalUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| |
| if (usage & Usage::CPU_READ) |
| internalUsage |= AHARDWAREBUFFER_USAGE_CPU_READ_RARELY; |
| |
| if (usage & Usage::CPU_WRITE) |
| internalUsage |= AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY; |
| #else |
| DE_UNREF(usage); |
| #endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER) |
| |
| return internalUsage; |
| } |
| |
| uint32_t AndroidHardwareBufferInstance::pixelStride(Format format) |
| { |
| return tcu::getPixelSize(formatToTextureFormat(format)); |
| } |
| |
| AndroidHardwareBufferInstance::~AndroidHardwareBufferInstance(void) |
| { |
| release(); |
| } |
| |
| bool AndroidHardwareBufferInstance::allocate(Format format, uint32_t width, uint32_t height, uint32_t layers, |
| Usage usage) |
| { |
| // Should never be called when there's no actual api to call with |
| DE_ASSERT(m_ahbApi); |
| |
| // Don't allocate another buffer before releasing previous |
| DE_ASSERT(m_handle.internal == nullptr); |
| |
| m_format = format; |
| m_internalFormat = formatToInternalFormat(m_format); |
| m_usage = usage; |
| m_internalUsage = usageToInternalUsage(m_usage); |
| m_width = width; |
| m_height = height; |
| m_layers = layers; |
| |
| m_handle = m_ahbApi->allocate(width, height, layers, m_internalFormat, m_internalUsage); |
| |
| return m_handle.internal != nullptr; |
| } |
| |
| void AndroidHardwareBufferInstance::release(void) |
| { |
| if (m_handle.internal != nullptr) |
| { |
| // Should never be called when there's no actual api to call with |
| DE_ASSERT(m_ahbApi); |
| |
| m_ahbApi->release(m_handle); |
| m_handle.internal = nullptr; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::lock(Usage usage) |
| { |
| // Should never be called when there's no actual api to call with |
| DE_ASSERT(m_ahbApi); |
| |
| // Only allowed to lock once |
| DE_ASSERT(m_accessData.m_planeCount == 0); |
| |
| // Cannot lock what we don't have |
| if (m_handle.internal == nullptr) |
| return false; |
| |
| // Validate buffer was allocated with wanted usage |
| if ((usage & m_usage) != usage) |
| return false; |
| |
| bool lockSuccessful = false; |
| uint64_t internalUsage = usageToInternalUsage(usage); |
| |
| if (isYuv()) |
| lockSuccessful = |
| m_ahbApi->lockPlanes(m_handle, internalUsage, m_accessData.m_planeCount, m_accessData.m_planeDataVoid, |
| m_accessData.m_planePixelStride, m_accessData.m_planeRowStride); |
| else |
| { |
| m_accessData.m_planeDataVoid[0] = m_ahbApi->lock(m_handle, internalUsage); |
| |
| // null data means locking failed |
| if (m_accessData.m_planeDataVoid[0]) |
| { |
| lockSuccessful = true; |
| |
| m_accessData.m_planePixelStride[0] = pixelStride(m_format); |
| // Need to retrieve row stride from description (will only return how many pixels). Need to multiply by pixel size |
| m_ahbApi->describe(m_handle, nullptr, nullptr, nullptr, nullptr, nullptr, |
| &m_accessData.m_planeRowStride[0]); |
| m_accessData.m_planeRowStride[0] *= m_accessData.m_planePixelStride[0]; |
| m_accessData.m_planeCount = 1u; // Non planar formats will be treated as a single plane |
| } |
| } |
| |
| return lockSuccessful; |
| } |
| |
| bool AndroidHardwareBufferInstance::unlock(void) |
| { |
| // Should never be called when there's no actual api to call with |
| DE_ASSERT(m_ahbApi); |
| |
| // Force locking again if we want to read/write again |
| m_accessData.m_planeCount = 0u; |
| |
| return m_ahbApi->unlock(m_handle); |
| } |
| |
| void AndroidHardwareBufferInstance::copyCpuBufferToAndroidBuffer(const tcu::TextureLevel &cpuBuffer) |
| { |
| // Running into this assertion means no locking was performed |
| DE_ASSERT(m_accessData.m_planeCount != 0); |
| |
| tcu::ConstPixelBufferAccess access = cpuBuffer.getAccess(); |
| |
| for (uint32_t y = 0u; y < m_height; ++y) |
| { |
| for (uint32_t x = 0u; x < m_width; ++x) |
| { |
| const uint8_t *cpuBufferPixel = static_cast<const uint8_t *>(access.getPixelPtr(x, y)); |
| uint32_t offset = (y * m_accessData.m_planeRowStride[0]) + (x * m_accessData.m_planePixelStride[0]); |
| uint8_t *androidBufferPixel = m_accessData.m_planeData[0] + offset; |
| |
| switch (m_format) |
| { |
| // YUV 4:2:0 formats |
| case Y8Cb8Cr8_420: |
| case YV12: |
| case NV21: |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // Component size is UNSIGNED_INT8. We can copy values directly |
| // YUV need to map RGB the following way according to Vulkan spec: |
| // G is Y |
| // B is Cb |
| // R is Cr |
| |
| // Plane 0 contains Y information |
| *(androidBufferPixel) = *(cpuBufferPixel + 1); |
| |
| // Plane 1 contains Cb information |
| // 4:2:0 has half size for Cb |
| offset = ((y / 2) * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| *(androidBufferPixel) = *(cpuBufferPixel + 2); |
| |
| // Plane 2 contains Cr information |
| // 4:2:0 has half size for Cr |
| offset = ((y / 2) * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| *(androidBufferPixel) = *(cpuBufferPixel); |
| |
| break; |
| |
| // YUV 4:2:2 formats |
| case NV16: |
| case YUY2: |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // Component size is UNSIGNED_INT8. We can copy values directly |
| // YUV need to map RGB the following way according to Vulkan spec: |
| // G is Y |
| // B is Cb |
| // R is Cr |
| |
| // Plane 0 contains Y information |
| *(androidBufferPixel) = *(cpuBufferPixel + 1); |
| |
| // Plane 1 contains Cb information |
| // 4:2:2 has half width for Cb |
| offset = (y * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| *(androidBufferPixel) = *(cpuBufferPixel + 2); |
| |
| // Plane 2 contains Cr information |
| // 4:2:2 has half width for Cr |
| offset = (y * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| *(androidBufferPixel) = *(cpuBufferPixel); |
| |
| break; |
| |
| // YUV 4:2:0 format |
| case YCbCr_P010: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // YCbCr_P010 does not have same comoponent size as m_cpuBuffer type (UNORM_INT_101010) |
| // We need to transform from UNORM_INT_101010 to YCbCr_P010 where data is stored in the higher bits of 16 bit values |
| |
| uint32_t redOffset = 22u; |
| uint32_t greenOffset = 12u; |
| uint32_t blueOffset = 2u; |
| uint32_t bitOffset = 6u; |
| uint32_t bitCount = 10u; |
| uint32_t mask = (1u << bitCount) - 1u; |
| uint32_t cpuValue = *(reinterpret_cast<const uint32_t *>(cpuBufferPixel)); |
| uint16_t red = static_cast<uint16_t>(((cpuValue >> redOffset) & mask) << bitOffset); |
| uint16_t green = static_cast<uint16_t>(((cpuValue >> greenOffset) & mask) << bitOffset); |
| uint16_t blue = static_cast<uint16_t>(((cpuValue >> blueOffset) & mask) << bitOffset); |
| |
| // m_cpuBuffer for YCbCr_P010 has order RGB, so we need to swizzle values |
| // Following Vulkan spec for ordering where: |
| // G is Y |
| // B is Cb |
| // R is Cr |
| |
| // Plane 0 contains Y information |
| *(reinterpret_cast<uint16_t *>(androidBufferPixel)) = green; |
| |
| // Plane 1 contains Cb information |
| // YCbCr_P010 is half size for Cb |
| offset = ((y / 2) * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| *(reinterpret_cast<uint16_t *>(androidBufferPixel)) = blue; |
| |
| // Plane 2 contains Cr information |
| // YCbCr_P010 is half size for Cr |
| offset = ((y / 2) * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| *(reinterpret_cast<uint16_t *>(androidBufferPixel)) = red; |
| |
| break; |
| } |
| |
| case RAW10: |
| case RAW12: |
| DE_ASSERT(false); // Use compressed variation |
| break; |
| |
| default: |
| memcpy(androidBufferPixel, cpuBufferPixel, m_accessData.m_planePixelStride[0]); |
| } |
| } |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::copyCpuBufferToAndroidBufferCompressed(const tcu::CompressedTexture &cpuBuffer) |
| { |
| // Running into this assertion means no locking was performed |
| DE_ASSERT(m_accessData.m_planeCount != 0); |
| |
| const uint8_t *cpuBufferPixel = static_cast<const uint8_t *>(cpuBuffer.getData()); |
| |
| for (uint32_t y = 0u; y < m_height; ++y) |
| { |
| for (uint32_t x = 0u; x < m_width; ++x) |
| { |
| uint32_t offset = (y * m_accessData.m_planeRowStride[0]) + (x * m_accessData.m_planePixelStride[0]); |
| uint8_t *androidBufferPixel = m_accessData.m_planeData[0] + offset; |
| |
| switch (m_format) |
| { |
| case RAW10: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 1u); |
| |
| // Packed format with 4 pixels in 5 bytes |
| // Layout: https://developer.android.com/reference/android/graphics/ImageFormat#RAW10 |
| memcpy(androidBufferPixel, cpuBufferPixel, 5u); // Copy 4 pixels packed in 5 bytes |
| |
| // Advance 3 pixels so in total we advance 4 |
| x += 3u; |
| cpuBufferPixel += 5u; |
| |
| break; |
| } |
| |
| case RAW12: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 1u); |
| |
| // Packed format with 2 pixels in 3 bytes |
| // Layout: https://developer.android.com/reference/android/graphics/ImageFormat#RAW12 |
| memcpy(androidBufferPixel, cpuBufferPixel, 3u); // Copy 2 pixels packed in 3 bytes |
| |
| // Advance 1 pixels so in total we advance 2 |
| x += 1u; |
| cpuBufferPixel += 3u; |
| |
| break; |
| } |
| |
| default: |
| DE_ASSERT(false); // Use non-compressed variant |
| break; |
| } |
| } |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::copyAndroidBufferToCpuBuffer(tcu::TextureLevel &cpuBuffer) const |
| { |
| // Running into this assertion means no locking was performed |
| DE_ASSERT(m_accessData.m_planeCount != 0); |
| |
| tcu::PixelBufferAccess access = cpuBuffer.getAccess(); |
| |
| for (uint32_t y = 0u; y < m_height; ++y) |
| { |
| for (uint32_t x = 0u; x < m_width; ++x) |
| { |
| uint32_t offset = (y * m_accessData.m_planeRowStride[0]) + (x * m_accessData.m_planePixelStride[0]); |
| uint8_t *cpuBufferPixel = static_cast<uint8_t *>(access.getPixelPtr(x, y)); |
| const uint8_t *androidBufferPixel = m_accessData.m_planeData[0] + offset; |
| |
| switch (m_format) |
| { |
| // YUV 4:2:0 formats |
| case Y8Cb8Cr8_420: |
| case YV12: |
| case NV21: |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // Component size is UNSIGNED_INT8. We can copy values directly |
| // YUV need to map RGB the following way according to Vulkan spec: |
| // Y is G |
| // Cb is B |
| // Cr is R |
| |
| // Plane 0 contains Y information |
| *(cpuBufferPixel + 1) = *(androidBufferPixel); |
| |
| // Plane 1 contains Cb information |
| // 4:2:0 has half size for Cb |
| offset = ((y / 2) * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| *(cpuBufferPixel + 2) = *(androidBufferPixel); |
| |
| // Plane 2 contains Cr information |
| // 4:2:0 has half size for Cr |
| offset = ((y / 2) * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| *(cpuBufferPixel) = *(androidBufferPixel); |
| |
| break; |
| |
| // YUV 4:2:2 formats |
| case NV16: |
| case YUY2: |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // Component size is UNSIGNED_INT8. We can copy values directly |
| // YUV need to map RGB the following way according to Vulkan spec: |
| // Y is G |
| // Cb is B |
| // Cr is R |
| |
| // Plane 0 contains Y information |
| *(cpuBufferPixel + 1) = *(androidBufferPixel); |
| |
| // Plane 1 contains Cb information |
| // 4:2:2 has half width for Cb |
| offset = (y * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| *(cpuBufferPixel + 2) = *(androidBufferPixel); |
| |
| // Plane 2 contains Cr information |
| // 4:2:2 has half width for Cr |
| offset = (y * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| *(cpuBufferPixel) = *(androidBufferPixel); |
| |
| break; |
| |
| // YUV 4:2:0 format |
| case YCbCr_P010: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 3u); |
| |
| // m_cpuBuffer for YCbCr_P010 has order RGB, so we need to swizzle values |
| // Following Vulkan spec for ordering where: |
| // Y is G |
| // Cb is B |
| // Cr is R |
| |
| // Plane 0 contains Y information |
| uint16_t green = *(reinterpret_cast<const uint16_t *>(androidBufferPixel)); |
| |
| // Plane 1 contains Cb information |
| // YCbCr_P010 is half size for Cb |
| offset = ((y / 2) * m_accessData.m_planeRowStride[1]) + ((x / 2) * m_accessData.m_planePixelStride[1]); |
| androidBufferPixel = m_accessData.m_planeData[1] + offset; |
| uint16_t blue = *(reinterpret_cast<const uint16_t *>(androidBufferPixel)); |
| |
| // Plane 2 contains Cr information |
| // YCbCr_P010 is half size for Cr |
| offset = ((y / 2) * m_accessData.m_planeRowStride[2]) + ((x / 2) * m_accessData.m_planePixelStride[2]); |
| androidBufferPixel = m_accessData.m_planeData[2] + offset; |
| uint16_t red = *(reinterpret_cast<const uint16_t *>(androidBufferPixel)); |
| |
| // YCbCr_P010 does not have same comoponent size as m_cpuBuffer type (UNORM_INT_101010) |
| // We need to transform from YCbCr_P010 where data is stored in the higher bits of 16 bit values to UNORM_INT_101010 |
| |
| uint32_t redOffset = 22u; |
| uint32_t greenOffset = 12u; |
| uint32_t blueOffset = 2u; |
| uint32_t bitOffset = 6u; |
| uint32_t finalValue = 0u; |
| |
| finalValue |= static_cast<uint32_t>(blue >> bitOffset) << blueOffset; |
| finalValue |= static_cast<uint32_t>(green >> bitOffset) << greenOffset; |
| finalValue |= static_cast<uint32_t>(red >> bitOffset) << redOffset; |
| |
| *(reinterpret_cast<uint32_t *>(cpuBufferPixel)) = finalValue; |
| |
| break; |
| } |
| |
| case RAW10: |
| case RAW12: |
| DE_ASSERT(false); // Use compressed variation |
| break; |
| |
| default: |
| memcpy(cpuBufferPixel, androidBufferPixel, m_accessData.m_planePixelStride[0]); |
| } |
| } |
| } |
| } |
| |
| void AndroidHardwareBufferInstance::copyAndroidBufferToCpuBufferCompressed(tcu::CompressedTexture &cpuBuffer) const |
| { |
| // Running into this assertion means no locking was performed |
| DE_ASSERT(m_accessData.m_planeCount != 0); |
| |
| uint8_t *cpuBufferPixel = static_cast<uint8_t *>(cpuBuffer.getData()); |
| |
| for (uint32_t y = 0u; y < m_height; ++y) |
| { |
| for (uint32_t x = 0u; x < m_width; ++x) |
| { |
| uint32_t offset = (y * m_accessData.m_planeRowStride[0]) + (x * m_accessData.m_planePixelStride[0]); |
| const uint8_t *androidBufferPixel = m_accessData.m_planeData[0] + offset; |
| |
| switch (m_format) |
| { |
| case RAW10: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 1u); |
| |
| // Packed format with 4 pixels in 5 bytes |
| // Layout: https://developer.android.com/reference/android/graphics/ImageFormat#RAW10 |
| memcpy(cpuBufferPixel, androidBufferPixel, 5u); // Copy 4 pixels packed in 5 bytes |
| |
| // Advance 3 pixels so in total we advance 4 |
| x += 3u; |
| cpuBufferPixel += 5u; |
| |
| break; |
| } |
| |
| case RAW12: |
| { |
| DE_ASSERT(m_accessData.m_planeCount == 1u); |
| |
| // Packed format with 2 pixels in 3 bytes |
| // Layout: https://developer.android.com/reference/android/graphics/ImageFormat#RAW12 |
| memcpy(cpuBufferPixel, androidBufferPixel, 3u); // Copy 2 pixels packed in 3 bytes |
| |
| // Advance 1 pixels so in total we advance 2 |
| x += 1u; |
| cpuBufferPixel += 3u; |
| |
| break; |
| } |
| |
| default: |
| DE_ASSERT(false); // Use non-compressed variant |
| break; |
| } |
| } |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::isYuv(void) const |
| { |
| return isFormatYuv(m_format); |
| } |
| |
| bool AndroidHardwareBufferInstance::isRaw(void) const |
| { |
| return isFormatRaw(m_format); |
| } |
| |
| bool AndroidHardwareBufferInstance::hasDepth(void) const |
| { |
| switch (m_format) |
| { |
| case D16_UNORM: |
| case D24_UNORM: |
| case D24_UNORM_S8_UINT: |
| case D32_FLOAT: |
| case D32_FLOAT_S8_UINT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AndroidHardwareBufferInstance::hasStencil(void) const |
| { |
| switch (m_format) |
| { |
| case D24_UNORM_S8_UINT: |
| case D32_FLOAT_S8_UINT: |
| case S8_UINT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| } // namespace ExternalMemoryUtil |
| |
| } // namespace vkt |
| |
| #endif // CTS_USES_VULKANSC |