Merge pull request #105701 from ColinSORourke/DrawableTexture

Implement DrawableTextures
This commit is contained in:
Thaddeus Crews 2026-01-30 09:32:05 -06:00
commit fd6e80d4e9
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
46 changed files with 2417 additions and 10 deletions

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BlitMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A material that processes blit calls to a DrawableTexture.
</brief_description>
<description>
A material resource that can be used by DrawableTextures when processing blit calls to draw.
</description>
<tutorials>
</tutorials>
<members>
<member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="BlitMaterial.BlendMode" default="0">
The manner in which the newly blitted texture is blended with the original DrawableTexture.
</member>
</members>
<constants>
<constant name="BLEND_MODE_MIX" value="0" enum="BlendMode">
Mix blending mode. Colors are assumed to be independent of the alpha (opacity) value.
</constant>
<constant name="BLEND_MODE_ADD" value="1" enum="BlendMode">
Additive blending mode.
</constant>
<constant name="BLEND_MODE_SUB" value="2" enum="BlendMode">
Subtractive blending mode.
</constant>
<constant name="BLEND_MODE_MUL" value="3" enum="BlendMode">
Multiplicative blending mode.
</constant>
<constant name="BLEND_MODE_DISABLED" value="4" enum="BlendMode">
No blending mode, direct color copy.
</constant>
</constants>
</class>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DrawableTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D texture that supports drawing to itself via Blit calls.
</brief_description>
<description>
A 2D texture that can be modified via blit calls, copying from a target texture to itself. Primarily intended to be managed in code, a user must call [method setup] to initialize the state before drawing. Each [method blit_rect] call takes at least a rectangle, the area to draw to, and another texture, what to be drawn. The draw calls use a Texture_Blit Shader to process and calculate the result, pixel by pixel. Users can supply their own ShaderMaterial with custom Texture_Blit shaders for more complex behaviors.
</description>
<tutorials>
</tutorials>
<methods>
<method name="blit_rect" experimental="This function and its parameters are likely to change in the 4.7 Dev Cycle">
<return type="void" />
<param index="0" name="rect" type="Rect2i" />
<param index="1" name="source" type="Texture2D" />
<param index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<param index="3" name="mipmap" type="int" default="0" />
<param index="4" name="material" type="Material" default="null" />
<description>
Draws to given [param rect] on this texture by copying from the given [param source]. A [param modulate] color can be passed in for the shader to use, but defaults to White. The [param mipmap] value can specify a draw to a lower mipmap level. The [param material] parameter can take a ShaderMaterial with a TextureBlit Shader for custom drawing behavior.
</description>
</method>
<method name="blit_rect_multi" experimental="This function and its parameters are likely to change in the 4.7 Dev Cycle">
<return type="void" />
<param index="0" name="rect" type="Rect2i" />
<param index="1" name="sources" type="Texture2D[]" />
<param index="2" name="extra_targets" type="DrawableTexture2D[]" />
<param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<param index="4" name="mipmap" type="int" default="0" />
<param index="5" name="material" type="Material" default="null" />
<description>
Draws to the given [param rect] on this texture, as well as on up to 3 DrawableTexture [param extra_targets]. All [param extra_targets] must be the same size and DrawableFormat as the original target, otherwise the Shader may fail. Expects up to 4 Texture [param sources], but will replace missing [param sources] with default Black Textures.
</description>
</method>
<method name="generate_mipmaps">
<return type="void" />
<description>
Re-calculates the mipmaps for this texture on demand.
</description>
</method>
<method name="setup" experimental="This function and its parameters are likely to change in the 4.7 Dev Cycle">
<return type="void" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
<param index="2" name="format" type="int" enum="DrawableTexture2D.DrawableFormat" />
<param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<param index="4" name="use_mipmaps" type="bool" default="false" />
<description>
Initializes the DrawableTexture to a White texture of the given [param width], [param height], and [param format].
</description>
</method>
</methods>
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
</members>
<constants>
<constant name="DRAWABLE_FORMAT_RGBA8" value="0" enum="DrawableFormat">
OpenGL texture format RGBA with four components, each with a bitdepth of 8.
</constant>
<constant name="DRAWABLE_FORMAT_RGBA8_SRGB" value="1" enum="DrawableFormat">
OpenGL texture format RGBA with four components, each with a bitdepth of 8.
When drawn to, an sRGB to linear color space conversion is performed.
</constant>
<constant name="DRAWABLE_FORMAT_RGBAH" value="2" enum="DrawableFormat">
OpenGL texture format GL_RGBA16F where there are four components, each a 16-bit "half-precision" floating-point value.
</constant>
<constant name="DRAWABLE_FORMAT_RGBAF" value="3" enum="DrawableFormat">
OpenGL texture format GL_RGBA32F where there are four components, each a 32-bit floating-point value.
</constant>
</constants>
</class>

View file

@ -3878,6 +3878,45 @@
[b]Note:[/b] If using only the rendering device renderer, it's recommend to use [method RenderingDevice.texture_create_from_extension] together with [method RenderingServer.texture_rd_create], rather than this method. This way, the texture's format and usage can be controlled more effectively.
</description>
</method>
<method name="texture_drawable_blit_rect">
<return type="void" />
<param index="0" name="textures" type="RID[]" />
<param index="1" name="rect" type="Rect2i" />
<param index="2" name="material" type="RID" />
<param index="3" name="modulate" type="Color" />
<param index="4" name="source_textures" type="RID[]" />
<param index="5" name="to_mipmap" type="int" default="0" />
<description>
Draws to [param rect] on up to 4 given Drawable [param textures], using a TextureBlit Shader from [param material]. [param modulate] and up to 4 [param source_textures] are uniforms for the Shader to process with. [param to_mipmap] can specify to perform this draw to a lower mipmap level.
[b]Note:[/b] All [param textures] must be the same size and format.
</description>
</method>
<method name="texture_drawable_create">
<return type="RID" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
<param index="2" name="format" type="int" enum="RenderingServer.TextureDrawableFormat" />
<param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<param index="4" name="with_mipmaps" type="bool" default="false" />
<description>
Creates a 2-dimensional texture and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]texture_drawable*[/code] RenderingServer functions.
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] method.
[b]Note:[/b] The equivalent resource is [DrawableTexture2D].
</description>
</method>
<method name="texture_drawable_generate_mipmaps">
<return type="void" />
<param index="0" name="texture" type="RID" />
<description>
Calculates new MipMaps for the given Drawable [param texture].
</description>
</method>
<method name="texture_drawable_get_default_material" qualifiers="const">
<return type="RID" />
<description>
Returns a ShaderMaterial with the default texture_blit Shader.
</description>
</method>
<method name="texture_get_format" qualifiers="const">
<return type="int" enum="Image.Format" />
<param index="0" name="texture" type="RID" />
@ -4677,6 +4716,19 @@
<constant name="CUBEMAP_LAYER_BACK" value="5" enum="CubeMapLayer">
Back face of a [Cubemap].
</constant>
<constant name="TEXTURE_DRAWABLE_FORMAT_RGBA8" value="0" enum="TextureDrawableFormat">
OpenGL texture format RGBA with four components, each with a bitdepth of 8.
</constant>
<constant name="TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB" value="1" enum="TextureDrawableFormat">
OpenGL texture format RGBA with four components, each with a bitdepth of 8.
When drawn to, an sRGB to linear color space conversion is performed.
</constant>
<constant name="TEXTURE_DRAWABLE_FORMAT_RGBAH" value="2" enum="TextureDrawableFormat">
OpenGL texture format GL_RGBA16F where there are four components, each a 16-bit "half-precision" floating-point value.
</constant>
<constant name="TEXTURE_DRAWABLE_FORMAT_RGBAF" value="3" enum="TextureDrawableFormat">
OpenGL texture format GL_RGBA32F where there are four components, each a 32-bit floating-point value.
</constant>
<constant name="SHADER_SPATIAL" value="0" enum="ShaderMode">
Shader is a 3D shader.
</constant>
@ -4692,7 +4744,10 @@
<constant name="SHADER_FOG" value="4" enum="ShaderMode">
Shader is a 3D fog shader.
</constant>
<constant name="SHADER_MAX" value="5" enum="ShaderMode">
<constant name="SHADER_TEXTURE_BLIT" value="5" enum="ShaderMode">
Shader is a texture_blit shader.
</constant>
<constant name="SHADER_MAX" value="6" enum="ShaderMode">
Represents the size of the [enum ShaderMode] enum.
</constant>
<constant name="MATERIAL_RENDER_PRIORITY_MIN" value="-128">

View file

@ -74,5 +74,8 @@
<constant name="MODE_FOG" value="4" enum="Mode">
Mode used for setting the color and density of volumetric fog effect.
</constant>
<constant name="MODE_TEXTURE_BLIT" value="5" enum="Mode">
Mode used for drawing to DrawableTexture resources via blit calls.
</constant>
</constants>
</class>

View file

@ -222,7 +222,10 @@
<constant name="TYPE_FOG" value="9" enum="Type">
A compute shader that runs for each froxel of the volumetric fog map.
</constant>
<constant name="TYPE_MAX" value="10" enum="Type">
<constant name="TYPE_TEXTURE_BLIT" value="10" enum="Type">
A shader used to process blit calls to a DrawableTexture.
</constant>
<constant name="TYPE_MAX" value="11" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="VARYING_MODE_VERTEX_TO_FRAG_LIGHT" value="0" enum="VaryingMode">

View file

