|
@@ -46,6 +46,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|
|
MATERIAL_UNIFORM_SET = 1,
|
|
|
TRANSFORMS_UNIFORM_SET = 2,
|
|
|
CANVAS_TEXTURE_UNIFORM_SET = 3,
|
|
|
+ INSTANCE_DATA_UNIFORM_SET = 4,
|
|
|
};
|
|
|
|
|
|
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
|
|
@@ -335,6 +336,146 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|
|
|
|
|
//state that does not vary across rendering all items
|
|
|
|
|
|
+ struct InstanceData {
|
|
|
+ float world[6];
|
|
|
+ uint32_t flags;
|
|
|
+ uint32_t specular_shininess;
|
|
|
+ union {
|
|
|
+ //rect
|
|
|
+ struct {
|
|
|
+ float modulation[4];
|
|
|
+ union {
|
|
|
+ float msdf[4];
|
|
|
+ float ninepatch_margins[4];
|
|
|
+ };
|
|
|
+ float dst_rect[4];
|
|
|
+ float src_rect[4];
|
|
|
+ float pad[2];
|
|
|
+ };
|
|
|
+ //primitive
|
|
|
+ struct {
|
|
|
+ float points[6]; // vec2 points[3]
|
|
|
+ float uvs[6]; // vec2 points[3]
|
|
|
+ uint32_t colors[6]; // colors encoded as half
|
|
|
+ };
|
|
|
+ };
|
|
|
+ float color_texture_pixel_size[2];
|
|
|
+ uint32_t lights[4];
|
|
|
+ };
|
|
|
+
|
|
|
+ struct PushConstant {
|
|
|
+ uint32_t base_instance_index;
|
|
|
+ uint32_t pad1;
|
|
|
+ uint32_t pad2;
|
|
|
+ uint32_t pad3;
|
|
|
+ };
|
|
|
+
|
|
|
+ // TextureState is used to determine when a new batch is required due to a change of texture state.
|
|
|
+ struct TextureState {
|
|
|
+ static const uint32_t FILTER_SHIFT = 0;
|
|
|
+ static const uint32_t FILTER_BITS = 3;
|
|
|
+ static const uint32_t FILTER_MASK = (1 << FILTER_BITS) - 1;
|
|
|
+ static const uint32_t REPEAT_SHIFT = FILTER_BITS;
|
|
|
+ static const uint32_t REPEAT_BITS = 2;
|
|
|
+ static const uint32_t REPEAT_MASK = (1 << REPEAT_BITS) - 1;
|
|
|
+ static const uint32_t TEXTURE_IS_DATA_SHIFT = REPEAT_SHIFT + REPEAT_BITS;
|
|
|
+ static const uint32_t TEXTURE_IS_DATA_BITS = 1;
|
|
|
+ static const uint32_t TEXTURE_IS_DATA_MASK = (1 << TEXTURE_IS_DATA_BITS) - 1;
|
|
|
+ static const uint32_t LINEAR_COLORS_SHIFT = TEXTURE_IS_DATA_SHIFT + TEXTURE_IS_DATA_BITS;
|
|
|
+ static const uint32_t LINEAR_COLORS_BITS = 1;
|
|
|
+ static const uint32_t LINEAR_COLORS_MASK = (1 << LINEAR_COLORS_BITS) - 1;
|
|
|
+
|
|
|
+ RID texture;
|
|
|
+ uint32_t other = 0;
|
|
|
+
|
|
|
+ TextureState() {}
|
|
|
+
|
|
|
+ TextureState(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_texture_is_data, bool p_use_linear_colors) {
|
|
|
+ texture = p_texture;
|
|
|
+ other = (((uint32_t)p_base_filter & FILTER_MASK) << FILTER_SHIFT) |
|
|
|
+ (((uint32_t)p_base_repeat & REPEAT_MASK) << REPEAT_SHIFT) |
|
|
|
+ (((uint32_t)p_texture_is_data & TEXTURE_IS_DATA_MASK) << TEXTURE_IS_DATA_SHIFT) |
|
|
|
+ (((uint32_t)p_use_linear_colors & LINEAR_COLORS_MASK) << LINEAR_COLORS_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ _FORCE_INLINE_ RS::CanvasItemTextureFilter texture_filter() const {
|
|
|
+ return (RS::CanvasItemTextureFilter)((other >> FILTER_SHIFT) & FILTER_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ _FORCE_INLINE_ RS::CanvasItemTextureRepeat texture_repeat() const {
|
|
|
+ return (RS::CanvasItemTextureRepeat)((other >> REPEAT_SHIFT) & REPEAT_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ _FORCE_INLINE_ bool linear_colors() const {
|
|
|
+ return (other >> LINEAR_COLORS_SHIFT) & LINEAR_COLORS_MASK;
|
|
|
+ }
|
|
|
+
|
|
|
+ _FORCE_INLINE_ bool texture_is_data() const {
|
|
|
+ return (other >> TEXTURE_IS_DATA_SHIFT) & TEXTURE_IS_DATA_MASK;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool operator==(const TextureState &p_val) const {
|
|
|
+ return (texture == p_val.texture) && (other == p_val.other);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool operator!=(const TextureState &p_val) const {
|
|
|
+ return (texture != p_val.texture) || (other != p_val.other);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ Color modulate = Color(1.0, 1.0, 1.0, 1.0);
|
|
|
+
|
|
|
+ Item *clip = nullptr;
|
|
|
+
|
|
|
+ RID material;
|
|
|
+ CanvasMaterialData *material_data = nullptr;
|
|
|
+ PipelineLightMode light_mode = PipelineLightMode::PIPELINE_LIGHT_MODE_DISABLED;
|
|
|
+ PipelineVariant pipeline_variant = PipelineVariant::PIPELINE_VARIANT_QUAD;
|
|
|
+
|
|
|
+ const Item::Command *command = nullptr;
|
|
|
+ Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
|
|
|
+
|
|
|
+ // batch-specific data
|
|
|
+ union {
|
|
|
+ // TYPE_PRIMITIVE
|
|
|
+ uint32_t primitive_points = 0;
|
|
|
+ // TYPE_PARTICLES
|
|
|
+ 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 {
|
|
|
+ LocalVector<RID> instance_buffers;
|
|
|
+ };
|
|
|
+
|
|
|
struct State {
|
|
|
//state buffer
|
|
|
struct Buffer {
|
|
@@ -357,6 +498,19 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|
|
uint32_t pad2;
|
|
|
};
|
|
|
|
|
|
+ LocalVector<DataBuffer> canvas_instance_data_buffers;
|
|
|
+ LocalVector<Batch> canvas_instance_batches;
|
|
|
+ uint32_t current_data_buffer_index = 0;
|
|
|
+ uint32_t current_instance_buffer_index = 0;
|
|
|
+ uint32_t current_batch_index = 0;
|
|
|
+ uint32_t last_instance_index = 0;
|
|
|
+ InstanceData *instance_data_array = nullptr;
|
|
|
+
|
|
|
+ uint32_t max_instances_per_buffer = 16384;
|
|
|
+ uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
|
|
|
+
|
|
|
+ RID current_tex_uniform_set;
|
|
|
+
|
|
|
LightUniform *light_uniforms = nullptr;
|
|
|
|
|
|
RID lights_uniform_buffer;
|
|
@@ -376,33 +530,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|
|
|
|
|
} state;
|
|
|
|
|
|
- struct PushConstant {
|
|
|
- float world[6];
|
|
|
- uint32_t flags;
|
|
|
- uint32_t specular_shininess;
|
|
|
- union {
|
|
|
- //rect
|
|
|
- struct {
|
|
|
- float modulation[4];
|
|
|
- union {
|
|
|
- float msdf[4];
|
|
|
- float ninepatch_margins[4];
|
|
|
- };
|
|
|
- float dst_rect[4];
|
|
|
- float src_rect[4];
|
|
|
- float pad[2];
|
|
|
- };
|
|
|
- //primitive
|
|
|
- struct {
|
|
|
- float points[6]; // vec2 points[3]
|
|
|
- float uvs[6]; // vec2 points[3]
|
|
|
- uint32_t colors[6]; // colors encoded as half
|
|
|
- };
|
|
|
- };
|
|
|
- float color_texture_pixel_size[2];
|
|
|
- uint32_t lights[4];
|
|
|
- };
|
|
|
-
|
|
|
Item *items[MAX_RENDER_ITEMS];
|
|
|
|
|
|
bool using_directional_lights = false;
|
|
@@ -422,9 +549,23 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|
|
Color debug_redraw_color;
|
|
|
double debug_redraw_time = 1.0;
|
|
|
|
|
|
- inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead.
|
|
|
- void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, const Point2 &p_repeat_offset, RenderingMethod::RenderInfo *r_render_info = nullptr);
|
|
|
- void _render_items(RID 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);
|
|
|
+ // A structure to store cached render target information
|
|
|
+ struct RenderTarget {
|
|
|
+ // Current render target for the canvas.
|
|
|
+ RID render_target;
|
|
|
+ // The base flags for each InstanceData, derived from the render target.
|
|
|
+ // Either FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR or 0
|
|
|
+ uint32_t base_flags = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
+ [[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();
|
|
|
|
|
|
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
|
|
|
_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
|