Skip to content

Commit 3b6fe6a

Browse files
committed
External Texture implementation for Vulkan
Add support for the new createTextureExternalImage2R API instead of createTextureExternalImageR. Add the support to import AHardwareBuffer objects into Vulkan in Android.
1 parent 0b5f95b commit 3b6fe6a

8 files changed

+236
-48
lines changed

filament/backend/CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ if (FILAMENT_SUPPORTS_VULKAN)
233233
elseif (APPLE OR IOS)
234234
list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm)
235235
elseif (ANDROID)
236-
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp)
236+
list(APPEND SRCS
237+
include/backend/platforms/VulkanPlatformAndroid.h
238+
src/vulkan/platform/VulkanPlatformAndroid.cpp
239+
)
237240
endif()
238241
endif()
239242

filament/backend/include/backend/platforms/VulkanPlatform.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -347,18 +347,20 @@ class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatf
347347
*/
348348
uint32_t memoryTypeBits;
349349
};
350-
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
350+
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
351351

352352
using ImageData = std::pair<VkImage, VkDeviceMemory>;
353-
virtual ImageData createExternalImage(void* externalImage,
353+
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
354354
const ExternalImageMetadata& metadata);
355355

356356
private:
357357
static ExtensionSet getSwapchainInstanceExtensions();
358-
static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage,
358+
359+
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
359360
VkDevice device);
360-
static ImageData createExternalImageImpl(void* externalImage, VkDevice device,
361-
const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata);
361+
362+
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
363+
VkDevice device, const ExternalImageMetadata& metadata);
362364

363365
// Platform dependent helper methods
364366
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
18+
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
19+
20+
#include <backend/Platform.h>
21+
22+
#include <android/hardware_buffer.h>
23+
24+
namespace filament::backend::fvkandroid {
25+
26+
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
27+
AHardwareBuffer *aHardwareBuffer = nullptr;
28+
bool sRGB = false;
29+
unsigned int width; // Texture width
30+
unsigned int height; // Texture height
31+
TextureFormat format; // Texture format
32+
TextureUsage usage; // Texture usage flags
33+
34+
protected:
35+
~ExternalImageVulkanAndroid() override;
36+
};
37+
38+
Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(
39+
AHardwareBuffer const *buffer, bool sRGB) noexcept;
40+
41+
} // namespace filament::backend::fvkandroid
42+
43+
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H

filament/backend/src/vulkan/VulkanDriver.cpp

+12-12
Original file line numberDiff line numberDiff line change
@@ -560,14 +560,6 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
560560
Platform::ExternalImageHandleRef externalImage) {
561561
FVK_SYSTRACE_SCOPE();
562562

563-
// FIXME: implement createTextureExternalImage2R
564-
}
565-
566-
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
567-
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
568-
void* externalImage) {
569-
FVK_SYSTRACE_SCOPE();
570-
571563
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
572564
if (metadata.isProtected) {
573565
usage |= backend::TextureUsage::PROTECTED;
@@ -577,15 +569,23 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
577569
assert_invariant(height == metadata.height);
578570
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
579571

580-
const auto& data = mPlatform->createExternalImage(externalImage, metadata);
572+
const auto& data = mPlatform->createExternalImageData(externalImage, metadata);
581573

582-
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
583-
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
584-
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
574+
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th,
575+
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
576+
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
585577

586578
texture.inc();
587579
}
588580

581+
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
582+
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
583+
void* externalImage) {
584+
FVK_SYSTRACE_SCOPE();
585+
586+
// not supported in this backend
587+
}
588+
589589
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
590590
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
591591
void* image, uint32_t plane) {

filament/backend/src/vulkan/platform/VulkanPlatform.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -978,13 +978,13 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
978978
}
979979

980980
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
981-
void* externalImage) {
981+
ExternalImageHandleRef externalImage) {
982982
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
983983
}
984984

985-
VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage,
986-
const ExternalImageMetadata& metadata) {
987-
return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata);
985+
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
986+
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata) {
987+
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata);
988988
}
989989

