diff options
Diffstat (limited to 'servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp')
-rw-r--r-- | servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp | 477 |
1 files changed, 319 insertions, 158 deletions
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 979f590c4c..165168cb29 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -666,6 +666,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0]); } + bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target); + { //update canvas state uniform buffer State::Buffer state_buffer; @@ -684,7 +686,6 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p normal_transform.columns[2] = Vector2(); _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); - bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target); Color modulate = p_modulate; if (use_linear_colors) { modulate = p_modulate.srgb_to_linear(); @@ -722,6 +723,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale)); state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5); + state_buffer.flags = use_linear_colors ? CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0; + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer); } @@ -752,8 +755,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p RenderTarget to_render_target; to_render_target.render_target = p_to_render_target; - bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target); - to_render_target.base_flags = use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0; + to_render_target.use_linear_colors = use_linear_colors; while (ci) { if (ci->copy_back_buffer && canvas_group_owner == nullptr) { @@ -911,7 +913,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p RenderingServerDefault::redraw_request(); } - state.current_data_buffer_index = (state.current_data_buffer_index + 1) % state.canvas_instance_data_buffers.size(); + state.current_data_buffer_index = (state.current_data_buffer_index + 1) % BATCH_DATA_BUFFER_COUNT; state.current_instance_buffer_index = 0; } @@ -993,36 +995,43 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, Vector<Color> cc; cc.push_back(Color(p_far, p_far, p_far, 1.0)); - for (int i = 0; i < 4; i++) { - //make sure it remains orthogonal, makes easy to read angle later + Projection projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; - Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } - Projection projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; + // Precomputed: + // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); + const Projection projections[4] = { + projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; + projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } + projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), + + projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)) + + }; - Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + for (int i = 0; i < 4; i++) { + Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); ShadowRenderPushConstant push_constant; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { - push_constant.projection[y * 4 + x] = projection.columns[y][x]; + push_constant.projection[y * 4 + x] = projections[i].columns[y][x]; } } static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; @@ -1647,6 +1656,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { default_samplers.default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; } + // preallocate 5 slots for uniform set 3 + state.batch_texture_uniforms.resize(5); + { //shader variants String global_defines; @@ -1974,15 +1986,18 @@ void fragment() { } { + uint32_t cache_size = uint32_t(GLOBAL_GET("rendering/2d/batching/uniform_set_cache_size")); + rid_set_to_uniform_set.set_capacity(cache_size); + } + + { state.max_instances_per_buffer = uint32_t(GLOBAL_GET("rendering/2d/batching/item_buffer_size")); state.max_instance_buffer_size = state.max_instances_per_buffer * sizeof(InstanceData); - state.canvas_instance_data_buffers.resize(3); state.canvas_instance_batches.reserve(200); - for (int i = 0; i < 3; i++) { - DataBuffer db; + for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) { + DataBuffer &db = state.canvas_instance_data_buffers[i]; db.instance_buffers.push_back(RD::get_singleton()->storage_buffer_create(state.max_instance_buffer_size)); - state.canvas_instance_data_buffers[i] = db; } state.instance_data_array = memnew_arr(InstanceData, state.max_instances_per_buffer); } @@ -2159,7 +2174,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors, 1, 0, Rect2(), RDD::BreadcrumbMarker::UI_PASS); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); @@ -2203,14 +2218,47 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target RD::get_singleton()->draw_list_end(); + texture_info_map.clear(); state.current_batch_index = 0; state.canvas_instance_batches.clear(); state.last_instance_index += instance_index; } +RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info) { + InstanceData *instance_data = &state.instance_data_array[p_index]; + // Zero out most fields. + for (int i = 0; i < 4; i++) { + instance_data->modulation[i] = 0.0; + instance_data->ninepatch_margins[i] = 0.0; + instance_data->src_rect[i] = 0.0; + instance_data->dst_rect[i] = 0.0; + } + + instance_data->pad[0] = 0.0; + instance_data->pad[1] = 0.0; + + instance_data->lights[0] = p_lights[0]; + instance_data->lights[1] = p_lights[1]; + instance_data->lights[2] = p_lights[2]; + instance_data->lights[3] = p_lights[3]; + + for (int i = 0; i < 6; i++) { + instance_data->world[i] = p_world[i]; + } + + instance_data->flags = p_base_flags; // Reset on each command for safety. + + instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width; + instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height; + + instance_data->pad1 = 0; + + return instance_data; +} + void RendererCanvasRenderRD::_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) { - RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter; - RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat; + const RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter; + const RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat; Transform2D base_transform = p_base_transform; @@ -2219,8 +2267,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar _update_transform_2d_to_mat2x3(base_transform, world); Color base_color = p_item->final_modulate; - bool use_linear_colors = bool(p_render_target.base_flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR); - uint32_t base_flags = p_render_target.base_flags; + bool use_linear_colors = p_render_target.use_linear_colors; + uint32_t base_flags = 0; bool reclip = false; @@ -2230,6 +2278,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar uint32_t lights[4] = { 0, 0, 0, 0 }; uint16_t light_count = 0; + uint16_t shadow_mask = 0; { Light *light = p_lights; @@ -2239,16 +2288,21 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar uint32_t light_index = light->render_index_cache; lights[light_count >> 2] |= light_index << ((light_count & 3) * 8); + if (p_item->light_mask & light->item_shadow_mask) { + shadow_mask |= 1 << light_count; + } + light_count++; - if (light_count == state.max_lights_per_item - 1) { + if (light_count == MAX_LIGHTS_PER_ITEM - 1) { break; } } light = light->next_ptr; } - base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT; + base_flags |= light_count << INSTANCE_FLAGS_LIGHT_COUNT_SHIFT; + base_flags |= shadow_mask << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT; } bool use_lighting = (light_count > 0 || using_directional_lights); @@ -2258,38 +2312,6 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->use_lighting = use_lighting; } - // new_instance_data should be called after the current_batch is set. - auto new_instance_data = [&]() -> InstanceData * { - InstanceData *instance_data = &state.instance_data_array[r_index]; - // Zero out most fields. - for (int i = 0; i < 4; i++) { - instance_data->modulation[i] = 0.0; - instance_data->ninepatch_margins[i] = 0.0; - instance_data->src_rect[i] = 0.0; - instance_data->dst_rect[i] = 0.0; - } - - instance_data->pad[0] = 0.0; - instance_data->pad[1] = 0.0; - - instance_data->lights[0] = lights[0]; - instance_data->lights[1] = lights[1]; - instance_data->lights[2] = lights[2]; - instance_data->lights[3] = lights[3]; - - for (int i = 0; i < 6; i++) { - instance_data->world[i] = world[i]; - } - - 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_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; - }; - const Item::Command *c = p_item->commands; while (c) { if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) { @@ -2309,19 +2331,12 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar // default variant r_current_batch->shader_variant = SHADER_VARIANT_QUAD; r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; + r_current_batch->flags = 0; } + RenderingServer::CanvasItemTextureRepeat rect_repeat = texture_repeat; if (bool(rect->flags & CANVAS_RECT_TILE)) { - texture_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; - } - - 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_info.state) { - r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, rect->texture); + rect_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; } Color modulated = rect->modulate * base_color; @@ -2340,12 +2355,25 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; } - InstanceData *instance_data = new_instance_data(); + bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF); + TextureState tex_state(rect->texture, texture_filter, rect_repeat, has_msdf, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(rect->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Rect2 src_rect; Rect2 dst_rect; if (rect->texture.is_valid()) { - 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); + src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * tex_info->texpixel_size, rect->source.size * tex_info->texpixel_size) : Rect2(0, 0, 1, 1); dst_rect = Rect2(rect->rect.position, rect->rect.size); if (dst_rect.size.width < 0) { @@ -2359,20 +2387,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar if (rect->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; - instance_data->flags |= FLAGS_FLIP_H; } if (rect->flags & CANVAS_RECT_FLIP_V) { src_rect.size.y *= -1; - instance_data->flags |= FLAGS_FLIP_V; } if (rect->flags & CANVAS_RECT_TRANSPOSE) { - instance_data->flags |= FLAGS_TRANSPOSE_RECT; + instance_data->flags |= INSTANCE_FLAGS_TRANSPOSE_RECT; } if (rect->flags & CANVAS_RECT_CLIP_UV) { - instance_data->flags |= FLAGS_CLIP_RECT_UV; + instance_data->flags |= INSTANCE_FLAGS_CLIP_RECT_UV; } } else { @@ -2391,13 +2417,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar } if (has_msdf) { - instance_data->flags |= FLAGS_USE_MSDF; + instance_data->flags |= INSTANCE_FLAGS_USE_MSDF; instance_data->msdf[0] = rect->px_range; // Pixel range. instance_data->msdf[1] = rect->outline; // Outline size. instance_data->msdf[2] = 0.f; // Reserved. instance_data->msdf[3] = 0.f; // Reserved. } else if (rect->flags & CANVAS_RECT_LCD) { - instance_data->flags |= FLAGS_USE_LCD; + instance_data->flags |= INSTANCE_FLAGS_USE_LCD; } instance_data->modulation[0] = modulated.r; @@ -2428,16 +2454,22 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->has_blend = false; r_current_batch->shader_variant = SHADER_VARIANT_NINEPATCH; r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; + r_current_batch->flags = 0; } TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(np->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, np->texture); + r_current_batch->tex_info = tex_info; } - InstanceData *instance_data = new_instance_data(); + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Rect2 src_rect; Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); @@ -2446,7 +2478,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_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); + src_rect = Rect2(np->source.position.x * tex_info->texpixel_size.width, np->source.position.y * tex_info->texpixel_size.height, np->source.size.x * tex_info->texpixel_size.width, np->source.size.y * 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 { @@ -2474,11 +2506,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar instance_data->dst_rect[2] = dst_rect.size.width; instance_data->dst_rect[3] = dst_rect.size.height; - instance_data->flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT; - instance_data->flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT; + instance_data->flags |= int(np->axis_x) << INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT; + instance_data->flags |= int(np->axis_y) << INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT; if (np->draw_center) { - instance_data->flags |= FLAGS_NINEPACH_DRAW_CENTER; + instance_data->flags |= INSTANCE_FLAGS_NINEPACH_DRAW_CENTER; } instance_data->ninepatch_margins[0] = np->margin[SIDE_LEFT]; @@ -2498,12 +2530,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->command_type = Item::Command::TYPE_POLYGON; r_current_batch->has_blend = false; r_current_batch->command = c; + r_current_batch->flags = 0; TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(polygon->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, polygon->texture); + r_current_batch->tex_info = tex_info; } // pipeline variant @@ -2513,7 +2551,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->render_primitive = _primitive_type_to_render_primitive(polygon->primitive); } - InstanceData *instance_data = new_instance_data(); + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Color color = base_color; if (use_linear_colors) { @@ -2537,6 +2575,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->has_blend = false; r_current_batch->command = c; r_current_batch->primitive_points = primitive->point_count; + r_current_batch->flags = 0; ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4); @@ -2557,17 +2596,22 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar default: // Unknown point count. break; - }; - - TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { - r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, primitive->texture); } } - InstanceData *instance_data = new_instance_data(); + TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(primitive->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) { instance_data->points[j * 2 + 0] = primitive->points[j].x; @@ -2585,7 +2629,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar _add_to_batch(r_index, r_batch_broken, r_current_batch); if (primitive->point_count == 4) { - instance_data = new_instance_data(); + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); for (uint32_t j = 0; j < 3; j++) { int offset = j == 0 ? 0 : 1; @@ -2594,7 +2638,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar instance_data->points[j * 2 + 1] = primitive->points[j + offset].y; instance_data->uvs[j * 2 + 0] = primitive->uvs[j + offset].x; instance_data->uvs[j * 2 + 1] = primitive->uvs[j + offset].y; - Color col = primitive->colors[j] * base_color; + Color col = primitive->colors[j + offset] * base_color; if (use_linear_colors) { col = col.srgb_to_linear(); } @@ -2614,6 +2658,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->command = c; r_current_batch->command_type = c->type; r_current_batch->has_blend = false; + r_current_batch->flags = 0; InstanceData *instance_data = nullptr; @@ -2621,9 +2666,13 @@ 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->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, m->texture); - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(m->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); r_current_batch->mesh_instance_count = 1; _update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, instance_data->world); @@ -2644,17 +2693,21 @@ 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->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, mm->texture); - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(mm->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); - instance_data->flags |= 1; // multimesh, trails disabled + r_current_batch->flags |= 1; // multimesh, trails disabled if (mesh_storage->multimesh_uses_colors(mm->multimesh)) { - instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS; + r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS; } if (mesh_storage->multimesh_uses_custom_data(mm->multimesh)) { - instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA; + r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA; } } else if (c->type == Item::Command::TYPE_PARTICLES) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); @@ -2662,20 +2715,23 @@ 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->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, pt->texture); - - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(pt->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); uint32_t divisor = 1; r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor); - instance_data->flags |= (divisor & FLAGS_INSTANCING_MASK); + r_current_batch->flags |= (divisor & BATCH_FLAGS_INSTANCING_MASK); r_current_batch->mesh_instance_count /= divisor; RID particles = pt->particles; - instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS; - instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA; + r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS; + r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA; if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target.render_target)) { // Pass collision information. @@ -2747,36 +2803,139 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_batch_broken = false; } +#ifdef DEBUG_ENABLED + if (debug_redraw && p_item->debug_redraw_time > 0.0) { + Color dc = debug_redraw_color; + dc.a *= p_item->debug_redraw_time / debug_redraw_time; + + // 1: If commands are different, start a new batch. + if (r_current_batch->command_type != Item::Command::TYPE_RECT) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->command_type = Item::Command::TYPE_RECT; + // it is ok to be null for a TYPE_RECT + r_current_batch->command = nullptr; + // default variant + r_current_batch->shader_variant = SHADER_VARIANT_QUAD; + r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; + r_current_batch->flags = 0; + } + + // 2: If the current batch has lighting, start a new batch. + if (r_current_batch->use_lighting) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->use_lighting = false; + } + + // 3: If the current batch has blend, start a new batch. + if (r_current_batch->has_blend) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->has_blend = false; + } + + TextureState tex_state(default_canvas_texture, texture_filter, texture_repeat, false, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(default_canvas_texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); + + Rect2 src_rect; + Rect2 dst_rect; + + dst_rect = Rect2(Vector2(), p_item->rect.size); + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + src_rect = Rect2(0, 0, 1, 1); + + instance_data->modulation[0] = dc.r; + instance_data->modulation[1] = dc.g; + instance_data->modulation[2] = dc.b; + instance_data->modulation[3] = dc.a; + + instance_data->src_rect[0] = src_rect.position.x; + instance_data->src_rect[1] = src_rect.position.y; + instance_data->src_rect[2] = src_rect.size.width; + instance_data->src_rect[3] = src_rect.size.height; + + instance_data->dst_rect[0] = dst_rect.position.x; + instance_data->dst_rect[1] = dst_rect.position.y; + instance_data->dst_rect[2] = dst_rect.size.width; + instance_data->dst_rect[3] = dst_rect.size.height; + + _add_to_batch(r_index, r_batch_broken, r_current_batch); + + p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time(); + + RenderingServerDefault::redraw_request(); + + r_batch_broken = false; + } +#endif + if (r_current_clip && reclip) { // will make it re-enable clipping if needed afterwards r_current_clip = nullptr; } } -void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) { - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); - ERR_FAIL_NULL(uniform_set_cache); +void RendererCanvasRenderRD::_before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid) { + RD::get_singleton()->uniform_set_set_invalidation_callback(p_rid, nullptr, nullptr); + RD::get_singleton()->free(p_rid); +} - ERR_FAIL_NULL(p_batch->command); +void RendererCanvasRenderRD::_uniform_set_invalidation_callback(void *p_userdata) { + const RIDSetKey *key = static_cast<RIDSetKey *>(p_userdata); + static_cast<RendererCanvasRenderRD *>(singleton)->rid_set_to_uniform_set.erase(*key); +} +void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) { { - 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); + RIDSetKey key( + p_batch->tex_info->state, + state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); + + const RID *uniform_set = rid_set_to_uniform_set.getptr(key); + if (uniform_set == nullptr) { + state.batch_texture_uniforms.write[0] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info->diffuse); + state.batch_texture_uniforms.write[1] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info->normal); + state.batch_texture_uniforms.write[2] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info->specular); + state.batch_texture_uniforms.write[3] = RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info->sampler); + state.batch_texture_uniforms.write[4] = RD::Uniform(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); + + RID rid = RD::get_singleton()->uniform_set_create(state.batch_texture_uniforms, shader.default_version_rd_shader, BATCH_UNIFORM_SET); + ERR_FAIL_COND_MSG(rid.is_null(), "Failed to create uniform set for batch."); + + const RIDCache::Pair *iter = rid_set_to_uniform_set.insert(key, rid); + uniform_set = &iter->data; + RD::get_singleton()->uniform_set_set_invalidation_callback(rid, RendererCanvasRenderRD::_uniform_set_invalidation_callback, (void *)&iter->key); + } - 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); + 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); } } + PushConstant push_constant; + push_constant.base_instance_index = p_batch->start; + push_constant.specular_shininess = p_batch->tex_info->specular_shininess; + push_constant.batch_flags = p_batch->tex_info->flags | p_batch->flags; RID pipeline; PipelineKey pipeline_key; - PushConstant push_constant; pipeline_key.framebuffer_format_id = p_framebuffer_format; pipeline_key.variant = p_batch->shader_variant; pipeline_key.render_primitive = p_batch->render_primitive; @@ -2792,7 +2951,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, p_batch->modulate); } - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); 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); @@ -2805,6 +2963,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha } break; case Item::Command::TYPE_POLYGON: { + ERR_FAIL_NULL(p_batch->command); + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(p_batch->command); PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id); @@ -2814,7 +2974,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array); if (pb->indices.is_valid()) { @@ -2830,12 +2989,13 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha } break; case Item::Command::TYPE_PRIMITIVE: { + ERR_FAIL_NULL(p_batch->command); + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(p_batch->command); pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); 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; @@ -2852,6 +3012,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha case Item::Command::TYPE_MESH: case Item::Command::TYPE_MULTIMESH: case Item::Command::TYPE_PARTICLES: { + ERR_FAIL_NULL(p_batch->command); + RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton(); @@ -2912,7 +3074,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant, mesh_instance, surface, j, &vertex_array); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RID index_array = mesh_storage->mesh_surface_get_index_array(surface, 0); @@ -2994,7 +3155,7 @@ 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_info(Batch *p_current_batch, RID p_texture) const { +void RendererCanvasRenderRD::_prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info) { if (p_texture.is_null()) { p_texture = default_canvas_texture; } @@ -3002,38 +3163,38 @@ void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, 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()); - + p_state.texture_filter(), + p_state.texture_repeat(), + p_state.linear_colors(), + p_state.texture_is_data()); // something odd happened if (info.is_null()) { - _prepare_batch_texture_info(p_current_batch, default_canvas_texture); + _prepare_batch_texture_info(default_canvas_texture, p_state, p_info); 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; + p_info->state = p_state; + p_info->diffuse = info.diffuse; + p_info->normal = info.normal; + p_info->specular = info.specular; + p_info->sampler = info.sampler; // 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; + p_info->flags |= BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED; } if (info.use_normal) { - p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; + p_info->flags |= BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED; } 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_info->specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r); - p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height)); + p_info->texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height)); } RendererCanvasRenderRD::~RendererCanvasRenderRD() { @@ -3075,7 +3236,7 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() { RD::get_singleton()->free(state.shadow_texture); memdelete_arr(state.instance_data_array); - for (uint32_t i = 0; i < state.canvas_instance_data_buffers.size(); i++) { + for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) { for (uint32_t j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) { RD::get_singleton()->free(state.canvas_instance_data_buffers[i].instance_buffers[j]); } |