Implementing blit shader with versions

This commit is contained in:
Bastiaan Olij 2021-05-11 23:08:38 +10:00
parent 0c693f8781
commit 02980be834
4 changed files with 179 additions and 59 deletions

View File

@ -59,7 +59,22 @@ public:
struct BlitToScreen { struct BlitToScreen {
RID render_target; RID render_target;
Rect2i rect; Rect2i rect;
//lens distorted parameters for VR should go here
struct {
bool use_layer = false;
uint32_t layer = 0;
} multi_view;
struct {
//lens distorted parameters for VR
bool apply = false;
Vector2 eye_center;
float k1 = 0.0;
float k2 = 0.0;
float upscale = 1.0;
float aspect_ratio = 1.0;
} lens_distortion;
}; };
virtual void prepare_for_blitting_render_targets() = 0; virtual void prepare_for_blitting_render_targets() = 0;

View File

@ -44,32 +44,40 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
ERR_CONTINUE(texture.is_null()); ERR_CONTINUE(texture.is_null());
RID rd_texture = storage->texture_get_rd_texture(texture); RID rd_texture = storage->texture_get_rd_texture(texture);
ERR_CONTINUE(rd_texture.is_null()); ERR_CONTINUE(rd_texture.is_null());
if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
Vector<RD::Uniform> uniforms; Vector<RD::Uniform> uniforms;
RD::Uniform u; RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u.binding = 0; u.binding = 0;
u.ids.push_back(copy_viewports_sampler); u.ids.push_back(blit.sampler);
u.ids.push_back(rd_texture); u.ids.push_back(rd_texture);
uniforms.push_back(u); uniforms.push_back(u);
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, copy_viewports_rd_shader, 0); RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0);
render_target_descriptors[rd_texture] = uniform_set; render_target_descriptors[rd_texture] = uniform_set;
} }
Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen)); Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen));
BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER :
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_viewports_rd_pipeline); BLIT_MODE_NORMAL;
RD::get_singleton()->draw_list_bind_index_array(draw_list, copy_viewports_rd_array); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[mode]);
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
float push_constant[4] = { blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width;
p_render_targets[i].rect.position.x / screen_size.width, blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height;
p_render_targets[i].rect.position.y / screen_size.height, blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width;
p_render_targets[i].rect.size.width / screen_size.width, blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height;
p_render_targets[i].rect.size.height / screen_size.height, blit.push_constant.layer = p_render_targets[i].multi_view.layer;
}; blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x;
RD::get_singleton()->draw_list_set_push_constant(draw_list, push_constant, 4 * sizeof(float)); blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y;
blit.push_constant.k1 = p_render_targets[i].lens_distortion.k1;
blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2;
blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale;
blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true); RD::get_singleton()->draw_list_draw(draw_list, true);
} }
@ -96,40 +104,22 @@ void RendererCompositorRD::end_frame(bool p_swap_buffers) {
} }
void RendererCompositorRD::initialize() { void RendererCompositorRD::initialize() {
{ //create framebuffer copy shader {
RenderingDevice::ShaderStageData vert; // Initialize blit
vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX; Vector<String> blit_modes;
vert.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_VERTEX, blit_modes.push_back("\n");
"#version 450\n" blit_modes.push_back("\n#define USE_LAYER\n");
"layout(push_constant, binding = 0, std140) uniform Pos { vec4 dst_rect; } pos;\n" blit_modes.push_back("\n#define USE_LAYER\n#define APPLY_LENS_DISTORTION\n");
"layout(location =0) out vec2 uv;\n"
"void main() { \n"
" vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0));\n"
" uv = base_arr[gl_VertexIndex];\n"
" vec2 vtx = pos.dst_rect.xy+uv*pos.dst_rect.zw;\n"
" gl_Position = vec4(vtx * 2.0 - 1.0,0.0,1.0);\n"
"}\n");
RenderingDevice::ShaderStageData frag; blit.shader.initialize(blit_modes);
frag.shader_stage = RenderingDevice::SHADER_STAGE_FRAGMENT;
frag.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_FRAGMENT,
"#version 450\n"
"layout (location = 0) in vec2 uv;\n"
"layout (location = 0) out vec4 color;\n"
"layout (binding = 0) uniform sampler2D src_rt;\n"
"void main() { color=texture(src_rt,uv); }\n");
Vector<RenderingDevice::ShaderStageData> source; blit.shader_version = blit.shader.version_create();
source.push_back(vert);
source.push_back(frag); for (int i = 0; i < BLIT_MODE_MAX; i++) {
String error; blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
copy_viewports_rd_shader = RD::get_singleton()->shader_create(source);
if (!copy_viewports_rd_shader.is_valid()) {
print_line("Failed compilation: " + error);
} }
}
{ //create index array for copy shader //create index array for copy shader
Vector<uint8_t> pv; Vector<uint8_t> pv;
pv.resize(6 * 4); pv.resize(6 * 4);
{ {
@ -142,15 +132,10 @@ void RendererCompositorRD::initialize() {
p32[4] = 2; p32[4] = 2;
p32[5] = 3; p32[5] = 3;
} }
copy_viewports_rd_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); blit.index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
copy_viewports_rd_array = RD::get_singleton()->index_array_create(copy_viewports_rd_index_buffer, 0, 6); blit.array = RD::get_singleton()->index_array_create(blit.index_buffer, 0, 6);
}
{ //pipeline blit.sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
copy_viewports_rd_pipeline = RD::get_singleton()->render_pipeline_create(copy_viewports_rd_shader, RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
}
{ // sampler
copy_viewports_sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
} }
} }
@ -162,9 +147,9 @@ void RendererCompositorRD::finalize() {
memdelete(storage); memdelete(storage);
//only need to erase these, the rest are erased by cascade //only need to erase these, the rest are erased by cascade
RD::get_singleton()->free(copy_viewports_rd_index_buffer); blit.shader.version_free(blit.shader_version);
RD::get_singleton()->free(copy_viewports_rd_shader); RD::get_singleton()->free(blit.index_buffer);
RD::get_singleton()->free(copy_viewports_sampler); RD::get_singleton()->free(blit.sampler);
} }
RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD *RendererCompositorRD::singleton = nullptr;

