Skip to content

Commit

Permalink
Add external texture support (Vulkan)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsnopek committed Sep 18, 2024
1 parent 6ed9781 commit 662f7f9
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 2 deletions.
4 changes: 4 additions & 0 deletions drivers/d3d12/rendering_device_driver_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,10 @@ RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(Tex
return TextureID(tex_info);
}

RDD::TextureID RenderingDeviceDriverD3D12::texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type) {
ERR_FAIL_V_MSG(RDD::TextureID(), "Not implemented.");
}

void RenderingDeviceDriverD3D12::texture_free(TextureID p_texture) {
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
VersatileResource::free(resources_allocator, tex_info);
Expand Down
1 change: 1 addition & 0 deletions drivers/d3d12/rendering_device_driver_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
virtual TextureID texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type = 0) override final;
virtual void texture_free(TextureID p_texture) override final;
virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
Expand Down
1 change: 1 addition & 0 deletions drivers/metal/rendering_device_driver_metal.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public
virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
virtual TextureID texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type = 0) override final;
virtual void texture_free(TextureID p_texture) override final;
virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
Expand Down
4 changes: 4 additions & 0 deletions drivers/metal/rendering_device_driver_metal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,10 @@ _FORCE_INLINE_ MTLSize mipmapLevelSizeFromSize(MTLSize p_size, NSUInteger p_leve
return rid::make(obj);
}

RDD::TextureID RenderingDeviceDriverMetal::texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type) {
ERR_FAIL_V_MSG(RDD::TextureID(), "not implemented");
}