@ -210,6 +210,8 @@ void RasterizerGLES3::initialize() {
}
void RasterizerGLES3::finalize() {
// Has to be a separate call due to TextureStorage & MaterialStorage needing to interact for TexBlit Shaders
texture_storage->_tex_blit_shader_free();
memdelete(scene);
memdelete(canvas);
memdelete(gi);
@ -372,6 +374,8 @@ RasterizerGLES3::RasterizerGLES3() {
fog = memnew(GLES3::Fog);
canvas = memnew(RasterizerCanvasGLES3());
scene = memnew(RasterizerSceneGLES3());
// Has to be a separate call due to TextureStorage & MaterialStorage needing to interact for TexBlit Shaders
texture_storage->_tex_blit_shader_initialize();
// Disable OpenGL linear to sRGB conversion, because Godot will always do this conversion itself.
if (config->srgb_framebuffer_supported) {

View file

@ -25,6 +25,7 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("particles.glsl")
env.GLES3_GLSL("particles_copy.glsl")
env.GLES3_GLSL("skeleton.glsl")
env.GLES3_GLSL("tex_blit.glsl")
# once we finish conversion we can introduce this to cover all files:
# for glsl_file in glsl_files:

View file

@ -0,0 +1,121 @@
/* clang-format off */
#[modes]
mode_default =
#[specializations]
USE_OUTPUT1 = true
USE_OUTPUT2 = true
USE_OUTPUT3 = true
#[vertex]
layout(location = 0) in vec2 vertex_attrib;
uniform vec2 offset;
uniform vec2 size;
out vec2 uv;
void main() {
uv = vertex_attrib * 0.5 + 0.5;
// This math scales the Vertex Attribute Quad to match the Rect the user passed in, based on Offset & Size
gl_Position = vec4( (offset * 2.0 - 1.0) + (size * (vertex_attrib + 1.0)), 1.0, 1.0);
}
#[fragment]
uniform sampler2D source0; // texunit:0
uniform sampler2D source1; // texunit:-1
uniform sampler2D source2; // texunit:-2
uniform sampler2D source3; // texunit:-3
#define OUTPUT0_SRGB uint(1)
#define OUTPUT1_SRGB uint(2)
#define OUTPUT2_SRGB uint(4)
#define OUTPUT3_SRGB uint(8)
uniform uint convert_to_srgb;
uniform vec4 modulate;
uniform float time;
in vec2 uv;
layout (location = 0) out vec4 out_color0;
#ifdef USE_OUTPUT1
layout (location = 1) out vec4 out_color1;
#endif
#ifdef USE_OUTPUT2
layout (location = 2) out vec4 out_color2;
#endif
#ifdef USE_OUTPUT3
layout (location = 3) out vec4 out_color3;
#endif
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{ //ubo:0
#MATERIAL_UNIFORMS
};
#endif
#GLOBALS
vec3 linear_to_srgb(vec3 color) {
// If going to srgb, clamp from 0 to 1.
color = clamp(color, vec3(0.0), vec3(1.0));
const vec3 a = vec3(0.055f);
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
void main() {
// Handles the case where user code uses extra outputs, but extra output targets were not bound
vec4 color0 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color1 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color2 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color3 = vec4(0.0, 0.0, 0.0, 1.0);
#CODE : BLIT
// Discards extra outputs if extra output targets were not bound
out_color0 = color0;
#ifdef USE_OUTPUT1
out_color1 = color1;
#endif
#ifdef USE_OUTPUT2
out_color2 = color2;
#endif
#ifdef USE_OUTPUT3
out_color3 = color3;
#endif
if (bool(convert_to_srgb & OUTPUT0_SRGB)) {
out_color0.rgb = linear_to_srgb(out_color0.rgb); // Regular linear -> SRGB conversion.
}
#ifdef USE_OUTPUT1
if (bool(convert_to_srgb & OUTPUT1_SRGB)) {
out_color1.rgb = linear_to_srgb(out_color1.rgb);
}
#endif
#ifdef USE_OUTPUT2
if (bool(convert_to_srgb & OUTPUT2_SRGB)) {
out_color2.rgb = linear_to_srgb(out_color2.rgb);
}
#endif
#ifdef USE_OUTPUT3
if (bool(convert_to_srgb & OUTPUT3_SRGB)) {
out_color3.rgb = linear_to_srgb(out_color3.rgb);
}
#endif
}

View file

@ -1137,12 +1137,14 @@ MaterialStorage::MaterialStorage() {
shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
shader_data_request_func[RS::SHADER_PARTICLES] = _create_particles_shader_func;
shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
shader_data_request_func[RS::SHADER_TEXTURE_BLIT] = _create_tex_blit_shader_func;
shader_data_request_func[RS::SHADER_FOG] = nullptr;
material_data_request_func[RS::SHADER_SPATIAL] = _create_scene_material_func;
material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
material_data_request_func[RS::SHADER_PARTICLES] = _create_particles_material_func;
material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
material_data_request_func[RS::SHADER_TEXTURE_BLIT] = _create_tex_blit_material_func;
material_data_request_func[RS::SHADER_FOG] = nullptr;
static_assert(sizeof(GlobalShaderUniforms::Value) == 16);
@ -1549,6 +1551,28 @@ MaterialStorage::MaterialStorage() {
shaders.compiler_sky.initialize(actions);
}
{
// Setup TextureBlit compiler
ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["UV"] = "uv";
actions.renames["MODULATE"] = "modulate";
actions.renames["COLOR0"] = "color0";
actions.renames["COLOR1"] = "color1";
actions.renames["COLOR2"] = "color2";
actions.renames["COLOR3"] = "color3";
shaders.compiler_tex_blit.initialize(actions);
}
}
MaterialStorage::~MaterialStorage() {
@ -2233,6 +2257,8 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
new_mode = RS::SHADER_SKY;
//} else if (mode_string == "fog") {
// new_mode = RS::SHADER_FOG;
} else if (mode_string == "texture_blit") {
new_mode = RS::SHADER_TEXTURE_BLIT;
} else {
new_mode = RS::SHADER_MAX;
ERR_PRINT("shader type " + mode_string + " not supported in OpenGL renderer");
@ -3329,4 +3355,119 @@ void ParticleProcessMaterialData::bind_uniforms() {
bind_uniforms_generic(texture_cache, shader_data->texture_uniforms, 1); // Start at GL_TEXTURE1 because texture slot 0 is reserved for the heightmap texture.
}
/* TextureBlit SHADER */
void TexBlitShaderData::set_code(const String &p_code) {
// Initialize and compile the shader.
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code.is_empty()) {
return; // Just invalid, but no error.
}
ShaderCompiler::GeneratedCode gen_code;
// Actual enum set further down after compilation.
int blend_modei = BLEND_MODE_MIX;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["blit"] = ShaderCompiler::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
actions.uniforms = &uniforms;
Error err = MaterialStorage::get_singleton()->shaders.compiler_tex_blit.compile(RS::SHADER_TEXTURE_BLIT, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = MaterialStorage::get_singleton()->shaders.tex_blit_shader.version_create();
}
blend_mode = BlendMode(blend_modei);
#if 0
print_line("**compiling shader:");
print_line("**defines:\n");
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
print_line("\n**code " + el->key + ":\n" + el->value);
++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);
MaterialStorage::get_singleton()->shaders.tex_blit_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.tex_blit_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
valid = true;
}
bool TexBlitShaderData::is_animated() const {
return false;
}
bool TexBlitShaderData::casts_shadows() const {
return false;
}
RS::ShaderNativeSourceCode TexBlitShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.tex_blit_shader.version_get_native_source_code(version);
}
TexBlitShaderData::TexBlitShaderData() {
valid = false;
}
TexBlitShaderData::~TexBlitShaderData() {
if (version.is_valid()) {
MaterialStorage::get_singleton()->shaders.tex_blit_shader.version_free(version);
}
}
GLES3::ShaderData *GLES3::_create_tex_blit_shader_func() {
TexBlitShaderData *shader_data = memnew(TexBlitShaderData);
return shader_data;
}
void TexBlitMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, false);
}
void TexBlitMaterialData::bind_uniforms() {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer);
bind_uniforms_generic(texture_cache, shader_data->texture_uniforms, 1);
}
TexBlitMaterialData::~TexBlitMaterialData() {
}
GLES3::MaterialData *GLES3::_create_tex_blit_material_func(ShaderData *p_shader) {
TexBlitMaterialData *material_data = memnew(TexBlitMaterialData);
material_data->shader_data = static_cast<TexBlitShaderData *>(p_shader);
//update will happen later anyway so do nothing.
return material_data;
}
#endif // !GLES3_ENABLED

View file

@ -43,6 +43,7 @@
#include "drivers/gles3/shaders/particles.glsl.gen.h"
#include "drivers/gles3/shaders/scene.glsl.gen.h"
#include "drivers/gles3/shaders/sky.glsl.gen.h"
#include "drivers/gles3/shaders/tex_blit.glsl.gen.h"
namespace GLES3 {
@ -423,6 +424,52 @@ struct ParticleProcessMaterialData : public MaterialData {
MaterialData *_create_particles_material_func(ShaderData *p_shader);
/* Texture Blit Shader */
struct TexBlitShaderData : public ShaderData {
enum BlendMode { // Used internally.
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_DISABLED,
};
bool valid;
RID version;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String code;
BlendMode blend_mode;
virtual void set_code(const String &p_code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
TexBlitShaderData();
virtual ~TexBlitShaderData();
};
ShaderData *_create_tex_blit_shader_func();
struct TexBlitMaterialData : public MaterialData {
TexBlitShaderData *shader_data = nullptr;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual void bind_uniforms();
virtual ~TexBlitMaterialData();
};
MaterialData *_create_tex_blit_material_func(ShaderData *p_shader);
/* Global shader uniform structs */
struct GlobalShaderUniforms {
enum {
@ -560,11 +607,13 @@ public:
SkyShaderGLES3 sky_shader;
SceneShaderGLES3 scene_shader;
ParticlesShaderGLES3 particles_process_shader;
TexBlitShaderGLES3 tex_blit_shader;
ShaderCompiler compiler_canvas;
ShaderCompiler compiler_scene;
ShaderCompiler compiler_particles;
ShaderCompiler compiler_sky;
ShaderCompiler compiler_tex_blit;
} shaders;
/* GLOBAL SHADER UNIFORM API */

View file

@ -303,6 +303,94 @@ TextureStorage::~TextureStorage() {
sdf_shader.shader.version_free(sdf_shader.shader_version);
}
// Has to be a separate call from TextureStorage initialization due to interacting with MaterialStorage
void TextureStorage::_tex_blit_shader_initialize() {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
{
String global_defines;
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
material_storage->shaders.tex_blit_shader.initialize(global_defines, 1);
}
{
// default material and shader for Texture Blit shader
tex_blit_shader.default_shader = material_storage->shader_allocate();
material_storage->shader_initialize(tex_blit_shader.default_shader);
material_storage->shader_set_code(tex_blit_shader.default_shader, R"(
// Default Texture Blit shader.
shader_type texture_blit;
render_mode blend_mix;
uniform sampler2D source_texture0 : hint_blit_source0;
uniform sampler2D source_texture1 : hint_blit_source1;
uniform sampler2D source_texture2 : hint_blit_source2;
uniform sampler2D source_texture3 : hint_blit_source3;
void blit() {
// Copies from each whole source texture to a rect on each output texture.
COLOR0 = texture(source_texture0, UV) * MODULATE;
COLOR1 = texture(source_texture1, UV) * MODULATE;
COLOR2 = texture(source_texture2, UV) * MODULATE;
COLOR3 = texture(source_texture3, UV) * MODULATE;
}
)");
tex_blit_shader.default_material = material_storage->material_allocate();
material_storage->material_initialize(tex_blit_shader.default_material);
material_storage->material_set_shader(tex_blit_shader.default_material, tex_blit_shader.default_shader);
}
{
// Set up Frame & Vertex Buffers for TextureBlit Shaders
// Just a 1x1 Quad to draw
glGenFramebuffers(1, &tex_blit_fbo);
glGenBuffers(1, &tex_blit_quad);
glBindBuffer(GL_ARRAY_BUFFER, tex_blit_quad);
const float qv[12] = {
-1.0f,
-1.0f,
1.0f,
-1.0f,
1.0f,
1.0f,
-1.0f,
-1.0f,
1.0f,
1.0f,
-1.0f,
1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, qv, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
glGenVertexArrays(1, &tex_blit_quad_array);
glBindVertexArray(tex_blit_quad_array);
glBindBuffer(GL_ARRAY_BUFFER, tex_blit_quad);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
tex_blit_shader.initialized = true;
}
// Has to be a separate call from TextureStorage destruction due to interacting with Material Storage
void TextureStorage::_tex_blit_shader_free() {
if (tex_blit_shader.initialized) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
glDeleteFramebuffers(1, &tex_blit_fbo);
glDeleteBuffers(1, &tex_blit_quad);
glDeleteVertexArrays(1, &tex_blit_quad_array);
material_storage->material_free(tex_blit_shader.default_material);
material_storage->shader_free(tex_blit_shader.default_shader);
}
}
/* Canvas Texture API */
RID TextureStorage::canvas_texture_allocate() {
@ -1113,6 +1201,51 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
texture_owner.initialize_rid(p_texture, proxy_tex);
}
void TextureStorage::texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) {
// Behaves identically to Texture_2D_Initialize by generating a white image based on parameters.
// GUARDRAIL: Bad Widths/Heights
ERR_FAIL_COND_MSG(p_width <= 0 || p_height <= 0, "Drawable Texture Width or Height cannot be less than 1.");
ERR_FAIL_COND_MSG(p_width >= 16384 || p_height >= 16384, "Drawable Texture Width or Height cannot be greater than 16383.");
Image::Format format;
switch (p_format) {
case RS::TEXTURE_DRAWABLE_FORMAT_RGBA8:
format = Image::FORMAT_RGBA8;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB:
format = Image::FORMAT_RGBA8;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBAH:
format = Image::FORMAT_RGBAH;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBAF:
format = Image::FORMAT_RGBAF;
break;
default:
format = Image::FORMAT_RGBA8;
}
Ref<Image> image = Image::create_empty(p_width, p_height, p_with_mipmaps, format);
image->fill(p_color);
Texture texture;
texture.width = image->get_width();
texture.height = image->get_height();
texture.alloc_width = texture.width;
texture.alloc_height = texture.height;
texture.mipmaps = image->get_mipmap_count() + 1;
texture.format = image->get_format();
texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D;
_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
texture.total_data_size = image->get_image_data_size(texture.width, texture.height, texture.format, texture.mipmaps);
texture.active = true;
glGenTextures(1, &texture.tex_id);
GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture 2D");
texture_owner.initialize_rid(p_texture, texture);
texture_set_data(p_texture, image);
}
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;
@ -1231,6 +1364,135 @@ void TextureStorage::texture_remap_proxies(RID p_from_texture, RID p_to_texture)
}
}
// Output textures in p_textures must ALL BE THE SAME SIZE
void TextureStorage::texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) {
ERR_FAIL_COND_MSG(!tex_blit_shader.initialized, "Texture Blit shader & materials not yet initialized.");
ERR_FAIL_COND_MSG(p_textures.size() == 0 || p_source_textures.size() == 0, "Blit Rect texture output and source arrays must contain at least 1 texture.");
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
TexBlitMaterialData *m = static_cast<TexBlitMaterialData *>(material_storage->material_get_data(p_material, RS::SHADER_TEXTURE_BLIT));
if (!m) {
m = static_cast<TexBlitMaterialData *>(material_storage->material_get_data(tex_blit_shader.default_material, RS::SHADER_TEXTURE_BLIT));
}
// GUARDRAIL: p_material MUST BE ShaderType TextureBlit
ERR_FAIL_NULL(m);
TexBlitShaderGLES3::ShaderVariant variant = TexBlitShaderGLES3::MODE_DEFAULT;
RID version = tex_blit_shader.default_shader_version;
if (m->shader_data->version.is_valid() && m->shader_data->valid) {
// Must be called to force user ShaderMaterials to actually populate uniform buffer before binding
// NOTE: Not an ideal work around, maybe in the future this can only update this MaterialData and remove it from the queue, instead of processing all queued updates
material_storage->_update_queued_materials();
// Bind material uniform buffer and textures.
m->bind_uniforms();
version = m->shader_data->version;
}
glBindFramebuffer(GL_FRAMEBUFFER, tex_blit_fbo);
TightLocalVector<GLenum> draw_buffers;
Texture *tar_textures[4];
int convert_to_srgb_mask = 0;
Texture *src_textures[4];
int i = 0;
uint32_t specialization = 0;
const int outputFlagArray[4] = { 0, TexBlitShaderGLES3::USE_OUTPUT1, TexBlitShaderGLES3::USE_OUTPUT2, TexBlitShaderGLES3::USE_OUTPUT3 };
const int srgbMaskArray[4] = { 1, 2, 4, 8 };
while (i < 4) {
// Attach Targets to Framebuffer
if (i < p_textures.size()) {
tar_textures[i] = get_texture(p_textures[i]);
ERR_FAIL_NULL_MSG(tar_textures[i], "Drawable Texture target cannot be null.");
if (i > 0) {
ERR_FAIL_COND_MSG(texture_get_size(p_textures[i - 1]) != texture_get_size(p_textures[i]), "All Blit_Rect output textures must be same size.");
}
specialization |= outputFlagArray[i];
draw_buffers.push_back(GL_COLOR_ATTACHMENT0 + i);
ERR_FAIL_COND_MSG(p_to_mipmap >= tar_textures[i]->mipmaps, vformat("Drawable Texture Target does not have mipmap level %d.", p_to_mipmap));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, tar_textures[i]->tex_id, p_to_mipmap);
convert_to_srgb_mask += tar_textures[i]->drawable_type == RS::TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB ? srgbMaskArray[i] : 0;
}
// Bind Sources to buffer. Use placeholder Black Texture if source is bad.
if (i < p_source_textures.size()) {
src_textures[i] = get_texture(p_source_textures[i]);
if (!src_textures[i]) {
src_textures[i] = get_texture(default_gl_textures[DEFAULT_GL_TEXTURE_WHITE]);
}
} else {
src_textures[i] = get_texture(default_gl_textures[DEFAULT_GL_TEXTURE_WHITE]);
}
int shift = i == 0 ? 0 : GLES3::Config::get_singleton()->max_texture_image_units - i;
glActiveTexture(GL_TEXTURE0 + shift);
glBindTexture(GL_TEXTURE_2D, src_textures[i]->tex_id);
i += 1;
}
bool success = material_storage->shaders.tex_blit_shader.version_bind_shader(version, variant, specialization);
if (!success) {
return;
}
// Calculates the Rects Offset & Size in UV space for Shader to scale Vertex Quad correctly
Vector3 size = texture_get_size(p_textures[0]);
Vector2 offset = Vector2(p_rect.position.x / size.x, p_rect.position.y / size.y);
Vector2 rect_size = Vector2(p_rect.size.x / size.x, p_rect.size.y / size.y);
Vector2i vp_size = Vector2i(tar_textures[0]->alloc_width, tar_textures[0]->alloc_height);
if (p_to_mipmap != 0) {
vp_size.x >>= p_to_mipmap;
vp_size.y >>= p_to_mipmap;
}
glViewport(0, 0, vp_size.x, vp_size.y);
material_storage->shaders.tex_blit_shader.version_set_uniform(TexBlitShaderGLES3::CONVERT_TO_SRGB, convert_to_srgb_mask, version, variant, specialization);
material_storage->shaders.tex_blit_shader.version_set_uniform(TexBlitShaderGLES3::SIZE, rect_size, version, variant, specialization);
material_storage->shaders.tex_blit_shader.version_set_uniform(TexBlitShaderGLES3::OFFSET, offset, version, variant, specialization);
material_storage->shaders.tex_blit_shader.version_set_uniform(TexBlitShaderGLES3::MODULATE, p_modulate, version, variant, specialization);
material_storage->shaders.tex_blit_shader.version_set_uniform(TexBlitShaderGLES3::TIME, RasterizerGLES3::get_singleton()->get_total_time(), version, variant, specialization);
// Set Blend_Mode correctly
GLES3::TexBlitShaderData::BlendMode blend_mode = m->shader_data->blend_mode;
glEnable(GL_BLEND);
switch (blend_mode) {
case GLES3::TexBlitShaderData::BLEND_MODE_ADD:
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
break;
case GLES3::TexBlitShaderData::BLEND_MODE_SUB:
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
break;
case GLES3::TexBlitShaderData::BLEND_MODE_MIX:
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
break;
case GLES3::TexBlitShaderData::BLEND_MODE_MUL:
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
break;
case GLES3::TexBlitShaderData::BLEND_MODE_DISABLED:
glDisable(GL_BLEND);
break;
}
glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
// DRAW!!
glBindVertexArray(tex_blit_quad_array);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// Reset to system FBO
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
}
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
texture_2d_initialize(p_texture, texture_2d_placeholder);
}
@ -1537,6 +1799,17 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
return ret;
}
void TextureStorage::texture_drawable_generate_mipmaps(RID p_texture) {
Texture *texture = get_texture(p_texture);
Vector3i size = texture_get_size(p_texture);
CopyEffects::get_singleton()->bilinear_blur(texture->tex_id, texture->mipmaps, Rect2i(0, 0, size.x, size.y));
}
RID TextureStorage::texture_drawable_get_default_material() const {
// This should never be called before DrawableTexture stuff is initialized.
return tex_blit_shader.default_material;
}
void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex_to = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL(tex_to);

