1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-29 16:16:38 +00:00

Implement signed distance fields for 2D shaders

This commit is contained in:
reduz
2020-11-26 09:50:21 -03:00
parent 4e5625ce30
commit 1bcf3c305b
26 changed files with 1028 additions and 89 deletions

View File

@@ -6029,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();
}
@@ -6299,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);
@@ -8155,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() {