Skip to content

Commit

Permalink
Combine texture and instance data into one uniform set in the 2D rend…
Browse files Browse the repository at this point in the history
…erer

Co-authored-by: Stuart Carnie <[email protected]>
  • Loading branch information
clayjohn and stuartcarnie committed Sep 27, 2024
1 parent 506d6e4 commit 4d635b7
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 195 deletions.
164 changes: 71 additions & 93 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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();
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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();

Expand Down Expand Up @@ -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:
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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 };

Expand Down Expand Up @@ -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;
}

// cache values to be copied to instance data
if (specular_shininess.a < 0.999) {
p_current_batch->tex_flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
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;

if (use_normal) {
p_current_batch->tex_flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
// cache values to be copied to instance data
if (info.specular_color.a < 0.999) {
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_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);

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;
if (info.use_normal) {
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
}

state.current_tex_uniform_set = p_uniform_set;
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);

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() {
Expand Down
43 changes: 18 additions & 25 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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 {
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 4d635b7

Please sign in to comment.