View file

@ -182,6 +182,7 @@ struct Texture {
Type type = TYPE_2D;
RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
RS::TextureDrawableFormat drawable_type = RS::TEXTURE_DRAWABLE_FORMAT_RGBA8;
GLenum target = GL_TEXTURE_2D;
GLenum gl_format_cache = 0;
@ -487,9 +488,25 @@ private:
RID shader_version;
} sdf_shader;
/* Texture Blit Shader API */
struct TexBlitShader {
bool initialized = false;
RID default_shader;
RID default_material;
RID default_shader_version;
} tex_blit_shader;
GLuint tex_blit_fbo;
GLuint tex_blit_quad;
GLuint tex_blit_quad_array;
public:
static TextureStorage *get_singleton();
void _tex_blit_shader_initialize();
void _tex_blit_shader_free();
TextureStorage();
virtual ~TextureStorage();
@ -535,6 +552,7 @@ public:
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_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 void texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) override;
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;
@ -544,6 +562,8 @@ public:
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
void texture_remap_proxies(RID p_from_texture, RID p_to_texture);
virtual void texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) override;
Ref<Image> texture_2d_placeholder;
Vector<Ref<Image>> texture_2d_array_placeholder;
Vector<Ref<Image>> cubemap_placeholder;
@ -558,6 +578,9 @@ public:
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override;
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override;
virtual void texture_drawable_generate_mipmaps(RID p_texture) override;
virtual RID texture_drawable_get_default_material() const override;
virtual void texture_replace(RID p_texture, RID p_by_texture) override;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override;

View file

@ -9225,6 +9225,10 @@ EditorNode::EditorNode() {
canvas_item_mat_convert.instantiate();
resource_conversion_plugins.push_back(canvas_item_mat_convert);
Ref<BlitMaterialConversionPlugin> blit_mat_convert;
blit_mat_convert.instantiate();
resource_conversion_plugins.push_back(blit_mat_convert);
Ref<ParticleProcessMaterialConversionPlugin> particles_mat_convert;
particles_mat_convert.instantiate();
resource_conversion_plugins.push_back(particles_mat_convert);

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><defs><linearGradient xlink:href="#a" id="b" x1="15.347" x2="15.347" y1="3.168" y2="17.103" gradientTransform="matrix(1.00467 0 0 1.04022 -7.419 -2.544)" gradientUnits="userSpaceOnUse"/></defs><linearGradient id="a" x2="0" y2="16" gradientUnits="userSpaceOnUse"><stop offset=".188" stop-color="#ff4545"/><stop stop-color="#ffe345"/><stop offset=".313" stop-color="#ffe345"/><stop stop-color="#80ff45"/><stop offset=".438" stop-color="#80ff45"/><stop stop-color="#45ffa2"/><stop offset=".563" stop-color="#45ffa2"/><stop stop-color="#45d7ff"/><stop offset=".688" stop-color="#45d7ff"/><stop stop-color="#8045ff"/><stop offset=".813" stop-color="#8045ff"/><stop stop-color="#ff4596"/></linearGradient><path fill="url(#b)" d="m 2.9291085,10.340767 c -0.2642273,0.312066 -0.4219599,0.759362 -0.4219599,1.287796 0,1.693483 -3.15264355,-0.18516 -0.3385726,2.777396 0.8881251,0.936201 2.6663848,0.696949 3.55451,-0.237171 a 2.3408729,2.4237201 0 0 0 0,-3.386967 C 4.6179529,9.6178118 3.5128197,9.6542196 2.9301132,10.340767 Z M 5.2398414,8.6348009 7.651041,11.131336 14.482773,4.0578184 a 1.7228275,1.783801 0 0 0 -2.4112,-2.5485469 z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z"/><path fill="#e0e0e0" d="M5 5V4H6V5H7V6H6V7H5V6H4V5ZM10 8V7h1v1h1v1h-1v1H10V9H9V8Z"/></svg>

After

Width:  |  Height:  |  Size: 344 B

View file

@ -42,6 +42,7 @@
#include "scene/gui/label.h"
#include "scene/gui/subviewport_container.h"
#include "scene/main/viewport.h"
#include "scene/resources/blit_material.h"
#include "scene/resources/canvas_item_material.h"
#include "scene/resources/particle_process_material.h"
@ -499,3 +500,42 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
ERR_FAIL_COND_V(!Object::cast_to<CanvasItemMaterial>(*p_resource) || !Object::cast_to<CanvasItemMaterial>(*p_resource)->_is_initialized(), Ref<CanvasItemMaterial>());
return MaterialEditor::make_shader_material(p_resource);
}
String BlitMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
}
bool BlitMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
Ref<BlitMaterial> mat = p_resource;
return mat.is_valid();
}
Ref<Resource> BlitMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
Ref<BlitMaterial> mat = p_resource;
ERR_FAIL_COND_V(mat.is_null(), Ref<Resource>());
Ref<ShaderMaterial> smat;
smat.instantiate();
Ref<Shader> shader;
shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
shader->set_code(code);
smat->set_shader(shader);
List<PropertyInfo> params;
RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
smat->set_local_to_scene(mat->is_local_to_scene());
smat->set_name(mat->get_name());
return smat;
}

View file

@ -153,3 +153,12 @@ public:
virtual bool handles(const Ref<Resource> &p_resource) const override;
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
class BlitMaterialConversionPlugin : public EditorResourceConversionPlugin {
GDCLASS(BlitMaterialConversionPlugin, EditorResourceConversionPlugin);
public:
virtual String converts_to() const override;
virtual bool handles(const Ref<Resource> &p_resource) const override;
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};

View file

@ -379,6 +379,8 @@ void ShaderTextEditor::_check_shader_mode() {
mode = Shader::MODE_SKY;
} else if (type == "fog") {
mode = Shader::MODE_FOG;
} else if (type == "texture_blit") {
mode = Shader::MODE_TEXTURE_BLIT;
} else {
mode = Shader::MODE_SPATIAL;
}

View file

