diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index cea9a4cec43b..23bd63c8dd17 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3583,6 +3583,21 @@
[b]Note:[/b] The [param texture] must have the same width, height, depth and format as the current texture data. Otherwise, an error will be printed and the original texture won't be modified. If you need to use different width, height, depth or format, use [method texture_replace] instead.
+
+
+
+
+
+
+
+
+
+
+
+ Creates a texture based on a native handle that was created outside of Godot's renderer.
+ [b]Note:[/b] If using the rendering device renderer, using [method RenderingDevice.texture_create_from_extension] rather than this method is recommended. It will give you much more control over the texture's format and usage.
+
+
@@ -4311,6 +4326,15 @@
The maximum number of surfaces a mesh can have.
+
+ 2D texture.
+
+
+ Layered texture.
+
+
+ 3D texture.
+
Array of 2-dimensional textures (see [Texture2DArray]).
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 54012c20e93f..bd824a076eff 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -729,7 +729,7 @@ void TextureStorage::texture_free(RID p_texture) {
}
}
} else {
- must_free_data = t->tex_id != 0 && !t->is_external;
+ must_free_data = t->tex_id != 0 && !t->is_from_native_handle;
}
if (must_free_data) {
GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id);
@@ -874,26 +874,28 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
texture_owner.initialize_rid(p_texture, proxy_tex);
}
-RID TextureStorage::texture_create_external(GLES3::Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
+RID TextureStorage::texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
Texture texture;
texture.active = true;
- texture.is_external = true;
- texture.type = p_type;
+ texture.is_from_native_handle = true;
switch (p_type) {
- case Texture::TYPE_2D: {
+ case RS::TEXTURE_TYPE_2D: {
+ texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D;
} break;
- case Texture::TYPE_3D: {
+ case RS::TEXTURE_TYPE_3D: {
+ texture.type = Texture::TYPE_3D;
texture.target = GL_TEXTURE_3D;
} break;
- case Texture::TYPE_LAYERED: {
+ case RS::TEXTURE_TYPE_LAYERED: {
+ texture.type = Texture::TYPE_LAYERED;
texture.target = GL_TEXTURE_2D_ARRAY;
} break;
}
texture.real_format = texture.format = p_format;
- texture.tex_id = p_image;
+ texture.tex_id = p_native_handle;
texture.alloc_width = texture.width = p_width;
texture.alloc_height = texture.height = p_height;
texture.depth = p_depth;
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 5569abcc7326..26864c2f3b70 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -146,7 +146,7 @@ struct Texture {
RID self;
bool is_proxy = false;
- bool is_external = false;
+ bool is_from_native_handle = false;
bool is_render_target = false;
RID proxy_to;
@@ -209,7 +209,7 @@ struct Texture {
void copy_from(const Texture &o) {
proxy_to = o.proxy_to;
is_proxy = o.is_proxy;
- is_external = o.is_external;
+ is_from_native_handle = o.is_from_native_handle;
width = o.width;
height = o.height;
alloc_width = o.alloc_width;
@@ -514,7 +514,7 @@ class TextureStorage : public RendererTextureStorage {
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector[> &p_data) override;
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
- RID texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY);
+ virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) override;
virtual void texture_3d_update(RID p_texture, const Vector][> &p_data) override;
diff --git a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp
index de4a9e4b8e9a..caded14ca768 100644
--- a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp
@@ -240,8 +240,8 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
Vector texture_rids;
for (uint64_t i = 0; i < swapchain_length; i++) {
- RID texture_rid = texture_storage->texture_create_external(
- p_array_size == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED,
+ RID texture_rid = texture_storage->texture_create_from_native_handle(
+ p_array_size == 1 ? RS::TEXTURE_TYPE_2D : RS::TEXTURE_TYPE_LAYERED,
format,
images[i].image,
p_width,
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 78a9db9b19e8..352d495dd4b1 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -561,8 +561,8 @@ RID WebXRInterfaceJS::_get_texture(unsigned int p_texture_id) {
uint32_t view_count = godot_webxr_get_view_count();
Size2 texture_size = get_render_target_size();
- RID texture = texture_storage->texture_create_external(
- view_count == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED,
+ RID texture = texture_storage->texture_create_from_native_handle(
+ view_count == 1 ? RS::TEXTURE_TYPE_2D : RS::TEXTURE_TYPE_LAYERED,
Image::FORMAT_RGBA8,
p_texture_id,
(int)texture_size.width,
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index 43572b65e097..609f19589fdb 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -92,6 +92,8 @@ class TextureStorage : public RendererTextureStorage {
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector][> &p_data) override{};
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override{}; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override { return RID(); }
+
virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) override{};
virtual void texture_3d_update(RID p_texture, const Vector][> &p_data) override{};
virtual void texture_proxy_update(RID p_proxy, RID p_base) override{};
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index be29716f451a..81ab384edcec 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1108,6 +1108,195 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
tex->proxies.push_back(p_texture);
}
+// Note: We make some big assumptions about format and usage. If developers need more control,
+// they should use RD::texture_create_from_extension() instead.
+RID TextureStorage::texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
+ RD::TextureType type;
+ switch (p_type) {
+ case RS::TEXTURE_TYPE_2D:
+ type = RD::TEXTURE_TYPE_2D;
+ break;
+
+ case RS::TEXTURE_TYPE_3D:
+ type = RD::TEXTURE_TYPE_3D;
+ break;
+
+ case RS::TEXTURE_TYPE_LAYERED:
+ if (p_layered_type == RS::TEXTURE_LAYERED_2D_ARRAY) {
+ type = RD::TEXTURE_TYPE_2D_ARRAY;
+ } else if (p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP) {
+ type = RD::TEXTURE_TYPE_CUBE;
+ } else if (p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {
+ type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+ } else {
+ // Arbitrary fallback.
+ type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
+ break;
+
+ default:
+ // Arbitrary fallback.
+ type = RD::TEXTURE_TYPE_2D;
+ }
+
+ // Only a rough conversion - see note above.
+ RD::DataFormat format;
+ switch (p_format) {
+ case Image::FORMAT_L8:
+ case Image::FORMAT_R8:
+ format = RD::DATA_FORMAT_R8_UNORM;
+ break;
+
+ case Image::FORMAT_LA8:
+ case Image::FORMAT_RG8:
+ format = RD::DATA_FORMAT_R8G8_UNORM;
+ break;
+
+ case Image::FORMAT_RGB8:
+ format = RD::DATA_FORMAT_R8G8B8_UNORM;
+ break;
+
+ case Image::FORMAT_RGBA8:
+ format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+
+ case Image::FORMAT_RGBA4444:
+ format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16;
+ break;
+
+ case Image::FORMAT_RGB565:
+ format = RD::DATA_FORMAT_B5G6R5_UNORM_PACK16;
+ break;
+
+ case Image::FORMAT_RF:
+ format = RD::DATA_FORMAT_R32_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGF:
+ format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGBF:
+ format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGBAF:
+ format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ break;
+
+ case Image::FORMAT_RH:
+ format = RD::DATA_FORMAT_R16_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGH:
+ format = RD::DATA_FORMAT_R16G16_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGBH:
+ format = RD::DATA_FORMAT_R16G16B16_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGBAH:
+ format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ break;
+
+ case Image::FORMAT_RGBE9995:
+ format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ break;
+
+ case Image::FORMAT_DXT1:
+ format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_DXT3:
+ format = RD::DATA_FORMAT_BC2_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_DXT5:
+ format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_RGTC_R:
+ format = RD::DATA_FORMAT_BC4_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_RGTC_RG:
+ format = RD::DATA_FORMAT_BC5_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_BPTC_RGBA:
+ format = RD::DATA_FORMAT_BC7_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_BPTC_RGBF:
+ format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK;
+ break;
+
+ case Image::FORMAT_BPTC_RGBFU:
+ format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC:
+ format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_R11:
+ format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_R11S:
+ format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RG11:
+ format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RG11S:
+ format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RGB8:
+ format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RGBA8:
+ format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RGB8A1:
+ format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ETC2_RA_AS_RG:
+ format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_DXT5_RA_AS_RG:
+ format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ASTC_4x4:
+ case Image::FORMAT_ASTC_4x4_HDR:
+ format = RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK;
+ break;
+
+ case Image::FORMAT_ASTC_8x8:
+ case Image::FORMAT_ASTC_8x8_HDR:
+ format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK;
+ break;
+
+ default:
+ // Arbitrary fallback.
+ format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ }
+
+ // Assumed to be a color attachment - see note above.
+ uint64_t usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ return RD::get_singleton()->texture_create_from_extension(type, format, RD::TEXTURE_SAMPLES_1, usage_flags, p_native_handle, p_width, p_height, p_depth, p_layers);
+}
+
void TextureStorage::_texture_2d_update(RID p_texture, const Ref &p_image, int p_layer, bool p_immediate) {
ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 704f5fb1bdad..d352690fff67 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -493,6 +493,8 @@ class TextureStorage : public RendererTextureStorage {
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector][> &p_data) override;
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
+
virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) override;
virtual void texture_3d_update(RID p_texture, const Vector][> &p_data) override;
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 60fa546e164c..fb4f4aa756ff 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -179,6 +179,11 @@ class RenderingServerDefault : public RenderingServer {
FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector][> &)
FUNCRIDTEX1(texture_proxy, RID)
+ // Called directly, not through the command queue.
+ virtual RID texture_create_from_native_handle(TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, TextureLayeredType p_layered_type = TEXTURE_LAYERED_2D_ARRAY) override {
+ return RSG::texture_storage->texture_create_from_native_handle(p_type, p_format, p_native_handle, p_width, p_height, p_depth, p_layers, p_layered_type);
+ }
+
//these go through command queue if they are in another thread
FUNC3(texture_2d_update, RID, const Ref &, int)
FUNC2(texture_3d_update, RID, const Vector][> &)
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 72c4dd305bde..7388307ac0f1 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -71,6 +71,8 @@ class RendererTextureStorage {
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector][> &p_data) = 0;
virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) = 0;
+
virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Vector][> &p_data) = 0;
virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index f354e83893b2..b15435965ed7 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2239,6 +2239,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_2d_layered_create", "layers", "layered_type"), &RenderingServer::_texture_2d_layered_create);
ClassDB::bind_method(D_METHOD("texture_3d_create", "format", "width", "height", "depth", "mipmaps", "data"), &RenderingServer::_texture_3d_create);
ClassDB::bind_method(D_METHOD("texture_proxy_create", "base"), &RenderingServer::texture_proxy_create);
+ ClassDB::bind_method(D_METHOD("texture_create_from_native_handle", "type", "format", "native_handle", "width", "height", "depth", "layers", "layered_type"), &RenderingServer::texture_create_from_native_handle, DEFVAL(1), DEFVAL(TEXTURE_LAYERED_2D_ARRAY));
ClassDB::bind_method(D_METHOD("texture_2d_update", "texture", "image", "layer"), &RenderingServer::texture_2d_update);
ClassDB::bind_method(D_METHOD("texture_3d_update", "texture", "data"), &RenderingServer::_texture_3d_update);
@@ -2265,6 +2266,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_get_rd_texture", "texture", "srgb"), &RenderingServer::texture_get_rd_texture, DEFVAL(false));
ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture", "srgb"), &RenderingServer::texture_get_native_handle, DEFVAL(false));
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_LAYERED);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D);
+
BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY);
BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP);
BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP_ARRAY);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 62ca6b3b6dc6..2b45b73f099e 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -113,6 +113,12 @@ class RenderingServer : public Object {
/* TEXTURE API */
+ enum TextureType {
+ TEXTURE_TYPE_2D,
+ TEXTURE_TYPE_LAYERED,
+ TEXTURE_TYPE_3D,
+ };
+
enum TextureLayeredType {
TEXTURE_LAYERED_2D_ARRAY,
TEXTURE_LAYERED_CUBEMAP,
@@ -133,6 +139,8 @@ class RenderingServer : public Object {
virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector][> &p_data) = 0; //all slices, then all the mipmaps, must be coherent
virtual RID texture_proxy_create(RID p_base) = 0;
+ virtual RID texture_create_from_native_handle(TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, TextureLayeredType p_layered_type = TEXTURE_LAYERED_2D_ARRAY) = 0;
+
virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Vector][> &p_data) = 0;
virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0;
@@ -1793,6 +1801,7 @@ class RenderingServer : public Object {
};
// Make variant understand the enums.
+VARIANT_ENUM_CAST(RenderingServer::TextureType);
VARIANT_ENUM_CAST(RenderingServer::TextureLayeredType);
VARIANT_ENUM_CAST(RenderingServer::CubeMapLayer);
VARIANT_ENUM_CAST(RenderingServer::ShaderMode);
]