View File

@ -38,6 +38,7 @@
#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h" #include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h" #include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/blit.glsl.gen.h"
class RendererCompositorRD : public RendererCompositor { class RendererCompositorRD : public RendererCompositor {
protected: protected:
@ -45,11 +46,35 @@ protected:
RendererStorageRD *storage; RendererStorageRD *storage;
RendererSceneRenderRD *scene; RendererSceneRenderRD *scene;
RID copy_viewports_rd_shader; enum BlitMode {
RID copy_viewports_rd_pipeline; BLIT_MODE_NORMAL,
RID copy_viewports_rd_index_buffer; BLIT_MODE_USE_LAYER,
RID copy_viewports_rd_array; BLIT_MODE_LENS,
RID copy_viewports_sampler; BLIT_MODE_MAX
};
struct BlitPushConstant {
float rect[4];
float eye_center[2];
float k1;
float k2;
float upscale;
float aspect_ratio;
uint32_t layer;
uint32_t pad1;
};
struct Blit {
BlitPushConstant push_constant;
BlitShaderRD shader;
RID shader_version;
RID pipelines[BLIT_MODE_MAX];
RID index_buffer;
RID array;
RID sampler;
} blit;
Map<RID, RID> render_target_descriptors; Map<RID, RID> render_target_descriptors;

View File

@ -0,0 +1,95 @@
#[vertex]
#version 450
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
vec4 dst_rect;
vec2 eye_center;
float k1;
float k2;
float upscale;
float aspect_ratio;
uint layer;
uint pad1;
}
data;
layout(location = 0) out vec2 uv;
void main() {
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
uv = base_arr[gl_VertexIndex];
vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw;
gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
}
#[fragment]
#version 450
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
vec4 dst_rect;
vec2 eye_center;
float k1;
float k2;
float upscale;
float aspect_ratio;
uint layer;
uint pad1;
}
data;
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 color;
#ifdef USE_LAYER
layout(binding = 0) uniform sampler2DArray src_rt;
#else
layout(binding = 0) uniform sampler2D src_rt;
#endif
void main() {
#ifdef APPLY_LENS_DISTORTION
vec2 coords = uv * 2.0 - 1.0;
vec2 offset = coords - data.eye_center;
// take aspect ratio into account
offset.y /= data.aspect_ratio;
// distort
vec2 offset_sq = offset * offset;
float radius_sq = offset_sq.x + offset_sq.y;
float radius_s4 = radius_sq * radius_sq;
float distortion_scale = 1.0 + (data.k1 * radius_sq) + (data.k2 * radius_s4);
offset *= distortion_scale;
// reapply aspect ratio
offset.y *= data.aspect_ratio;
// add our eye center back in
coords = offset + data.eye_center;
coords /= data.upscale;
// and check our color
if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
color = vec4(0.0, 0.0, 0.0, 1.0);
} else {
// layer is always used here
coords = (coords + vec2(1.0)) / vec2(2.0);
color = texture(src_rt, vec3(coords, data.layer));
}
#elif defined(USE_LAYER)
color = texture(src_rt, vec3(uv, data.layer));
#else
color = texture(src_rt, uv);
#endif
}