@ -125,6 +125,13 @@ void fog() {
// of the associated FogVolume. This means that froxels that just barely touch
// a given FogVolume will still be used.
}
)";
} break;
case Shader::MODE_TEXTURE_BLIT: {
code += R"(
void blit() {
// Called for each pixel inside the given rect on the DrawableTexture.
}
)";
} break;
case Shader::MODE_MAX: {

View file

@ -1732,6 +1732,10 @@ void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_
} break;
case Shader::MODE_FOG: {
r_begin_type = VisualShader::TYPE_FOG;
r_end_type = VisualShader::TYPE_TEXTURE_BLIT;
} break;
case Shader::MODE_TEXTURE_BLIT: {
r_begin_type = VisualShader::TYPE_TEXTURE_BLIT;
r_end_type = VisualShader::TYPE_MAX;
} break;
default: {
@ -2470,6 +2474,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_particles->set_visible(false);
edit_type_sky->set_visible(true);
edit_type_fog->set_visible(false);
edit_type_texture_blit->set_visible(false);
edit_type = edit_type_sky;
custom_mode_box->set_visible(false);
varying_button->hide();
@ -2479,6 +2484,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_particles->set_visible(false);
edit_type_sky->set_visible(false);
edit_type_fog->set_visible(true);
edit_type_texture_blit->set_visible(false);
edit_type = edit_type_fog;
custom_mode_box->set_visible(false);
varying_button->hide();
@ -2488,6 +2494,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_particles->set_visible(true);
edit_type_sky->set_visible(false);
edit_type_fog->set_visible(false);
edit_type_texture_blit->set_visible(false);
edit_type = edit_type_particles;
if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {
custom_mode_box->set_visible(false);
@ -2496,11 +2503,26 @@ void VisualShaderEditor::_set_mode(int p_which) {
}
varying_button->hide();
mode = MODE_FLAGS_PARTICLES;
} else if (p_which == VisualShader::MODE_TEXTURE_BLIT) {
edit_type_standard->set_visible(false);
edit_type_particles->set_visible(false);
edit_type_sky->set_visible(false);
edit_type_fog->set_visible(false);
edit_type_texture_blit->set_visible(true);
edit_type = edit_type_texture_blit;
if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {
custom_mode_box->set_visible(false);
} else {
custom_mode_box->set_visible(true);
}
varying_button->hide();
mode = MODE_FLAGS_TEXTURE_BLIT;
} else {
edit_type_particles->set_visible(false);
edit_type_standard->set_visible(true);
edit_type_sky->set_visible(false);
edit_type_fog->set_visible(false);
edit_type_texture_blit->set_visible(false);
edit_type = edit_type_standard;
custom_mode_box->set_visible(false);
varying_button->show();
@ -2519,6 +2541,9 @@ void VisualShaderEditor::_set_mode(int p_which) {
upper_type = VisualShader::TYPE_FOG;
} else if (mode & MODE_FLAGS_FOG) {
default_type = VisualShader::TYPE_FOG;
upper_type = VisualShader::TYPE_TEXTURE_BLIT;
} else if (mode & MODE_FLAGS_TEXTURE_BLIT) {
default_type = VisualShader::TYPE_TEXTURE_BLIT;
upper_type = VisualShader::TYPE_MAX;
}
@ -5679,6 +5704,8 @@ void VisualShaderEditor::_type_selected(int p_id) {
offset = VisualShader::TYPE_SKY;
} else if (mode & MODE_FLAGS_FOG) {
offset = VisualShader::TYPE_FOG;
} else if (mode & MODE_FLAGS_TEXTURE_BLIT) {
offset = VisualShader::TYPE_TEXTURE_BLIT;
}
set_current_shader_type(VisualShader::Type(p_id + offset));
@ -6686,6 +6713,11 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_fog->select(0);
edit_type_fog->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type_texture_blit = memnew(OptionButton);
edit_type_texture_blit->add_item(TTR("Blit"));
edit_type_texture_blit->select(0);
edit_type_texture_blit->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type = edit_type_standard;
toolbar_hflow->add_child(custom_mode_box);
@ -6698,6 +6730,8 @@ VisualShaderEditor::VisualShaderEditor() {
toolbar_hflow->move_child(edit_type_sky, 0);
toolbar_hflow->add_child(edit_type_fog);
toolbar_hflow->move_child(edit_type_fog, 0);
toolbar_hflow->add_child(edit_type_texture_blit);
toolbar_hflow->move_child(edit_type_texture_blit, 0);
add_node = memnew(Button);
add_node->set_theme_type_variation(SceneStringName(FlatButton));
@ -7192,6 +7226,7 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.") + translation_gdsl;
const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.") + translation_gdsl;
const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.") + translation_gdsl;
const String input_param_for_texture_blit_shader_mode = TTR("'%s' input parameter for blit shader mode.") + translation_gdsl;
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.") + translation_gdsl;
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.") + translation_gdsl;
const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.") + translation_gdsl;
@ -7341,6 +7376,15 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("UVW", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
add_options.push_back(AddOption("WorldPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
// TEXTURE BLIT INPUTS
add_options.push_back(AddOption("UV", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Modulate", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Modulate", "MODULATE"), { "Modulate" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Fragcoord", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Fragcoord", "FRAGCOORD"), { "Fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Source Texture", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture", "source_texture"), { "Source Texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Source Texture 2", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 2", "source_texture2"), { "Source Texture 2" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Source Texture 3", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 3", "source_texture3"), { "Source Texture 3" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
add_options.push_back(AddOption("Source Texture 4", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 4", "source_texture4"), { "Source Texture 4" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));
// PARTICLES INPUTS
add_options.push_back(AddOption("CollisionDepth", "Input/Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth", "COLLISION_DEPTH"), { "collision_depth" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
@ -8288,7 +8332,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
}
//4. delete varyings (if needed)
if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG) {
if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG || p_which == VisualShader::MODE_TEXTURE_BLIT) {
int var_count = visual_shader->get_varyings_count();
if (var_count > 0) {

View file

@ -232,6 +232,7 @@ class VisualShaderEditor : public ShaderEditor {
OptionButton *edit_type_particles = nullptr;
OptionButton *edit_type_sky = nullptr;
OptionButton *edit_type_fog = nullptr;
OptionButton *edit_type_texture_blit = nullptr;
CheckBox *custom_mode_box = nullptr;
bool custom_mode_enabled = false;
@ -297,6 +298,7 @@ class VisualShaderEditor : public ShaderEditor {
MODE_FLAGS_SKY = 2,
MODE_FLAGS_PARTICLES = 4,
MODE_FLAGS_FOG = 8,
MODE_FLAGS_TEXTURE_BLIT = 16,
};
int mode = MODE_FLAGS_SPATIAL_CANVASITEM;
@ -324,6 +326,10 @@ class VisualShaderEditor : public ShaderEditor {
TYPE_FLAGS_FOG = 1,
};
enum TextureBlitTypeFlags {
TYPE_FLAGS_BLIT = 1,
};
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL

View file

@ -113,6 +113,7 @@
#include "scene/resources/audio_stream_polyphonic.h"
#include "scene/resources/audio_stream_wav.h"
#include "scene/resources/bit_map.h"
#include "scene/resources/blit_material.h"
#include "scene/resources/bone_map.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/camera_texture.h"
@ -121,6 +122,7 @@
#include "scene/resources/compositor.h"
#include "scene/resources/compressed_texture.h"
#include "scene/resources/curve_texture.h"
#include "scene/resources/drawable_texture_2d.h"
#include "scene/resources/environment.h"
#include "scene/resources/external_texture.h"
#include "scene/resources/font.h"
@ -889,8 +891,10 @@ void register_scene_types() {
GDREGISTER_CLASS(ShaderMaterial);
GDREGISTER_CLASS(CanvasTexture);
GDREGISTER_CLASS(CanvasItemMaterial);
SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes);
CanvasItemMaterial::init_shaders();
GDREGISTER_CLASS(BlitMaterial);
/* REGISTER 2D */
@ -1057,6 +1061,7 @@ void register_scene_types() {
GDREGISTER_CLASS(GradientTexture2D);
GDREGISTER_CLASS(CameraTexture);
GDREGISTER_CLASS(ExternalTexture);
GDREGISTER_CLASS(DrawableTexture2D);
GDREGISTER_VIRTUAL_CLASS(TextureLayered);
GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered);
GDREGISTER_VIRTUAL_CLASS(Texture3D);
@ -1475,6 +1480,7 @@ void unregister_scene_types() {
ParticleProcessMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
ColorPickerShape::finish_shaders();
BlitMaterial::cleanup_shader();
GraphEdit::finish_shaders();
SceneStringNames::free();

View file

@ -0,0 +1,140 @@
/**************************************************************************/
/* blit_material.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 "blit_material.h"
#include "core/version.h"
void BlitMaterial::_update_shader(BlendMode p_blend) {
MutexLock shader_lock(shader_mutex);
int index = int(p_blend);
if (shader_cache[p_blend].is_null()) {
shader_cache[p_blend] = RS::get_singleton()->shader_create();
String code = "// NOTE: Shader automatically converted from " GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG "'s BlitMaterial.\n\n";
code += "shader_type texture_blit;\nrender_mode ";
switch (p_blend) {
case BLEND_MODE_MIX:
code += "blend_mix";
break;
case BLEND_MODE_ADD:
code += "blend_add";
break;
case BLEND_MODE_SUB:
code += "blend_sub";
break;
case BLEND_MODE_MUL:
code += "blend_mul";
break;
case BLEND_MODE_DISABLED:
code += "blend_disabled";
break;
default:
code += "blend_mix";
break;
}
code += ";\n\n";
code += "uniform sampler2D source_texture0 : hint_blit_source0;\n";
code += "uniform sampler2D source_texture1 : hint_blit_source1;\n";
code += "uniform sampler2D source_texture2 : hint_blit_source2;\n";
code += "uniform sampler2D source_texture3 : hint_blit_source3;\n\n";
code += "void blit() {\n";
code += " // Copies from each whole source texture to a rect on each output texture.\n";
code += " COLOR0 = texture(source_texture0, UV) * MODULATE;\n";
code += " COLOR1 = texture(source_texture1, UV) * MODULATE;\n";
code += " COLOR2 = texture(source_texture2, UV) * MODULATE;\n";
code += " COLOR3 = texture(source_texture3, UV) * MODULATE;\n}";
RS::get_singleton()->shader_set_code(shader_cache[index], code);
}
}
void BlitMaterial::set_blend_mode(BlendMode p_blend_mode) {
blend_mode = p_blend_mode;
_update_shader(blend_mode);
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(blend_mode)]);
}
}
BlitMaterial::BlendMode BlitMaterial::get_blend_mode() const {
return blend_mode;
}
RID BlitMaterial::get_shader_rid() const {
_update_shader(blend_mode);
return shader_cache[int(blend_mode)];
}
Shader::Mode BlitMaterial::get_shader_mode() const {
return Shader::MODE_TEXTURE_BLIT;
}
RID BlitMaterial::get_rid() const {
_update_shader(blend_mode);
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(blend_mode)]);
shader_set = true;
}
return _get_material();
}
Mutex BlitMaterial::shader_mutex;
RID BlitMaterial::shader_cache[5];
void BlitMaterial::cleanup_shader() {
for (int i = 0; i < 5; i++) {
if (shader_cache[i].is_valid()) {
RS::get_singleton()->free_rid(shader_cache[i]);
}
}
}
void BlitMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &BlitMaterial::set_blend_mode);
ClassDB::bind_method(D_METHOD("get_blend_mode"), &BlitMaterial::get_blend_mode);
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply,Disabled"), "set_blend_mode", "get_blend_mode");
BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
BIND_ENUM_CONSTANT(BLEND_MODE_DISABLED);
}
BlitMaterial::BlitMaterial() {
_set_material(RS::get_singleton()->material_create());
set_blend_mode(BLEND_MODE_MIX);
}
BlitMaterial::~BlitMaterial() {
}

View file

@ -0,0 +1,72 @@
/**************************************************************************/
/* blit_material.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. */
/**************************************************************************/
#pragma once
#include "scene/resources/material.h"
class BlitMaterial : public Material {
GDCLASS(BlitMaterial, Material);
public:
enum BlendMode {
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_DISABLED
};
private:
static Mutex shader_mutex;
static RID shader_cache[5];
static void _update_shader(BlendMode p_blend);
mutable bool shader_set = false;
BlendMode blend_mode = BLEND_MODE_MIX;
protected:
static void _bind_methods();
public:
void set_blend_mode(BlendMode p_blend_mode);
BlendMode get_blend_mode() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
static void cleanup_shader();
BlitMaterial();
virtual ~BlitMaterial();
};
VARIANT_ENUM_CAST(BlitMaterial::BlendMode);

View file

@ -0,0 +1,241 @@
/**************************************************************************/
/* drawable_texture_2d.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 "drawable_texture_2d.h"
DrawableTexture2D::DrawableTexture2D() {
default_material = RS::get_singleton()->texture_drawable_get_default_material();
}
DrawableTexture2D::~DrawableTexture2D() {
if (texture.is_valid()) {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free_rid(texture);
}
}
// Initialize Texture Resource with a call to rendering server. Overwrite existing.
void DrawableTexture2D::_initialize() {
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_drawable_create(width, height, (RS::TextureDrawableFormat)format, base_color, mipmaps);
RS::get_singleton()->texture_replace(texture, new_texture);
} else {
texture = RS::get_singleton()->texture_drawable_create(width, height, (RS::TextureDrawableFormat)format, base_color, mipmaps);
}
}
// Setup basic parameters on the Drawable Texture
void DrawableTexture2D::setup(int p_width, int p_height, DrawableFormat p_format, const Color &p_color, bool p_use_mipmaps) {
ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be in the 1 to 16384 range.");
ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be in the 1 to 16384 range.");
width = p_width;
height = p_height;
format = p_format;
mipmaps = p_use_mipmaps;
base_color = p_color;
_initialize();
notify_property_list_changed();
emit_changed();
}
void DrawableTexture2D::set_width(int p_width) {
ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be in the 1 to 16384 range.");
if (width == p_width) {
return;
}
width = p_width;
notify_property_list_changed();
emit_changed();
}
int DrawableTexture2D::get_width() const {
return width;
}
void DrawableTexture2D::set_height(int p_height) {
ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be in the 1 to 16384 range.");
if (height == p_height) {
return;
}
height = p_height;
notify_property_list_changed();
emit_changed();
}
int DrawableTexture2D::get_height() const {
return height;
}
void DrawableTexture2D::set_format(DrawableFormat p_format) {
if (format == p_format) {
return;
}
format = p_format;
notify_property_list_changed();
emit_changed();
}
DrawableTexture2D::DrawableFormat DrawableTexture2D::get_format() const {
return format;
}
void DrawableTexture2D::set_use_mipmaps(bool p_mipmaps) {
if (mipmaps == p_mipmaps) {
return;
}
mipmaps = p_mipmaps;
notify_property_list_changed();
emit_changed();
}
bool DrawableTexture2D::get_use_mipmaps() const {
return mipmaps;
}
RID DrawableTexture2D::get_rid() const {
if (texture.is_null()) {
// We are in trouble, create something temporary.
// 4, 4, false, Image::FORMAT_RGBA8
texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
}
return texture;
}
void DrawableTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
if ((width | height) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(width, height)), texture, false, p_modulate, p_transpose);
}
void DrawableTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
if ((width | height) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
}
void DrawableTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
if ((width | height) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
// Perform a blit operation from the given source to the given rect on self.
void DrawableTexture2D::blit_rect(const Rect2i p_rect, const Ref<Texture2D> &p_source, const Color &p_modulate, int p_mipmap, const Ref<Material> &p_material) {
// Use user Shader if exists.
RID material = default_material;
if (p_material.is_valid()) {
material = p_material->get_rid();
if (p_material->get_shader_mode() != Shader::MODE_TEXTURE_BLIT) {
WARN_PRINT("ShaderMaterial passed to blit_rect() is not a texture_blit shader. Using default instead.");
}
}
// Rendering server expects textureParameters as a TypedArray[RID]
Array textures;
textures.push_back(texture);
if (p_source.is_valid()) {
ERR_FAIL_COND_MSG(texture == p_source->get_rid(), "Cannot use self as a source.");
}
Array src_textures;
if (Ref<AtlasTexture>(p_source).is_valid()) {
WARN_PRINT("AtlasTexture not supported as a source for blit_rect. Using default White.");
src_textures.push_back(RID());
} else {
src_textures.push_back(p_source);
}
RS::get_singleton()->texture_drawable_blit_rect(textures, p_rect, material, p_modulate, src_textures, p_mipmap);
notify_property_list_changed();
}
// Perform a blit operation from the given sources to the given rect on self and extra targets
void DrawableTexture2D::blit_rect_multi(const Rect2i p_rect, const TypedArray<Texture2D> &p_sources, const TypedArray<DrawableTexture2D> &p_extra_targets, const Color &p_modulate, int p_mipmap, const Ref<Material> &p_material) {
RID material = default_material;
if (p_material.is_valid()) {
material = p_material->get_rid();
if (p_material->get_shader_mode() != Shader::MODE_TEXTURE_BLIT) {
WARN_PRINT("ShaderMaterial passed to blit_rect_multi() is not a texture_blit shader. Using default instead.");
}
}
// Rendering server expects textureParameters as a TypedArray[RID]
Array textures;
textures.push_back(texture);
int i = 0;
while (i < p_extra_targets.size()) {
textures.push_back(RID(p_extra_targets[i]));
i += 1;
}
i = 0;
Array src_textures;
while (i < p_sources.size()) {
if (Ref<AtlasTexture>(p_sources[i]).is_valid()) {
WARN_PRINT("AtlasTexture not supported as a source for blit_rect. Using default White.");
src_textures.push_back(RID());
} else {
src_textures.push_back(RID(p_sources[i]));
}
ERR_FAIL_COND_MSG(textures.has(RID(src_textures[i])), "Cannot use self as a source.");
i += 1;
}
RS::get_singleton()->texture_drawable_blit_rect(textures, p_rect, material, p_modulate, src_textures, p_mipmap);
notify_property_list_changed();
}
Ref<Image> DrawableTexture2D::get_image() const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_2d_get(texture);
} else {
return Ref<Image>();
}
}
void DrawableTexture2D::generate_mipmaps() {
if (texture.is_valid()) {
RS::get_singleton()->texture_drawable_generate_mipmaps(texture);
}
}
void DrawableTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("setup", "width", "height", "format", "color", "use_mipmaps"), &DrawableTexture2D::setup, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("blit_rect", "rect", "source", "modulate", "mipmap", "material"), &DrawableTexture2D::blit_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0), DEFVAL(Ref<Material>()));
ClassDB::bind_method(D_METHOD("blit_rect_multi", "rect", "sources", "extra_targets", "modulate", "mipmap", "material"), &DrawableTexture2D::blit_rect_multi, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0), DEFVAL(Ref<Material>()));
ClassDB::bind_method(D_METHOD("generate_mipmaps"), &DrawableTexture2D::generate_mipmaps);
BIND_ENUM_CONSTANT(DRAWABLE_FORMAT_RGBA8);
BIND_ENUM_CONSTANT(DRAWABLE_FORMAT_RGBA8_SRGB);
BIND_ENUM_CONSTANT(DRAWABLE_FORMAT_RGBAH);
BIND_ENUM_CONSTANT(DRAWABLE_FORMAT_RGBAF);
}

View file

@ -0,0 +1,95 @@
/**************************************************************************/
/* drawable_texture_2d.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. */
/**************************************************************************/
#pragma once
#include "scene/resources/atlas_texture.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/material.h"
class DrawableTexture2D : public Texture2D {
GDCLASS(DrawableTexture2D, Texture2D);
RES_BASE_EXTENSION("tex");
public:
enum DrawableFormat {
DRAWABLE_FORMAT_RGBA8,
DRAWABLE_FORMAT_RGBA8_SRGB,
DRAWABLE_FORMAT_RGBAH,
DRAWABLE_FORMAT_RGBAF,
};
private:
mutable RID texture;
int width = 64;
int height = 64;
bool mipmaps = false;
DrawableFormat format = DRAWABLE_FORMAT_RGBA8;
Color base_color = Color(1, 1, 1, 1);
RID default_material;
void _initialize();
protected:
static void _bind_methods();
public:
void set_width(int p_width);
int get_width() const override;
void set_height(int p_height);
int get_height() const override;
void set_format(DrawableFormat p_format);
DrawableFormat get_format() const;
void set_use_mipmaps(bool p_mipmaps);
bool get_use_mipmaps() const;
virtual RID get_rid() const override;
virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
void setup(int p_width, int p_height, DrawableFormat p_format, const Color &p_modulate = Color(1, 1, 1, 1), bool p_use_mipmaps = false);
void blit_rect(const Rect2i p_rect, const Ref<Texture2D> &p_source, const Color &p_modulate = Color(1, 1, 1, 1), int p_mipmap = 0, const Ref<Material> &p_material = Ref<Material>());
void blit_rect_multi(const Rect2i p_rect, const TypedArray<Texture2D> &p_sources, const TypedArray<DrawableTexture2D> &p_extra_targets, const Color &p_modulate = Color(1, 1, 1, 1), int p_mipmap = 0, const Ref<Material> &p_material = Ref<Material>());
virtual Ref<Image> get_image() const override;
void generate_mipmaps();
DrawableTexture2D();
~DrawableTexture2D();
};
VARIANT_ENUM_CAST(DrawableTexture2D::DrawableFormat)

View file

@ -118,6 +118,8 @@ void Shader::set_code(const String &p_code) {
mode = MODE_SKY;
} else if (type == "fog") {
mode = MODE_FOG;
} else if (type == "texture_blit") {
mode = MODE_TEXTURE_BLIT;
} else {
mode = MODE_SPATIAL;
}
@ -290,6 +292,7 @@ void Shader::_bind_methods() {
BIND_ENUM_CONSTANT(MODE_PARTICLES);
BIND_ENUM_CONSTANT(MODE_SKY);
BIND_ENUM_CONSTANT(MODE_FOG);
BIND_ENUM_CONSTANT(MODE_TEXTURE_BLIT);
}
Shader::Shader() {

View file

@ -48,6 +48,7 @@ public:
MODE_PARTICLES,
MODE_SKY,
MODE_FOG,
MODE_TEXTURE_BLIT,
MODE_MAX
};

View file

@ -37,7 +37,7 @@
#include "visual_shader_particle_nodes.h"
String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) {
static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog", "texture_blit" };
return p_name + "_" + String(typepf[p_type]) + "_" + itos(p_id);
}
@ -1718,6 +1718,7 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
"process_custom",
"sky",
"fog",
"texture_blit",
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
@ -1958,7 +1959,7 @@ void VisualShader::reset_state() {
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Spatial,CanvasItem,Particles,Sky,Fog"));
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Spatial,CanvasItem,Particles,Sky,Fog,TextureBlit"));
//render modes
HashMap<String, String> blend_mode_enums;
@ -2683,7 +2684,7 @@ void VisualShader::_update_shader() const {
Vector<VisualShader::DefaultTextureParam> default_tex_params;
HashSet<StringName> classes;
HashMap<int, int> insertion_pos;
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog" };
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog", "texture_blit" };
global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
@ -2786,7 +2787,7 @@ void VisualShader::_update_shader() const {
global_code += "stencil_mode " + stencil_mode + ";\n\n";
}
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog", "blit" };
String global_expressions;
HashSet<String> used_parameter_names;
@ -2794,6 +2795,13 @@ void VisualShader::_update_shader() const {
HashMap<int, List<int>> emitters;
HashMap<int, List<int>> varying_setters;
if (shader_mode == Shader::MODE_TEXTURE_BLIT) {
global_code += "uniform sampler2D source_texture0 : hint_blit_source0;\n";
global_code += "uniform sampler2D source_texture1 : hint_blit_source1;\n";
global_code += "uniform sampler2D source_texture2 : hint_blit_source2;\n";
global_code += "uniform sampler2D source_texture3 : hint_blit_source3;\n\n";
}
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
continue;
@ -2905,7 +2913,7 @@ void VisualShader::_update_shader() const {
HashSet<int> processed;
bool is_empty_func = false;
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG && shader_mode != Shader::MODE_TEXTURE_BLIT) {
is_empty_func = true;
}
@ -3221,6 +3229,7 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_PROCESS_CUSTOM);
BIND_ENUM_CONSTANT(TYPE_SKY);
BIND_ENUM_CONSTANT(TYPE_FOG);
BIND_ENUM_CONSTANT(TYPE_TEXTURE_BLIT);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_ENUM_CONSTANT(VARYING_MODE_VERTEX_TO_FRAG_LIGHT);
@ -3550,6 +3559,15 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "uvw", "UVW" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "world_position", "WORLD_POSITION" },
// Blit, Blit
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "modulate", "MODULATE" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_SAMPLER, "source_texture", "source_texture" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_SAMPLER, "source_texture2", "source_texture2" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_SAMPLER, "source_texture3", "source_texture3" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_SAMPLER, "source_texture4", "source_texture4" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@ -3630,6 +3648,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Blit
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "modulate", "MODULATE" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_SAMPLER, "source_texture", "source_texture" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@ -4265,6 +4288,14 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
////////////////////////////////////////////////////////////////////////
// Blit, Blit.
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color0", "COLOR0" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color1", "COLOR1" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color2", "COLOR2" },
{ Shader::MODE_TEXTURE_BLIT, VisualShader::TYPE_TEXTURE_BLIT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color3", "COLOR3" },
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};

View file

@ -53,6 +53,7 @@ public:
TYPE_PROCESS_CUSTOM,
TYPE_SKY,
TYPE_FOG,
TYPE_TEXTURE_BLIT,
TYPE_MAX
};

View file

@ -178,6 +178,8 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
new_mode = RS::SHADER_SKY;
} else if (mode_string == "fog") {
new_mode = RS::SHADER_FOG;
} else if (mode_string == "texture_blit") {
new_mode = RS::SHADER_TEXTURE_BLIT;
} else {
new_mode = RS::SHADER_MAX;
ERR_FAIL_MSG("Shader type " + mode_string + " not supported in Dummy renderer.");

View file

@ -88,6 +88,7 @@ public:
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_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 void texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) override {}
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(); }
@ -96,6 +97,8 @@ public:
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 {}
virtual void texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) override {}
//these two APIs can be used together or in combination with the others.
virtual void texture_2d_placeholder_initialize(RID p_texture) override {}
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override {}
@ -109,6 +112,9 @@ public:
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); }
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }
virtual void texture_drawable_generate_mipmaps(RID p_texture) override {}
virtual RID texture_drawable_get_default_material() const override { return RID(); }
virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); }
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override {}

View file

@ -164,6 +164,7 @@ void RendererCompositorRD::initialize() {
uint64_t RendererCompositorRD::frame = 1;
void RendererCompositorRD::finalize() {
texture_storage->_tex_blit_shader_free();
memdelete(scene);
memdelete(canvas);
memdelete(fog);
@ -318,6 +319,7 @@ RendererCompositorRD::RendererCompositorRD() {
particles_storage = memnew(RendererRD::ParticlesStorage);
fog = memnew(RendererRD::Fog);
canvas = memnew(RendererCanvasRenderRD());
texture_storage->_tex_blit_shader_initialize();
String rendering_method = OS::get_singleton()->get_current_rendering_method();
uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);

View file

@ -0,0 +1,128 @@
/* clang-format off */
#[vertex]
#version 450
// Has to be same push_constant for vertex & frag
layout(push_constant, std430) uniform TexBlitData {
vec2 offset;
vec2 size;
vec4 modulate;
vec2 pad;
int convert_to_srgb;
float time;
} data;
layout(location = 0) out vec2 uv;
void main() {
vec2 base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(0.0), vec2(1.0, 0.0), vec2(1.0, 1.0));
uv = base_arr[gl_VertexIndex];
// gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
gl_Position = vec4( (data.offset + (uv * data.size)) * 2.0 - 1.0, 1.0, 1.0);
}
#[fragment]
#version 450
#VERSION_DEFINES
#include "samplers_inc.glsl"
#define OUTPUT0_SRGB uint(1)
#define OUTPUT1_SRGB uint(2)
#define OUTPUT2_SRGB uint(4)
#define OUTPUT3_SRGB uint(8)
layout(push_constant, std430) uniform TexBlitData {
vec2 offset;
vec2 size;
vec4 modulate;
vec2 pad;
int convert_to_srgb;
float time;
} data;
layout(set = 0, binding = 0) uniform texture2D source0;
layout(set = 0, binding = 1) uniform texture2D source1;
layout(set = 0, binding = 2) uniform texture2D source2;
layout(set = 0, binding = 3) uniform texture2D source3;
layout(location = 0) in vec2 uv;
layout (location = 0) out vec4 out_color0;
#ifdef USE_OUTPUT1
layout (location = 1) out vec4 out_color1;
#endif
#ifdef USE_OUTPUT2
layout (location = 2) out vec4 out_color2;
#endif
#ifdef USE_OUTPUT3
layout (location = 3) out vec4 out_color3;
#endif
#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms {
#MATERIAL_UNIFORMS
} material;
#endif
#GLOBALS
vec3 linear_to_srgb(vec3 color) {
// If going to srgb, clamp from 0 to 1.
color = clamp(color, vec3(0.0), vec3(1.0));
const vec3 a = vec3(0.055f);
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
void main() {
// Handles the case where user code uses extra outputs, but extra output targets were not bound
vec4 color0 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color1 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color2 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 color3 = vec4(0.0, 0.0, 0.0, 1.0);
#CODE : BLIT
// Discards extra outputs if extra output targets were not bound
out_color0 = color0;
#ifdef USE_OUTPUT1
out_color1 = color1;
#endif
#ifdef USE_OUTPUT2
out_color2 = color2;
#endif
#ifdef USE_OUTPUT3
out_color3 = color3;
#endif
if (bool(data.convert_to_srgb & OUTPUT0_SRGB)) {
out_color0.rgb = linear_to_srgb(out_color0.rgb); // Regular linear -> SRGB conversion.
}
#ifdef USE_OUTPUT1
if (bool(data.convert_to_srgb & OUTPUT1_SRGB)) {
out_color1.rgb = linear_to_srgb(out_color1.rgb);
}
#endif
#ifdef USE_OUTPUT2
if (bool(data.convert_to_srgb & OUTPUT2_SRGB)) {
out_color2.rgb = linear_to_srgb(out_color2.rgb);
}
#endif
#ifdef USE_OUTPUT3
if (bool(data.convert_to_srgb & OUTPUT3_SRGB)) {
out_color3.rgb = linear_to_srgb(out_color3.rgb);
}
#endif
}

View file

@ -1243,6 +1243,178 @@ void MaterialStorage::MaterialData::set_as_used() {
}
}
/* TextureBlit SHADER */
void MaterialStorage::TexBlitShaderData::set_code(const String &p_code) {
TextureStorage *texture_storage = TextureStorage::get_singleton();
// Initialize and compile the shader.
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code.is_empty()) {
return; // Just invalid, but no error.
}
ShaderCompiler::GeneratedCode gen_code;
// Actual enum set further down after compilation.
int blend_modei = BLEND_MODE_DISABLED;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["blit"] = ShaderCompiler::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
actions.uniforms = &uniforms;
Error err = texture_storage->tex_blit_shader.compiler.compile(RS::SHADER_TEXTURE_BLIT, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = texture_storage->tex_blit_shader.shader.version_create();
}
blend_mode = BlendMode(blend_modei);
#if 0
print_line("**compiling shader:");
print_line("**defines:\n");
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
print_line("\n**code " + el->key + ":\n" + el->value);
++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
texture_storage->tex_blit_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!texture_storage->tex_blit_shader.shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
RD::PipelineColorBlendState blend_state_color_blend;
RD::PipelineColorBlendState::Attachment attachment;
// blend_mode_to_blend_attachment(blend_mode) does not work
// Because we want BlendAdd and BlendSub to behave differently for Texture_Blit
switch (blend_mode) {
case BLEND_MODE_MIX: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_SUB: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_MUL: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_DISABLED:
default: {
// Use default attachment values.
} break;
}
blend_state_color_blend.attachments = { attachment, attachment, attachment, attachment };
// Update Pipelines
for (int i = 0; i < 4; i++) {
RID shader_variant = texture_storage->tex_blit_shader.shader.version_get_shader(version, i);
pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_color_blend, 0);
}
valid = true;
}
bool MaterialStorage::TexBlitShaderData::is_animated() const {
return false;
}
bool MaterialStorage::TexBlitShaderData::casts_shadows() const {
return false;
}
RS::ShaderNativeSourceCode MaterialStorage::TexBlitShaderData::get_native_source_code() const {
return TextureStorage::get_singleton()->tex_blit_shader.shader.version_get_native_source_code(version);
}
Pair<ShaderRD *, RID> MaterialStorage::TexBlitShaderData::get_native_shader_and_version() const {
return { &TextureStorage::get_singleton()->tex_blit_shader.shader, version };
}
MaterialStorage::TexBlitShaderData::TexBlitShaderData() {
valid = false;
}
MaterialStorage::TexBlitShaderData::~TexBlitShaderData() {
if (version.is_valid()) {
TextureStorage::get_singleton()->tex_blit_shader.shader.version_free(version);
}
}
MaterialStorage::ShaderData *MaterialStorage::_create_tex_blit_shader_func() {
MaterialStorage::TexBlitShaderData *shader_data = memnew(MaterialStorage::TexBlitShaderData);
return shader_data;
}
bool MaterialStorage::TexBlitMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
uniform_set_updated = true;
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, TextureStorage::get_singleton()->tex_blit_shader.shader.version_get_shader(shader_data->version, 0), 1, true, false);
}
MaterialStorage::TexBlitMaterialData::~TexBlitMaterialData() {
free_parameters_uniform_set(uniform_set);
}
MaterialStorage::MaterialData *MaterialStorage::_create_tex_blit_material_func(MaterialStorage::ShaderData *p_shader) {
MaterialStorage::TexBlitMaterialData *material_data = memnew(TexBlitMaterialData);
material_data->shader_data = static_cast<TexBlitShaderData *>(p_shader);
//update will happen later anyway so do nothing.
return material_data;
}
///////////////////////////////////////////////////////////////////////////
// MaterialStorage::Samplers
@ -2033,6 +2205,8 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
new_type = SHADER_TYPE_SKY;
} else if (mode_string == "fog") {
new_type = SHADER_TYPE_FOG;
} else if (mode_string == "texture_blit") {
new_type = SHADER_TYPE_TEXTURE_BLIT;
} else {
new_type = SHADER_TYPE_MAX;
}