void RenderingDeviceDriverMetal::texture_free(TextureID p_texture) {
rid::release(p_texture);
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/vulkan/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if env["use_volk"]:
env.Prepend(CPPPATH=[thirdparty_volk_dir])

if env["platform"] == "android":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"])
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR", "VK_ANDROID_external_memory_android_hardware_buffer"])
elif env["platform"] == "ios":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK", "VK_USE_PLATFORM_METAL_EXT"])
elif env["platform"] == "linuxbsd":
Expand Down
97 changes: 96 additions & 1 deletion drivers/vulkan/rendering_device_driver_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
#include "thirdparty/misc/smolv.h"
#include "vulkan_hooks.h"

#if defined(ANDROID_ENABLED) && defined(__ANDROID_API__) && __ANDROID_API__ >= 26
#include <android/hardware_buffer.h>
#include <vulkan/vulkan_android.h>
#endif

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

#define PRINT_NATIVE_COMMANDS 0
Expand Down Expand Up @@ -499,6 +504,11 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() {
_register_requested_device_extension(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
_register_requested_device_extension(VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, false);

#if defined(ANDROID_ENABLED) && defined(__ANDROID_API__) && __ANDROID_API__ >= 26
_register_requested_device_extension(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, false);
_register_requested_device_extension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, false);
#endif

if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
_register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true);
}
Expand Down Expand Up @@ -981,7 +991,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVector<VkDevice
vulkan_1_1_features.variablePointersStorageBuffer = 0;
vulkan_1_1_features.variablePointers = 0;
vulkan_1_1_features.protectedMemory = 0;
vulkan_1_1_features.samplerYcbcrConversion = 0;
vulkan_1_1_features.samplerYcbcrConversion = enabled_device_extension_names.has(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
vulkan_1_1_features.shaderDrawParameters = 0;
create_info_next = &vulkan_1_1_features;
} else {
Expand Down Expand Up @@ -1888,6 +1898,91 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(Tex
return TextureID(tex_info);
}

RDD::TextureID RenderingDeviceDriverVulkan::texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type) {
#if defined(ANDROID_ENABLED) && defined(__ANDROID_API__) && __ANDROID_API__ >= 26
if (p_external_buffer_type == 0) {
p_external_buffer_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
}
ERR_FAIL_COND_V_MSG(p_external_buffer_type != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, TextureID(), "Unknown external buffer type.");
ERR_FAIL_COND_V_MSG(!enabled_device_extension_names.has(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME), TextureID(), "VK_ANDROID_external_memory_android_hardware_buffer extension is required to create an external texture");
ERR_FAIL_COND_V_MSG(!enabled_device_extension_names.has(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME), TextureID(), "VK_KHR_sampler_ycbcr_conversion extension is required to create an external texture");

AHardwareBuffer *hardware_buffer = reinterpret_cast<AHardwareBuffer *>(p_external_buffer);
VkResult err;

AHardwareBuffer_Desc buffer_desc = {};
AHardwareBuffer_describe(hardware_buffer, &buffer_desc);

VkAndroidHardwareBufferFormatPropertiesANDROID format_info = {};
format_info.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;

VkAndroidHardwareBufferPropertiesANDROID properties = {};
properties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
properties.pNext = &format_info;

err = vkGetAndroidHardwareBufferPropertiesANDROID(vk_device, hardware_buffer, &properties);
ERR_FAIL_COND_V_MSG(err, TextureID(), "vkGetAndroidHardwareBufferPropertiesANDROID failed with error " + itos(err) + ".");

VkExternalFormatANDROID external_format = {};
external_format.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
external_format.externalFormat = format_info.externalFormat;

VkExternalMemoryImageCreateInfo external_create_info = {};
external_create_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
external_create_info.pNext = &external_format;
external_create_info.handleTypes = p_external_buffer_type;

VkImageCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
create_info.pNext = &external_create_info;
create_info.flags = 0u;
create_info.imageType = VK_IMAGE_TYPE_2D;
create_info.format = format_info.format;
create_info.extent.width = buffer_desc.width;
create_info.extent.height = buffer_desc.height;
create_info.extent.depth = 1;
create_info.mipLevels = 1;
create_info.arrayLayers = 1;
create_info.samples = VK_SAMPLE_COUNT_1_BIT;
create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

VkImage vk_image = VK_NULL_HANDLE;
err = vkCreateImage(vk_device, &create_info, nullptr, &vk_image);
ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImage failed with error " + itos(err) + ".");

// @todo Finish implementing this!
// @see https://github.com/google-ar/arcore-android-sdk/blob/main/samples/hello_ar_vulkan_c/app/src/main/cpp/vulkan_handler.cc

/*
VkImportAndroidHardwareBufferInfoANDROID android_hardware_buffer_info = {};
android_hardware_buffer_info.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
android_hardware_buffer_info.buffer = hardware_buffer;
VkMemoryDedicatedAllocateInfo memory_dedicated_allocate_info = {};
memory_dedicated_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
memory_dedicated_allocate_info.pNext = &android_hardware_buffer_info;
memory_dedicated_allocate_info.image = vk_image;
memory_dedicated_allocate_info.buffer = VK_NULL_HANDLE;
*/

TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
tex_info->vk_image = vk_image;
//tex_info->vk_view = vk_image_view;
tex_info->rd_format = DATA_FORMAT_A8B8G8R8_UNORM_PACK32;
tex_info->vk_create_info = create_info;
//tex_info->vk_view_create_info = image_view_create_info;
//tex_info->allocation.handle = allocation;
//vmaGetAllocationInfo(allocator, tex_info->allocation.handle, &tex_info->allocation.info);

return TextureID(tex_info);
#else
ERR_FAIL_V_MSG(RDD::TextureID(), "Not implemented.");
#endif
}

void RenderingDeviceDriverVulkan::texture_free(TextureID p_texture) {
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
vkDestroyImageView(vk_device, tex_info->vk_view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW));
Expand Down
4 changes: 4 additions & 0 deletions drivers/vulkan/rendering_device_driver_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
} allocation; // All 0/null if just a view.
#ifdef DEBUG_ENABLED
bool created_from_extension = false;
#endif
#if defined(ANDROID_ENABLED) && defined(__ANDROID_API__) && __ANDROID_API__ >= 26
VkSamplerYcbcrConversion ycbcr_conversion = VK_NULL_HANDLE;
#endif
};

