Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External Texture implementation for Vulkan #8488

Merged
merged 2 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion filament/backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
12 changes: 7 additions & 5 deletions filament/backend/include/backend/platforms/VulkanPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,18 +347,20 @@ class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatf
*/
uint32_t memoryTypeBits;
};
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);

using ImageData = std::pair<VkImage, VkDeviceMemory>;
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<VkSurfaceKHR, VkExtent2D>;
Expand Down
43 changes: 43 additions & 0 deletions filament/backend/include/backend/platforms/VulkanPlatformAndroid.h
Original file line number Diff line number Diff line change
@@ -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 <backend/Platform.h>

#include <android/hardware_buffer.h>

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
24 changes: 12 additions & 12 deletions filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,14 +560,6 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
Platform::ExternalImageHandleRef externalImage) {
FVK_SYSTRACE_SCOPE();

// FIXME: implement createTextureExternalImage2R
}

void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> 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;
Expand All @@ -577,15 +569,23 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> 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<VulkanTexture>::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<VulkanTexture>::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<HwTexture> 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<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane) {
Expand Down
8 changes: 4 additions & 4 deletions filament/backend/src/vulkan/platform/VulkanPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
113 changes: 89 additions & 24 deletions filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
#include <backend/platforms/VulkanPlatform.h>

#include <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatformAndroid.h>
#include <private/backend/BackendUtilsAndroid.h>

#include "vulkan/VulkanConstants.h"

#include <utils/Panic.h>
Expand All @@ -24,17 +28,44 @@
#include <android/hardware_buffer.h>
#include <android/native_window.h>

#include <utility>

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<VkFormat, VkImageUsageFlags> 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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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<AHardwareBuffer*>(externalBuffer);

// if external format we need to specifiy it in the allocation
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
Expand Down Expand Up @@ -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<int32_t>(result);

Expand All @@ -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<int32_t>(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<AHardwareBuffer*>(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<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());

VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
VkDevice device) {
ExternalImageMetadata metadata;
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(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) {
Expand All @@ -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<int32_t>(result);
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format)
<< "mismatched image format for external image (AHB)";
<< "vkGetAndroidHardwareBufferProperties failed with error="
<< static_cast<int32_t>(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<fvkandroid::ExternalImageVulkanAndroid const*>(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<int32_t>(result);
Expand Down
6 changes: 3 additions & 3 deletions filament/backend/src/vulkan/platform/VulkanPlatformApple.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
}
Expand Down
Loading