Combine texture and instance data into one uniform set in the 2D renderer

Co-authored-by: Stuart Carnie <stuart.carnie@gmail.com>
This commit is contained in:
clayjohn 2024-09-27 11:05:46 -07:00
parent 506d6e427a
commit 4d635b7a3a
5 changed files with 146 additions and 195 deletions

View file

@ -1974,6 +1974,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
default_canvas_texture = texture_storage->canvas_texture_allocate();
texture_storage->canvas_texture_initialize(default_canvas_texture);
RendererRD::TextureStorage::CanvasTextureInfo info = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(default_canvas_texture, default_filter, default_repeat, false, false);
default_texture_info.diffuse = info.diffuse;
default_texture_info.normal = info.normal;
default_texture_info.specular = info.specular;
default_texture_info.sampler = info.sampler;
state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size");
//create functions for shader and material
@ -2219,7 +2225,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
Item *current_clip = nullptr;
state.current_tex_uniform_set = RID();
state.current_batch_uniform_set = RID();
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
Batch *current_batch = &state.canvas_instance_batches[i];
@ -2337,11 +2343,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->world[i] = world[i];
}
instance_data->flags = base_flags | r_current_batch->tex_flags; // Reset on each command for safety, keep canvas texture binding config.
instance_data->flags = base_flags | r_current_batch->tex_info.flags; // Reset on each command for safety, keep canvas texture binding config.
instance_data->color_texture_pixel_size[0] = r_current_batch->tex_texpixel_size.width;
instance_data->color_texture_pixel_size[1] = r_current_batch->tex_texpixel_size.height;
instance_data->specular_shininess = r_current_batch->tex_specular_shininess;
instance_data->color_texture_pixel_size[0] = r_current_batch->tex_info.texpixel_size.width;
instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height;
instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess;
return instance_data;
};
@ -2373,10 +2379,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors);
if (tex_state != r_current_batch->tex_state) {
if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, rect->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, rect->texture);
}
Color modulated = rect->modulate * base_color;
@ -2399,7 +2405,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
Rect2 dst_rect;
if (rect->texture.is_valid()) {
src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_texpixel_size, rect->source.size * r_current_batch->tex_texpixel_size) : Rect2(0, 0, 1, 1);
src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_info.texpixel_size, rect->source.size * r_current_batch->tex_info.texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@ -2484,10 +2490,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
if (tex_state != r_current_batch->tex_state) {
if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, np->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, np->texture);
}
InstanceData *instance_data = new_instance_data();
@ -2499,7 +2505,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
src_rect = Rect2(np->source.position.x * r_current_batch->tex_texpixel_size.width, np->source.position.y * r_current_batch->tex_texpixel_size.height, np->source.size.x * r_current_batch->tex_texpixel_size.width, np->source.size.y * r_current_batch->tex_texpixel_size.height);
src_rect = Rect2(np->source.position.x * r_current_batch->tex_info.texpixel_size.width, np->source.position.y * r_current_batch->tex_info.texpixel_size.height, np->source.size.x * r_current_batch->tex_info.texpixel_size.width, np->source.size.y * r_current_batch->tex_info.texpixel_size.height);
instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width;
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
} else {
@ -2553,10 +2559,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
if (tex_state != r_current_batch->tex_state) {
if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, polygon->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, polygon->texture);
}
// pipeline variant
@ -2596,10 +2602,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->pipeline_variant = variant[primitive->point_count - 1];
TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
if (tex_state != r_current_batch->tex_state) {
if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, primitive->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, primitive->texture);
}
}
@ -2657,8 +2663,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, m->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, m->texture);
instance_data = new_instance_data();
r_current_batch->mesh_instance_count = 1;
@ -2680,8 +2686,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, mm->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, mm->texture);
instance_data = new_instance_data();
instance_data->flags |= 1; // multimesh, trails disabled
@ -2698,8 +2704,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
r_current_batch->set_tex_state(tex_state);
_prepare_batch_texture(r_current_batch, pt->texture);
r_current_batch->tex_info.state = tex_state;
_prepare_batch_texture_info(r_current_batch, pt->texture);
instance_data = new_instance_data();
@ -2795,7 +2801,20 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
ERR_FAIL_NULL(p_batch->command);
_bind_canvas_texture(p_draw_list, p_batch->tex_uniform_set);
{
RD::Uniform u_diffuse(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info.diffuse);
RD::Uniform u_normal(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info.normal);
RD::Uniform u_specular(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info.specular);
RD::Uniform u_sampler(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info.sampler);
RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
RID uniform_set = uniform_set_cache->get_cache(shader.default_version_rd_shader, BATCH_UNIFORM_SET, u_diffuse, u_normal, u_specular, u_sampler, u_instance_data);
if (state.current_batch_uniform_set != uniform_set) {
state.current_batch_uniform_set = uniform_set;
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, BATCH_UNIFORM_SET);
}
}
switch (p_batch->command_type) {
case Item::Command::TYPE_RECT:
@ -2810,13 +2829,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
RD::get_singleton()->draw_list_bind_uniform_set(
p_draw_list,
uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
INSTANCE_DATA_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count);
@ -2839,13 +2851,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
RD::get_singleton()->draw_list_bind_uniform_set(
p_draw_list,
uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
INSTANCE_DATA_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
if (pb->indices.is_valid()) {
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices);
@ -2868,13 +2873,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
RD::get_singleton()->draw_list_bind_uniform_set(
p_draw_list,
uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
INSTANCE_DATA_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]);
uint32_t instance_count = p_batch->instance_count;
RD::get_singleton()->draw_list_draw(p_draw_list, true, instance_count);
@ -2934,12 +2932,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
break;
}
RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
RD::get_singleton()->draw_list_bind_uniform_set(
p_draw_list,
uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
INSTANCE_DATA_UNIFORM_SET);
uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
@ -3046,60 +3038,46 @@ void RendererCanvasRenderRD::_allocate_instance_buffer() {
state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(buf);
}
void RendererCanvasRenderRD::_prepare_batch_texture(Batch *p_current_batch, RID p_texture) const {
void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const {
if (p_texture.is_null()) {
p_texture = default_canvas_texture;
}
Color specular_shininess;
bool use_normal;
bool use_specular;
Size2i size;
bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(
p_texture,
p_current_batch->tex_state.texture_filter(),
p_current_batch->tex_state.texture_repeat(),
shader.default_version_rd_shader,
CANVAS_TEXTURE_UNIFORM_SET,
p_current_batch->tex_state.linear_colors(),
p_current_batch->tex_uniform_set,
size,
specular_shininess,
use_normal,
use_specular,
p_current_batch->tex_state.texture_is_data());
RendererRD::TextureStorage::CanvasTextureInfo info =
RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(
p_texture,
p_current_batch->tex_info.state.texture_filter(),
p_current_batch->tex_info.state.texture_repeat(),
p_current_batch->tex_info.state.linear_colors(),
p_current_batch->tex_info.state.texture_is_data());
// something odd happened
if (!success) {
_prepare_batch_texture(p_current_batch, default_canvas_texture);
if (info.is_null()) {
_prepare_batch_texture_info(p_current_batch, default_canvas_texture);
return;
}
p_current_batch->tex_info.diffuse = info.diffuse;
p_current_batch->tex_info.normal = info.normal;
p_current_batch->tex_info.specular = info.specular;
p_current_batch->tex_info.sampler = info.sampler;
// cache values to be copied to instance data
if (specular_shininess.a < 0.999) {
p_current_batch->tex_flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
if (info.specular_color.a < 0.999) {
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (use_normal) {
p_current_batch->tex_flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
if (info.use_normal) {
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
}
uint8_t a = uint8_t(CLAMP(specular_shininess.a * 255.0, 0.0, 255.0));
uint8_t b = uint8_t(CLAMP(specular_shininess.b * 255.0, 0.0, 255.0));
uint8_t g = uint8_t(CLAMP(specular_shininess.g * 255.0, 0.0, 255.0));
uint8_t r = uint8_t(CLAMP(specular_shininess.r * 255.0, 0.0, 255.0));
p_current_batch->tex_specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
uint8_t b = uint8_t(CLAMP(info.specular_color.b * 255.0, 0.0, 255.0));
uint8_t g = uint8_t(CLAMP(info.specular_color.g * 255.0, 0.0, 255.0));
uint8_t r = uint8_t(CLAMP(info.specular_color.r * 255.0, 0.0, 255.0));
p_current_batch->tex_info.specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
p_current_batch->tex_texpixel_size = Vector2(1.0 / float(size.width), 1.0 / float(size.height));
}
void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set) {
if (state.current_tex_uniform_set == p_uniform_set) {
return;
}
state.current_tex_uniform_set = p_uniform_set;
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, p_uniform_set, CANVAS_TEXTURE_UNIFORM_SET);
p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height));
}
RendererCanvasRenderRD::~RendererCanvasRenderRD() {

View file

@ -45,8 +45,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
BASE_UNIFORM_SET = 0,
MATERIAL_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
CANVAS_TEXTURE_UNIFORM_SET = 3,
INSTANCE_DATA_UNIFORM_SET = 4,
BATCH_UNIFORM_SET = 3,
};
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
@ -423,24 +422,25 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
}
};
struct TextureInfo {
TextureState state;
uint32_t specular_shininess = 0;
uint32_t flags = 0;
Vector2 texpixel_size;
RID diffuse;
RID normal;
RID specular;
RID sampler;
};
struct Batch {
// Position in the UBO measured in bytes
uint32_t start = 0;
uint32_t instance_count = 0;
uint32_t instance_buffer_index = 0;
TextureState tex_state;
RID tex_uniform_set;
// The following tex_ prefixed fields are used to cache the texture data for the current batch.
// These values are applied to new InstanceData for the batch
// The cached specular shininess derived from the current texture.
uint32_t tex_specular_shininess = 0;
// The cached texture flags, such as FLAGS_DEFAULT_SPECULAR_MAP_USED and FLAGS_DEFAULT_NORMAL_MAP_USED
uint32_t tex_flags = 0;
// The cached texture pixel size.
Vector2 tex_texpixel_size;
TextureInfo tex_info;
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
@ -462,14 +462,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t mesh_instance_count;
};
bool has_blend = false;
void set_tex_state(TextureState &p_tex_state) {
tex_state = p_tex_state;
tex_uniform_set = RID();
tex_texpixel_size = Size2();
tex_specular_shininess = 0;
tex_flags = 0;
}
};
struct DataBuffer {
@ -509,7 +501,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t max_instances_per_buffer = 16384;
uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
RID current_tex_uniform_set;
RID current_batch_uniform_set;
LightUniform *light_uniforms = nullptr;
@ -532,6 +524,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
Item *items[MAX_RENDER_ITEMS];
TextureInfo default_texture_info;
bool using_directional_lights = false;
RID default_canvas_texture;
@ -561,8 +555,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _prepare_batch_texture(Batch *p_current_batch, RID p_texture) const;
void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set);
void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const;
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
void _allocate_instance_buffer();