View file

@ -36,6 +36,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/shader_compiler.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering/storage/material_storage.h"
@ -51,6 +52,7 @@ public:
SHADER_TYPE_PARTICLES,
SHADER_TYPE_SKY,
SHADER_TYPE_FOG,
SHADER_TYPE_TEXTURE_BLIT,
SHADER_TYPE_MAX
};
@ -134,6 +136,53 @@ public:
bool is_null() const;
};
/* Texture Blit Shader */
struct TexBlitShaderData : public ShaderData {
bool valid;
RID version;
PipelineCacheRD pipelines[4];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String code;
BlendMode blend_mode;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
virtual Pair<ShaderRD *, RID> get_native_shader_and_version() const;
TexBlitShaderData();
virtual ~TexBlitShaderData();
};
ShaderData *_create_tex_blit_shader_func();
static MaterialStorage::ShaderData *_create_tex_blit_shader_funcs() {
return get_singleton()->_create_tex_blit_shader_func();
}
struct TexBlitMaterialData : public MaterialData {
TexBlitShaderData *shader_data = nullptr;
RID uniform_set;
bool uniform_set_updated;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~TexBlitMaterialData();
};
MaterialData *_create_tex_blit_material_func(ShaderData *p_shader);
static MaterialStorage::MaterialData *_create_tex_blit_material_funcs(MaterialStorage::ShaderData *p_shader) {
return get_singleton()->_create_tex_blit_material_func(static_cast<TexBlitShaderData *>(p_shader));
}
private:
static MaterialStorage *singleton;