990990
#undef SWAPCHAIN_RET_FUNC

filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp

+160-20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
#include <backend/platforms/VulkanPlatform.h>
1717

18+
#include <backend/DriverEnums.h>
19+
#include <backend/platforms/VulkanPlatformAndroid.h>
20+
1821
#include "vulkan/VulkanConstants.h"
1922

2023
#include <utils/Panic.h>
@@ -24,17 +27,43 @@
2427
#include <android/hardware_buffer.h>
2528
#include <android/native_window.h>
2629

30+
#include <utility>
31+
2732
using namespace bluevk;
2833

2934
namespace filament::backend {
3035

3136
namespace {
32-
void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
33-
VkImageUsageFlags& usage, bool& isProtected) {
37+
38+
VkFormat transformVkFormat(VkFormat format, bool sRGB) {
39+
if (!sRGB) {
40+
return format;
41+
}
42+
43+
switch (format) {
44+
case VK_FORMAT_R8G8B8A8_UNORM:
45+
format = VK_FORMAT_R8G8B8A8_SRGB;
46+
break;
47+
case VK_FORMAT_R8G8B8_UNORM:
48+
format = VK_FORMAT_R8G8B8_SRGB;
49+
break;
50+
default:
51+
break;
52+
}
53+
54+
return format;
55+
}
56+
57+
bool isProtectedFromUsage(uint64_t usage) {
58+
return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false;
59+
}
60+
61+
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, bool sRGB) {
62+
VkFormat format = VK_FORMAT_UNDEFINED;
63+
VkImageUsageFlags usage = 0;
3464
// Refer to "11.2.17. External Memory Handle Types" in the spec, and
3565
// Tables 13/14 for how the following derivation works.
3666
bool isDepthFormat = false;
37-
isProtected = false;
3867
switch (desc.format) {
3968
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
4069
format = VK_FORMAT_R8G8B8A8_UNORM;
@@ -82,6 +111,8 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
82111
format = VK_FORMAT_UNDEFINED;
83112
}
84113

114+
format = transformVkFormat(format, sRGB);
115+
85116
// The following only concern usage flags derived from Table 14.
86117
usage = 0;
87118
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
@@ -98,16 +129,89 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
98129
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
99130
usage = VK_IMAGE_USAGE_STORAGE_BIT;
100131
}
101-
if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
102-
isProtected = true;
132+
133+
return {format, usage};
134+
}
135+
136+
TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept {
137+
if (isSrgbTransfer) {
138+
switch (format) {
139+
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
140+
return TextureFormat::SRGB8;
141+
default:
142+
return TextureFormat::SRGB8_A8;
143+
}
144+
}
145+
switch (format) {
146+
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
147+
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
148+
return TextureFormat::RGBA8;
149+
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
150+
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
151+
return TextureFormat::RGB8;
152+
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
153+
return TextureFormat::RGB565;
154+
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
155+
return TextureFormat::RGBA16F;
156+
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
157+
return TextureFormat::RGB10_A2;
158+
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
159+
return TextureFormat::DEPTH16;
160+
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
161+
return TextureFormat::DEPTH24;
162+
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
163+
return TextureFormat::DEPTH24_STENCIL8;
164+
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
165+
return TextureFormat::DEPTH32F;
166+
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
167+
return TextureFormat::DEPTH32F_STENCIL8;
168+
case AHARDWAREBUFFER_FORMAT_S8_UINT:
169+
return TextureFormat::STENCIL8;
170+
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
171+
return TextureFormat::R8;
172+
default:
173+
return TextureFormat::UNUSED;
174+
}
175+
}
176+
177+
TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept {
178+
TextureUsage usageFlags = TextureUsage::NONE;
179+
180+
if (usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
181+
usageFlags |= TextureUsage::SAMPLEABLE;
182+
}
183+
184+
if (usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
185+
if (isDepthFormat(format)) {
186+
usageFlags |= TextureUsage::DEPTH_ATTACHMENT;
187+
}
188+
if (isStencilFormat(format)) {
189+
usageFlags |= TextureUsage::STENCIL_ATTACHMENT;
190+
}
191+
if (isColorFormat(format)) {
192+
usageFlags |= TextureUsage::COLOR_ATTACHMENT;
193+
}
194+
}
195+
196+
if (usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
197+
usageFlags |= TextureUsage::UPLOADABLE;
198+
}
199+
200+
if (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
201+
usageFlags |= TextureUsage::PROTECTED;
202+
}
203+
204+
if (usageFlags == TextureUsage::NONE) {
205+
usageFlags = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
103206
}
207+
208+
return usageFlags;
104209
}
105210

