diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index a445006058cd..2c0bf59ad7dc 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -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); diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index d8381279ec83..301ada694d59 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -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; diff --git a/drivers/metal/rendering_device_driver_metal.h b/drivers/metal/rendering_device_driver_metal.h index 7c23624e43a5..270af6a1d2bf 100644 --- a/drivers/metal/rendering_device_driver_metal.h +++ b/drivers/metal/rendering_device_driver_metal.h @@ -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; diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index 9d691a0d2307..ad6222584572 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -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); } diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index 1efef5ad7748..5725b485a25a 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -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": diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index bd395f41e228..900d8ba5404e 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -35,6 +35,11 @@ #include "thirdparty/misc/smolv.h" #include "vulkan_hooks.h" +#if defined(ANDROID_ENABLED) && defined(__ANDROID_API__) && __ANDROID_API__ >= 26 +#include +#include +#endif + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define PRINT_NATIVE_COMMANDS 0 @@ -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); } @@ -981,7 +991,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVector= 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(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(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)); diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 81f4256941e1..77b67f1b92d1 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -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 }; @@ -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; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index e5a8dbb9b2b8..508c90ae1707 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -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) { @@ -1365,6 +1392,18 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector> & } 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) { diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index e322bba76878..72e2ab5f4a1c 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -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 &p_data) { return _texture_update(p_texture, p_layer, p_data, false, true); } @@ -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); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 1405f585b249..7d0523e63e0b 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -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 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 &p_data); Vector texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 97c84c9d05f9..9ba5ec116042 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -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;