View file

@ -32,7 +32,9 @@
#include "../effects/copy_effects.h"
#include "../framebuffer_cache_rd.h"
#include "../uniform_set_cache_rd.h"
#include "material_storage.h"
#include "render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
using namespace RendererRD;
@ -633,6 +635,92 @@ TextureStorage::~TextureStorage() {
singleton = nullptr;
}
// Has to be a separate call from TextureStorage initialization due to interacting with Material Storage
void TextureStorage::_tex_blit_shader_initialize() {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
{
Vector<String> tex_blit_modes;
tex_blit_modes.push_back(""); // Only 1 Output
tex_blit_modes.push_back("\n#define USE_OUTPUT1\n"); // 2 Outputs
tex_blit_modes.push_back("\n#define USE_OUTPUT1\n#define USE_OUTPUT2\n"); // 3 Outputs
tex_blit_modes.push_back("\n#define USE_OUTPUT1\n#define USE_OUTPUT2\n#define USE_OUTPUT3\n"); // 4 Outputs
String global_defines;
global_defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
tex_blit_shader.shader.initialize(tex_blit_modes, global_defines);
}
material_storage->shader_set_data_request_function(MaterialStorage::SHADER_TYPE_TEXTURE_BLIT, MaterialStorage::_create_tex_blit_shader_funcs);
material_storage->material_set_data_request_function(MaterialStorage::SHADER_TYPE_TEXTURE_BLIT, MaterialStorage::_create_tex_blit_material_funcs);
{
// Setup TextureBlit compiler
ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["TIME"] = "data.time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["UV"] = "uv";
actions.renames["MODULATE"] = "data.modulate";
actions.renames["COLOR0"] = "color0";
actions.renames["COLOR1"] = "color1";
actions.renames["COLOR2"] = "color2";
actions.renames["COLOR3"] = "color3";
actions.base_uniform_string = "material.";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = 1;
tex_blit_shader.compiler.initialize(actions);
}
{
// default material and shader for Texture Blit shader
tex_blit_shader.default_shader = material_storage->shader_allocate();
material_storage->shader_initialize(tex_blit_shader.default_shader);
material_storage->shader_set_code(tex_blit_shader.default_shader, R"(
// Default Texture Blit shader.
shader_type texture_blit;
render_mode blend_mix;
uniform sampler2D source_texture0 : hint_blit_source0;
uniform sampler2D source_texture1 : hint_blit_source1;
uniform sampler2D source_texture2 : hint_blit_source2;
uniform sampler2D source_texture3 : hint_blit_source3;
void blit() {
// Copies from each whole source texture to a rect on each output texture.
COLOR0 = texture(source_texture0, UV) * MODULATE;
COLOR1 = texture(source_texture1, UV) * MODULATE;
COLOR2 = texture(source_texture2, UV) * MODULATE;
COLOR3 = texture(source_texture3, UV) * MODULATE;
}
)");
tex_blit_shader.default_material = material_storage->material_allocate();
material_storage->material_initialize(tex_blit_shader.default_material);
material_storage->material_set_shader(tex_blit_shader.default_material, tex_blit_shader.default_shader);
}
tex_blit_shader.initialized = true;
}
// Has to be a separate call from TextureStorage destruction due to interacting with Material Storage
void TextureStorage::_tex_blit_shader_free() {
if (tex_blit_shader.initialized) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
print_verbose("Freeing Default Tex_Blit Shader");
material_storage->material_free(tex_blit_shader.default_material);
material_storage->shader_free(tex_blit_shader.default_shader);
}
}
bool TextureStorage::free(RID p_rid) {
if (owns_texture(p_rid)) {
texture_free(p_rid);
@ -1164,6 +1252,106 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
tex->proxies.push_back(p_texture);
}
void TextureStorage::texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) {
// Near identical to Texture_2D_initialize, Generates an empty white image based on parameters
// GUARDRAIL: Bad Widths/Heights
ERR_FAIL_COND_MSG(p_width <= 0 || p_height <= 0, "Drawable Texture Width or Height cannot be less than 1.");
ERR_FAIL_COND_MSG(p_width >= 16384 || p_height >= 16384, "Drawable Texture Width or Height cannot be greater than 16383.");
Image::Format format;
switch (p_format) {
case RS::TEXTURE_DRAWABLE_FORMAT_RGBA8:
format = Image::FORMAT_RGBA8;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB:
format = Image::FORMAT_RGBA8;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBAH:
format = Image::FORMAT_RGBAH;
break;
case RS::TEXTURE_DRAWABLE_FORMAT_RGBAF:
format = Image::FORMAT_RGBAF;
break;
default:
format = Image::FORMAT_RGBA8;
}
Ref<Image> image = Image::create_empty(p_width, p_height, p_with_mipmaps, format);
image->fill(p_color);
TextureToRDFormat ret_format;
Ref<Image> valid_image = _validate_texture_format(image, ret_format);
Texture texture;
texture.type = TextureStorage::TYPE_2D;
texture.width = p_width;
texture.height = p_height;
texture.layers = 1;
texture.mipmaps = image->get_mipmap_count() + 1;
texture.depth = 1;
texture.format = image->get_format();
texture.validated_format = image->get_format();
texture.rd_type = RD::TEXTURE_TYPE_2D;
texture.rd_format = ret_format.format;
texture.rd_format_srgb = ret_format.format_srgb;
RD::TextureFormat rd_format;
RD::TextureView rd_view;
{ //attempt register
rd_format.format = texture.rd_format;
rd_format.width = texture.width;
rd_format.height = texture.height;
rd_format.depth = 1;
rd_format.array_layers = 1;
rd_format.mipmaps = texture.mipmaps;
rd_format.texture_type = texture.rd_type;
rd_format.samples = RD::TEXTURE_SAMPLES_1;
// The Color Attachment Usage bit here is what differentiates a DrawableTexture from a regular Texture2D
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_format.shareable_formats.push_back(texture.rd_format);
rd_format.shareable_formats.push_back(texture.rd_format_srgb);
}
}
{
rd_view.swizzle_r = ret_format.swizzle_r;
rd_view.swizzle_g = ret_format.swizzle_g;
rd_view.swizzle_b = ret_format.swizzle_b;
rd_view.swizzle_a = ret_format.swizzle_a;
}
Vector<uint8_t> data = image->get_data(); //use image data
Vector<Vector<uint8_t>> data_slices;
data_slices.push_back(data);
texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices);
ERR_FAIL_COND(texture.rd_texture.is_null());
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_view.format_override = texture.rd_format_srgb;
texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture);
if (texture.rd_texture_srgb.is_null()) {
RD::get_singleton()->free_rid(texture.rd_texture);
ERR_FAIL_COND(texture.rd_texture_srgb.is_null());
}
}
// Used for Drawable Textures.
for (int i = 0; i < texture.mipmaps; i++) {
texture.cached_rd_slices.append(RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture.rd_texture, 0, i));
}
//used for 2D, overridable
texture.width_2d = texture.width;
texture.height_2d = texture.height;
texture.is_render_target = false;
texture.rd_view = rd_view;
texture.is_proxy = false;
texture_owner.initialize_rid(p_texture, 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) {
@ -1474,6 +1662,145 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
}
}
// Output textures in p_textures must ALL BE THE SAME SIZE
void TextureStorage::texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) {
ERR_FAIL_COND_MSG(!tex_blit_shader.initialized, "Texture Blit shader & materials not yet initialized.");
ERR_FAIL_COND_MSG(p_textures.is_empty() || p_source_textures.is_empty(), "Blit Rect texture output and source arrays must contain at least 1 texture.");
const RID default_tex_rid = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
RendererRD::MaterialStorage::TexBlitMaterialData *m = static_cast<RendererRD::MaterialStorage::TexBlitMaterialData *>(material_storage->material_get_data(p_material, RendererRD::MaterialStorage::SHADER_TYPE_TEXTURE_BLIT));
if (!m) {
m = static_cast<RendererRD::MaterialStorage::TexBlitMaterialData *>(material_storage->material_get_data(tex_blit_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_TEXTURE_BLIT));
}
// GUARDRAIL:: p_material MUST BE ShaderType TextureBlit
ERR_FAIL_NULL(m);
RendererRD::MaterialStorage::TexBlitShaderData *shader_data = m->shader_data;
ERR_FAIL_NULL(shader_data);
material_storage->_update_queued_materials();
RID shaderRD = tex_blit_shader.shader.version_get_shader(shader_data->version, p_source_textures.size() - 1);
RID tar_textures[4];
Texture *src_textures[4];
RID uniform_texture_set;
int TEX_BLIT_MATERIAL_SET = 1;
int TEX_BLIT_TEXTURE_SET = 0;
int srgb_mask = 0;
const int srgbMaskArray[4] = { 1, 2, 4, 8 };
LocalVector<RD::Uniform> texture_uniforms;
int i = 0;
while (i < 4) {
// Load Target Textures
if (i < p_textures.size()) {
Texture *tex = get_texture(p_textures[i]);
srgb_mask += get_texture(p_textures[i])->drawable_type == RS::TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB ? srgbMaskArray[i] : 0;
ERR_FAIL_NULL_MSG(tex, "Drawable Texture target cannot be null.");
ERR_FAIL_COND_MSG(p_to_mipmap >= tex->mipmaps || p_to_mipmap >= tex->cached_rd_slices.size(), vformat("Drawable Texture Target does not have mipmap level %d.", p_to_mipmap));
if (i > 0) {
ERR_FAIL_COND_MSG(texture_2d_get_size(p_textures[i - 1]) != texture_2d_get_size(p_textures[i]), "All Blit_Rect output textures must be same size.");
}
tar_textures[i] = tex->cached_rd_slices[p_to_mipmap];
}
// Load and bind source textures, load default Black if source is bad.
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = i;
if (i < p_source_textures.size()) {
src_textures[i] = get_texture(p_source_textures[i]);
if (!src_textures[i]) {
u.append_id(default_tex_rid);
} else {
u.append_id(src_textures[i]->rd_texture);
}
} else {
u.append_id(default_tex_rid);
}
texture_uniforms.push_back(u);
i += 1;
}
// Calculates the Rects Offset & Size in UV space for Shader to scale Vertex Quad correctly
Vector2i size = texture_2d_get_size(p_textures[0]);
Vector2 offset = Vector2(float(p_rect.position.x) / size.x, float(p_rect.position.y) / size.y);
Vector2 rect_size = Vector2(float(p_rect.size.x) / size.x, float(p_rect.size.y) / size.y);
// Select Pipeline based on # of targets.
RID tex_blit_fb;
PipelineCacheRD *pipeline;
switch (p_textures.size()) {
case 1:
tex_blit_fb = FramebufferCacheRD::get_singleton()->get_cache(tar_textures[0]);
pipeline = &shader_data->pipelines[0];
break;
case 2:
tex_blit_fb = FramebufferCacheRD::get_singleton()->get_cache(tar_textures[0], tar_textures[1]);
pipeline = &shader_data->pipelines[1];
break;
case 3:
tex_blit_fb = FramebufferCacheRD::get_singleton()->get_cache(tar_textures[0], tar_textures[1], tar_textures[2]);
pipeline = &shader_data->pipelines[2];
break;
case 4:
tex_blit_fb = FramebufferCacheRD::get_singleton()->get_cache(tar_textures[0], tar_textures[1], tar_textures[2], tar_textures[3]);
pipeline = &shader_data->pipelines[3];
break;
default:
tex_blit_fb = FramebufferCacheRD::get_singleton()->get_cache(tar_textures[0], tar_textures[1], tar_textures[2], tar_textures[3]);
pipeline = &shader_data->pipelines[3];
}
// Bind uniforms via push_constant
TexBlitPushConstant push_constant;
memset(&push_constant, 0, sizeof(TexBlitPushConstant));
push_constant.offset[0] = offset.x;
push_constant.offset[1] = offset.y;
push_constant.size[0] = rect_size.x;
push_constant.size[1] = rect_size.y;
push_constant.modulate[0] = p_modulate.r;
push_constant.modulate[1] = p_modulate.g;
push_constant.modulate[2] = p_modulate.b;
push_constant.modulate[3] = p_modulate.a;
push_constant.convert_to_srgb = srgb_mask;
push_constant.time = RSG::rasterizer->get_total_time();
Rect2i tex_blit_rr;
RD::get_singleton()->draw_command_begin_label("Blit Rect");
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(tex_blit_fb, RD::DRAW_DEFAULT_ALL, Vector<Color>(), 1.0f, 0u, tex_blit_rr);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(tex_blit_fb);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, 0));
material_storage->samplers_rd_get_default().append_uniforms(texture_uniforms, 4);
uniform_texture_set = UniformSetCacheRD::get_singleton()->get_cache_vec(shaderRD, TEX_BLIT_TEXTURE_SET, texture_uniforms);
{
// Push Constants
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(TexBlitPushConstant));
// Material Uniforms
if (m->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(m->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, m->uniform_set, TEX_BLIT_MATERIAL_SET);
}
// Texture Uniforms
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_texture_set, TEX_BLIT_TEXTURE_SET);
}
// DRAW!!
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 6u);
RD::get_singleton()->draw_list_end();
RD::get_singleton()->draw_command_end_label();
}
//these two APIs can be used together or in combination with the others.
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
texture_2d_initialize(p_texture, texture_2d_placeholder);
@ -1599,6 +1926,38 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
return ret;
}
void TextureStorage::texture_drawable_generate_mipmaps(RID p_texture) {
Texture *tex = get_texture(p_texture);
CopyEffects *copy_effects = CopyEffects::get_singleton();
ERR_FAIL_NULL(copy_effects);
uint32_t mipmaps = tex->mipmaps;
int width = tex->width;
int height = tex->height;
RID source = tex->rd_texture;
RID dest = tex->cached_rd_slices[0];
for (uint32_t m = 1; m < mipmaps; m++) {
width = MAX(1, width >> 1);
height = MAX(1, height >> 1);
source = dest;
dest = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), source, 0, m, 1, RD::TEXTURE_SLICE_2D);
if (copy_effects->get_raster_effects().has_flag(CopyEffects::RASTER_EFFECT_COPY)) {
copy_effects->make_mipmap_raster(source, dest, Size2i(width, height));
} else {
copy_effects->make_mipmap(source, dest, Size2i(width, height));
}
}
}
RID TextureStorage::texture_drawable_get_default_material() const {
// Return a material with a default Texture_Blit shader for DrawableTexture2D to use
return tex_blit_shader.default_material;
}
void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL(tex);