Expand All @@ -225,6 +228,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
virtual TextureID texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type = 0) override final;
virtual void texture_free(TextureID p_texture) override final;
virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
Expand Down
39 changes: 39 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,33 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format p_format
}

void TextureStorage::texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) {
Texture texture;

texture.type = TextureStorage::TYPE_2D;

texture.width = p_width;
texture.height = p_height;
texture.layers = 1;
texture.mipmaps = 1;
texture.depth = 1;
texture.format = Image::FORMAT_RGB8;
texture.validated_format = Image::FORMAT_RGB8;

texture.rd_type = RD::TEXTURE_TYPE_2D;
texture.rd_format = RD::DATA_FORMAT_A8B8G8R8_UNORM_PACK32;
texture.rd_format_srgb = RD::DATA_FORMAT_A8B8G8R8_SRGB_PACK32;

texture.width_2d = texture.width;
texture.height_2d = texture.height;
texture.is_render_target = false;
texture.is_proxy = false;

if (p_external_buffer) {
texture.rd_texture = RD::get_singleton()->texture_create_external(p_width, p_height, p_external_buffer);
ERR_FAIL_COND(texture.rd_texture.is_null());
}

texture_owner.initialize_rid(p_texture, texture);
}

void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
Expand Down Expand Up @@ -1365,6 +1392,18 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &
}

void TextureStorage::texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL(tex);

tex->width = p_width;
tex->height = p_height;

if (p_external_buffer) {
if (tex->rd_texture.is_valid()) {
RD::get_singleton()->free(tex->rd_texture);
}
tex->rd_texture = RD::get_singleton()->texture_create_external(p_width, p_height, p_external_buffer);
}
}

void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
Expand Down
30 changes: 30 additions & 0 deletions servers/rendering/rendering_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,35 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
return id;
}

RID RenderingDevice::texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type) {
_THREAD_SAFE_METHOD_

Texture texture;
texture.type = TEXTURE_TYPE_2D;
texture.format = DATA_FORMAT_A8B8G8R8_UNORM_PACK32;
texture.samples = TEXTURE_SAMPLES_1;
texture.width = p_width;
texture.height = p_height;
texture.depth = 1;
texture.layers = 1;
texture.mipmaps = 1;
texture.usage_flags = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
texture.base_mipmap = 0;
texture.base_layer = 0;
texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);

texture.driver_id = driver->texture_create_external(p_width, p_height, p_external_buffer, p_external_buffer_type);
ERR_FAIL_COND_V(!texture.driver_id, RID());

RID id = texture_owner.make_rid(texture);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif

return id;
}

Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) {
return _texture_update(p_texture, p_layer, p_data, false, true);
}
Expand Down Expand Up @@ -5940,6 +5969,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared);
ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D));
ClassDB::bind_method(D_METHOD("texture_create_from_extension", "type", "format", "samples", "usage_flags", "image", "width", "height", "depth", "layers"), &RenderingDevice::texture_create_from_extension);
ClassDB::bind_method(D_METHOD("texture_create_external", "width", "height", "external_buffer", "external_buffer_type"), &RenderingDevice::texture_create_external, DEFVAL(0));

ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data"), &RenderingDevice::texture_update);
ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data);
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/rendering_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ class RenderingDevice : public RenderingDeviceCommons {
RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0);
RID texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type = 0);
Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data);
Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush

Expand Down
1 change: 1 addition & 0 deletions servers/rendering/rendering_device_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class RenderingDeviceDriver : public RenderingDeviceCommons {
// texture_create_shared_*() can only use original, non-view textures as original. RenderingDevice is responsible for ensuring that.
virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) = 0;
virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) = 0;
virtual TextureID texture_create_external(int p_width, int p_height, uint64_t p_external_buffer, uint64_t p_external_buffer_type = 0) = 0;
virtual void texture_free(TextureID p_texture) = 0;
virtual uint64_t texture_get_allocation_size(TextureID p_texture) = 0;
virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) = 0;
Expand Down

0 comments on commit 662f7f9

Please sign in to comment.