106-
VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
211+
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer,
107212
VkDevice device, const VkAllocationCallbacks* allocator,
108213
VulkanPlatform::ExternalImageMetadata const& metadata) {
109214
VulkanPlatform::ImageData data;
110-
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalBuffer);
111215

112216
// if external format we need to specifiy it in the allocation
113217
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
@@ -167,20 +271,50 @@ VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
167271
return data;
168272
}
169273

170-
}// namespace
274+
} // namespace
275+
276+
namespace fvkandroid {
277+
278+
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
279+
280+
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer,
281+
bool sRGB) noexcept {
282+
if (__builtin_available(android 26, *)) {
283+
AHardwareBuffer_Desc hardwareBufferDescription = {};
284+
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
285+
286+
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
287+
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
288+
p->sRGB = sRGB;
289+
p->height = hardwareBufferDescription.height;
290+
p->width = hardwareBufferDescription.width;
291+
TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
292+
p->format = textureFormat;
293+
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
294+
return Platform::ExternalImageHandle{p};
295+
}
296+
297+
return Platform::ExternalImageHandle{};
298+
}
299+
300+
}
301+
302+
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
303+
ExternalImageHandleRef externalImage, VkDevice device) {
304+
auto const *fvkExternalImage =
305+
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
171306

172-
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
173-
VkDevice device) {
174307
ExternalImageMetadata metadata;
175-
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalImage);
308+
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
176309
if (__builtin_available(android 26, *)) {
177310
AHardwareBuffer_Desc bufferDesc;
178311
AHardwareBuffer_describe(buffer, &bufferDesc);
179312
metadata.width = bufferDesc.width;
180313
metadata.height = bufferDesc.height;
181314
metadata.layers = bufferDesc.layers;
182-
183-
getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected);
315+
metadata.isProtected = isProtectedFromUsage(bufferDesc.usage);
316+
std::tie(metadata.format, metadata.usage) = getVKFormatAndUsage(bufferDesc,
317+
fvkExternalImage->sRGB);
184318
}
185319
// In the unprotected case add R/W capabilities
186320
if (metadata.isProtected == false) {
@@ -197,20 +331,26 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
197331
};
198332
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
199333
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
200-
<< "vkGetAndroidHardwareBufferProperties failed with error="
201-
<< static_cast<int32_t>(result);
202-
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format)
203-
<< "mismatched image format for external image (AHB)";
334+
<< "vkGetAndroidHardwareBufferProperties failed with error="
335+
<< static_cast<int32_t>(result);
336+
337+
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
338+
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
339+
<< "mismatched image format( " << metadata.format << ") and queried format("
340+
<< bufferPropertiesFormat << ") for external image (AHB)";
204341
metadata.externalFormat = formatInfo.externalFormat;
205342
metadata.allocationSize = properties.allocationSize;
206343
metadata.memoryTypeBits = properties.memoryTypeBits;
207344
return metadata;
208345
}
209346

210-
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
211-
VkDevice device, const VkAllocationCallbacks* allocator,
347+
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
348+
ExternalImageHandleRef externalImage, VkDevice device,
212349
const ExternalImageMetadata& metadata) {
213-
ImageData data = allocateExternalImage(externalImage, device, allocator, metadata);
350+
auto const* fvkExternalImage =
351+
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
352+
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer,
353+
device, VKALLOC, metadata);
214354
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
215355
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
216356
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);

0 commit comments

Comments
 (0)