View file

@ -33,8 +33,10 @@
#include "core/templates/paged_array.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/tex_blit.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/shader_compiler.h"
#include "servers/rendering/storage/texture_storage.h"
#include "servers/rendering/storage/utilities.h"
@ -45,6 +47,8 @@ class MaterialStorage;
class TextureStorage : public RendererTextureStorage {
public:
const int SAMPLERS_BINDING_FIRST_INDEX = 4;
enum DefaultRDTexture {
DEFAULT_RD_TEXTURE_WHITE,
DEFAULT_RD_TEXTURE_BLACK,
@ -144,12 +148,14 @@ private:
public:
TextureType type;
RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
RS::TextureDrawableFormat drawable_type = RS::TEXTURE_DRAWABLE_FORMAT_RGBA8;
RenderingDevice::TextureType rd_type;
RID rd_texture;
RID rd_texture_srgb;
RenderingDevice::DataFormat rd_format;
RenderingDevice::DataFormat rd_format_srgb;
Vector<RID> cached_rd_slices;
RD::TextureView rd_view;
@ -482,9 +488,32 @@ private:
RID pipelines[SHADER_MAX];
} rt_sdf;
struct TextureBlitShader {
TexBlitShaderRD shader;
ShaderCompiler compiler;
bool initialized = false;
RID default_shader;
RID default_material;
RID default_shader_version;
} tex_blit_shader;
struct TexBlitPushConstant {
float offset[2]; // 8 - 8
float size[2]; // 8 - 16
float modulate[4]; // 16 - 32
float pad[2]; // 8 - 40
uint32_t convert_to_srgb; // 4 - 44
float time; // 4 - 48
// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
public:
static TextureStorage *get_singleton();
void _tex_blit_shader_initialize();
void _tex_blit_shader_free();
_FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
return default_rd_textures[p_texture];
}
@ -523,6 +552,7 @@ public:
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_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 void texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) override;
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;
@ -531,6 +561,8 @@ public:
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;
virtual void texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) override;
Ref<Image> texture_2d_placeholder;
Vector<Ref<Image>> texture_2d_array_placeholder;
Vector<Ref<Image>> cubemap_placeholder;
@ -545,6 +577,9 @@ public:
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override;
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override;
virtual void texture_drawable_generate_mipmaps(RID p_texture) override;
virtual RID texture_drawable_get_default_material() const override;
virtual void texture_replace(RID p_texture, RID p_by_texture) override;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override;

View file

