diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd')
13 files changed, 835 insertions, 53 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index 5d9e68f2b4..921a7b966e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -30,6 +30,7 @@ #include "rasterizer_canvas_rd.h" #include "core/config/project_settings.h" +#include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" #include "rasterizer_rd.h" @@ -687,7 +688,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ #if 0 case Item::Command::TYPE_MESH: { - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); _set_texture_rect_mode(false); @@ -702,7 +702,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); if (mesh_data) { - for (int j = 0; j < mesh_data->surfaces.size(); j++) { RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing @@ -723,7 +722,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); @@ -786,7 +784,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int custom_data_ofs = color_ofs; switch (multi_mesh->color_format) { - case RS::MULTIMESH_COLOR_NONE: { glDisableVertexAttribArray(11); glVertexAttrib4f(11, 1, 1, 1, 1); @@ -807,7 +804,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } switch (multi_mesh->custom_data_format) { - case RS::MULTIMESH_CUSTOM_DATA_NONE: { glDisableVertexAttribArray(12); glVertexAttrib4f(12, 1, 1, 1, 1); @@ -841,7 +837,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_PARTICLES: { - Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); @@ -875,7 +870,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } if (!particles->use_local_coords) { - Transform2D inv_xf; inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); @@ -893,7 +887,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int amount = particles->amount; if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) { - glEnableVertexAttribArray(8); //xform x glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); @@ -1059,10 +1052,19 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ } { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 7; + RID sdf = storage->render_target_get_sdf_texture(p_to_render_target); + u.ids.push_back(sdf); + uniforms.push_back(u); + } + + { //needs samplers for the material (uses custom textures) create them RD::Uniform u; u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 7; + u.binding = 8; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -1083,7 +1085,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 8; + u.binding = 9; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } @@ -1190,7 +1192,8 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::get_singleton()->draw_list_end(); } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { +void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { + r_sdf_used = false; int item_count = 0; //setup canvas state uniforms if needed @@ -1373,6 +1376,25 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite state_buffer.directional_light_count = directional_light_count; + Vector2 canvas_scale = p_canvas_transform.get_scale(); + + state_buffer.sdf_to_screen[0] = render_target_size.width / canvas_scale.x; + state_buffer.sdf_to_screen[1] = render_target_size.height / canvas_scale.y; + + state_buffer.screen_to_sdf[0] = 1.0 / state_buffer.sdf_to_screen[0]; + state_buffer.screen_to_sdf[1] = 1.0 / state_buffer.sdf_to_screen[1]; + + Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_to_render_target); + Rect2 sdf_tex_rect(sdf_rect.position / canvas_scale, sdf_rect.size / canvas_scale); + + state_buffer.sdf_to_tex[0] = 1.0 / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[1] = 1.0 / sdf_tex_rect.size.height; + state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height; + + //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); + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); } @@ -1410,6 +1432,9 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } + if (md->shader_data->uses_sdf) { + r_sdf_used = true; + } if (md->last_frame != RasterizerRD::singleton->get_frame_number()) { md->last_frame = RasterizerRD::singleton->get_frame_number(); if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { @@ -1695,18 +1720,102 @@ void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow cl->shadow.directional_xform = to_shadow * to_light_xform; } +void RasterizerCanvasRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { + RID fb = storage->render_target_get_sdf_framebuffer(p_render_target); + Rect2i rect = storage->render_target_get_sdf_rect(p_render_target); + + Transform2D to_sdf; + to_sdf.elements[0] *= rect.size.width; + to_sdf.elements[1] *= rect.size.height; + to_sdf.elements[2] = rect.position; + + Transform2D to_clip; + to_clip.elements[0] *= 2.0; + to_clip.elements[1] *= 2.0; + to_clip.elements[2] = -Vector2(1.0, 1.0); + + to_clip = to_clip * to_sdf.affine_inverse(); + + Vector<Color> cc; + cc.push_back(Color(0, 0, 0, 0)); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc); + + CameraMatrix projection; + + ShadowRenderPushConstant push_constant; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + push_constant.projection[y * 4 + x] = projection.matrix[y][x]; + } + } + + push_constant.direction[0] = 0.0; + push_constant.direction[1] = 0.0; + push_constant.z_far = 0; + push_constant.pad = 0; + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + + if (!co || co->sdf_index_array.is_null()) { + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat2x4(to_clip * instance->xform_cache, push_constant.modelview); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.sdf_render_pipelines[co->sdf_is_lines ? SHADOW_RENDER_SDF_LINES : SHADOW_RENDER_SDF_TRIANGLES]); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->sdf_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->sdf_index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + + instance = instance->next; + } + + RD::get_singleton()->draw_list_end(); + + storage->render_target_sdf_process(p_render_target); //done rendering, process it +} + RID RasterizerCanvasRD::occluder_polygon_create() { OccluderPolygon occluder; - occluder.point_count = 0; + occluder.line_point_count = 0; + occluder.sdf_point_count = 0; + occluder.sdf_index_count = 0; occluder.cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; return occluder_polygon_owner.make_rid(occluder); } -void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) { +void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); - if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) { + Vector<Vector2> lines; + int lc = p_points.size() * 2; + + lines.resize(lc - (p_closed ? 0 : 2)); + { + Vector2 *w = lines.ptrw(); + const Vector2 *r = p_points.ptr(); + + int max = lc / 2; + if (!p_closed) { + max--; + } + for (int i = 0; i < max; i++) { + Vector2 a = r[i]; + Vector2 b = r[(i + 1) % (lc / 2)]; + w[i * 2 + 0] = a; + w[i * 2 + 1] = b; + } + } + + if (oc->line_point_count != lines.size() && oc->vertex_array.is_valid()) { RD::get_singleton()->free(oc->vertex_array); RD::get_singleton()->free(oc->vertex_buffer); RD::get_singleton()->free(oc->index_array); @@ -1716,12 +1825,14 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con oc->vertex_buffer = RID(); oc->index_array = RID(); oc->index_buffer = RID(); + + oc->line_point_count = lines.size(); } - if (p_lines.size()) { + if (lines.size()) { Vector<uint8_t> geometry; Vector<uint8_t> indices; - int lc = p_lines.size(); + lc = lines.size(); geometry.resize(lc * 6 * sizeof(float)); indices.resize(lc * 3 * sizeof(uint16_t)); @@ -1732,7 +1843,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con uint8_t *iw = indices.ptrw(); uint16_t *iwptr = (uint16_t *)iw; - const Vector2 *lr = p_lines.ptr(); + const Vector2 *lr = lines.ptr(); const int POLY_HEIGHT = 16384; @@ -1786,6 +1897,62 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir); } } + + // sdf + + Vector<int> sdf_indices; + + if (p_closed) { + sdf_indices = Geometry2D::triangulate_polygon(p_points); + oc->sdf_is_lines = false; + } else { + int max = p_points.size(); + sdf_indices.resize(max * 2); + + int *iw = sdf_indices.ptrw(); + for (int i = 0; i < max; i++) { + iw[i * 2 + 0] = i; + iw[i * 2 + 1] = (i + 1) % max; + } + oc->sdf_is_lines = true; + } + + if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) { + RD::get_singleton()->free(oc->sdf_vertex_array); + RD::get_singleton()->free(oc->sdf_vertex_buffer); + RD::get_singleton()->free(oc->sdf_index_array); + RD::get_singleton()->free(oc->sdf_index_buffer); + + oc->sdf_vertex_array = RID(); + oc->sdf_vertex_buffer = RID(); + oc->sdf_index_array = RID(); + oc->sdf_index_buffer = RID(); + + oc->sdf_index_count = sdf_indices.size(); + oc->sdf_point_count = p_points.size(); + + oc->sdf_is_lines = false; + } + + if (sdf_indices.size()) { + if (oc->sdf_vertex_array.is_null()) { + //create from scratch + //vertices + oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(real_t), p_points.to_byte_array()); + oc->sdf_index_buffer = RD::get_singleton()->index_buffer_create(sdf_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, sdf_indices.to_byte_array()); + oc->sdf_index_array = RD::get_singleton()->index_array_create(oc->sdf_index_buffer, 0, sdf_indices.size()); + + Vector<RID> buffer; + buffer.push_back(oc->sdf_vertex_buffer); + oc->sdf_vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), shadow_render.sdf_vertex_format, buffer); + //indices + + } else { + //update existing + RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr()); + RD::get_singleton()->buffer_update(oc->index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr()); + } + } } void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { @@ -1802,6 +1969,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); uses_screen_texture = false; + uses_sdf = false; if (code == String()) { return; //just invalid, but no error @@ -1809,7 +1977,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ShaderCompilerRD::GeneratedCode gen_code; - int light_mode = LIGHT_MODE_NORMAL; int blend_mode = BLEND_MODE_MIX; uses_screen_texture = false; @@ -1822,10 +1989,8 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA); actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED); - actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED); - actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY); - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; actions.uniforms = &uniforms; @@ -2046,6 +2211,7 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName & RasterizerCanvasRD::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; + uses_sdf = false; } RasterizerCanvasRD::ShaderData::~ShaderData() { @@ -2310,6 +2476,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["LIGHT"] = "light"; actions.renames["SHADOW_MODULATE"] = "shadow_modulate"; + actions.renames["texture_sdf"] = "texture_sdf"; + actions.renames["texture_sdf_normal"] = "texture_sdf_normal"; + actions.renames["sdf_to_screen_uv"] = "sdf_to_screen_uv"; + actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; @@ -2319,6 +2490,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n"; actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n"; actions.custom_samplers["TEXTURE"] = "texture_sampler"; actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler"; @@ -2339,7 +2512,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //shadow rendering Vector<String> versions; - versions.push_back(String()); //no versions + versions.push_back("\n#define MODE_SHADOW\n"); //shadow + versions.push_back("\n#define MODE_SDF\n"); //sdf shadow_render.shader.initialize(versions); { @@ -2360,16 +2534,34 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); } + { + Vector<RD::AttachmentFormat> attachments; + + RD::AttachmentFormat af_color; + af_color.format = RD::DATA_FORMAT_R8_UNORM; + af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + attachments.push_back(af_color); + + shadow_render.sdf_framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); + } + //pipelines Vector<RD::VertexAttribute> vf; RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32B32_SFLOAT : RD::DATA_FORMAT_R64G64B64_SFLOAT; vd.location = 0; vd.offset = 0; - vd.stride = sizeof(float) * 3; + vd.stride = sizeof(real_t) * 3; vf.push_back(vd); shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf); + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32_SFLOAT : RD::DATA_FORMAT_R64G64_SFLOAT; + vd.stride = sizeof(real_t) * 2; + + vf.write[0] = vd; + shadow_render.sdf_vertex_format = RD::get_singleton()->vertex_format_create(vf); + shadow_render.shader_version = shadow_render.shader.version_create(); for (int i = 0; i < 3; i++) { @@ -2379,7 +2571,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { ds.enable_depth_write = true; ds.enable_depth_test = true; ds.depth_compare_operator = RD::COMPARE_OP_LESS; - shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } + + for (int i = 0; i < 2; i++) { + shadow_render.sdf_render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SDF), shadow_render.sdf_framebuffer_format, shadow_render.sdf_vertex_format, i == 0 ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_LINES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); } } @@ -2490,7 +2686,7 @@ bool RasterizerCanvasRD::free(RID p_rid) { light_set_use_shadow(p_rid, false); canvas_light_owner.free(p_rid); } else if (occluder_polygon_owner.owns(p_rid)) { - occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>()); + occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false); occluder_polygon_owner.free(p_rid); } else { return false; diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index b516f63cbf..b09d6578f3 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -161,12 +161,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { BLEND_MODE_DISABLED, }; - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - bool valid; RID version; PipelineVariants pipeline_variants; @@ -181,7 +175,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { String code; Map<StringName, RID> default_texture_params; - bool uses_screen_texture; + bool uses_screen_texture = false; + bool uses_sdf = false; virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); @@ -284,11 +279,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { struct OccluderPolygon { RS::CanvasOccluderPolygonCullMode cull_mode; - int point_count; + int line_point_count; RID vertex_buffer; RID vertex_array; RID index_buffer; RID index_array; + + int sdf_point_count; + int sdf_index_count; + RID sdf_vertex_buffer; + RID sdf_vertex_array; + RID sdf_index_buffer; + RID sdf_index_array; + bool sdf_is_lines; }; struct LightUniform { @@ -310,12 +313,25 @@ class RasterizerCanvasRD : public RasterizerCanvas { RID_Owner<OccluderPolygon> occluder_polygon_owner; + enum ShadowRenderMode { + SHADOW_RENDER_MODE_SHADOW, + SHADOW_RENDER_MODE_SDF, + }; + + enum { + SHADOW_RENDER_SDF_TRIANGLES, + SHADOW_RENDER_SDF_LINES, + }; + struct { CanvasOcclusionShaderRD shader; RID shader_version; RID render_pipelines[3]; + RID sdf_render_pipelines[2]; RD::VertexFormatID vertex_format; + RD::VertexFormatID sdf_vertex_format; RD::FramebufferFormatID framebuffer_format; + RD::FramebufferFormatID sdf_framebuffer_format; } shadow_render; /***************/ @@ -336,8 +352,14 @@ class RasterizerCanvasRD : public RasterizerCanvas { float time; uint32_t use_pixel_snap; + float sdf_to_tex[4]; + float sdf_to_screen[2]; + float screen_to_sdf[2]; + uint32_t directional_light_count; - uint32_t pad[3]; + float tex_to_sdf; + uint32_t pad1; + uint32_t pad2; }; LightUniform *light_uniforms; @@ -423,11 +445,13 @@ public: void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders); + virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders); + RID occluder_polygon_create(); - void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines); + void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed); void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode); - void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {} diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index a275e46473..313188ba87 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -1238,7 +1238,6 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende } #if 0 if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance @@ -1583,7 +1582,6 @@ void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, i } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); ERR_CONTINUE(!immediate); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index e1be9b0ef4..12fcc6fbb9 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -351,8 +351,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co RD::TextureFormat tf_probe_average = tf_probes; tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed - tf_probe_average.type = RD::TEXTURE_TYPE_2D_ARRAY; - tf_probe_average.array_layers = 1; + tf_probe_average.type = RD::TEXTURE_TYPE_2D; sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); @@ -1471,7 +1470,9 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } if (giprobes_changed) { - RD::get_singleton()->free(rb->gi_uniform_set); + if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { + RD::get_singleton()->free(rb->gi_uniform_set); + } rb->gi_uniform_set = RID(); if (rb->volumetric_fog) { if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { @@ -8216,7 +8217,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { RD::Uniform u; u.type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); uniforms.push_back(u); } { diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 8bd4362637..444ef9c49a 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -5549,7 +5549,6 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t } RID shared_tex; { - RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_R8_UINT; shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture); @@ -6030,6 +6029,8 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->backbuffer_uniform_set = RID(); //chain deleted } + _render_target_clear_sdf(rt); + rt->framebuffer = RID(); rt->color = RID(); } @@ -6300,6 +6301,275 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } +void RasterizerStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) { + return; + } + + rt->sdf_oversize = p_size; + rt->sdf_scale = p_scale; + + _render_target_clear_sdf(rt); +} + +Rect2i RasterizerStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const { + Size2i margin; + int scale; + switch (rt->sdf_oversize) { + case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: { + scale = 120; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: { + scale = 150; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: { + scale = 200; + } break; + default: { + } + } + + margin = (rt->size * scale / 100) - rt->size; + + Rect2i r(Vector2i(), rt->size); + r.position -= margin; + r.size += margin * 2; + + return r; +} + +Rect2i RasterizerStorageRD::render_target_get_sdf_rect(RID p_render_target) const { + const RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Rect2i()); + + return _render_target_get_sdf_rect(rt); +} + +RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + if (rt->sdf_buffer_read.is_null()) { + // no texture, create a dummy one for the 2D uniform set + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + zeromem(pv.ptrw(), 16 * 4); + Vector<Vector<uint8_t>> vpv; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + return rt->sdf_buffer_read; +} + +void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_valid()); + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + + Size2i size = _render_target_get_sdf_rect(rt).size; + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8_UNORM; + tformat.width = size.width; + tformat.height = size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RID> write_fb; + write_fb.push_back(rt->sdf_buffer_write); + rt->sdf_buffer_write_fb = RD::get_singleton()->framebuffer_create(write_fb); + } + + int scale; + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + scale = 50; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + scale = 25; + } break; + default: { + scale = 100; + } break; + } + + rt->process_size = size * scale / 100; + rt->process_size.x = MAX(rt->process_size.x, 1); + rt->process_size.y = MAX(rt->process_size.y, 1); + + tformat.format = RD::DATA_FORMAT_R16G16_UINT; + tformat.width = rt->process_size.width; + tformat.height = rt->process_size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + tformat.format = RD::DATA_FORMAT_R16_UNORM; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(rt->sdf_buffer_write); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(rt->sdf_buffer_read); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(rt->sdf_buffer_process[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 4; + u.ids.push_back(rt->sdf_buffer_process[1]); + uniforms.push_back(u); + } + + rt->sdf_buffer_process_uniform_sets[0] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + SWAP(uniforms.write[2].ids.write[0], uniforms.write[3].ids.write[0]); + rt->sdf_buffer_process_uniform_sets[1] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + } +} + +void RasterizerStorageRD::_render_target_clear_sdf(RenderTarget *rt) { + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + if (rt->sdf_buffer_write_fb.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_write); + RD::get_singleton()->free(rt->sdf_buffer_process[0]); + RD::get_singleton()->free(rt->sdf_buffer_process[1]); + rt->sdf_buffer_write = RID(); + rt->sdf_buffer_write_fb = RID(); + rt->sdf_buffer_process[0] = RID(); + rt->sdf_buffer_process[1] = RID(); + rt->sdf_buffer_process_uniform_sets[0] = RID(); + rt->sdf_buffer_process_uniform_sets[1] = RID(); + } +} + +RID RasterizerStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->sdf_buffer_write_fb.is_null()) { + _render_target_allocate_sdf(rt); + } + + return rt->sdf_buffer_write_fb; +} +void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null()); + + RenderTargetSDF::PushConstant push_constant; + + Rect2i r = _render_target_get_sdf_rect(rt); + + push_constant.size[0] = r.size.width; + push_constant.size[1] = r.size.height; + push_constant.stride = 0; + push_constant.shift = 0; + push_constant.base_size[0] = r.size.width; + push_constant.base_size[1] = r.size.height; + + bool shrink = false; + + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + push_constant.size[0] >>= 1; + push_constant.size[1] >>= 1; + push_constant.shift = 1; + shrink = true; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + push_constant.size[0] >>= 2; + push_constant.size[1] >>= 2; + push_constant.shift = 2; + shrink = true; + } break; + default: { + }; + } + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + /* Load */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_LOAD_SHRINK : RenderTargetSDF::SHADER_LOAD]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[1], 0); //fill [0] + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + /* Process */ + + int stride = nearest_power_of_2_templated(MAX(push_constant.size[0], push_constant.size[1]) / 2); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[RenderTargetSDF::SHADER_PROCESS]); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + bool swap = false; + + //jumpflood + while (stride > 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + push_constant.stride = stride; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + stride /= 2; + swap = !swap; + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + + /* Store */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_STORE_SHRINK : RenderTargetSDF::SHADER_STORE]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + RD::get_singleton()->compute_list_end(); +} + void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -7756,6 +8026,34 @@ RasterizerStorageRD::RasterizerStorageRD() { } } + { //create default cubemap white array + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.array_layers = 6; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.type = RD::TEXTURE_TYPE_CUBE; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<Vector<uint8_t>> vpv; + for (int i = 0; i < 6; i++) { + vpv.push_back(pv); + } + default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + } + { //create default 3D RD::TextureFormat tformat; @@ -8128,6 +8426,24 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i)); } } + + { + Vector<String> sdf_modes; + sdf_modes.push_back("\n#define MODE_LOAD\n"); + sdf_modes.push_back("\n#define MODE_LOAD_SHRINK\n"); + sdf_modes.push_back("\n#define MODE_PROCESS\n"); + sdf_modes.push_back("\n#define MODE_PROCESS_OPTIMIZED\n"); + sdf_modes.push_back("\n#define MODE_STORE\n"); + sdf_modes.push_back("\n#define MODE_STORE_SHRINK\n"); + + rt_sdf.shader.initialize(sdf_modes); + + rt_sdf.shader_version = rt_sdf.shader.version_create(); + + for (int i = 0; i < RenderTargetSDF::SHADER_MAX; i++) { + rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i)); + } + } } RasterizerStorageRD::~RasterizerStorageRD() { diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 05cb1b4a73..4a708fc94f 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -35,6 +35,7 @@ #include "servers/rendering/rasterizer.h" #include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h" #include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" +#include "servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h" @@ -155,6 +156,7 @@ public: DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER, DEFAULT_RD_TEXTURE_CUBEMAP_BLACK, DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK, + DEFAULT_RD_TEXTURE_CUBEMAP_WHITE, DEFAULT_RD_TEXTURE_3D_WHITE, DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE, DEFAULT_RD_TEXTURE_2D_UINT, @@ -1002,6 +1004,15 @@ private: RID framebuffer_uniform_set; RID backbuffer_uniform_set; + RID sdf_buffer_write; + RID sdf_buffer_write_fb; + RID sdf_buffer_process[2]; + RID sdf_buffer_read; + RID sdf_buffer_process_uniform_sets[2]; + RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT; + RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT; + Size2i process_size; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -1011,11 +1022,38 @@ private: Color clear_color; }; - RID_Owner<RenderTarget> render_target_owner; + mutable RID_Owner<RenderTarget> render_target_owner; void _clear_render_target(RenderTarget *rt); void _update_render_target(RenderTarget *rt); void _create_render_target_backbuffer(RenderTarget *rt); + void _render_target_allocate_sdf(RenderTarget *rt); + void _render_target_clear_sdf(RenderTarget *rt); + Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const; + + struct RenderTargetSDF { + enum { + SHADER_LOAD, + SHADER_LOAD_SHRINK, + SHADER_PROCESS, + SHADER_PROCESS_OPTIMIZED, + SHADER_STORE, + SHADER_STORE_SHRINK, + SHADER_MAX + }; + + struct PushConstant { + int32_t size[2]; + int32_t stride; + int32_t shift; + int32_t base_size[2]; + int32_t pad[2]; + }; + + CanvasSdfShaderRD shader; + RID shader_version; + RID pipelines[SHADER_MAX]; + } rt_sdf; /* GLOBAL SHADER VARIABLES */ @@ -1929,6 +1967,12 @@ public: virtual void render_target_disable_clear_request(RID p_render_target); virtual void render_target_do_clear_request(RID p_render_target); + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale); + RID render_target_get_sdf_texture(RID p_render_target); + RID render_target_get_sdf_framebuffer(RID p_render_target); + void render_target_sdf_process(RID p_render_target); + virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const; + Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp index 1a33e9a567..df5513435a 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp @@ -671,7 +671,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } /* for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) { - if (SL::is_sampler_type(E->get().type)) { continue; } @@ -1073,6 +1072,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } else if (onode->op == SL::OP_CONSTRUCT) { code += String(vnode->name); } else { + if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { + *p_actions.usage_flag_pointers[vnode->name] = true; + used_flag_pointers.insert(vnode->name); + } + if (internal_functions.has(vnode->name)) { code += vnode->name; is_texture_func = texture_functions.has(vnode->name); diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 9d531d63ad..4cddf0f685 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -5,6 +5,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") + env.RD_GLSL("canvas_sdf.glsl") env.RD_GLSL("copy.glsl") env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl index 2a0f94e733..51d7193a03 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl @@ -233,6 +233,30 @@ MATERIAL_UNIFORMS } material; #endif +vec2 screen_uv_to_sdf(vec2 p_uv) { + return canvas_data.screen_to_sdf * p_uv; +} + +float texture_sdf(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r; + d = d * SDF_MAX_LENGTH - 1.0; + return d * canvas_data.tex_to_sdf; +} + +vec2 texture_sdf_normal(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + + const float EPSILON = 0.001; + return normalize(vec2( + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r, + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r)); +} + +vec2 sdf_to_screen_uv(vec2 p_sdf) { + return p_sdf * canvas_data.sdf_to_screen; +} + /* clang-format off */ FRAGMENT_SHADER_GLOBALS /* clang-format on */ @@ -500,8 +524,13 @@ FRAGMENT_SHADER_CODE color = vec4(0.0); //invisible by default due to using light mask } +#ifdef MODE_LIGHT_ONLY + color = vec4(0.0); +#else color *= canvas_data.canvas_modulation; -#ifdef USE_LIGHTING +#endif + +#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED) // Directional Lights diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl index 421282cd4d..5c25235c58 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl @@ -2,6 +2,8 @@ #version 450 +VERSION_DEFINES + layout(location = 0) in highp vec3 vertex; layout(push_constant, binding = 0, std430) uniform Constants { @@ -13,12 +15,16 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) out highp float depth; +#endif void main() { highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - depth = dot(constants.direction, vtx.xy); +#ifdef MODE_SHADOW + depth = dot(constants.direction, vtx.xy); +#endif gl_Position = constants.projection * vtx; } @@ -26,6 +32,8 @@ void main() { #version 450 +VERSION_DEFINES + layout(push_constant, binding = 0, std430) uniform Constants { mat4 projection; mat2x4 modelview; @@ -35,9 +43,17 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) in highp float depth; layout(location = 0) out highp float distance_buf; +#else +layout(location = 0) out highp float sdf_buf; +#endif void main() { +#ifdef MODE_SHADOW distance_buf = depth / constants.z_far; +#else + sdf_buf = 1.0; +#endif } diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl new file mode 100644 index 0000000000..302ad03b41 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl @@ -0,0 +1,135 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels; +layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf; + +layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process; +layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process; + +layout(push_constant, binding = 0, std430) uniform Params { + ivec2 size; + int stride; + int shift; + ivec2 base_size; + uvec2 pad; +} +params; + +#define SDF_MAX_LENGTH 16384.0 + +void main() { + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing + return; + } + +#ifdef MODE_LOAD + + bool solid = imageLoad(src_pixels, pos).r > 0.5; + imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0)); +#endif + +#ifdef MODE_LOAD_SHRINK + + int s = 1 << params.shift; + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = ivec2(32767); + float d = 1e20; + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + ivec2 src_pos = base + ivec2(i, j); + if (any(greaterThanEqual(src_pos, params.base_size))) { + continue; + } + bool solid = imageLoad(src_pixels, src_pos).r > 0.5; + if (solid) { + float dist = length(vec2(src_pos - center)); + if (dist < d) { + d = dist; + rel = src_pos; + } + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_PROCESS + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + + if (center != rel) { + //only process if it does not point to itself + const int ofs_table_size = 8; + const ivec2 ofs_table[ofs_table_size] = ivec2[]( + ivec2(-1, -1), + ivec2(0, -1), + ivec2(+1, -1), + + ivec2(-1, 0), + ivec2(+1, 0), + + ivec2(-1, +1), + ivec2(0, +1), + ivec2(+1, +1)); + + float dist = length(vec2(rel - center)); + for (int i = 0; i < ofs_table_size; i++) { + ivec2 src_pos = pos + ofs_table[i] * params.stride; + if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) { + continue; + } + ivec2 src_rel = imageLoad(src_process, src_pos).xy; + float src_dist = length(vec2(src_rel - center)); + if (src_dist < dist) { + dist = src_dist; + rel = src_rel; + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_STORE + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - pos)); + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif + +#ifdef MODE_STORE_SHRINK + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - center)); + + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index bb39584cbb..cf7678ea31 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -3,6 +3,8 @@ #define M_PI 3.14159265359 +#define SDF_MAX_LENGTH 16384.0 + #define FLAGS_INSTANCING_STRIDE_MASK 0xF #define FLAGS_INSTANCING_ENABLED (1 << 4) #define FLAGS_INSTANCING_HAS_COLORS (1 << 5) @@ -24,6 +26,19 @@ #define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + // Push Constant layout(push_constant, binding = 0, std430) uniform DrawData { @@ -68,8 +83,12 @@ layout(set = 0, binding = 1, std140) uniform CanvasData { float time; bool use_pixel_snap; + vec4 sdf_to_tex; + vec2 screen_to_sdf; + vec2 sdf_to_screen; + uint directional_light_count; - uint pad0; + float tex_to_sdf; uint pad1; uint pad2; } @@ -115,10 +134,11 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture; layout(set = 0, binding = 5) uniform sampler shadow_sampler; layout(set = 0, binding = 6) uniform texture2D screen_texture; +layout(set = 0, binding = 7) uniform texture2D sdf_texture; -layout(set = 0, binding = 7) uniform sampler material_samplers[12]; +layout(set = 0, binding = 8) uniform sampler material_samplers[12]; -layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index da3c60af04..285698f060 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -868,7 +868,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v inout float alpha, #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); float normalized_distance = light_length * lights.data[idx].inv_radius; @@ -1158,7 +1157,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); float normalized_distance = light_length * lights.data[idx].inv_radius; |