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

Expose a function to create textures from a native handle in the compatibility renderer #96928

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
24 changes: 24 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</description>
</method>
<method name="texture_create_from_native_handle">
<return type="RID" />
<param index="0" name="type" type="int" enum="RenderingServer.TextureType" />
<param index="1" name="format" type="int" enum="Image.Format" />
<param index="2" name="native_handle" type="int" />
<param index="3" name="width" type="int" />
<param index="4" name="height" type="int" />
<param index="5" name="depth" type="int" />
<param index="6" name="layers" type="int" default="1" />
<param index="7" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType" default="0" />
<description>
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.
</description>
</method>
<method name="texture_get_format" qualifiers="const">
<return type="int" enum="Image.Format" />
<param index="0" name="texture" type="RID" />
Expand Down Expand Up @@ -4311,6 +4326,15 @@
<constant name="MAX_MESH_SURFACES" value="256">
The maximum number of surfaces a mesh can have.
</constant>
<constant name="TEXTURE_TYPE_2D" value="0" enum="TextureType">
2D texture.
</constant>
<constant name="TEXTURE_TYPE_LAYERED" value="1" enum="TextureType">
Layered texture.
</constant>
<constant name="TEXTURE_TYPE_3D" value="2" enum="TextureType">
3D texture.
</constant>
<constant name="TEXTURE_LAYERED_2D_ARRAY" value="0" enum="TextureLayeredType">
Array of 2-dimensional textures (see [Texture2DArray]).
</constant>
Expand Down
18 changes: 10 additions & 8 deletions drivers/gles3/storage/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions drivers/gles3/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<Ref<Image>> &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<Image> &p_image, int p_layer = 0) override;
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
Vector<RID> 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,
Expand Down
4 changes: 2 additions & 2 deletions modules/webxr/webxr_interface_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/dummy/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ref<Image>> &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<Image> &p_image, int p_layer = 0) override{};
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
virtual void texture_proxy_update(RID p_proxy, RID p_base) override{};
Expand Down
189 changes: 189 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct this comment refers to texture_create_from_extension ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! This PR adds RenderingServer::texture_create_from_native_handle() which is implemented by both OpenGL and the rendering device renderers, but if you're using rendering device you can get more control by using the pre-existing RenderingDevice::texture_create_from_extension() which has more options. I put a similar note in the docs.

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<Image> &p_image, int p_layer, bool p_immediate) {
ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());

Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ref<Image>> &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<Image> &p_image, int p_layer = 0) override;
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override;
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
Expand Down
5 changes: 5 additions & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ class RenderingServerDefault : public RenderingServer {
FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &)
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<Image> &, int)
FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &)
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ref<Image>> &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<Image> &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0;
virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0;
Expand Down
5 changes: 5 additions & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Loading
Loading