From 6bb51179555a21991f4fef32ed2efd3905a7fdd3 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Sat, 29 Feb 2020 17:16:50 -0800 Subject: [PATCH] Improve cubemap importance sampling --- .../rasterizer_rd/rasterizer_effects_rd.cpp | 26 ++++--- .../rasterizer_rd/rasterizer_effects_rd.h | 6 +- .../rasterizer_rd/rasterizer_scene_rd.cpp | 60 ++++++++++----- .../rasterizer_rd/rasterizer_scene_rd.h | 3 +- .../shaders/cubemap_roughness.glsl | 73 ++++--------------- 5 files changed, 76 insertions(+), 92 deletions(-) diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp index be9f1901a77..00f51d3e5d9 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp @@ -248,26 +248,30 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_framebuff RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness) { +void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); - roughness.push_constant.face_id = p_face_id; + roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; roughness.push_constant.roughness = p_roughness; roughness.push_constant.sample_count = p_sample_count; roughness.push_constant.use_direct_write = p_roughness == 0.0; + roughness.push_constant.face_size = p_size; - //RUN - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP]); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_framebuffer), 1); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + int x_groups = (p_size - 1) / 8 + 1; + int y_groups = (p_size - 1) / 8 + 1; + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1); + + RD::get_singleton()->compute_list_end(); } void RasterizerEffectsRD::render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler) { @@ -830,7 +834,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { roughness.shader_version = roughness.shader.version_create(); for (int i = 0; i < CUBEMAP_ROUGHNESS_SOURCE_MAX; i++) { - roughness.pipelines[i].setup(roughness.shader.version_get_shader(roughness.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + roughness.pipelines[i] = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, i)); } } diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h index 003ea335169..a371f1fe449 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h @@ -127,6 +127,8 @@ class RasterizerEffectsRD { uint32_t sample_count; float roughness; uint32_t use_direct_write; + float face_size; + float pad[3]; }; struct CubemapRoughness { @@ -134,7 +136,7 @@ class RasterizerEffectsRD { CubemapRoughnessPushConstant push_constant; CubemapRoughnessShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX]; + RID pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX]; } roughness; struct SkyPushConstant { @@ -418,7 +420,7 @@ public: void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); void gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); - void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness); + void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler); void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size); void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 7476bb6ae4d..4c339020e0f 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -146,9 +146,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID if (p_quality) { //render directly to the layers for (int i = 0; i < rd.layers.size(); i++) { - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0)); - } + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].views[0], 10, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0), rd.layers[i].mipmaps[0].size.x); } } else { // Use fast filtering. Render directly to base mip levels @@ -169,9 +167,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID if (p_quality) { //render directly to the layers for (int i = 0; i < rd.layers[0].mipmaps.size(); i++) { - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); - } + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].views[i], 10, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[i].size.x); } } else { // Use fast filtering. Render directly to each mip level @@ -185,15 +181,13 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID } } -void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side) { +void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer) { if (p_use_arrays) { if (p_quality) { //render directly to the layers - for (int i = 1; i < rd.layers.size(); i++) { - storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[i].mipmaps[0].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0)); - } + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x); } else { storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size); @@ -211,10 +205,8 @@ void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, } else { if (p_quality) { - //render directly to the layers - for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) { - storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); - } + + storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], false, rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x); } else { storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size); @@ -739,6 +731,21 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R reflection_atlas_set_size(p_reflection_atlas, 128, atlas->count); } + if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 7) { + // Invalidate reflection atlas, need to regenerate + RD::get_singleton()->free(atlas->reflection); + atlas->reflection = RID(); + + for (int i = 0; i < atlas->reflections.size(); i++) { + if (atlas->reflections[i].owner.is_null()) { + continue; + } + reflection_probe_release_atlas_index(atlas->reflections[i].owner); + } + + atlas->reflections.clear(); + } + if (atlas->reflection.is_null()) { int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1); mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS ? 7 : mipmaps; // always use 7 mipmaps with real time filtering @@ -805,6 +812,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R rpi->atlas = p_reflection_atlas; rpi->rendering = true; rpi->dirty = false; + rpi->processing_layer = 1; rpi->processing_side = 0; return true; @@ -824,24 +832,36 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc return false; } - _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side); + if (rpi->processing_layer > 1) { + _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, 10, rpi->processing_layer); + rpi->processing_layer++; + if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { + rpi->rendering = false; + rpi->processing_side = 0; + rpi->processing_layer = 1; + return true; + } + return false; + + } else { + _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side, rpi->processing_layer); + } if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) { // Using real time reflections, all roughness is done in one step rpi->rendering = false; rpi->processing_side = 0; + rpi->processing_layer = 1; return true; } rpi->processing_side++; - if (rpi->processing_side == 6) { - rpi->rendering = false; rpi->processing_side = 0; - return true; - } else { - return false; + rpi->processing_layer++; } + + return false; } uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index 3e3ad5e4f5f..0fa853f2dfb 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -108,7 +108,7 @@ private: void _clear_reflection_data(ReflectionData &rd); void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality); void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality); - void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side); + void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer); void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality); /* SKY */ @@ -165,6 +165,7 @@ private: bool dirty = true; bool rendering = false; + int processing_layer = 1; int processing_side = 0; uint32_t render_step = 0; diff --git a/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl b/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl index 011dfce9852..3dba143e56d 100644 --- a/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl +++ b/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl @@ -1,83 +1,38 @@ /* clang-format off */ -[vertex] +[compute] #version 450 VERSION_DEFINES -layout(location = 0) out highp vec2 uv_interp; +#define GROUP_SIZE 8 + +layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in; /* clang-format on */ -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_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); -} - -/* clang-format off */ -[fragment] - -#version 450 - -VERSION_DEFINES - #ifdef MODE_SOURCE_PANORAMA layout(set = 0, binding = 0) uniform sampler2D source_panorama; -/* clang-format on */ #endif #ifdef MODE_SOURCE_CUBEMAP layout(set = 0, binding = 0) uniform samplerCube source_cube; #endif +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap; + layout(push_constant, binding = 1, std430) uniform Params { uint face_id; uint sample_count; float roughness; bool use_direct_write; + float face_size; } params; -layout(location = 0) in vec2 uv_interp; - -layout(location = 0) out vec4 frag_color; - #define M_PI 3.14159265359 vec3 texelCoordToVec(vec2 uv, uint faceID) { mat3 faceUvVectors[6]; - /* - // -x - faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face - - // +x - faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face - - // -y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face - - // +y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face - - // -z - faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face - - // +z - faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face - */ // -x faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z @@ -179,21 +134,23 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) { #endif void main() { + uvec3 id = gl_GlobalInvocationID; + id.z += params.face_id; - vec2 uv = (uv_interp * 2.0) - 1.0; - vec3 N = texelCoordToVec(uv, params.face_id); + vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0); + vec3 N = texelCoordToVec(uv, id.z); //vec4 color = color_interp; if (params.use_direct_write) { #ifdef MODE_SOURCE_PANORAMA - - frag_color = vec4(texturePanorama(N, source_panorama).rgb, 1.0); + imageStore(dest_cubemap, ivec3(id), vec4(texturePanorama(N, source_panorama).rgb, 1.0)); #endif #ifdef MODE_SOURCE_CUBEMAP - frag_color = vec4(texture(source_cube, N).rgb, 1.0); + imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0)); + #endif } else { @@ -222,6 +179,6 @@ void main() { } sum /= sum.a; - frag_color = vec4(sum.rgb, 1.0); + imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0)); } }