View file

@ -54,11 +54,6 @@ struct InstanceData {
uint lights[4];
};
layout(set = 4, binding = 0, std430) restrict readonly buffer DrawData {
InstanceData data[];
}
instances;
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint pad1;
@ -163,3 +158,8 @@ layout(set = 3, binding = 0) uniform texture2D color_texture;
layout(set = 3, binding = 1) uniform texture2D normal_texture;
layout(set = 3, binding = 2) uniform texture2D specular_texture;
layout(set = 3, binding = 3) uniform sampler texture_sampler;
layout(set = 3, binding = 4, std430) restrict readonly buffer DrawData {
InstanceData data[];
}
instances;

View file

@ -40,25 +40,12 @@ using namespace RendererRD;
///////////////////////////////////////////////////////////////////////////
// TextureStorage::CanvasTexture
void TextureStorage::CanvasTexture::clear_sets() {
if (cleared_cache) {
return;
}
for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
for (int k = 0; k < 2; k++) {
if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) {
RD::get_singleton()->free(uniform_sets[i][j][k]);
uniform_sets[i][j][k] = RID();
}
}
}
}
cleared_cache = true;
void TextureStorage::CanvasTexture::clear_cache() {
info_cache[0] = CanvasTextureCache();
info_cache[1] = CanvasTextureCache();
}
TextureStorage::CanvasTexture::~CanvasTexture() {
clear_sets();
}
///////////////////////////////////////////////////////////////////////////
@ -612,8 +599,7 @@ void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::Canvas
ct->specular = p_texture;
} break;
}
ct->clear_sets();
ct->clear_cache();
}
void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
@ -624,7 +610,6 @@ void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture,
ct->specular_color.g = p_specular_color.g;
ct->specular_color.b = p_specular_color.b;
ct->specular_color.a = p_shininess;
ct->clear_sets();
}
void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
@ -632,7 +617,6 @@ void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS:
ERR_FAIL_NULL(ct);
ct->texture_filter = p_filter;
ct->clear_sets();
}
void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
@ -640,17 +624,14 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
ERR_FAIL_NULL(ct);
ct->texture_repeat = p_repeat;
ct->clear_sets();
}
bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data) {
TextureStorage::CanvasTextureInfo TextureStorage::canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
CanvasTexture *ct = nullptr;
Texture *t = get_texture(p_texture);
// TODO once we have our texture storage split off we'll look into moving this code into canvas_texture
if (t) {
//regular texture
if (!t->canvas_texture) {
@ -667,93 +648,71 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
}
if (!ct) {
return false; //invalid texture RID
return CanvasTextureInfo(); //invalid texture RID
}
RS::CanvasItemTextureFilter filter = ct->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct->texture_filter : p_base_filter;
ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, false);
ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasTextureInfo());
RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat;
ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false);
ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, CanvasTextureInfo());
RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)];
if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
//create and update
Vector<RD::Uniform> uniforms;
CanvasTextureCache &ctc = ct->info_cache[int(p_use_srgb)];
if (!RD::get_singleton()->texture_is_valid(ctc.diffuse) ||
!RD::get_singleton()->texture_is_valid(ctc.normal) ||
!RD::get_singleton()->texture_is_valid(ctc.specular)) {
{ //diffuse
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
t = get_texture(ct->diffuse);
if (!t) {
u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ctc.diffuse = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
ct->size_cache = Size2i(1, 1);
} else {
u.append_id(t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture);
ctc.diffuse = t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture;
ct->size_cache = Size2i(t->width_2d, t->height_2d);
if (t->render_target) {
t->render_target->was_used = true;
}
}
uniforms.push_back(u);
}
{ //normal
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
t = get_texture(ct->normal_map);
if (!t) {
u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL));
ctc.normal = texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
ct->use_normal_cache = false;
} else {
u.append_id(t->rd_texture);
ctc.normal = t->rd_texture;
ct->use_normal_cache = true;
if (t->render_target) {
t->render_target->was_used = true;
}
}
uniforms.push_back(u);
}
{ //specular
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
t = get_texture(ct->specular);
if (!t) {
u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ctc.specular = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
ct->use_specular_cache = false;
} else {
u.append_id(t->rd_texture);
ctc.specular = t->rd_texture;
ct->use_specular_cache = true;
if (t->render_target) {
t->render_target->was_used = true;
}
}
uniforms.push_back(u);
}
{ //sampler
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 3;
u.append_id(material_storage->sampler_rd_get_default(filter, repeat));
uniforms.push_back(u);
}
uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set);
ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set;
ct->cleared_cache = false;
}
r_uniform_set = uniform_set;
r_size = ct->size_cache;
r_specular_shininess = ct->specular_color;
r_use_normal = ct->use_normal_cache;
r_use_specular = ct->use_specular_cache;
CanvasTextureInfo res;
res.diffuse = ctc.diffuse;
res.normal = ctc.normal;
res.specular = ctc.specular;
res.sampler = material_storage->sampler_rd_get_default(filter, repeat);
res.size = ct->size_cache;
res.specular_color = ct->specular_color;
res.use_normal = ct->use_normal_cache;
res.use_specular = ct->use_specular_cache;
return true;
return res;
}
/* Texture API */

View file

@ -76,6 +76,21 @@ public:
TYPE_3D
};
struct CanvasTextureInfo {
RID diffuse;
RID normal;
RID specular;
RID sampler;
Size2i size;
Color specular_color;
bool use_normal = false;
bool use_specular = false;
_FORCE_INLINE_ bool is_valid() const { return diffuse.is_valid(); }
_FORCE_INLINE_ bool is_null() const { return diffuse.is_null(); }
};
private:
friend class LightStorage;
friend class MaterialStorage;
@ -86,6 +101,12 @@ private:
/* Canvas Texture API */
struct CanvasTextureCache {
RID diffuse = RID();
RID normal = RID();
RID specular = RID();
};
class CanvasTexture {
public:
RID diffuse;
@ -96,14 +117,14 @@ private:
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2];
CanvasTextureCache info_cache[2];
Size2i size_cache = Size2i(1, 1);
bool use_normal_cache = false;
bool use_specular_cache = false;
bool cleared_cache = true;
void clear_sets();
void clear_cache();
~CanvasTexture();
};
@ -477,7 +498,7 @@ public:
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data);
CanvasTextureInfo canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data);
/* Texture API */