@ -2329,11 +2329,14 @@ void RenderingServer::_bind_methods() {
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_drawable_create", "width", "height", "format", "color", "with_mipmaps"), &RenderingServer::texture_drawable_create, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
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);
ClassDB::bind_method(D_METHOD("texture_proxy_update", "texture", "proxy_to"), &RenderingServer::texture_proxy_update);
ClassDB::bind_method(D_METHOD("texture_drawable_blit_rect", "textures", "rect", "material", "modulate", "source_textures", "to_mipmap"), &RenderingServer::texture_drawable_blit_rect, DEFVAL(0));
ClassDB::bind_method(D_METHOD("texture_2d_placeholder_create"), &RenderingServer::texture_2d_placeholder_create);
ClassDB::bind_method(D_METHOD("texture_2d_layered_placeholder_create", "layered_type"), &RenderingServer::texture_2d_layered_placeholder_create);
ClassDB::bind_method(D_METHOD("texture_3d_placeholder_create"), &RenderingServer::texture_3d_placeholder_create);
@ -2342,6 +2345,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_2d_layer_get", "texture", "layer"), &RenderingServer::texture_2d_layer_get);
ClassDB::bind_method(D_METHOD("texture_3d_get", "texture"), &RenderingServer::_texture_3d_get);
ClassDB::bind_method(D_METHOD("texture_drawable_generate_mipmaps", "texture"), &RenderingServer::texture_drawable_generate_mipmaps);
ClassDB::bind_method(D_METHOD("texture_drawable_get_default_material"), &RenderingServer::texture_drawable_get_default_material);
ClassDB::bind_method(D_METHOD("texture_replace", "texture", "by_texture"), &RenderingServer::texture_replace);
ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height"), &RenderingServer::texture_set_size_override);
@ -2370,6 +2376,11 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT);
BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK);
BIND_ENUM_CONSTANT(TEXTURE_DRAWABLE_FORMAT_RGBA8);
BIND_ENUM_CONSTANT(TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB);
BIND_ENUM_CONSTANT(TEXTURE_DRAWABLE_FORMAT_RGBAH);
BIND_ENUM_CONSTANT(TEXTURE_DRAWABLE_FORMAT_RGBAF);
/* SHADER */
ClassDB::bind_method(D_METHOD("shader_create"), &RenderingServer::shader_create);
@ -2387,6 +2398,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(SHADER_PARTICLES);
BIND_ENUM_CONSTANT(SHADER_SKY);
BIND_ENUM_CONSTANT(SHADER_FOG);
BIND_ENUM_CONSTANT(SHADER_TEXTURE_BLIT);
BIND_ENUM_CONSTANT(SHADER_MAX);
/* MATERIAL */

View file

@ -136,11 +136,19 @@ public:
CUBEMAP_LAYER_BACK
};
enum TextureDrawableFormat {
TEXTURE_DRAWABLE_FORMAT_RGBA8,
TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB, // Use this if you want to read the result from both 2D (non-hdr) and 3D.
TEXTURE_DRAWABLE_FORMAT_RGBAH,
TEXTURE_DRAWABLE_FORMAT_RGBAF,
};
virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &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<Ref<Image>> &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_drawable_create(int p_width, int p_height, TextureDrawableFormat p_format, const Color &p_color = Color(1, 1, 1, 1), bool p_with_mipmaps = false) = 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;
@ -149,6 +157,8 @@ public:
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;
virtual void texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap = 0) = 0;
// These two APIs can be used together or in combination with the others.
virtual RID texture_2d_placeholder_create() = 0;
virtual RID texture_2d_layered_placeholder_create(TextureLayeredType p_layered_type) = 0;
@ -164,6 +174,9 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
virtual String texture_get_path(RID p_texture) const = 0;
virtual void texture_drawable_generate_mipmaps(RID p_texture) = 0; // Update mipmaps if modified
virtual RID texture_drawable_get_default_material() const = 0; // To use with simplified functions in DrawableTexture2D
virtual Image::Format texture_get_format(RID p_texture) const = 0;
typedef void (*TextureDetectCallback)(void *);
@ -221,6 +234,7 @@ public:
SHADER_PARTICLES,
SHADER_SKY,
SHADER_FOG,
SHADER_TEXTURE_BLIT,
SHADER_MAX
};
@ -1947,6 +1961,7 @@ private:
VARIANT_ENUM_CAST(RenderingServer::TextureType);
VARIANT_ENUM_CAST(RenderingServer::TextureLayeredType);
VARIANT_ENUM_CAST(RenderingServer::CubeMapLayer);
VARIANT_ENUM_CAST(RenderingServer::TextureDrawableFormat);
VARIANT_ENUM_CAST(RenderingServer::PipelineSource);
VARIANT_ENUM_CAST(RenderingServer::ShaderMode);
VARIANT_ENUM_CAST(RenderingServer::ArrayType);

View file

@ -174,6 +174,28 @@ public:
return ret; \
}
#define FUNCRIDTEX4(m_type, m_type1, m_type2, m_type3, m_type4) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3, p4); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3, p4); \
} \
return ret; \
}
#define FUNCRIDTEX5(m_type, m_type1, m_type2, m_type3, m_type4, m_type5) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3, p4, p5); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3, p4, p5); \
} \
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(); \
@ -191,6 +213,7 @@ public:
FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &)
FUNCRIDTEX3(texture_external, int, int, uint64_t)
FUNCRIDTEX1(texture_proxy, RID)
FUNCRIDTEX5(texture_drawable, int, int, TextureDrawableFormat, const Color &, bool)
// 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 {
@ -203,6 +226,8 @@ public:
FUNC4(texture_external_update, RID, int, int, uint64_t)
FUNC2(texture_proxy_update, RID, RID)
FUNC6(texture_drawable_blit_rect, const TypedArray<RID> &, const Rect2i &, RID, const Color &, const TypedArray<RID> &, int)
//these also go pass-through
FUNCRIDTEX0(texture_2d_placeholder)
FUNCRIDTEX1(texture_2d_layered_placeholder, TextureLayeredType)
@ -212,6 +237,9 @@ public:
FUNC2RC(Ref<Image>, texture_2d_layer_get, RID, int)
FUNC1RC(Vector<Ref<Image>>, texture_3d_get, RID)
FUNC1(texture_drawable_generate_mipmaps, RID)
FUNC0RC(RID, texture_drawable_get_default_material)
FUNC2(texture_replace, RID, RID)
FUNC3(texture_set_size_override, RID, int, int)

View file

@ -527,7 +527,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (SL::is_sampler_type(E.value.type)) {
if (E.value.hint == SL::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
E.value.hint == SL::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
E.value.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
E.value.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE ||
E.value.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE0 ||
E.value.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE1 ||
E.value.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE2 ||
E.value.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE3) {
continue; // Don't create uniforms in the generated code for these.
}
max_texture_uniforms++;
@ -572,7 +576,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (uniform.hint == SL::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
uniform.hint == SL::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
uniform.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
uniform.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE ||
uniform.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE0 ||
uniform.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE1 ||
uniform.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE2 ||
uniform.hint == SL::ShaderNode::Uniform::HINT_BLIT_SOURCE3) {
continue; // Don't create uniforms in the generated code for these.
}
@ -937,6 +945,14 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
name = "depth_buffer";
r_gen_code.uses_depth_texture = true;
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLIT_SOURCE0) {
name = "source0";
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLIT_SOURCE1) {
name = "source1";
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLIT_SOURCE2) {
name = "source2";
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLIT_SOURCE3) {
name = "source3";
} else {
name = _mkid(vnode->name); //texture, use as is
}

View file

@ -220,6 +220,10 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"HINT_SCREEN_TEXTURE",
"HINT_NORMAL_ROUGHNESS_TEXTURE",
"HINT_DEPTH_TEXTURE",
"HINT_BLIT_SOURCE0",
"HINT_BLIT_SOURCE1",
"HINT_BLIT_SOURCE2",
"HINT_BLIT_SOURCE3",
"FILTER_NEAREST",
"FILTER_LINEAR",
"FILTER_NEAREST_MIPMAP",
@ -392,6 +396,11 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_NORMAL_ROUGHNESS_TEXTURE, "hint_normal_roughness_texture", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_DEPTH_TEXTURE, "hint_depth_texture", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_BLIT_SOURCE0, "hint_blit_source0", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_BLIT_SOURCE1, "hint_blit_source1", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_BLIT_SOURCE2, "hint_blit_source2", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_BLIT_SOURCE3, "hint_blit_source3", CF_UNSPECIFIED, {}, {} },
{ TK_FILTER_NEAREST, "filter_nearest", CF_UNSPECIFIED, {}, {} },
{ TK_FILTER_LINEAR, "filter_linear", CF_UNSPECIFIED, {}, {} },
{ TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap", CF_UNSPECIFIED, {}, {} },
@ -1236,6 +1245,18 @@ String ShaderLanguage::get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint) {
case ShaderNode::Uniform::HINT_DEPTH_TEXTURE: {
result = "hint_depth_texture";
} break;
case ShaderNode::Uniform::HINT_BLIT_SOURCE0: {
result = "hint_blit_source0";
} break;
case ShaderNode::Uniform::HINT_BLIT_SOURCE1: {
result = "hint_blit_source1";
} break;
case ShaderNode::Uniform::HINT_BLIT_SOURCE2: {
result = "hint_blit_source2";
} break;
case ShaderNode::Uniform::HINT_BLIT_SOURCE3: {
result = "hint_blit_source3";
} break;
default:
break;
}
@ -10029,6 +10050,42 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
} break;
case TK_HINT_BLIT_SOURCE0: {
new_hint = ShaderNode::Uniform::HINT_BLIT_SOURCE0;
--texture_uniforms;
--texture_binding;
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "texture_blit") {
_set_error(vformat(RTR("'hint_blit_source' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
} break;
case TK_HINT_BLIT_SOURCE1: {
new_hint = ShaderNode::Uniform::HINT_BLIT_SOURCE1;
--texture_uniforms;
--texture_binding;
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "texture_blit") {
_set_error(vformat(RTR("'hint_blit_source' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
} break;
case TK_HINT_BLIT_SOURCE2: {
new_hint = ShaderNode::Uniform::HINT_BLIT_SOURCE2;
--texture_uniforms;
--texture_binding;
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "texture_blit") {
_set_error(vformat(RTR("'hint_blit_source' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
} break;
case TK_HINT_BLIT_SOURCE3: {
new_hint = ShaderNode::Uniform::HINT_BLIT_SOURCE3;
--texture_uniforms;
--texture_binding;
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "texture_blit") {
_set_error(vformat(RTR("'hint_blit_source' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
} break;
case TK_FILTER_NEAREST: {
new_filter = FILTER_NEAREST;
} break;
@ -12072,6 +12129,10 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
options.push_back("hint_screen_texture");
options.push_back("hint_normal_roughness_texture");
options.push_back("hint_depth_texture");
options.push_back("hint_blit_source0");
options.push_back("hint_blit_source1");
options.push_back("hint_blit_source2");
options.push_back("hint_blit_source3");
options.push_back("source_color");
}
}

View file

@ -184,6 +184,10 @@ public:
TK_HINT_SCREEN_TEXTURE,
TK_HINT_NORMAL_ROUGHNESS_TEXTURE,
TK_HINT_DEPTH_TEXTURE,
TK_HINT_BLIT_SOURCE0,
TK_HINT_BLIT_SOURCE1,
TK_HINT_BLIT_SOURCE2,
TK_HINT_BLIT_SOURCE3,
TK_FILTER_NEAREST,
TK_FILTER_LINEAR,
TK_FILTER_NEAREST_MIPMAP,
@ -676,6 +680,10 @@ public:
HINT_DEFAULT_TRANSPARENT,
HINT_ANISOTROPY,
HINT_SCREEN_TEXTURE,
HINT_BLIT_SOURCE0,
HINT_BLIT_SOURCE1,
HINT_BLIT_SOURCE2,
HINT_BLIT_SOURCE3,
HINT_NORMAL_ROUGHNESS_TEXTURE,
HINT_DEPTH_TEXTURE,
HINT_MAX

View file

@ -519,12 +519,37 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_FOG].functions["fog"].main_function = true;
/************ TEXTURE_BLIT **************************/
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["MODULATE"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["COLOR0"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["COLOR1"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["COLOR2"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].built_ins["COLOR3"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_TEXTURE_BLIT].functions["blit"].main_function = true;
// Texture Blit Modes
{
shader_modes[RS::SHADER_TEXTURE_BLIT].modes.push_back({ PNAME("blend"), "mix", "add", "sub", "mul", "disabled" });
}
// Must be kept in sync with the Shader::Mode enum.
shader_types_list.push_back("spatial");
shader_types_list.push_back("canvas_item");
shader_types_list.push_back("particles");
shader_types_list.push_back("sky");
shader_types_list.push_back("fog");
shader_types_list.push_back("texture_blit");
DEV_ASSERT(shader_types_list.size() == Shader::MODE_MAX);
for (const String &type : shader_types_list) {

View file

@ -69,6 +69,7 @@ public:
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_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 void texture_drawable_initialize(RID p_texture, int p_width, int p_height, RS::TextureDrawableFormat p_format, const Color &p_color, bool p_with_mipmaps) = 0;
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;
@ -77,6 +78,8 @@ public:
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;
virtual void texture_drawable_blit_rect(const TypedArray<RID> &p_textures, const Rect2i &p_rect, RID p_material, const Color &p_modulate, const TypedArray<RID> &p_source_textures, int p_to_mipmap) = 0;
//these two APIs can be used together or in combination with the others.
virtual void texture_2d_placeholder_initialize(RID p_texture) = 0;
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) = 0;
@ -86,6 +89,9 @@ public:
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0;
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const = 0;
virtual void texture_drawable_generate_mipmaps(RID p_texture) = 0;
virtual RID texture_drawable_get_default_material() const = 0;
virtual void texture_replace(RID p_texture, RID p_by_texture) = 0;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;