diff --git a/doc/classes/ExternalTexture.xml b/doc/classes/ExternalTexture.xml new file mode 100644 index 000000000000..6f27b62f249d --- /dev/null +++ b/doc/classes/ExternalTexture.xml @@ -0,0 +1,36 @@ + + + + Texture which displays the content of an external buffer. + + + Displays the content of an external buffer provided by the platform. + Requires the [url=https://registry.khronos.org/OpenGL/extensions/OES/OES_EGL_image_external.txt]OES_EGL_image_external[/url] extension (OpenGL) or [url=https://registry.khronos.org/vulkan/specs/1.1-extensions/html/vkspec.html#VK_ANDROID_external_memory_android_hardware_buffer]VK_ANDROID_external_memory_android_hardware_buffer[/url] extension (Vulkan). + [b]Note:[/b] This is currently only supported in Android builds. + + + + + + + + Returns the external texture ID. + Depending on your use case, you may need to pass this to platform APIs, for example, when creating an [code]android.graphics.SurfaceTexture[/code] on Android. + + + + + + + Sets the external buffer ID. + Depending on your use case, you may need to call this with data received from a platform API, for example, [code]SurfaceTexture.getHardwareBuffer()[/code] on Android. + + + + + + + External texture size. + + + diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 531151ca393f..7e3f646d2293 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -5660,7 +5660,10 @@ Cubemap sampler global shader parameter ([code]global uniform samplerCube ...[/code]). Exposed as a [Cubemap] in the editor UI. - + + External sampler global shader parameter ([code]global uniform samplerExternalOES ...[/code]). Exposed as a [ExternalTexture] in the editor UI. + + Represents the size of the [enum GlobalShaderParameterType] enum. diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 5a0f394db0be..b73debf04a27 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -189,6 +189,14 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant } builder.append("\n"); //make sure defines begin at newline + // Optional support for external textures. + if (GLES3::Config::get_singleton()->external_texture_supported) { + builder.append("#extension GL_OES_EGL_image_external : enable\n"); + builder.append("#extension GL_OES_EGL_image_external_essl3 : enable\n"); + } else { + builder.append("#define samplerExternalOES sampler2D\n"); + } + // Insert multiview extension loading, because it needs to appear before // any non-preprocessor code (like the "precision highp..." lines below). builder.append("#ifdef USE_MULTIVIEW\n"); diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index d6472c44c13e..4947d5d4ce72 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -138,6 +138,7 @@ Config::Config() { // These are GLES only rt_msaa_supported = extensions.has("GL_EXT_multisampled_render_to_texture"); rt_msaa_multiview_supported = extensions.has("GL_OVR_multiview_multisampled_render_to_texture"); + external_texture_supported = extensions.has("GL_OES_EGL_image_external_essl3"); if (multiview_supported) { eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR"); @@ -166,6 +167,13 @@ Config::Config() { rt_msaa_multiview_supported = false; } } + + if (external_texture_supported) { + eglEGLImageTargetTexture2DOES = (PFNEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); + if (eglEGLImageTargetTexture2DOES == nullptr) { + external_texture_supported = false; + } + } #endif force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index ff72fc5b5893..1de00094f0e3 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -45,6 +45,7 @@ typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, typedef void (*PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean); typedef void (*PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei); +typedef void (*PFNEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum, void *); #endif namespace GLES3 { @@ -91,6 +92,7 @@ class Config { bool rt_msaa_supported = false; bool rt_msaa_multiview_supported = false; bool multiview_supported = false; + bool external_texture_supported = false; // Adreno 3XX compatibility bool disable_particles_workaround = false; // set to 'true' to disable 'GPUParticles' @@ -104,6 +106,7 @@ class Config { PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr; PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr; PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr; + PFNEGLIMAGETARGETTEXTURE2DOESPROC eglEGLImageTargetTexture2DOES = nullptr; #endif static Config *get_singleton() { return singleton; }; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 7d5af48384c0..c29c741c2a16 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -675,6 +675,7 @@ static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = { GL_TEXTURE_3D, // TYPE_USAMPLER3D, GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBE, GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBEARRAY, + _GL_TEXTURE_EXTERNAL_OES, // TYPE_SAMPLEREXT GL_TEXTURE_2D, // TYPE_STRUCT }; @@ -946,6 +947,9 @@ void MaterialData::update_textures(const HashMap &p_paramet case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { ERR_PRINT_ONCE("Type: SamplerCubeArray not supported in GL Compatibility rendering backend, please use another type."); } break; + case ShaderLanguage::TYPE_SAMPLEREXT: { + gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_EXT); + } break; case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: @@ -1949,6 +1953,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture "sampler2DArray", "sampler3D", "samplerCube", + "samplerExternalOES" }; RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX; @@ -2661,7 +2666,11 @@ static void bind_uniforms_generic(const Vector &p_textures, const Vectortex_id); + GLenum target = target_from_type[texture_uniform.type]; + if (target == _GL_TEXTURE_EXTERNAL_OES && !GLES3::Config::get_singleton()->external_texture_supported) { + target = GL_TEXTURE_2D; + } + glBindTexture(target, texture->tex_id); if (texture->render_target) { texture->render_target->used_in_frame = true; } diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index bd824a076eff..27ba89aa5fa0 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -152,6 +152,11 @@ TextureStorage::TextureStorage() { texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_ANISO], image); } + { + default_gl_textures[DEFAULT_GL_TEXTURE_EXT] = texture_allocate(); + texture_external_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_EXT], 1, 1, 0); + } + { unsigned char pixel_data[4 * 4 * 4]; for (int i = 0; i < 16; i++) { @@ -769,6 +774,48 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref &p_im texture_set_data(p_texture, p_image); } +void TextureStorage::texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { + Texture texture; + texture.active = true; + texture.alloc_width = texture.width = p_width; + texture.alloc_height = texture.height = p_height; + texture.real_format = texture.format = Image::FORMAT_RGB8; + texture.type = Texture::TYPE_2D; + + if (GLES3::Config::get_singleton()->external_texture_supported) { + texture.target = _GL_TEXTURE_EXTERNAL_OES; + } else { + texture.target = GL_TEXTURE_2D; + } + + glGenTextures(1, &texture.tex_id); + glBindTexture(texture.target, texture.tex_id); + +#ifdef ANDROID_ENABLED + if (texture.target == _GL_TEXTURE_EXTERNAL_OES) { + if (p_external_buffer) { + GLES3::Config::get_singleton()->eglEGLImageTargetTexture2DOES(_GL_TEXTURE_EXTERNAL_OES, reinterpret_cast(p_external_buffer)); + } + texture.total_data_size = 0; + } else +#endif + { + // If external textures aren't supported, allocate an empty 1x1 texture. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + texture.total_data_size = 3; + } + + glTexParameteri(texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture External"); + texture_owner.initialize_rid(p_texture, texture); + + glBindTexture(texture.target, 0); +} + void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) { ERR_FAIL_COND(p_layers.is_empty()); @@ -930,6 +977,22 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector> & GLES3::Utilities::get_singleton()->texture_resize_data(tex->tex_id, tex->total_data_size); } +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->alloc_width = tex->width = p_width; + tex->alloc_height = tex->height = p_height; + +#ifdef ANDROID_ENABLED + if (tex->target == _GL_TEXTURE_EXTERNAL_OES && p_external_buffer) { + glBindTexture(_GL_TEXTURE_EXTERNAL_OES, tex->tex_id); + GLES3::Config::get_singleton()->eglEGLImageTargetTexture2DOES(_GL_TEXTURE_EXTERNAL_OES, reinterpret_cast(p_external_buffer)); + glBindTexture(_GL_TEXTURE_EXTERNAL_OES, 0); + } +#endif +} + void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL(tex); diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 26864c2f3b70..1472d58fa0a9 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -126,6 +126,7 @@ enum DefaultGLTexture { DEFAULT_GL_TEXTURE_3D_BLACK, DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE, DEFAULT_GL_TEXTURE_2D_UINT, + DEFAULT_GL_TEXTURE_EXT, DEFAULT_GL_TEXTURE_MAX }; @@ -512,12 +513,14 @@ class TextureStorage : public RendererTextureStorage { virtual void texture_2d_initialize(RID p_texture, const Ref &p_image) override; virtual void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) override; 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_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) 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_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_update(RID p_proxy, RID p_base) override; //these two APIs can be used together or in combination with the others. diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp index 8eab3fbea968..ae7c86a5e586 100644 --- a/editor/renames_map_3_to_4.cpp +++ b/editor/renames_map_3_to_4.cpp @@ -1518,7 +1518,6 @@ const char *RenamesMap3To4::class_renames[][2] = { { "EditorSceneImporterGLTF", "EditorSceneFormatImporterGLTF" }, { "EditorSpatialGizmo", "EditorNode3DGizmo" }, { "EditorSpatialGizmoPlugin", "EditorNode3DGizmoPlugin" }, - { "ExternalTexture", "ImageTexture" }, { "GIProbe", "VoxelGI" }, { "GIProbeData", "VoxelGIData" }, { "Generic6DOFJoint", "Generic6DOFJoint3D" }, diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 76678e609a9d..09227e260f11 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -117,6 +117,7 @@ #include "scene/resources/compressed_texture.h" #include "scene/resources/curve_texture.h" #include "scene/resources/environment.h" +#include "scene/resources/external_texture.h" #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/gradient_texture.h" @@ -926,6 +927,7 @@ void register_scene_types() { GDREGISTER_CLASS(GradientTexture2D); GDREGISTER_CLASS(AnimatedTexture); GDREGISTER_CLASS(CameraTexture); + GDREGISTER_CLASS(ExternalTexture); GDREGISTER_VIRTUAL_CLASS(TextureLayered); GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered); GDREGISTER_VIRTUAL_CLASS(Texture3D); diff --git a/scene/resources/external_texture.cpp b/scene/resources/external_texture.cpp new file mode 100644 index 000000000000..436bf0bb6f50 --- /dev/null +++ b/scene/resources/external_texture.cpp @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* external_texture.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "external_texture.h" +#include "drivers/gles3/storage/texture_storage.h" +#include "servers/rendering/rendering_server_globals.h" + +void ExternalTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &ExternalTexture::set_size); + ClassDB::bind_method(D_METHOD("get_external_texture_id"), &ExternalTexture::get_external_texture_id); + ClassDB::bind_method(D_METHOD("set_external_buffer_id", "external_buffer_id"), &ExternalTexture::set_external_buffer_id); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); +} + +uint64_t ExternalTexture::get_external_texture_id() const { + return RenderingServer::get_singleton()->texture_get_native_handle(texture); +} + +void ExternalTexture::set_size(const Size2 &p_size) { + if (p_size.width > 0 && p_size.height > 0 && p_size != size) { + size = p_size; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + emit_changed(); + } +} + +Size2 ExternalTexture::get_size() const { + return size; +} + +void ExternalTexture::set_external_buffer_id(uint64_t p_external_buffer) { + if (p_external_buffer != external_buffer) { + external_buffer = p_external_buffer; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + } +} + +int ExternalTexture::get_width() const { + return size.width; +} + +int ExternalTexture::get_height() const { + return size.height; +} + +bool ExternalTexture::has_alpha() const { + return false; +} + +RID ExternalTexture::get_rid() const { + return texture; +} + +ExternalTexture::ExternalTexture() { + texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height); +} + +ExternalTexture::~ExternalTexture() { + if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RenderingServer::get_singleton()->free(texture); + } +} diff --git a/scene/resources/external_texture.h b/scene/resources/external_texture.h new file mode 100644 index 000000000000..96bcd8d0fe46 --- /dev/null +++ b/scene/resources/external_texture.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* external_texture.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef EXTERNAL_TEXTURE_H +#define EXTERNAL_TEXTURE_H + +#include "scene/resources/texture.h" + +// External textures as defined by OES_EGL_image_external (GLES) or VK_ANDROID_external_memory_android_hardware_buffer (Vulkan). +class ExternalTexture : public Texture2D { + GDCLASS(ExternalTexture, Texture2D); + +private: + RID texture; + Size2 size = Size2(256, 256); + uint64_t external_buffer = 0; + +protected: + static void _bind_methods(); + +public: + uint64_t get_external_texture_id() const; + + virtual Size2 get_size() const override; + void set_size(const Size2 &p_size); + + void set_external_buffer_id(uint64_t p_external_buffer); + + virtual int get_width() const override; + virtual int get_height() const override; + + virtual RID get_rid() const override; + virtual bool has_alpha() const override; + + ExternalTexture(); + ~ExternalTexture(); +}; + +#endif // EXTERNAL_TEXTURE_H diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 609f19589fdb..2f7eaf873230 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -90,12 +90,14 @@ class TextureStorage : public RendererTextureStorage { }; virtual void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) override{}; 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_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) 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_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override{}; virtual void texture_proxy_update(RID p_proxy, RID p_base) override{}; //these two APIs can be used together or in combination with the others. diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index e6a745d3b44a..39c3e9b168a1 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -200,6 +200,8 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c #endif builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n"); + builder.append("#define samplerExternalOES sampler2D\n"); + builder.append("#define textureExternalOES texture2D\n"); } break; case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 9f390c99f913..3bfc1bd15ca1 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -1639,6 +1639,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture "sampler2DArray", "sampler3D", "samplerCube", + "samplerExternalOES", }; RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 81ab384edcec..e5a8dbb9b2b8 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1087,6 +1087,9 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format p_format texture_owner.initialize_rid(p_texture, texture); } +void TextureStorage::texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { +} + void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) { Texture *tex = texture_owner.get_or_null(p_base); ERR_FAIL_NULL(tex); @@ -1361,6 +1364,9 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector> & RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data); } +void TextureStorage::texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { +} + void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL(tex); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index d352690fff67..9de4ff7b6b91 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -491,12 +491,14 @@ class TextureStorage : public RendererTextureStorage { virtual void texture_2d_initialize(RID p_texture, const Ref &p_image) override; virtual void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) override; 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_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) 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_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_update(RID p_proxy, RID p_base) override; //these two APIs can be used together or in combination with the others. diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index fb4f4aa756ff..2dcdc3f2543d 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -162,6 +162,17 @@ class RenderingServerDefault : public RenderingServer { return ret; \ } +#define FUNCRIDTEX3(m_type, m_type1, m_type2, m_type3) \ + virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3) override { \ + RID ret = RSG::texture_storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \ + RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3); \ + } else { \ + command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3); \ + } \ + return ret; \ + } + #define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \ RID ret = RSG::texture_storage->texture_allocate(); \ @@ -177,6 +188,7 @@ class RenderingServerDefault : public RenderingServer { FUNCRIDTEX1(texture_2d, const Ref &) FUNCRIDTEX2(texture_2d_layered, const Vector> &, TextureLayeredType) FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector> &) + FUNCRIDTEX3(texture_external, int, int, uint64_t) FUNCRIDTEX1(texture_proxy, RID) // Called directly, not through the command queue. @@ -187,6 +199,7 @@ class RenderingServerDefault : public RenderingServer { //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> &) + FUNC4(texture_external_update, RID, int, int, uint64_t) FUNC2(texture_proxy_update, RID, RID) //these also go pass-through diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 5f97fa0c9b7d..3a0b9cf1580f 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -113,6 +113,8 @@ static int _get_datatype_alignment(SL::DataType p_type) { return 16; case SL::TYPE_SAMPLERCUBEARRAY: return 16; + case SL::TYPE_SAMPLEREXT: + return 16; case SL::TYPE_STRUCT: return 0; case SL::TYPE_MAX: { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5a3c5d2fd093..14bd3841dfa1 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -315,6 +315,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_USAMPLER3D, "usampler3D", KCF_SAMPLER_DATATYPE, {}, {} }, { TK_TYPE_SAMPLERCUBE, "samplerCube", KCF_SAMPLER_DATATYPE, {}, {} }, { TK_TYPE_SAMPLERCUBEARRAY, "samplerCubeArray", KCF_SAMPLER_DATATYPE, {}, {} }, + { TK_TYPE_SAMPLEREXT, "samplerExternalOES", KCF_SAMPLER_DATATYPE, {}, {} }, // interpolation qualifiers @@ -1027,7 +1028,8 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) { p_type == TK_TYPE_ISAMPLER3D || p_type == TK_TYPE_USAMPLER3D || p_type == TK_TYPE_SAMPLERCUBE || - p_type == TK_TYPE_SAMPLERCUBEARRAY); + p_type == TK_TYPE_SAMPLERCUBEARRAY || + p_type == TK_TYPE_SAMPLEREXT); } ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) { @@ -1162,6 +1164,8 @@ String ShaderLanguage::get_datatype_name(DataType p_type) { return "samplerCube"; case TYPE_SAMPLERCUBEARRAY: return "samplerCubeArray"; + case TYPE_SAMPLEREXT: + return "samplerExternalOES"; case TYPE_STRUCT: return "struct"; case TYPE_MAX: @@ -3169,6 +3173,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, // textureProj @@ -4482,7 +4488,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector &p_value, case ShaderLanguage::TYPE_USAMPLER2D: case ShaderLanguage::TYPE_USAMPLER3D: case ShaderLanguage::TYPE_SAMPLERCUBE: - case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: + case ShaderLanguage::TYPE_SAMPLEREXT: { // Texture types, likely not relevant here. break; } @@ -4707,6 +4714,17 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.hint_string = "Texture3D"; } } break; + case ShaderLanguage::TYPE_SAMPLEREXT: { + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + pi.hint = PROPERTY_HINT_ARRAY_TYPE; + pi.hint_string = MAKE_RESOURCE_TYPE_HINT("ExternalTexture"); + } else { + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "ExternalTexture"; + } + } break; case ShaderLanguage::TYPE_STRUCT: { // FIXME: Implement this. } break; @@ -4780,6 +4798,8 @@ uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) { return 16; case TYPE_SAMPLERCUBEARRAY: return 16; + case TYPE_SAMPLEREXT: + return 16; case TYPE_STRUCT: return 0; case TYPE_MAX: { @@ -4921,6 +4941,7 @@ ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) { TYPE_UINT, TYPE_FLOAT, TYPE_FLOAT, + TYPE_FLOAT, TYPE_VOID, }; @@ -4963,6 +4984,7 @@ int ShaderLanguage::get_cardinality(DataType p_type) { 1, 1, 1, + 1, }; static_assert(sizeof(cardinality_table) / sizeof(*cardinality_table) == TYPE_MAX); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index b0d579dfe763..48df77f6bbfc 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -91,6 +91,7 @@ class ShaderLanguage { TK_TYPE_USAMPLER3D, TK_TYPE_SAMPLERCUBE, TK_TYPE_SAMPLERCUBEARRAY, + TK_TYPE_SAMPLEREXT, TK_INTERPOLATION_FLAT, TK_INTERPOLATION_SMOOTH, TK_CONST, @@ -235,6 +236,7 @@ class ShaderLanguage { TYPE_USAMPLER3D, TYPE_SAMPLERCUBE, TYPE_SAMPLERCUBEARRAY, + TYPE_SAMPLEREXT, TYPE_STRUCT, TYPE_MAX }; diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 7388307ac0f1..cc77d0e8cb3a 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -69,12 +69,14 @@ class RendererTextureStorage { virtual void texture_2d_initialize(RID p_texture, const Ref &p_image) = 0; virtual void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) = 0; 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_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) = 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_external_update(RID p_proxy, int p_width, int p_height, uint64_t p_external_buffer) = 0; virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; //these two APIs can be used together or in combination with the others. diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index a1c05fa2e755..0ad56961c0c7 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3405,6 +3405,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLER2DARRAY); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLER3D); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLERCUBE); + BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLEREXT); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_MAX); /* Free */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 2b45b73f099e..a130ae0ba27e 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -137,12 +137,14 @@ class RenderingServer : public Object { virtual RID texture_2d_create(const Ref &p_image) = 0; virtual RID texture_2d_layered_create(const Vector> &p_layers, TextureLayeredType p_layered_type) = 0; 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_external_create(int p_width, int p_height, uint64_t p_external_buffer = 0) = 0; 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_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer = 0) = 0; virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0; // These two APIs can be used together or in combination with the others. @@ -1647,6 +1649,7 @@ class RenderingServer : public Object { GLOBAL_VAR_TYPE_SAMPLER2DARRAY, GLOBAL_VAR_TYPE_SAMPLER3D, GLOBAL_VAR_TYPE_SAMPLERCUBE, + GLOBAL_VAR_TYPE_SAMPLEREXT, GLOBAL_VAR_TYPE_MAX };