diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index b987e18ecb65..3c6ec5cca08d 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -233,7 +233,10 @@ if (FILAMENT_SUPPORTS_VULKAN) elseif (APPLE OR IOS) list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm) elseif (ANDROID) - list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp) + list(APPEND SRCS + include/backend/platforms/VulkanPlatformAndroid.h + src/vulkan/platform/VulkanPlatformAndroid.cpp + ) endif() endif() diff --git a/filament/backend/include/backend/platforms/VulkanPlatform.h b/filament/backend/include/backend/platforms/VulkanPlatform.h index 666260e6b7d7..57646247bc70 100644 --- a/filament/backend/include/backend/platforms/VulkanPlatform.h +++ b/filament/backend/include/backend/platforms/VulkanPlatform.h @@ -347,18 +347,20 @@ class VulkanPlatform : public Platform, utils::PrivateImplementation; - virtual ImageData createExternalImage(void* externalImage, + virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata); private: static ExtensionSet getSwapchainInstanceExtensions(); - static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage, + + static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage, VkDevice device); - static ImageData createExternalImageImpl(void* externalImage, VkDevice device, - const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata); + + static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage, + VkDevice device, const ExternalImageMetadata& metadata); // Platform dependent helper methods using SurfaceBundle = std::tuple; diff --git a/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h b/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h new file mode 100644 index 000000000000..ca6cd888aeed --- /dev/null +++ b/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H +#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H + +#include + +#include + +namespace filament::backend::fvkandroid { + +struct ExternalImageVulkanAndroid : public Platform::ExternalImage { + AHardwareBuffer* aHardwareBuffer = nullptr; + bool sRGB = false; + unsigned int width; // Texture width + unsigned int height; // Texture height + TextureFormat format; // Texture format + TextureUsage usage; // Texture usage flags + +protected: + ~ExternalImageVulkanAndroid() override; +}; + +Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, + bool sRGB) noexcept; + +} // namespace filament::backend::fvkandroid + +#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index bd44b8c7f326..5db4251033e8 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -560,14 +560,6 @@ void VulkanDriver::createTextureExternalImage2R(Handle th, Platform::ExternalImageHandleRef externalImage) { FVK_SYSTRACE_SCOPE(); - // FIXME: implement createTextureExternalImage2R -} - -void VulkanDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, - backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, - void* externalImage) { - FVK_SYSTRACE_SCOPE(); - const auto& metadata = mPlatform->getExternalImageMetadata(externalImage); if (metadata.isProtected) { usage |= backend::TextureUsage::PROTECTED; @@ -577,15 +569,23 @@ void VulkanDriver::createTextureExternalImageR(Handle th, backend::Sa assert_invariant(height == metadata.height); assert_invariant(fvkutils::getVkFormat(format) == metadata.format); - const auto& data = mPlatform->createExternalImage(externalImage, metadata); + const auto& data = mPlatform->createExternalImageData(externalImage, metadata); - auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), - mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format, - 1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool); + auto texture = resource_ptr::make(&mResourceManager, th, + mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format, + 1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool); texture.inc(); } +void VulkanDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, + backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, + void* externalImage) { + FVK_SYSTRACE_SCOPE(); + + // not supported in this backend +} + void VulkanDriver::createTextureExternalImagePlaneR(Handle th, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image, uint32_t plane) { diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index 5c9c0deda6a4..dd8ca248a340 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -978,13 +978,13 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept { } VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata( - void* externalImage) { + ExternalImageHandleRef externalImage) { return getExternalImageMetadataImpl(externalImage, mImpl->mDevice); } -VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage, - const ExternalImageMetadata& metadata) { - return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata); +VulkanPlatform::ImageData VulkanPlatform::createExternalImageData( + ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata) { + return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata); } #undef SWAPCHAIN_RET_FUNC diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp index 268f2a4d02d8..612c79290164 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp @@ -15,6 +15,10 @@ */ #include +#include +#include +#include + #include "vulkan/VulkanConstants.h" #include @@ -24,17 +28,44 @@ #include #include +#include + using namespace bluevk; namespace filament::backend { namespace { -void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format, - VkImageUsageFlags& usage, bool& isProtected) { + +VkFormat transformVkFormat(VkFormat format, bool sRGB) { + if (!sRGB) { + return format; + } + + switch (format) { + case VK_FORMAT_R8G8B8A8_UNORM: + format = VK_FORMAT_R8G8B8A8_SRGB; + break; + case VK_FORMAT_R8G8B8_UNORM: + format = VK_FORMAT_R8G8B8_SRGB; + break; + default: + break; + } + + return format; +} + +bool isProtectedFromUsage(uint64_t usage) { + return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false; +} + +std::pair getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, + bool sRGB) { + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageUsageFlags usage = 0; // Refer to "11.2.17. External Memory Handle Types" in the spec, and // Tables 13/14 for how the following derivation works. bool isDepthFormat = false; - isProtected = false; switch (desc.format) { case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: format = VK_FORMAT_R8G8B8A8_UNORM; @@ -82,6 +113,8 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format, format = VK_FORMAT_UNDEFINED; } + format = transformVkFormat(format, sRGB); + // The following only concern usage flags derived from Table 14. usage = 0; if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) { @@ -98,16 +131,13 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format, if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) { usage = VK_IMAGE_USAGE_STORAGE_BIT; } - if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) { - isProtected = true; - } + + return { format, usage }; } -VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer, - VkDevice device, const VkAllocationCallbacks* allocator, +VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device, VulkanPlatform::ExternalImageMetadata const& metadata) { VulkanPlatform::ImageData data; - AHardwareBuffer* buffer = static_cast(externalBuffer); // if external format we need to specifiy it in the allocation const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED; @@ -140,7 +170,7 @@ VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer, if (metadata.isProtected == false) imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - VkResult result = vkCreateImage(device, &imageInfo, allocator, &data.first); + VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateImage failed with error=" << static_cast(result); @@ -160,27 +190,57 @@ VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer, .pNext = &memoryDedicatedAllocateInfo, .allocationSize = metadata.allocationSize, .memoryTypeIndex = metadata.memoryTypeBits}; - result = vkAllocateMemory(device, &allocInfo, allocator, &data.second); + result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkAllocateMemory failed with error=" << static_cast(result); return data; } -}// namespace +} // namespace + +namespace fvkandroid { + +ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default; + +Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, + bool sRGB) noexcept { + if (__builtin_available(android 26, *)) { + AHardwareBuffer_Desc hardwareBufferDescription = {}; + AHardwareBuffer_describe(buffer, &hardwareBufferDescription); + + auto* const p = new (std::nothrow) ExternalImageVulkanAndroid; + p->aHardwareBuffer = const_cast(buffer); + p->sRGB = sRGB; + p->height = hardwareBufferDescription.height; + p->width = hardwareBufferDescription.width; + TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB); + p->format = textureFormat; + p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat); + return Platform::ExternalImageHandle{ p }; + } + + return Platform::ExternalImageHandle{}; +} + +} // namespace fvkandroid + +VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl( + ExternalImageHandleRef externalImage, VkDevice device) { + auto const* fvkExternalImage = + static_cast(externalImage.get()); -VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage, - VkDevice device) { ExternalImageMetadata metadata; - AHardwareBuffer* buffer = static_cast(externalImage); + AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer; if (__builtin_available(android 26, *)) { AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(buffer, &bufferDesc); metadata.width = bufferDesc.width; metadata.height = bufferDesc.height; metadata.layers = bufferDesc.layers; - - getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected); + metadata.isProtected = isProtectedFromUsage(bufferDesc.usage); + std::tie(metadata.format, metadata.usage) = + getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB); } // In the unprotected case add R/W capabilities if (metadata.isProtected == false) { @@ -197,20 +257,25 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm }; VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) - << "vkGetAndroidHardwareBufferProperties failed with error=" - << static_cast(result); - FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format) - << "mismatched image format for external image (AHB)"; + << "vkGetAndroidHardwareBufferProperties failed with error=" + << static_cast(result); + + VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB); + FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat) + << "mismatched image format( " << metadata.format << ") and queried format(" + << bufferPropertiesFormat << ") for external image (AHB)"; metadata.externalFormat = formatInfo.externalFormat; metadata.allocationSize = properties.allocationSize; metadata.memoryTypeBits = properties.memoryTypeBits; return metadata; } -VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage, - VkDevice device, const VkAllocationCallbacks* allocator, +VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl( + ExternalImageHandleRef externalImage, VkDevice device, const ExternalImageMetadata& metadata) { - ImageData data = allocateExternalImage(externalImage, device, allocator, metadata); + auto const* fvkExternalImage = + static_cast(externalImage.get()); + ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata); VkResult result = vkBindImageMemory(device, data.first, data.second, 0); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkBindImageMemory error=" << static_cast(result); diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm index 578bde3b117a..447c96fc9e5b 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm +++ b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm @@ -64,12 +64,12 @@ } VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl( - void* externalImage, VkDevice device) { + ExternalImageHandleRef externalImage, VkDevice device) { return {}; } -VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage, - VkDevice device, const VkAllocationCallbacks* allocator, +VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl( + ExternalImageHandleRef externalImage, VkDevice device, const ExternalImageMetadata& metadata) { return {}; } diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp index d7ae009724f5..33c40b25cfae 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp @@ -85,12 +85,12 @@ using namespace bluevk; namespace filament::backend { VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl( - void* externalImage, VkDevice device) { + ExternalImageHandleRef externalImage, VkDevice device) { return {}; } -VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage, - VkDevice device, const VkAllocationCallbacks* allocator, +VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl( + ExternalImageHandleRef externalImage, VkDevice device, const ExternalImageMetadata& metadata) { return {}; }