diff options
Diffstat (limited to 'servers/rendering')
41 files changed, 2106 insertions, 532 deletions
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h index ebb81abdad..c0c03eb26a 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.h +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -235,7 +235,7 @@ public: Transform3D xform = view_xform * p_transform; float radius = xform.basis.get_uniform_scale(); - if (radius > 0.98 || radius < 1.02) { + if (radius < 0.98 || radius > 1.02) { xform.basis.orthonormalize(); } diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 5cf8895c8e..699f4a4b90 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -37,6 +37,10 @@ #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "thirdparty/misc/cubemap_coeffs.h" +bool EffectsRD::get_prefer_raster_effects() { + return prefer_raster_effects; +} + static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -383,6 +387,8 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i } void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the compute version of the gaussian blur with the mobile renderer."); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); uint32_t base_flags = 0; @@ -416,6 +422,8 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back } void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer."); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; @@ -449,6 +457,57 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const RD::get_singleton()->compute_list_end(); } +void EffectsRD::gaussian_glow_raster(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, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer."); + + memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + + BlurRasterMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW; + uint32_t base_flags = 0; + + blur_raster.push_constant.pixel_size[0] = p_pixel_size.x; + blur_raster.push_constant.pixel_size[1] = p_pixel_size.y; + + blur_raster.push_constant.glow_strength = p_strength; + blur_raster.push_constant.glow_bloom = p_bloom; + blur_raster.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; + blur_raster.push_constant.glow_hdr_scale = p_hdr_bleed_scale; + blur_raster.push_constant.glow_exposure = p_exposure; + blur_raster.push_constant.glow_white = 0; //actually unused + blur_raster.push_constant.glow_luminance_cap = p_luminance_cap; + + blur_raster.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also + + //HORIZONTAL + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, 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, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + if (p_auto_exposure.is_valid() && p_first_pass) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_auto_exposure), 1); + } + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + blur_mode = BLUR_MODE_GAUSSIAN_GLOW; + + //VERTICAL + 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, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur_raster.push_constant.flags = base_flags; + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -736,6 +795,8 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone } void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer."); + luminance_reduce.push_constant.source_size[0] = p_source_size.x; luminance_reduce.push_constant.source_size[1] = p_source_size.y; luminance_reduce.push_constant.max_luminance = p_max_luminance; @@ -774,7 +835,41 @@ void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_ RD::get_singleton()->compute_list_end(); } +void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster version of luminance reduction with the clustered renderer."); + ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction."); + + luminance_reduce_raster.push_constant.max_luminance = p_max_luminance; + luminance_reduce_raster.push_constant.min_luminance = p_min_luminance; + luminance_reduce_raster.push_constant.exposure_adjust = p_adjust; + + for (int i = 0; i < p_reduce.size(); i++) { + luminance_reduce_raster.push_constant.source_size[0] = i == 0 ? p_source_size.x : luminance_reduce_raster.push_constant.dest_size[0]; + luminance_reduce_raster.push_constant.source_size[1] = i == 0 ? p_source_size.y : luminance_reduce_raster.push_constant.dest_size[1]; + luminance_reduce_raster.push_constant.dest_size[0] = MAX(luminance_reduce_raster.push_constant.source_size[0] / 8, 1); + luminance_reduce_raster.push_constant.dest_size[1] = MAX(luminance_reduce_raster.push_constant.source_size[1] / 8, 1); + + bool final = !p_set && (luminance_reduce_raster.push_constant.dest_size[0] == 1) && (luminance_reduce_raster.push_constant.dest_size[1] == 1); + LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb[i], 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, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_fb[i]))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(i == 0 ? p_source_texture : p_reduce[i - 1]), 0); + if (final) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_prev_luminance), 1); + } + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &luminance_reduce_raster.push_constant, sizeof(LuminanceReduceRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } +} + void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer."); + bokeh.push_constant.blur_far_active = p_dof_far; bokeh.push_constant.blur_far_begin = p_dof_far_begin; bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size; @@ -924,6 +1019,78 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i RD::get_singleton()->compute_list_end(); } +void EffectsRD::blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer."); + + memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + + BlurRasterMode blur_mode; + int qsteps[4] = { 4, 4, 10, 20 }; + uint32_t base_flags = p_cam_orthogonal ? BLUR_FLAG_USE_ORTHOGONAL_PROJECTION : 0; + + Vector2 pixel_size = Vector2(1.0 / p_base_texture_size.width, 1.0 / p_base_texture_size.height); + + blur_raster.push_constant.dof_radius = (p_dof_blur_amount * p_dof_blur_amount) / qsteps[p_quality]; + blur_raster.push_constant.pixel_size[0] = pixel_size.x; + blur_raster.push_constant.pixel_size[1] = pixel_size.y; + blur_raster.push_constant.camera_z_far = p_cam_zfar; + blur_raster.push_constant.camera_z_near = p_cam_znear; + + if (p_dof_far || p_dof_near) { + if (p_quality == RS::DOF_BLUR_QUALITY_HIGH) { + blur_mode = BLUR_MODE_DOF_HIGH; + } else if (p_quality == RS::DOF_BLUR_QUALITY_MEDIUM) { + blur_mode = BLUR_MODE_DOF_MEDIUM; + } else { // for LOW or VERYLOW we use LOW + blur_mode = BLUR_MODE_DOF_LOW; + } + + if (p_dof_far) { + base_flags |= BLUR_FLAG_DOF_FAR; + blur_raster.push_constant.dof_far_begin = p_dof_far_begin; + blur_raster.push_constant.dof_far_end = p_dof_far_begin + p_dof_far_size; + } + + if (p_dof_near) { + base_flags |= BLUR_FLAG_DOF_NEAR; + blur_raster.push_constant.dof_near_begin = p_dof_near_begin; + blur_raster.push_constant.dof_near_end = p_dof_near_begin - p_dof_near_size; + } + + //HORIZONTAL + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_secondary_fb, 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, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_secondary_fb))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base_texture), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL; + blur_raster.push_constant.dof_dir[0] = 1.0; + blur_raster.push_constant.dof_dir[1] = 0.0; + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + //VERTICAL + draw_list = RD::get_singleton()->draw_list_begin(p_base_fb, 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, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_base_fb))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary_texture), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur_raster.push_constant.flags = base_flags; + blur_raster.push_constant.dof_dir[0] = 0.0; + blur_raster.push_constant.dof_dir[1] = 1.0; + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } +} + void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { @@ -1188,8 +1355,9 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { if (pass < blur_passes - 2) { blur_pipeline = SSAO_BLUR_PASS_WIDE; + } else { + blur_pipeline = SSAO_BLUR_PASS_SMART; } - blur_pipeline = SSAO_BLUR_PASS_SMART; } for (int i = 0; i < 4; i++) { @@ -1283,7 +1451,9 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size RD::get_singleton()->compute_list_end(); } -void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { +void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer."); + memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; @@ -1293,10 +1463,10 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe roughness.push_constant.face_size = p_size; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipeline); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline); 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()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); @@ -1308,11 +1478,37 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe RD::get_singleton()->compute_list_end(); } +void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time."); + + memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); + + roughness.push_constant.face_id = 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; + + 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.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + 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()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer."); + cubemap_downsampler.push_constant.face_size = p_size.x; + cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipeline); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1); @@ -1326,7 +1522,27 @@ void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, con RD::get_singleton()->compute_list_end(); } +void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time."); + + cubemap_downsampler.push_constant.face_size = p_size.x; + cubemap_downsampler.push_constant.face_id = p_face_id; + + 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, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer."); + Vector<RD::Uniform> uniforms; for (int i = 0; i < p_dest_cubemap.size(); i++) { RD::Uniform u; @@ -1338,12 +1554,12 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { RD::get_singleton()->free(filter.image_uniform_set); } - filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2); + filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2); int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY; pipeline = filter.use_high_quality ? pipeline : pipeline + 1; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2); @@ -1355,6 +1571,29 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, RD::get_singleton()->compute_list_end(); } +void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time."); + + // TODO implement! + CubemapFilterRasterPushConstant push_constant; + push_constant.mip_level = p_mip_level; + push_constant.face_id = p_face_id; + + CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY; + + 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, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { ResolvePushConstant push_constant; push_constant.screen_size[0] = p_screen_size.x; @@ -1464,7 +1703,35 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { RD::get_singleton()->compute_list_end(); } -EffectsRD::EffectsRD() { +EffectsRD::EffectsRD(bool p_prefer_raster_effects) { + prefer_raster_effects = p_prefer_raster_effects; + + if (prefer_raster_effects) { + // init blur shader (on compute use copy shader) + + Vector<String> blur_modes; + blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR + blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW + blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE + blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_LOW\n"); // BLUR_MODE_DOF_LOW + blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_MEDIUM\n"); // BLUR_MODE_DOF_MEDIUM + blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_HIGH\n"); // BLUR_MODE_DOF_HIGH + + blur_raster.shader.initialize(blur_modes); + memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + blur_raster.shader_version = blur_raster.shader.version_create(); + + for (int i = 0; i < BLUR_MODE_MAX; i++) { + blur_raster.pipelines[i].setup(blur_raster.shader.version_get_shader(blur_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } + + } else { + // not used in clustered + for (int i = 0; i < BLUR_MODE_MAX; i++) { + blur_raster.pipelines[i].clear(); + } + } + { // Initialize copy Vector<String> copy_modes; copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); @@ -1483,10 +1750,21 @@ EffectsRD::EffectsRD() { copy.shader.initialize(copy_modes); memset(©.push_constant, 0, sizeof(CopyPushConstant)); + + if (prefer_raster_effects) { + // disable shaders we can't use + copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY, false); + copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY_8BIT, false); + copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW, false); + copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, false); + } + copy.shader_version = copy.shader.version_create(); for (int i = 0; i < COPY_MODE_MAX; i++) { - copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i)); + if (copy.shader.is_variant_enabled(i)) { + copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i)); + } } } { @@ -1510,11 +1788,22 @@ EffectsRD::EffectsRD() { // Initialize roughness Vector<String> cubemap_roughness_modes; cubemap_roughness_modes.push_back(""); - roughness.shader.initialize(cubemap_roughness_modes); - roughness.shader_version = roughness.shader.version_create(); + if (prefer_raster_effects) { + roughness.raster_shader.initialize(cubemap_roughness_modes); + + roughness.shader_version = roughness.raster_shader.version_create(); + + roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + + } else { + roughness.compute_shader.initialize(cubemap_roughness_modes); + + roughness.shader_version = roughness.compute_shader.version_create(); - roughness.pipeline = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, 0)); + roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0)); + roughness.raster_pipeline.clear(); + } } { @@ -1551,7 +1840,20 @@ EffectsRD::EffectsRD() { } } - { + if (prefer_raster_effects) { + Vector<String> luminance_reduce_modes; + luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST + luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT + luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL + + luminance_reduce_raster.shader.initialize(luminance_reduce_modes); + memset(&luminance_reduce_raster.push_constant, 0, sizeof(LuminanceReduceRasterPushConstant)); + luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create(); + + for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { + luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } + } else { // Initialize luminance_reduce Vector<String> luminance_reduce_modes; luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n"); @@ -1565,6 +1867,10 @@ EffectsRD::EffectsRD() { for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) { luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i)); } + + for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { + luminance_reduce_raster.pipelines[i].clear(); + } } { @@ -1583,7 +1889,9 @@ EffectsRD::EffectsRD() { cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); } - { + if (prefer_raster_effects) { + // not supported + } else { // Initialize bokeh Vector<String> bokeh_modes; bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n"); @@ -1761,11 +2069,21 @@ EffectsRD::EffectsRD() { //Initialize cubemap downsampler Vector<String> cubemap_downsampler_modes; cubemap_downsampler_modes.push_back(""); - cubemap_downsampler.shader.initialize(cubemap_downsampler_modes); - cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create(); + if (prefer_raster_effects) { + cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes); + + cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create(); + + cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes); + + cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create(); - cubemap_downsampler.pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, 0)); + cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0)); + cubemap_downsampler.raster_pipeline.clear(); + } } { @@ -1777,12 +2095,6 @@ EffectsRD::EffectsRD() { cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n"); cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n"); cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n"); - filter.shader.initialize(cubemap_filter_modes); - filter.shader_version = filter.shader.version_create(); - - for (int i = 0; i < FILTER_MODE_MAX; i++) { - filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i)); - } if (filter.use_high_quality) { filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs)); @@ -1792,15 +2104,50 @@ EffectsRD::EffectsRD() { RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); } - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 0; - u.ids.push_back(filter.coefficient_buffer); - uniforms.push_back(u); + if (prefer_raster_effects) { + filter.raster_shader.initialize(cubemap_filter_modes); + filter.shader_version = filter.raster_shader.version_create(); + + // array variants are not supported in raster + filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false); + filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false); + + for (int i = 0; i < FILTER_MODE_MAX; i++) { + if (filter.raster_shader.is_variant_enabled(i)) { + filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + filter.raster_pipelines[i].clear(); + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(filter.coefficient_buffer); + uniforms.push_back(u); + } + filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); + } else { + filter.compute_shader.initialize(cubemap_filter_modes); + filter.shader_version = filter.compute_shader.version_create(); + + for (int i = 0; i < FILTER_MODE_MAX; i++) { + filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i)); + filter.raster_pipelines[i].clear(); + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(filter.coefficient_buffer); + uniforms.push_back(u); + } + filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); } - filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); } { @@ -1974,15 +2321,23 @@ EffectsRD::~EffectsRD() { RD::get_singleton()->free(ssao.gather_constants_buffer); RD::get_singleton()->free(ssao.importance_map_load_counter); - bokeh.shader.version_free(bokeh.shader_version); + if (prefer_raster_effects) { + blur_raster.shader.version_free(blur_raster.shader_version); + luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version); + roughness.raster_shader.version_free(roughness.shader_version); + cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version); + filter.raster_shader.version_free(filter.shader_version); + } else { + bokeh.shader.version_free(bokeh.shader_version); + luminance_reduce.shader.version_free(luminance_reduce.shader_version); + roughness.compute_shader.version_free(roughness.shader_version); + cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); + filter.compute_shader.version_free(filter.shader_version); + } copy.shader.version_free(copy.shader_version); copy_to_fb.shader.version_free(copy_to_fb.shader_version); cube_to_dp.shader.version_free(cube_to_dp.shader_version); - cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version); - filter.shader.version_free(filter.shader_version); - luminance_reduce.shader.version_free(luminance_reduce.shader_version); resolve.shader.version_free(resolve.shader_version); - roughness.shader.version_free(roughness.shader_version); roughness_limiter.shader.version_free(roughness_limiter.shader_version); sort.shader.version_free(sort.shader_version); specular_merge.shader.version_free(specular_merge.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 33d32f0c57..eff891571a 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -33,14 +33,19 @@ #include "core/math/camera_matrix.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h" @@ -60,6 +65,66 @@ #include "servers/rendering_server.h" class EffectsRD { +private: + bool prefer_raster_effects; + + enum BlurRasterMode { + BLUR_MODE_GAUSSIAN_BLUR, + BLUR_MODE_GAUSSIAN_GLOW, + BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, + + BLUR_MODE_DOF_LOW, + BLUR_MODE_DOF_MEDIUM, + BLUR_MODE_DOF_HIGH, + + BLUR_MODE_MAX + }; + + enum { + BLUR_FLAG_HORIZONTAL = (1 << 0), + BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1), + BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2), + BLUR_FLAG_DOF_FAR = (1 << 3), + BLUR_FLAG_DOF_NEAR = (1 << 4), + }; + + struct BlurRasterPushConstant { + float pixel_size[2]; + uint32_t flags; + uint32_t pad; + + //glow + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + + //dof + float dof_far_begin; + float dof_far_end; + float dof_near_begin; + float dof_near_end; + + float dof_radius; + float dof_pad[3]; + + float dof_dir[2]; + float camera_z_far; + float camera_z_near; + }; + + struct BlurRaster { + BlurRasterPushConstant push_constant; + BlurRasterShaderRD shader; + RID shader_version; + PipelineCacheRD pipelines[BLUR_MODE_MAX]; + } blur_raster; + enum CopyMode { COPY_MODE_GAUSSIAN_COPY, COPY_MODE_GAUSSIAN_COPY_8BIT, @@ -161,9 +226,11 @@ class EffectsRD { struct CubemapRoughness { CubemapRoughnessPushConstant push_constant; - CubemapRoughnessShaderRD shader; + CubemapRoughnessShaderRD compute_shader; + CubemapRoughnessRasterShaderRD raster_shader; RID shader_version; - RID pipeline; + RID compute_pipeline; + PipelineCacheRD raster_pipeline; } roughness; enum TonemapMode { @@ -239,6 +306,29 @@ class EffectsRD { RID pipelines[LUMINANCE_REDUCE_MAX]; } luminance_reduce; + enum LuminanceReduceRasterMode { + LUMINANCE_REDUCE_FRAGMENT_FIRST, + LUMINANCE_REDUCE_FRAGMENT, + LUMINANCE_REDUCE_FRAGMENT_FINAL, + LUMINANCE_REDUCE_FRAGMENT_MAX + }; + + struct LuminanceReduceRasterPushConstant { + int32_t source_size[2]; + int32_t dest_size[2]; + float exposure_adjust; + float min_luminance; + float max_luminance; + float pad[1]; + }; + + struct LuminanceReduceFragment { + LuminanceReduceRasterPushConstant push_constant; + LuminanceReduceRasterShaderRD shader; + RID shader_version; + PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX]; + } luminance_reduce_raster; + struct CopyToDPPushConstant { float z_far; float z_near; @@ -426,15 +516,17 @@ class EffectsRD { struct CubemapDownsamplerPushConstant { uint32_t face_size; - float pad[3]; + uint32_t face_id; + float pad[2]; }; struct CubemapDownsampler { CubemapDownsamplerPushConstant push_constant; - CubemapDownsamplerShaderRD shader; + CubemapDownsamplerShaderRD compute_shader; + CubemapDownsamplerRasterShaderRD raster_shader; RID shader_version; - RID pipeline; - + RID compute_pipeline; + PipelineCacheRD raster_pipeline; } cubemap_downsampler; enum CubemapFilterMode { @@ -445,10 +537,19 @@ class EffectsRD { FILTER_MODE_MAX, }; + struct CubemapFilterRasterPushConstant { + uint32_t mip_level; + uint32_t face_id; + float pad[2]; + }; + struct CubemapFilter { - CubemapFilterShaderRD shader; + CubemapFilterShaderRD compute_shader; + CubemapFilterRasterShaderRD raster_shader; RID shader_version; - RID pipelines[FILTER_MODE_MAX]; + RID compute_pipelines[FILTER_MODE_MAX]; + PipelineCacheRD raster_pipelines[FILTER_MODE_MAX]; + RID uniform_set; RID image_uniform_set; RID coefficient_buffer; @@ -657,6 +758,8 @@ class EffectsRD { RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); public: + bool get_prefer_raster_effects(); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); @@ -666,12 +769,17 @@ public: void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, 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 gaussian_glow_raster(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_high_quality = false, 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, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); + void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); + void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); + void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); + void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); + void blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); struct TonemapSettings { bool use_glow = false; @@ -740,7 +848,9 @@ public: void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); + void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size); void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); + void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level); void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); @@ -751,7 +861,7 @@ public: void sort_buffer(RID p_uniform_set, int p_size); - EffectsRD(); + EffectsRD(bool p_prefer_raster_effects); ~EffectsRD(); }; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 438bbff53c..4725599148 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -96,10 +96,6 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format(); if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { - if (color_format == RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32) { - // @TODO add a second color buffer for alpha as this format is RGB only - } - Vector<RID> fb; fb.push_back(p_color_buffer); fb.push_back(depth); @@ -164,16 +160,13 @@ bool RenderForwardMobile::free(RID p_rid) { /* Render functions */ RD::DataFormat RenderForwardMobile::_render_buffers_get_color_format() { - // Using 32bit buffers enables AFBC on mobile devices which should have a definate performance improvement (MALI G710 and newer support this on 64bit RTs) - // NO ALPHA and unsigned float. - // @TODO No alpha is an issue, recommendation here is to add a second RT for alpha + // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs) return RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; } bool RenderForwardMobile::_render_buffers_can_be_storage() { - // Using 32bit buffers enables AFBC on mobile devices which should have a definate performance improvement (MALI G710 and newer support this on 64bit RTs) - // NO ALPHA and unsigned float. - // @TODO No alpha is an issue, recommendation here is to add a second RT for alpha + // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs) + // Doesn't support storage return false; } @@ -2332,6 +2325,8 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) : RendererSceneRenderRD(p_storage) { singleton = this; + sky.set_texture_format(_render_buffers_get_color_format()); + String defines; defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 6a66e9fa01..18c1fe02a0 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -620,7 +620,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); RD::get_singleton()->draw_list_draw(p_draw_list, true); - //restore if overrided + // Restore if overridden. push_constant.color_texture_pixel_size[0] = texpixel_size.x; push_constant.color_texture_pixel_size[1] = texpixel_size.y; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index e6ae66d56f..02d548bf13 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -222,7 +222,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color RD::get_singleton()->swap_buffers(); - RD::get_singleton()->free(texture); + storage->free(texture); } RendererCompositorRD *RendererCompositorRD::singleton = nullptr; @@ -280,6 +280,9 @@ RendererCompositorRD::RendererCompositorRD() { // default to our high end renderer scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage)); } + + // now we're ready to create our effects, + storage->init_effects(!scene->_render_buffers_can_be_storage()); } RendererCompositorRD::~RendererCompositorRD() { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 4870f5f397..e3516df800 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -629,6 +629,8 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); + RD::get_singleton()->draw_command_begin_label("Reflection probe render"); + if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) { WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings."); reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count); @@ -675,7 +677,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc } atlas->reflections.resize(atlas->count); for (int i = 0; i < atlas->count; i++) { - atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers); + atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format()); for (int j = 0; j < 6; j++) { Vector<RID> fb; fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]); @@ -721,6 +723,8 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc rpi->processing_layer = 1; rpi->processing_side = 0; + RD::get_singleton()->draw_command_end_label(); + return true; } @@ -1383,12 +1387,20 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH); + // TODO make sure texture_create_shared_from_slice works for multiview + RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.texture_type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; + tf.array_layers = rb->view_count; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + if (_render_buffers_can_be_storage()) { + tf.usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT; + } else { + tf.usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } tf.mipmaps = mipmaps_required; rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -1408,11 +1420,40 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { mm.width = base_width; mm.height = base_height; + if (!_render_buffers_can_be_storage()) { + Vector<RID> fb; + fb.push_back(mm.texture); + + mm.fb = RD::get_singleton()->framebuffer_create(fb); + } + + if (!_render_buffers_can_be_storage()) { + // and half texture, this is an intermediate result so just allocate a texture, is this good enough? + tf.width = MAX(1, base_width >> 1); + tf.height = base_height; + tf.mipmaps = 1; // 1 or 0? + + mm.half_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> half_fb; + half_fb.push_back(mm.half_texture); + mm.half_fb = RD::get_singleton()->framebuffer_create(half_fb); + } + rb->blur[0].mipmaps.push_back(mm); if (i > 0) { mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1); + if (!_render_buffers_can_be_storage()) { + Vector<RID> fb; + fb.push_back(mm.texture); + + mm.fb = RD::get_singleton()->framebuffer_create(fb); + + // We can re-use the half texture here as it is an intermediate result + } + rb->blur[1].mipmaps.push_back(mm); } @@ -1435,26 +1476,48 @@ void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = w; tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; bool final = w == 1 && h == 1; - if (final) { - tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; + if (_render_buffers_can_be_storage()) { + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + if (final) { + tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; + } + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; } RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); rb->luminance.reduce.push_back(texture); + if (!_render_buffers_can_be_storage()) { + Vector<RID> fb; + fb.push_back(texture); + + rb->luminance.fb.push_back(RD::get_singleton()->framebuffer_create(fb)); + } if (final) { rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + if (!_render_buffers_can_be_storage()) { + Vector<RID> fb; + fb.push_back(rb->luminance.current); + + rb->luminance.current_fb = RD::get_singleton()->framebuffer_create(fb); + } break; } } } void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { + if (rb->texture_fb.is_valid()) { + RD::get_singleton()->free(rb->texture_fb); + rb->texture_fb = RID(); + } + if (rb->texture.is_valid()) { RD::get_singleton()->free(rb->texture); rb->texture = RID(); @@ -1466,19 +1529,43 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { } for (int i = 0; i < 2; i++) { + for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) { + // do we free the texture slice here? or is it enough to free the main texture? + + // do free the mobile extra stuff + if (rb->blur[i].mipmaps[m].fb.is_valid()) { + RD::get_singleton()->free(rb->blur[i].mipmaps[m].fb); + } + if (rb->blur[i].mipmaps[m].half_fb.is_valid()) { + RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_fb); + } + if (rb->blur[i].mipmaps[m].half_texture.is_valid()) { + RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_texture); + } + } + rb->blur[i].mipmaps.clear(); + if (rb->blur[i].texture.is_valid()) { RD::get_singleton()->free(rb->blur[i].texture); rb->blur[i].texture = RID(); - rb->blur[i].mipmaps.clear(); } } + for (int i = 0; i < rb->luminance.fb.size(); i++) { + RD::get_singleton()->free(rb->luminance.fb[i]); + } + rb->luminance.fb.clear(); + for (int i = 0; i < rb->luminance.reduce.size(); i++) { RD::get_singleton()->free(rb->luminance.reduce[i]); } - rb->luminance.reduce.clear(); + if (rb->luminance.current_fb.is_valid()) { + RD::get_singleton()->free(rb->luminance.current_fb); + rb->luminance.current_fb = RID(); + } + if (rb->luminance.current.is_valid()) { RD::get_singleton()->free(rb->luminance.current); rb->luminance.current = RID(); @@ -1750,17 +1837,27 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->camera_effects); bool can_use_effects = rb->width >= 8 && rb->height >= 8; + bool can_use_storage = _render_buffers_can_be_storage(); + + // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) { + RD::get_singleton()->draw_command_begin_label("DOF"); if (rb->blur[0].texture.is_null()) { _allocate_blur_textures(rb); } - float bokeh_size = camfx->dof_blur_amount * 64.0; - storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); + if (can_use_storage) { + float bokeh_size = camfx->dof_blur_amount * 64.0; + storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); + } else { + storage->get_effects()->blur_dof_raster(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->texture_fb, rb->blur[0].mipmaps[0].texture, rb->blur[0].mipmaps[0].fb, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, camfx->dof_blur_amount, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); + } + RD::get_singleton()->draw_command_end_label(); } if (can_use_effects && env && env->auto_exposure) { + RD::get_singleton()->draw_command_begin_label("Auto exposure"); if (rb->luminance.current.is_null()) { _allocate_luminance_textures(rb); } @@ -1769,16 +1866,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende rb->auto_exposure_version = env->auto_exposure_version; double step = env->auto_exp_speed * time_step; - storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); - + if (can_use_storage) { + storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + } else { + storage->get_effects()->luminance_reduction_raster(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + } //swap final reduce with prev luminance SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); + if (!can_use_storage) { + SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]); + } + RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on + RD::get_singleton()->draw_command_end_label(); } int max_glow_level = -1; if (can_use_effects && env && env->glow_enabled) { + RD::get_singleton()->draw_command_begin_label("Gaussian Glow"); + /* see that blur textures are allocated */ if (rb->blur[1].texture.is_null()) { @@ -1804,14 +1911,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende if (env->auto_exposure && rb->luminance.current.is_valid()) { luminance_texture = rb->luminance.current; } - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + if (can_use_storage) { + storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + } else { + storage->get_effects()->gaussian_glow_raster(rb->texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + } } else { - storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality); + if (can_use_storage) { + storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality); + } else { + storage->get_effects()->gaussian_glow_raster(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, glow_high_quality); + } } } + + RD::get_singleton()->draw_command_end_label(); } { + RD::get_singleton()->draw_command_begin_label("Tonemap"); + //tonemap EffectsRD::TonemapSettings tonemap; @@ -1870,6 +1989,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.view_count = p_render_data->view_count; storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + + RD::get_singleton()->draw_command_end_label(); } storage->render_target_disable_clear_request(rb->render_target); @@ -2133,7 +2254,7 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() { } void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { - ERR_FAIL_COND_MSG(p_view_count == 0, "Must have atleast 1 view"); + ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view"); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; @@ -2197,6 +2318,14 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } + if (!_render_buffers_can_be_storage()) { + // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS! + Vector<RID> fb; + fb.push_back(rb->texture); + + rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count); + } + rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count); if (is_clustered_enabled()) { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 5e0281002d..bb06eb608f 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -450,6 +450,7 @@ private: RID texture; //main texture for rendering to, must be filled after done rendering RID depth_texture; //main depth texture + RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!! RendererSceneGIRD::SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; @@ -465,6 +466,11 @@ private: RID texture; int width; int height; + + // only used on mobile renderer + RID fb; + RID half_texture; + RID half_fb; }; Vector<Mipmap> mipmaps; @@ -475,6 +481,10 @@ private: struct Luminance { Vector<RID> reduce; RID current; + + // used only on mobile renderer + Vector<RID> fb; + RID current_fb; } luminance; struct SSAO { diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index bc1603a219..cadf759ec3 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -313,12 +313,16 @@ void RendererSceneSkyRD::ReflectionData::clear_reflection_data() { coefficient_buffer = RID(); } -void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) { +void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) { //recreate radiance and all data int mipmaps = p_mipmaps; uint32_t w = p_size, h = p_size; + EffectsRD *effects = p_storage->get_effects(); + ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); + bool prefer_raster_effects = effects->get_prefer_raster_effects(); + if (p_use_array) { int num_layers = p_low_quality ? 8 : p_roughness_layers; @@ -377,9 +381,9 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int } radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); - + RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.format = p_texture_format; tf.width = 64; // Always 64x64 tf.height = 64; tf.texture_type = RD::TEXTURE_TYPE_CUBE; @@ -388,6 +392,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap"); { uint32_t mmw = 64; uint32_t mmh = 64; @@ -397,6 +402,18 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int mm.size.width = mmw; mm.size.height = mmh; mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP); + RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); + if (prefer_raster_effects) { + // we need a framebuffer for each side of our cubemap + + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j); + RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " "); + Vector<RID> fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + } mmw = MAX(1, mmw >> 1); mmh = MAX(1, mmh >> 1); @@ -405,50 +422,128 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int } void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) { - p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + EffectsRD *effects = p_storage->get_effects(); + ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); + bool prefer_raster_effects = effects->get_prefer_raster_effects(); + + if (prefer_raster_effects) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + for (int k = 0; k < 6; k++) { + effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + } - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); - } + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + for (int k = 0; k < 6; k++) { + effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + } + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance - Vector<RID> views; - if (p_use_arrays) { - for (int i = 1; i < layers.size(); i++) { - views.push_back(layers[i].views[0]); + if (p_use_arrays) { + RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads"); + for (int i = 0; i < layers.size(); i++) { + for (int k = 0; k < 6; k++) { + effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); + } + } + } else { + RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly"); + for (int j = 0; j < layers[0].mipmaps.size(); j++) { + for (int k = 0; k < 6; k++) { + effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); + } + } } + RD::get_singleton()->draw_command_end_label(); // Filter radiance } else { - for (int i = 1; i < layers[0].views.size(); i++) { - views.push_back(layers[0].views[i]); + effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + } + + Vector<RID> views; + if (p_use_arrays) { + for (int i = 1; i < layers.size(); i++) { + views.push_back(layers[i].views[0]); + } + } else { + for (int i = 1; i < layers[0].views.size(); i++) { + views.push_back(layers[0].views[i]); + } } - } - p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + } } void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { - if (p_use_arrays) { - //render directly to the layers - p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + EffectsRD *effects = p_storage->get_effects(); + ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); + bool prefer_raster_effects = effects->get_prefer_raster_effects(); + + if (prefer_raster_effects) { + // Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call + // here we need to do them one by one so ignoring p_cube_side + if (p_use_arrays) { + for (int k = 0; k < 6; k++) { + effects->cubemap_roughness_raster( + radiance_base_cubemap, + layers[p_base_layer].mipmaps[0].framebuffers[k], + k, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers.size() - 1.0), + layers[p_base_layer].mipmaps[0].size.x); + } + } else { + for (int k = 0; k < 6; k++) { + effects->cubemap_roughness_raster( + layers[0].views[p_base_layer - 1], + layers[0].mipmaps[p_base_layer].framebuffers[k], + k, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), + layers[0].mipmaps[p_base_layer].size.x); + } + } } else { - p_storage->get_effects()->cubemap_roughness( - layers[0].views[p_base_layer - 1], - layers[0].views[p_base_layer], - p_cube_side, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), - layers[0].mipmaps[p_base_layer].size.x); + if (p_use_arrays) { + //render directly to the layers + effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + } else { + effects->cubemap_roughness( + layers[0].views[p_base_layer - 1], + layers[0].views[p_base_layer], + p_cube_side, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), + layers[0].mipmaps[p_base_layer].size.x); + } } } void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) { + EffectsRD *effects = p_storage->get_effects(); + ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); + bool prefer_raster_effects = effects->get_prefer_raster_effects(); + + RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps"); for (int i = p_start; i < p_end; i++) { for (int j = 0; j < layers[i].views.size() - 1; j++) { RID view = layers[i].views[j]; - RID texture = layers[i].views[j + 1]; Size2i size = layers[i].mipmaps[j + 1].size; - p_storage->get_effects()->cubemap_downsample(view, texture, size); + if (prefer_raster_effects) { + for (int k = 0; k < 6; k++) { + RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k]; + effects->cubemap_downsample_raster(view, framebuffer, k, size); + } + } else { + RID texture = layers[i].views[j + 1]; + effects->cubemap_downsample(view, texture, size); + } } } + RD::get_singleton()->draw_command_end_label(); } //////////////////////////////////////////////////////////////////////////////// @@ -902,6 +997,10 @@ void sky() { } } +void RendererSceneSkyRD::set_texture_format(RD::DataFormat p_texture_format) { + texture_format = p_texture_format; +} + RendererSceneSkyRD::~RendererSceneSkyRD() { // TODO cleanup anything created in init... @@ -1170,6 +1269,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM cm = correction * cm; if (shader_data->uses_quarter_res) { + RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap"); PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; Vector<Color> clear_colors; @@ -1185,9 +1285,11 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } + RD::get_singleton()->draw_command_end_label(); } if (shader_data->uses_half_res) { + RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap"); PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; Vector<Color> clear_colors; @@ -1203,11 +1305,13 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } + RD::get_singleton()->draw_command_end_label(); } RD::DrawListID cubemap_draw_list; PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap"); for (int i = 0; i < 6; i++) { Transform3D local_view; local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); @@ -1217,6 +1321,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } + RD::get_singleton()->draw_command_end_label(); if (sky_mode == RS::SKY_MODE_REALTIME) { sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array); @@ -1393,7 +1498,7 @@ void RendererSceneSkyRD::update_dirty_skys() { //array (higher quality, 6 times more memory) RD::TextureFormat tf; tf.array_layers = layers * 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.format = texture_format; tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = w; @@ -1402,13 +1507,13 @@ void RendererSceneSkyRD::update_dirty_skys() { sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers); + sky->reflection.update_reflection_data(storage, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); } else { //regular cubemap, lower quality (aliasing, less memory) RD::TextureFormat tf; tf.array_layers = 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.format = texture_format; tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.mipmaps = MIN(mipmaps, layers); tf.width = w; @@ -1417,7 +1522,7 @@ void RendererSceneSkyRD::update_dirty_skys() { sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers); + sky->reflection.update_reflection_data(storage, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); } texture_set_dirty = true; } @@ -1425,7 +1530,7 @@ void RendererSceneSkyRD::update_dirty_skys() { // Create subpass buffers if they haven't been created already if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { RD::TextureFormat tformat; - tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tformat.format = texture_format; tformat.width = sky->screen_size.x / 2; tformat.height = sky->screen_size.y / 2; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -1440,7 +1545,7 @@ void RendererSceneSkyRD::update_dirty_skys() { if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { RD::TextureFormat tformat; - tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tformat.format = texture_format; tformat.width = sky->screen_size.x / 4; tformat.height = sky->screen_size.y / 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 4f852e55a7..7e0b01d58e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -64,6 +64,7 @@ public: private: RendererStorageRD *storage; + RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; RID index_buffer; RID index_array; @@ -190,6 +191,10 @@ public: struct Mipmap { RID view; Size2i size; + + // for mobile only + RID views[6]; + RID framebuffers[6]; }; Vector<Mipmap> mipmaps; }; @@ -204,7 +209,7 @@ public: Vector<Layer> layers; void clear_reflection_data(); - void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers); + void update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format); void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays); void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality); void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end); @@ -284,6 +289,7 @@ public: RendererSceneSkyRD(); void init(RendererStorageRD *p_storage); + void set_texture_format(RD::DataFormat p_texture_format); ~RendererSceneSkyRD(); void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 2657fa3ae8..d5c7db6fd2 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -2716,9 +2716,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su mesh->surfaces[mesh->surface_count] = s; mesh->surface_count++; - for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { - //update instances - MeshInstance *mi = E->get(); + for (MeshInstance *mi : mesh->instances) { _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1); } @@ -3029,8 +3027,7 @@ void RendererStorageRD::mesh_clear(RID p_mesh) { mesh->surface_count = 0; mesh->material_cache.clear(); //clear instance data - for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { - MeshInstance *mi = E->get(); + for (MeshInstance *mi : mesh->instances) { _mesh_instance_clear(mi); } mesh->has_bone_weights = false; @@ -4962,7 +4959,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); RD::get_singleton()->compute_list_end(); - effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount); + effects->sort_buffer(particles->particles_sort_uniform_set, particles->amount); } copy_push_constant.total_particles *= copy_push_constant.total_particles; @@ -7538,7 +7535,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c //single texture copy for backbuffer //RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); - effects.copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); if (!p_gen_mipmaps) { return; @@ -7554,7 +7551,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c region.size.y = MAX(1, region.size.y >> 1); const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); + effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); prev_texture = mm.mipmap; } } @@ -7577,7 +7574,7 @@ void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, con } //single texture copy for backbuffer - effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); + effects->set_color(rt->backbuffer_mipmap0, p_color, region, true); } void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { @@ -7607,7 +7604,7 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe region.size.y = MAX(1, region.size.y >> 1); const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); + effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); prev_texture = mm.mipmap; } } @@ -7928,14 +7925,14 @@ void RendererStorageRD::_update_decal_atlas() { while ((K = decal_atlas.textures.next(K))) { DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K); Texture *src_tex = texture_owner.getornull(*K); - effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); + effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); } RD::get_singleton()->draw_list_end(); prev_texture = mm.texture; } else { - effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size)); + effects->copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size)); prev_texture = mm.texture; } } else { @@ -8413,10 +8410,10 @@ void RendererStorageRD::global_variables_load_settings(bool p_load_textures) { List<PropertyInfo> settings; ProjectSettings::get_singleton()->get_property_list(&settings); - for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) { - if (E->get().name.begins_with("shader_globals/")) { - StringName name = E->get().name.get_slice("/", 1); - Dictionary d = ProjectSettings::get_singleton()->get(E->get().name); + for (const PropertyInfo &E : settings) { + if (E.name.begins_with("shader_globals/")) { + StringName name = E.name.get_slice("/", 1); + Dictionary d = ProjectSettings::get_singleton()->get(E.name); ERR_CONTINUE(!d.has("type")); ERR_CONTINUE(!d.has("value")); @@ -8584,8 +8581,8 @@ void RendererStorageRD::_update_global_variables() { if (global_variables.must_update_buffer_materials) { // only happens in the case of a buffer variable added or removed, // so not often. - for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) { - Material *material = material_owner.getornull(E->get()); + for (const RID &E : global_variables.materials_using_buffer) { + Material *material = material_owner.getornull(E); ERR_CONTINUE(!material); //wtf _material_queue_update(material, true, false); @@ -8597,8 +8594,8 @@ void RendererStorageRD::_update_global_variables() { if (global_variables.must_update_texture_materials) { // only happens in the case of a buffer variable added or removed, // so not often. - for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) { - Material *material = material_owner.getornull(E->get()); + for (const RID &E : global_variables.materials_using_texture) { + Material *material = material_owner.getornull(E); ERR_CONTINUE(!material); //wtf _material_queue_update(material, false, true); @@ -8807,8 +8804,13 @@ bool RendererStorageRD::free(RID p_rid) { return true; } +void RendererStorageRD::init_effects(bool p_prefer_raster_effects) { + effects = memnew(EffectsRD(p_prefer_raster_effects)); +} + EffectsRD *RendererStorageRD::get_effects() { - return &effects; + ERR_FAIL_NULL_V_MSG(effects, nullptr, "Effects haven't been initialised yet."); + return effects; } void RendererStorageRD::capture_timestamps_begin() { @@ -9538,4 +9540,9 @@ RendererStorageRD::~RendererStorageRD() { if (decal_atlas.texture.is_valid()) { RD::get_singleton()->free(decal_atlas.texture); } + + if (effects) { + memdelete(effects); + effects = NULL; + } } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index f471874c8e..b290c07705 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1290,7 +1290,7 @@ private: void _update_global_variables(); /* EFFECTS */ - EffectsRD effects; + EffectsRD *effects = NULL; public: virtual bool can_create_resources_async() const; @@ -2374,6 +2374,7 @@ public: static RendererStorageRD *base_singleton; + void init_effects(bool p_prefer_raster_effects); EffectsRD *get_effects(); RendererStorageRD(); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 1dde92d8ff..9c1068ea2e 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -571,7 +571,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge max_texture_uniforms++; } else { if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; //instances are indexed directly, dont need index uniforms + continue; // Instances are indexed directly, don't need index uniforms. } max_uniforms++; @@ -605,7 +605,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { //insert, but don't generate any code. p_actions.uniforms->insert(uniform_name, uniform); - continue; //instances are indexed directly, dont need index uniforms + continue; // Instances are indexed directly, don't need index uniforms. } if (SL::is_sampler_type(uniform.type)) { ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform "; @@ -760,11 +760,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (var_frag_to_light.size() > 0) { String gcode = "\n\nstruct {\n"; - for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) { - gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first); - if (E->get().second.array_size > 0) { + for (const Pair<StringName, SL::ShaderNode::Varying> &E : var_frag_to_light) { + gcode += "\t" + _prestr(E.second.precision) + _typestr(E.second.type) + " " + _mkid(E.first); + if (E.second.array_size > 0) { gcode += "["; - gcode += itos(E->get().second.array_size); + gcode += itos(E.second.array_size); gcode += "]"; } gcode += ";\n"; @@ -1394,8 +1394,8 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) { ShaderLanguage::get_builtin_funcs(&func_list); - for (List<String>::Element *E = func_list.front(); E; E = E->next()) { - internal_functions.insert(E->get()); + for (const String &E : func_list) { + internal_functions.insert(E); } texture_functions.insert("texture"); texture_functions.insert("textureProj"); diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 27305cc938..5bb12fc168 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -116,8 +116,10 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con } StringBuilder tohash; - tohash.append("[VersionKey]"); - tohash.append(RenderingDevice::get_singleton()->shader_get_cache_key()); + tohash.append("[SpirvCacheKey]"); + tohash.append(RenderingDevice::get_singleton()->shader_get_spirv_cache_key()); + tohash.append("[BinaryCacheKey]"); + tohash.append(RenderingDevice::get_singleton()->shader_get_binary_cache_key()); tohash.append("[Vertex]"); tohash.append(p_vertex_code ? p_vertex_code : ""); tohash.append("[Fragment]"); @@ -144,12 +146,14 @@ void ShaderRD::_clear_version(Version *p_version) { //clear versions if they exist if (p_version->variants) { for (int i = 0; i < variant_defines.size(); i++) { - RD::get_singleton()->free(p_version->variants[i]); + if (variants_enabled[i]) { + RD::get_singleton()->free(p_version->variants[i]); + } } memdelete_arr(p_version->variants); - if (p_version->variant_stages) { - memdelete_arr(p_version->variant_stages); + if (p_version->variant_data) { + memdelete_arr(p_version->variant_data); } p_version->variants = nullptr; } @@ -203,7 +207,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { return; //variant is disabled, return } - Vector<RD::ShaderStageData> &stages = p_version->variant_stages[p_variant]; + Vector<RD::ShaderStageSPIRVData> stages; String error; String current_source; @@ -217,8 +221,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]); current_source = builder.as_string(); - RD::ShaderStageData stage; - stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + RD::ShaderStageSPIRVData stage; + stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error); if (stage.spir_v.size() == 0) { build_ok = false; } else { @@ -235,8 +239,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]); current_source = builder.as_string(); - RD::ShaderStageData stage; - stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + RD::ShaderStageSPIRVData stage; + stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error); if (stage.spir_v.size() == 0) { build_ok = false; } else { @@ -254,8 +258,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { current_source = builder.as_string(); - RD::ShaderStageData stage; - stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + RD::ShaderStageSPIRVData stage; + stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error); if (stage.spir_v.size() == 0) { build_ok = false; } else { @@ -275,10 +279,15 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { return; } - RID shader = RD::get_singleton()->shader_create(stages); + Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages); + + ERR_FAIL_COND(shader_data.size() == 0); + + RID shader = RD::get_singleton()->shader_create_from_bytecode(shader_data); { MutexLock lock(variant_set_mutex); p_version->variants[p_variant] = shader; + p_version->variant_data[p_variant] = shader_data; } } @@ -364,14 +373,12 @@ String ShaderRD::_version_get_sha1(Version *p_version) const { } static const char *shader_file_header = "GDSC"; -static const uint32_t cache_file_version = 1; +static const uint32_t cache_file_version = 2; bool ShaderRD::_load_from_cache(Version *p_version) { String sha1 = _version_get_sha1(p_version); String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache"; - uint64_t time_from = OS::get_singleton()->get_ticks_usec(); - FileAccessRef f = FileAccess::open(path, FileAccess::READ); if (!f) { return false; @@ -390,76 +397,43 @@ bool ShaderRD::_load_from_cache(Version *p_version) { ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check - bool success = true; for (uint32_t i = 0; i < variant_count; i++) { - uint32_t stage_count = f->get_32(); - p_version->variant_stages[i].resize(stage_count); - for (uint32_t j = 0; j < stage_count; j++) { - p_version->variant_stages[i].write[j].shader_stage = RD::ShaderStage(f->get_32()); - - int compression = f->get_32(); - uint32_t length = f->get_32(); - - if (compression == 0) { - Vector<uint8_t> data; - data.resize(length); - - f->get_buffer(data.ptrw(), length); - - p_version->variant_stages[i].write[j].spir_v = data; - } else { - Vector<uint8_t> data; - - if (compression == 2) { - //zstd - int smol_length = f->get_32(); - Vector<uint8_t> zstd_data; - - zstd_data.resize(smol_length); - f->get_buffer(zstd_data.ptrw(), smol_length); - - data.resize(length); - Compression::decompress(data.ptrw(), data.size(), zstd_data.ptr(), zstd_data.size(), Compression::MODE_ZSTD); - - } else { - data.resize(length); - f->get_buffer(data.ptrw(), length); - } - - Vector<uint8_t> spirv; - uint32_t spirv_size = smolv::GetDecodedBufferSize(data.ptr(), data.size()); - spirv.resize(spirv_size); - if (!smolv::Decode(data.ptr(), data.size(), spirv.ptrw(), spirv_size)) { - ERR_PRINT("Malformed smolv input uncompressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(j)); - success = false; - break; - } - p_version->variant_stages[i].write[j].spir_v = spirv; - } + uint32_t variant_size = f->get_32(); + ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false); + if (!variants_enabled[i]) { + continue; } - } + Vector<uint8_t> variant_bytes; + variant_bytes.resize(variant_size); - if (!success) { - for (uint32_t i = 0; i < variant_count; i++) { - p_version->variant_stages[i].resize(0); - } - return false; - } + uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size); - float time_ms = double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + ERR_FAIL_COND_V(br != variant_size, false); - print_verbose("Shader cache load success '" + path + "' " + rtos(time_ms) + "ms."); + p_version->variant_data[i] = variant_bytes; + } for (uint32_t i = 0; i < variant_count; i++) { - RID shader = RD::get_singleton()->shader_create(p_version->variant_stages[i]); + if (!variants_enabled[i]) { + MutexLock lock(variant_set_mutex); + p_version->variants[i] = RID(); + continue; + } + RID shader = RD::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]); + if (shader.is_null()) { + for (uint32_t j = 0; j < i; j++) { + RD::get_singleton()->free(p_version->variants[i]); + } + ERR_FAIL_COND_V(shader.is_null(), false); + } { MutexLock lock(variant_set_mutex); p_version->variants[i] = shader; } } - memdelete_arr(p_version->variant_stages); //clear stages - p_version->variant_stages = nullptr; + memdelete_arr(p_version->variant_data); //clear stages + p_version->variant_data = nullptr; p_version->valid = true; return true; } @@ -476,49 +450,8 @@ void ShaderRD::_save_to_cache(Version *p_version) { f->store_32(variant_count); //variant count for (uint32_t i = 0; i < variant_count; i++) { - f->store_32(p_version->variant_stages[i].size()); //stage count - for (int j = 0; j < p_version->variant_stages[i].size(); j++) { - f->store_32(p_version->variant_stages[i][j].shader_stage); //stage count - Vector<uint8_t> spirv = p_version->variant_stages[i][j].spir_v; - - bool save_uncompressed = true; - if (shader_cache_save_compressed) { - smolv::ByteArray smolv; - bool strip_debug = !shader_cache_save_debug; - if (!smolv::Encode(spirv.ptr(), spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) { - ERR_PRINT("Error compressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(i)); - } else { - bool compress_zstd = shader_cache_save_compressed_zstd; - - if (compress_zstd) { - Vector<uint8_t> zstd; - zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD)); - int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD); - if (dst_size >= 0 && (uint32_t)dst_size < smolv.size()) { - f->store_32(2); //compressed zstd - f->store_32(smolv.size()); //size of smolv buffer - f->store_32(dst_size); //size of smolv buffer - f->store_buffer(zstd.ptr(), dst_size); //smolv buffer - } else { - compress_zstd = false; - } - } - - if (!compress_zstd) { - f->store_32(1); //compressed - f->store_32(smolv.size()); //size of smolv buffer - f->store_buffer(&smolv[0], smolv.size()); //smolv buffer - } - save_uncompressed = false; - } - } - - if (save_uncompressed) { - f->store_32(0); //uncompressed - f->store_32(spirv.size()); //stage count - f->store_buffer(spirv.ptr(), spirv.size()); //stage count - } - } + f->store_32(p_version->variant_data[i].size()); //stage count + f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size()); } f->close(); @@ -531,8 +464,8 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->dirty = false; p_version->variants = memnew_arr(RID, variant_defines.size()); - typedef Vector<RD::ShaderStageData> ShaderStageArray; - p_version->variant_stages = memnew_arr(ShaderStageArray, variant_defines.size()); + typedef Vector<uint8_t> ShaderStageData; + p_version->variant_data = memnew_arr(ShaderStageData, variant_defines.size()); if (shader_cache_dir_valid) { if (_load_from_cache(p_version)) { @@ -571,19 +504,19 @@ void ShaderRD::_compile_version(Version *p_version) { } } memdelete_arr(p_version->variants); - if (p_version->variant_stages) { - memdelete_arr(p_version->variant_stages); + if (p_version->variant_data) { + memdelete_arr(p_version->variant_data); } p_version->variants = nullptr; - p_version->variant_stages = nullptr; + p_version->variant_data = nullptr; return; } else if (shader_cache_dir_valid) { //save shader cache _save_to_cache(p_version); } - memdelete_arr(p_version->variant_stages); //clear stages - p_version->variant_stages = nullptr; + memdelete_arr(p_version->variant_data); //clear stages + p_version->variant_data = nullptr; p_version->valid = true; } diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 9a68e02007..529328f0ed 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -59,7 +59,7 @@ class ShaderRD { Map<StringName, CharString> code_sections; Vector<CharString> custom_defines; - Vector<RD::ShaderStageData> *variant_stages = nullptr; + Vector<uint8_t> *variant_data = nullptr; RID *variants = nullptr; //same size as version defines bool valid; diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl new file mode 100644 index 0000000000..b1d1c2365e --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl @@ -0,0 +1,228 @@ +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "blur_raster_inc.glsl" + +layout(location = 0) out vec2 uv_interp; +/* 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 + +#include "blur_raster_inc.glsl" + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D source_color; + +#ifdef GLOW_USE_AUTO_EXPOSURE +layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; +#endif + +layout(location = 0) out vec4 frag_color; + +//DOF +#ifdef MODE_DOF_BLUR + +layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; + +#ifdef DOF_QUALITY_LOW +const int dof_kernel_size = 5; +const int dof_kernel_from = 2; +const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); +#endif + +#ifdef DOF_QUALITY_MEDIUM +const int dof_kernel_size = 11; +const int dof_kernel_from = 5; +const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); + +#endif + +#ifdef DOF_QUALITY_HIGH +const int dof_kernel_size = 21; +const int dof_kernel_from = 10; +const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); +#endif + +#endif + +void main() { +#ifdef MODE_MIPMAP + + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size); + color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size); + color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size); + color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size); + frag_color = color / 4.0; + +#endif + +#ifdef MODE_GAUSSIAN_BLUR + + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect + + if (bool(blur.flags & FLAG_HORIZONTAL)) { + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607; + color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303; + color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303; + frag_color = color; + } else { + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774; + color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136; + color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136; + frag_color = color; + } +#endif + +#ifdef MODE_GAUSSIAN_GLOW + + //Glow uses larger sigma 1 for a more rounded blur effect + +#define GLOW_ADD(m_ofs, m_mult) \ + { \ + vec2 ofs = uv_interp + m_ofs * pix_size; \ + vec4 c = texture(source_color, ofs) * m_mult; \ + if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \ + c *= 0.0; \ + } \ + color += c; \ + } + + if (bool(blur.flags & FLAG_HORIZONTAL)) { + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938; + GLOW_ADD(vec2(1.0, 0.0), 0.165569); + GLOW_ADD(vec2(2.0, 0.0), 0.140367); + GLOW_ADD(vec2(3.0, 0.0), 0.106595); + GLOW_ADD(vec2(-1.0, 0.0), 0.165569); + GLOW_ADD(vec2(-2.0, 0.0), 0.140367); + GLOW_ADD(vec2(-3.0, 0.0), 0.106595); + color *= blur.glow_strength; + frag_color = color; + } else { + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713; + GLOW_ADD(vec2(0.0, 1.0), 0.233062); + GLOW_ADD(vec2(0.0, 2.0), 0.122581); + GLOW_ADD(vec2(0.0, -1.0), 0.233062); + GLOW_ADD(vec2(0.0, -2.0), 0.122581); + color *= blur.glow_strength; + frag_color = color; + } + +#undef GLOW_ADD + + if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey; +#endif + frag_color *= blur.glow_exposure; + + float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); + float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom); + + frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)); + } + +#endif + +#ifdef MODE_DOF_BLUR + + vec4 color_accum = vec4(0.0); + + float depth = texture(dof_source_depth, uv_interp, 0.0).r; + depth = depth * 2.0 - 1.0; + + if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { + depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); + } + + // mix near and far blur amount + float amount = 1.0; + if (bool(blur.flags & FLAG_DOF_FAR)) { + amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth); + } + if (bool(blur.flags & FLAG_DOF_NEAR)) { + amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth); + } + amount = 1.0 - amount; + + if (amount > 0.0) { + float k_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; + + float tap_k = dof_kernel[i]; + + float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; + + if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { + tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); + } + + // mix near and far blur amount + float tap_amount = 1.0; + if (bool(blur.flags & FLAG_DOF_FAR)) { + tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0); + } + if (bool(blur.flags & FLAG_DOF_NEAR)) { + tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0); + } + tap_amount = 1.0 - tap_amount; + + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; + + k_accum += tap_k * tap_amount; + color_accum += tap_color * tap_amount; + } + + if (k_accum > 0.0) { + color_accum /= k_accum; + } + + frag_color = color_accum; ///k_accum; + } else { + // we are in focus, don't waste time + frag_color = texture(source_color, uv_interp, 0.0); + } + +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl new file mode 100644 index 0000000000..6ea968e595 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl @@ -0,0 +1,36 @@ +#define FLAG_HORIZONTAL (1 << 0) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1) +#define FLAG_GLOW_FIRST_PASS (1 << 2) +#define FLAG_DOF_FAR (1 << 3) +#define FLAG_DOF_NEAR (1 << 4) + +layout(push_constant, binding = 1, std430) uniform Blur { + vec2 pixel_size; + uint flags; + uint pad; + + // Glow. + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + + // DOF. + float dof_far_begin; + float dof_far_end; + float dof_near_begin; + float dof_near_end; + + float dof_radius; + float dof_pad[3]; + + vec2 dof_dir; + float camera_z_far; + float camera_z_near; +} +blur; diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl index 9fa84657d1..63f0ce690e 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl @@ -32,53 +32,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cubemap; layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap; -layout(push_constant, binding = 1, std430) uniform Params { - uint face_size; -} -params; - -#define M_PI 3.14159265359 - -void get_dir_0(out vec3 dir, in float u, in float v) { - dir[0] = 1.0; - dir[1] = v; - dir[2] = -u; -} - -void get_dir_1(out vec3 dir, in float u, in float v) { - dir[0] = -1.0; - dir[1] = v; - dir[2] = u; -} - -void get_dir_2(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = 1.0; - dir[2] = -v; -} - -void get_dir_3(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = -1.0; - dir[2] = v; -} - -void get_dir_4(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = v; - dir[2] = 1.0; -} - -void get_dir_5(out vec3 dir, in float u, in float v) { - dir[0] = -u; - dir[1] = v; - dir[2] = -1.0; -} - -float calcWeight(float u, float v) { - float val = u * u + v * v + 1.0; - return val * sqrt(val); -} +#include "cubemap_downsampler_inc.glsl" void main() { uvec3 id = gl_GlobalInvocationID; diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl new file mode 100644 index 0000000000..b329e67293 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl @@ -0,0 +1,48 @@ +layout(push_constant, binding = 1, std430) uniform Params { + uint face_size; + uint face_id; // only used in raster shader +} +params; + +#define M_PI 3.14159265359 + +void get_dir_0(out vec3 dir, in float u, in float v) { + dir[0] = 1.0; + dir[1] = v; + dir[2] = -u; +} + +void get_dir_1(out vec3 dir, in float u, in float v) { + dir[0] = -1.0; + dir[1] = v; + dir[2] = u; +} + +void get_dir_2(out vec3 dir, in float u, in float v) { + dir[0] = u; + dir[1] = 1.0; + dir[2] = -v; +} + +void get_dir_3(out vec3 dir, in float u, in float v) { + dir[0] = u; + dir[1] = -1.0; + dir[2] = v; +} + +void get_dir_4(out vec3 dir, in float u, in float v) { + dir[0] = u; + dir[1] = v; + dir[2] = 1.0; +} + +void get_dir_5(out vec3 dir, in float u, in float v) { + dir[0] = -u; + dir[1] = v; + dir[2] = -1.0; +} + +float calcWeight(float u, float v) { + float val = u * u + v * v + 1.0; + return val * sqrt(val); +} diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl new file mode 100644 index 0000000000..0828ffd921 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl @@ -0,0 +1,163 @@ +// Copyright 2016 Activision Publishing, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "cubemap_downsampler_inc.glsl" + +layout(location = 0) out vec2 uv_interp; +/* 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] * float(params.face_size); + gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0); +} + +/* clang-format off */ +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#include "cubemap_downsampler_inc.glsl" + +layout(set = 0, binding = 0) uniform samplerCube source_cubemap; + +layout(location = 0) in vec2 uv_interp; +layout(location = 0) out vec4 frag_color; +/* clang-format on */ + +void main() { + // Converted from compute shader which uses absolute coordinates. + // Could possibly simplify this + float face_size = float(params.face_size); + + if (uv_interp.x < face_size && uv_interp.y < face_size) { + float inv_face_size = 1.0 / face_size; + + float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0; + float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0; + + float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0; + float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0; + + float weights[4]; + weights[0] = calcWeight(u0, v0); + weights[1] = calcWeight(u1, v0); + weights[2] = calcWeight(u0, v1); + weights[3] = calcWeight(u1, v1); + + const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]); + for (int i = 0; i < 4; i++) { + weights[i] = weights[i] * wsum + .125; + } + + vec3 dir; + vec4 color; + switch (params.face_id) { + case 0: + get_dir_0(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_0(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_0(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_0(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + case 1: + get_dir_1(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_1(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_1(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_1(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + case 2: + get_dir_2(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_2(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_2(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_2(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + case 3: + get_dir_3(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_3(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_3(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_3(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + case 4: + get_dir_4(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_4(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_4(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_4(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + default: + get_dir_5(dir, u0, v0); + color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; + + get_dir_5(dir, u1, v0); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; + + get_dir_5(dir, u0, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; + + get_dir_5(dir, u1, v1); + color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; + break; + } + frag_color = color; + } +} diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl new file mode 100644 index 0000000000..324d306218 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl @@ -0,0 +1,256 @@ +// Copyright 2016 Activision Publishing, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +layout(push_constant, binding = 1, std430) uniform Params { + int mip_level; + uint face_id; +} +params; + +layout(location = 0) out vec2 uv_interp; +/* 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(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0); +} + +/* clang-format off */ +#[fragment] + +#version 450 + +#VERSION_DEFINES + +layout(push_constant, binding = 1, std430) uniform Params { + int mip_level; + uint face_id; +} +params; + +layout(set = 0, binding = 0) uniform samplerCube source_cubemap; + +layout(location = 0) in vec2 uv_interp; +layout(location = 0) out vec4 frag_color; + +/* clang-format on */ + +#ifdef USE_HIGH_QUALITY +#define NUM_TAPS 32 +#else +#define NUM_TAPS 8 +#endif + +#define BASE_RESOLUTION 128 + +#ifdef USE_HIGH_QUALITY +layout(set = 1, binding = 0, std430) buffer restrict readonly Data { + vec4[7][5][3][24] coeffs; +} +data; +#else +layout(set = 1, binding = 0, std430) buffer restrict readonly Data { + vec4[7][5][6] coeffs; +} +data; +#endif + +void get_dir(out vec3 dir, in vec2 uv, in uint face) { + switch (face) { + case 0: + dir = vec3(1.0, uv[1], -uv[0]); + break; + case 1: + dir = vec3(-1.0, uv[1], uv[0]); + break; + case 2: + dir = vec3(uv[0], 1.0, -uv[1]); + break; + case 3: + dir = vec3(uv[0], -1.0, uv[1]); + break; + case 4: + dir = vec3(uv[0], uv[1], 1.0); + break; + default: + dir = vec3(-uv[0], uv[1], -1.0); + break; + } +} + +void main() { + // determine dir / pos for the texel + vec3 dir, adir, frameZ; + { + vec2 uv; + uv.x = uv_interp.x; + uv.y = 1.0 - uv_interp.y; + uv = uv * 2.0 - 1.0; + + get_dir(dir, uv, params.face_id); + frameZ = normalize(dir); + + adir = abs(dir); + } + + // determine which texel this is + // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name. + int mip_level = 0; + + if (params.mip_level < 0) { + // return as is + frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb; + frag_color.a = 1.0; + return; + } else if (params.mip_level > 6) { + // maximum level + mip_level = 6; + } else { + mip_level = params.mip_level; + } + + // GGX gather colors + vec4 color = vec4(0.0); + for (int axis = 0; axis < 3; axis++) { + const int otherAxis0 = 1 - (axis & 1) - (axis >> 1); + const int otherAxis1 = 2 - (axis >> 1); + + float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25; + if (frameweight > 0.0) { + // determine frame + vec3 UpVector; + switch (axis) { + case 0: + UpVector = vec3(1, 0, 0); + break; + case 1: + UpVector = vec3(0, 1, 0); + break; + default: + UpVector = vec3(0, 0, 1); + break; + } + + vec3 frameX = normalize(cross(UpVector, frameZ)); + vec3 frameY = cross(frameZ, frameX); + + // calculate parametrization for polynomial + float Nx = dir[otherAxis0]; + float Ny = dir[otherAxis1]; + float Nz = adir[axis]; + + float NmaxXY = max(abs(Ny), abs(Nx)); + Nx /= NmaxXY; + Ny /= NmaxXY; + + float theta; + if (Ny < Nx) { + if (Ny <= -0.999) + theta = Nx; + else + theta = Ny; + } else { + if (Ny >= 0.999) + theta = -Nx; + else + theta = -Ny; + } + + float phi; + if (Nz <= -0.999) + phi = -NmaxXY; + else if (Nz >= 0.999) + phi = NmaxXY; + else + phi = Nz; + + float theta2 = theta * theta; + float phi2 = phi * phi; + + // sample + for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) { + const int index = (NUM_TAPS / 4) * axis + iSuperTap; + +#ifdef USE_HIGH_QUALITY + vec4 coeffsDir0[3]; + vec4 coeffsDir1[3]; + vec4 coeffsDir2[3]; + vec4 coeffsLevel[3]; + vec4 coeffsWeight[3]; + + for (int iCoeff = 0; iCoeff < 3; iCoeff++) { + coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index]; + coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index]; + coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index]; + coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index]; + coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index]; + } + + for (int iSubTap = 0; iSubTap < 4; iSubTap++) { + // determine sample attributes (dir, weight, mip_level) + vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2); + + float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2; + + float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2; +#else + vec4 coeffsDir0 = data.coeffs[mip_level][0][index]; + vec4 coeffsDir1 = data.coeffs[mip_level][1][index]; + vec4 coeffsDir2 = data.coeffs[mip_level][2][index]; + vec4 coeffsLevel = data.coeffs[mip_level][3][index]; + vec4 coeffsWeight = data.coeffs[mip_level][4][index]; + + for (int iSubTap = 0; iSubTap < 4; iSubTap++) { + // determine sample attributes (dir, weight, mip_level) + vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap]; + + float sample_level = coeffsLevel[iSubTap]; + + float sample_weight = coeffsWeight[iSubTap]; +#endif + + sample_weight *= frameweight; + + // adjust for jacobian + sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2]))); + sample_level += 0.75 * log2(dot(sample_dir, sample_dir)); + // sample cubemap + color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight; + color.w += sample_weight; + } + } + } + } + color /= color.w; + + // write color + color.xyz = max(vec3(0.0), color.xyz); + color.w = 1.0; + + frag_color = color; +} diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl index ce7c03c1d4..28f4dc59ec 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl @@ -12,100 +12,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube; 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; - -#define M_PI 3.14159265359 - -vec3 texelCoordToVec(vec2 uv, uint faceID) { - mat3 faceUvVectors[6]; - - // -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 - - // +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 - - // -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 - - // +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 - - // -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 - - // +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 - - // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; - return normalize(result); -} - -vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { - float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] - - // Compute distribution direction - float Phi = 2.0 * M_PI * Xi.x; - float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); - float SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); - - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; -} - -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html -float GGX(float NdotV, float a) { - float k = a / 2.0; - return NdotV / (NdotV * (1.0 - k) + k); -} - -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html -float G_Smith(float a, float nDotV, float nDotL) { - return GGX(nDotL, a * a) * GGX(nDotV, a * a); -} - -float radicalInverse_VdC(uint bits) { - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10; // / 0x100000000 -} - -vec2 Hammersley(uint i, uint N) { - return vec2(float(i) / float(N), radicalInverse_VdC(i)); -} +#include "cubemap_roughness_inc.glsl" void main() { uvec3 id = gl_GlobalInvocationID; diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl new file mode 100644 index 0000000000..80c0ac4fb4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl @@ -0,0 +1,94 @@ +#define M_PI 3.14159265359 + +layout(push_constant, binding = 1, std430) uniform Params { + uint face_id; + uint sample_count; + float roughness; + bool use_direct_write; + float face_size; +} +params; + +vec3 texelCoordToVec(vec2 uv, uint faceID) { + mat3 faceUvVectors[6]; + + // -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 + + // +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 + + // -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 + + // +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 + + // -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 + + // +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 + + // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. + vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; + return normalize(result); +} + +vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { + float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] + + // Compute distribution direction + float Phi = 2.0 * M_PI * Xi.x; + float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); + float SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 TangentX = normalize(cross(UpVector, N)); + vec3 TangentY = cross(N, TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float GGX(float NdotV, float a) { + float k = a / 2.0; + return NdotV / (NdotV * (1.0 - k) + k); +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float G_Smith(float a, float nDotV, float nDotL) { + return GGX(nDotL, a * a) * GGX(nDotV, a * a); +} + +float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) { + return vec2(float(i) / float(N), radicalInverse_VdC(i)); +} diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl new file mode 100644 index 0000000000..2570308816 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl @@ -0,0 +1,63 @@ +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "cubemap_roughness_inc.glsl" + +layout(location = 0) out vec2 uv_interp; +/* 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 + +#include "cubemap_roughness_inc.glsl" + +layout(location = 0) in vec2 uv_interp; + +layout(set = 0, binding = 0) uniform samplerCube source_cube; + +layout(location = 0) out vec4 frag_color; +/* clang-format on */ + +void main() { + vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id); + + //vec4 color = color_interp; + + if (params.use_direct_write) { + frag_color = vec4(texture(source_cube, N).rgb, 1.0); + } else { + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + + for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) { + vec2 xi = Hammersley(sampleNum, params.sample_count); + + vec3 H = ImportanceSampleGGX(xi, params.roughness, N); + vec3 V = N; + vec3 L = (2.0 * dot(V, H) * H - V); + + float ndotl = clamp(dot(N, L), 0.0, 1.0); + + if (ndotl > 0.0) { + sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl; + sum.a += ndotl; + } + } + sum /= sum.a; + + frag_color = vec4(sum.rgb, 1.0); + } +} diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl new file mode 100644 index 0000000000..29ebd74a90 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl @@ -0,0 +1,74 @@ +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "luminance_reduce_raster_inc.glsl" + +layout(location = 0) out vec2 uv_interp; +/* 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 + +#include "luminance_reduce_raster_inc.glsl" + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D source_exposure; + +#ifdef FINAL_PASS +layout(set = 1, binding = 0) uniform sampler2D prev_luminance; +#endif + +layout(location = 0) out highp float luminance; + +void main() { + ivec2 dest_pos = ivec2(uv_interp * settings.dest_size); + ivec2 src_pos = ivec2(uv_interp * settings.source_size); + + ivec2 next_pos = (dest_pos + ivec2(1)) * settings.source_size / settings.dest_size; + next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel + + highp vec3 source_color = vec3(0.0); + for (int i = src_pos.x; i < next_pos.x; i++) { + for (int j = src_pos.y; j < next_pos.y; j++) { + source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb; + } + } + + source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y)); + +#ifdef FIRST_PASS + luminance = max(source_color.r, max(source_color.g, source_color.b)); + + // This formula should be more "accurate" but gave an overexposed result when testing. + // Leaving it here so we can revisit it if we want. + // luminance = source_color.r * 0.21 + source_color.g * 0.71 + source_color.b * 0.07; +#else + luminance = source_color.r; +#endif + +#ifdef FINAL_PASS + // Obtain our target luminance + luminance = clamp(luminance, settings.min_luminance, settings.max_luminance); + + // Now smooth to our transition + highp float prev_lum = texelFetch(prev_luminance, ivec2(0, 0), 0).r; //1 pixel previous luminance + luminance = prev_lum + (luminance - prev_lum) * clamp(settings.exposure_adjust, 0.0, 1.0); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl new file mode 100644 index 0000000000..ed389ffe56 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl @@ -0,0 +1,11 @@ + +layout(push_constant, binding = 1, std430) uniform PushConstant { + ivec2 source_size; + ivec2 dest_size; + + float exposure_adjust; + float min_luminance; + float max_luminance; + float pad; +} +settings; diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 4dceeea995..e88e68b511 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -138,7 +138,7 @@ void main() { if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) { txform = particles.data[particle].xform; if (params.trail_size > 1) { - // since the steps dont fit precisely in the history frames, must do a tiny bit of + // Since the steps don't fit precisely in the history frames, must do a tiny bit of // interpolation to get them close to their intended location. uint part_ofs = particle % params.trail_size; float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index ef1c9bacfb..b3a349c948 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -1214,7 +1214,7 @@ void main() { specular_light *= specular * metallic * albedo * 2.0; #else - // scales the specular reflections, needs to be be computed before lighting happens, + // scales the specular reflections, needs to be computed before lighting happens, // but after environment, GI, and reflection probes are added // Environment brdf approximation (Lazarov 2013) // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index 3a05275652..b53bf6a6d4 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -177,7 +177,7 @@ layout(set = 1, binding = 0, std140) uniform SceneData { uint cluster_type_size; uint max_cluster_element_count_div_32; - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. vec4 directional_penumbra_shadow_kernel[32]; vec4 directional_soft_shadow_kernel[32]; vec4 penumbra_shadow_kernel[32]; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 7e72ece5dc..70900a847c 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -981,7 +981,7 @@ void main() { specular_light *= specular * metallic * albedo * 2.0; #else - // scales the specular reflections, needs to be be computed before lighting happens, + // scales the specular reflections, needs to be computed before lighting happens, // but after environment, GI, and reflection probes are added // Environment brdf approximation (Lazarov 2013) // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index 1b8e21551c..d9682d7b23 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -138,7 +138,7 @@ layout(set = 1, binding = 0, std140) uniform SceneData { vec2 viewport_size; vec2 screen_pixel_size; - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. vec4 directional_penumbra_shadow_kernel[32]; vec4 directional_soft_shadow_kernel[32]; vec4 penumbra_shadow_kernel[32]; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl index 99db35bb34..d6e5c6a92e 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl @@ -20,10 +20,10 @@ layout(set = 0, binding = 3, std430) restrict readonly buffer DispatchData { dispatch_data; struct ProcessVoxel { - uint position; //xyz 7 bit packed, extra 11 bits for neigbours - uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours - uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours + uint position; // xyz 7 bit packed, extra 11 bits for neighbors. + uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors. + uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors. + uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors. //total neighbours: 26 }; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl index bc376e9522..eedd28959c 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl @@ -266,9 +266,9 @@ void main() { } else if (params.sky_mode == SKY_MODE_SKY) { #ifdef USE_CUBEMAP_ARRAY - light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates + light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #else - light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates + light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #endif light.rgb *= params.sky_energy; light.a = 0.0; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl index aa4ded146f..4d9fa85a74 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl @@ -101,7 +101,7 @@ layout(set = 0, binding = 10, std430) restrict buffer DispatchData { dispatch_data; struct ProcessVoxel { - uint position; //xyz 7 bit packed, extra 11 bits for neigbours + uint position; // xyz 7 bit packed, extra 11 bits for neighbors. uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours @@ -134,7 +134,7 @@ layout(set = 0, binding = 5, std430) restrict buffer readonly DispatchData { dispatch_data; struct ProcessVoxel { - uint position; //xyz 7 bit packed, extra 11 bits for neigbours + uint position; // xyz 7 bit packed, extra 11 bits for neighbors. uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours @@ -183,7 +183,7 @@ void main() { ivec3 write_pos = read_pos + params.scroll; if (any(lessThan(write_pos, ivec3(0))) || any(greaterThanEqual(write_pos, ivec3(params.grid_size)))) { - return; //fits outside the 3D texture, dont do anything + return; // Fits outside the 3D texture, don't do anything. } uint albedo = ((src_process_voxels.data[index].albedo & 0x7FFF) << 1) | 1; //add solid bit diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 3336623f21..83d1b33bf2 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1259,7 +1259,7 @@ void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) } if (cycle_detected) { - ERR_PRINT("Cycle detected in the visibility dependecies tree."); + ERR_PRINT("Cycle detected in the visibility dependencies tree."); for (Set<Instance *>::Element *E = traversed_nodes.front(); E; E = E->next()) { Instance *instance = E->get(); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); @@ -2876,8 +2876,8 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c Vector<Instance *> lights_with_shadow; - for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { - if (!E->get()->visible) { + for (Instance *E : scenario->directional_lights) { + if (!E->visible) { continue; } @@ -2885,13 +2885,13 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c break; } - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data); //check shadow.. if (light) { - if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) { - lights_with_shadow.push_back(E->get()); + if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->base) && !(RSG::storage->light_get_type(E->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->base))) { + lights_with_shadow.push_back(E); } //add to list directional_lights.push_back(light->instance); @@ -3391,8 +3391,7 @@ void RendererSceneCull::render_probes() { idx++; } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); + for (const Instance *instance : probe->owner->scenario->directional_lights) { InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; if (!instance->visible) { continue; @@ -3465,8 +3464,7 @@ void RendererSceneCull::render_probes() { idx++; } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); + for (const Instance *instance : probe->owner->scenario->directional_lights) { InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; if (!instance->visible) { continue; @@ -3573,26 +3571,26 @@ void RendererSceneCull::render_particle_colliders() { void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) { List<RendererStorage::InstanceShaderParam> plist; RSG::storage->material_get_instance_shader_parameters(p_material, &plist); - for (List<RendererStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { - StringName name = E->get().info.name; + for (const RendererStorage::InstanceShaderParam &E : plist) { + StringName name = E.info.name; if (isparams.has(name)) { - if (isparams[name].info.type != E->get().info.type) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); + if (isparams[name].info.type != E.info.type) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); } - if (isparams[name].index != E->get().index) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); + if (isparams[name].index != E.index) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); } continue; //first one found always has priority } Instance::InstanceShaderParameter isp; - isp.index = E->get().index; - isp.info = E->get().info; - isp.default_value = E->get().default_value; + isp.index = E.index; + isp.info = E.info; + isp.default_value = E.default_value; if (existing_isparams.has(name)) { isp.value = existing_isparams[name].value; } else { - isp.value = E->get().default_value; + isp.value = E.default_value; } isparams[name] = isp; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 3594939362..b298ad193b 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -38,23 +38,23 @@ RenderingDevice *RenderingDevice::get_singleton() { return singleton; } -RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr; +RenderingDevice::ShaderCompileToSPIRVFunction RenderingDevice::compile_to_spirv_function = nullptr; RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr; -RenderingDevice::ShaderGetCacheKeyFunction RenderingDevice::get_cache_key_function = nullptr; +RenderingDevice::ShaderSPIRVGetCacheKeyFunction RenderingDevice::get_spirv_cache_key_function = nullptr; -void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) { - compile_function = p_function; +void RenderingDevice::shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function) { + compile_to_spirv_function = p_function; } -void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function) { +void RenderingDevice::shader_set_spirv_cache_function(ShaderCacheFunction p_function) { cache_function = p_function; } -void RenderingDevice::shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function) { - get_cache_key_function = p_function; +void RenderingDevice::shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function) { + get_spirv_cache_key_function = p_function; } -Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) { +Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) { if (p_allow_cache && cache_function) { Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language); if (cache.size()) { @@ -62,18 +62,24 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, } } - ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>()); + ERR_FAIL_COND_V(!compile_to_spirv_function, Vector<uint8_t>()); - return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities); + return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, &device_capabilities); } -String RenderingDevice::shader_get_cache_key() const { - if (get_cache_key_function) { - return get_cache_key_function(&device_capabilities); +String RenderingDevice::shader_get_spirv_cache_key() const { + if (get_spirv_cache_key_function) { + return get_spirv_cache_key_function(&device_capabilities); } return String(); } +RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv) { + Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv); + ERR_FAIL_COND_V(bytecode.size() == 0, RID()); + return shader_create_from_bytecode(bytecode); +} + RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) { ERR_FAIL_COND_V(p_format.is_null(), RID()); ERR_FAIL_COND_V(p_view.is_null(), RID()); @@ -170,40 +176,59 @@ RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatI return vertex_array_create(p_vertex_count, p_vertex_format, buffers); } -Ref<RDShaderBytecode> RenderingDevice::_shader_compile_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) { - ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderBytecode>()); +Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) { + ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>()); - Ref<RDShaderBytecode> bytecode; + Ref<RDShaderSPIRV> bytecode; bytecode.instantiate(); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String error; ShaderStage stage = ShaderStage(i); - Vector<uint8_t> spirv = shader_compile_from_source(stage, p_source->get_stage_source(stage), p_source->get_language(), &error, p_allow_cache); + Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, p_source->get_stage_source(stage), p_source->get_language(), &error, p_allow_cache); bytecode->set_stage_bytecode(stage, spirv); bytecode->set_stage_compile_error(stage, error); } return bytecode; } -RID RenderingDevice::shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_bytecode) { - ERR_FAIL_COND_V(p_bytecode.is_null(), RID()); +Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv) { + ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>()); - Vector<ShaderStageData> stage_data; + Vector<ShaderStageSPIRVData> stage_data; for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { ShaderStage stage = ShaderStage(i); - ShaderStageData sd; + ShaderStageSPIRVData sd; sd.shader_stage = stage; - String error = p_bytecode->get_stage_compile_error(stage); - ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); - sd.spir_v = p_bytecode->get_stage_bytecode(stage); + String error = p_spirv->get_stage_compile_error(stage); + ERR_FAIL_COND_V_MSG(error != String(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); + sd.spir_v = p_spirv->get_stage_bytecode(stage); if (sd.spir_v.is_empty()) { continue; } stage_data.push_back(sd); } - return shader_create(stage_data); + return shader_compile_binary_from_spirv(stage_data); +} + +RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv) { + ERR_FAIL_COND_V(p_spirv.is_null(), RID()); + + Vector<ShaderStageSPIRVData> stage_data; + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + ShaderStage stage = ShaderStage(i); + ShaderStageSPIRVData sd; + sd.shader_stage = stage; + String error = p_spirv->get_stage_compile_error(stage); + ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); + sd.spir_v = p_spirv->get_stage_bytecode(stage); + if (sd.spir_v.is_empty()) { + continue; + } + stage_data.push_back(sd); + } + return shader_create_from_spirv(stage_data); } RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set) { @@ -366,8 +391,10 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create); - ClassDB::bind_method(D_METHOD("shader_compile_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_from_source, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("shader_create", "shader_data"), &RenderingDevice::shader_create_from_bytecode); + ClassDB::bind_method(D_METHOD("shader_compile_spirv_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_spirv_from_source, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data"), &RenderingDevice::_shader_compile_binary_from_spirv); + ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data"), &RenderingDevice::_shader_compile_binary_from_spirv); + ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::shader_create_from_bytecode); ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask); ClassDB::bind_method(D_METHOD("uniform_buffer_create", "size_bytes", "data"), &RenderingDevice::uniform_buffer_create, DEFVAL(Vector<uint8_t>())); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 9a154ef7e9..eaf1ace798 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -41,7 +41,7 @@ class RDAttachmentFormat; class RDSamplerState; class RDVertexAttribute; class RDShaderSource; -class RDShaderBytecode; +class RDShaderSPIRV; class RDUniforms; class RDPipelineRasterizationState; class RDPipelineMultisampleState; @@ -105,14 +105,14 @@ public: bool supports_multiview = false; // If true this device supports multiview options }; - typedef String (*ShaderGetCacheKeyFunction)(const Capabilities *p_capabilities); - typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities); + typedef String (*ShaderSPIRVGetCacheKeyFunction)(const Capabilities *p_capabilities); + typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities); typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language); private: - static ShaderCompileFunction compile_function; + static ShaderCompileToSPIRVFunction compile_to_spirv_function; static ShaderCacheFunction cache_function; - static ShaderGetCacheKeyFunction get_cache_key_function; + static ShaderSPIRVGetCacheKeyFunction get_spirv_cache_key_function; static RenderingDevice *singleton; @@ -651,24 +651,28 @@ public: const Capabilities *get_device_capabilities() const { return &device_capabilities; }; - virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true); - virtual String shader_get_cache_key() const; + virtual Vector<uint8_t> shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true); + virtual String shader_get_spirv_cache_key() const; - static void shader_set_compile_function(ShaderCompileFunction p_function); - static void shader_set_cache_function(ShaderCacheFunction p_function); - static void shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function); + static void shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function); + static void shader_set_spirv_cache_function(ShaderCacheFunction p_function); + static void shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function); - struct ShaderStageData { + struct ShaderStageSPIRVData { ShaderStage shader_stage; Vector<uint8_t> spir_v; - ShaderStageData() { + ShaderStageSPIRVData() { shader_stage = SHADER_STAGE_VERTEX; } }; - RID shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_bytecode); - virtual RID shader_create(const Vector<ShaderStageData> &p_stages) = 0; + virtual String shader_get_binary_cache_key() const = 0; + virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv) = 0; + + virtual RID shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv); + virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary) = 0; + virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0; /******************/ @@ -1194,7 +1198,9 @@ protected: VertexFormatID _vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats); RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers); - Ref<RDShaderBytecode> _shader_compile_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true); + Ref<RDShaderSPIRV> _shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true); + Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode); + RID _shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv); RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 2652edb1bc..fa3f2f3895 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -172,7 +172,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String /* STEP 2, Compile the versions, add to shader file */ for (Map<StringName, String>::Element *E = version_texts.front(); E; E = E->next()) { - Ref<RDShaderBytecode> bytecode; + Ref<RDShaderSPIRV> bytecode; bytecode.instantiate(); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { @@ -182,7 +182,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } code = code.replace("VERSION_DEFINES", E->get()); String error; - Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false); + Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_spirv_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false); bytecode->set_stage_bytecode(RD::ShaderStage(i), spirv); if (error != "") { error += String() + "\n\nStage '" + stage_str[i] + "' source code: \n\n"; diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 4c31880faf..ccc3e2fb39 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -263,8 +263,8 @@ protected: } }; -class RDShaderBytecode : public Resource { - GDCLASS(RDShaderBytecode, Resource) +class RDShaderSPIRV : public Resource { + GDCLASS(RDShaderSPIRV, Resource) Vector<uint8_t> bytecode[RD::SHADER_STAGE_MAX]; String compile_error[RD::SHADER_STAGE_MAX]; @@ -280,6 +280,19 @@ public: return bytecode[p_stage]; } + Vector<RD::ShaderStageSPIRVData> get_stages() const { + Vector<RD::ShaderStageSPIRVData> stages; + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + if (bytecode[i].size()) { + RD::ShaderStageSPIRVData stage; + stage.shader_stage = RD::ShaderStage(i); + stage.spir_v = bytecode[i]; + stages.push_back(stage); + } + } + return stages; + } + void set_stage_compile_error(RD::ShaderStage p_stage, const String &p_compile_error) { ERR_FAIL_INDEX(p_stage, RD::SHADER_STAGE_MAX); compile_error[p_stage] = p_compile_error; @@ -292,11 +305,11 @@ public: protected: static void _bind_methods() { - ClassDB::bind_method(D_METHOD("set_stage_bytecode", "stage", "bytecode"), &RDShaderBytecode::set_stage_bytecode); - ClassDB::bind_method(D_METHOD("get_stage_bytecode", "stage"), &RDShaderBytecode::get_stage_bytecode); + ClassDB::bind_method(D_METHOD("set_stage_bytecode", "stage", "bytecode"), &RDShaderSPIRV::set_stage_bytecode); + ClassDB::bind_method(D_METHOD("get_stage_bytecode", "stage"), &RDShaderSPIRV::get_stage_bytecode); - ClassDB::bind_method(D_METHOD("set_stage_compile_error", "stage", "compile_error"), &RDShaderBytecode::set_stage_compile_error); - ClassDB::bind_method(D_METHOD("get_stage_compile_error", "stage"), &RDShaderBytecode::get_stage_compile_error); + ClassDB::bind_method(D_METHOD("set_stage_compile_error", "stage", "compile_error"), &RDShaderSPIRV::set_stage_compile_error); + ClassDB::bind_method(D_METHOD("get_stage_compile_error", "stage"), &RDShaderSPIRV::get_stage_compile_error); ADD_GROUP("Bytecode", "bytecode_"); ADD_PROPERTYI(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytecode_vertex"), "set_stage_bytecode", "get_stage_bytecode", RD::SHADER_STAGE_VERTEX); @@ -316,24 +329,29 @@ protected: class RDShaderFile : public Resource { GDCLASS(RDShaderFile, Resource) - Map<StringName, Ref<RDShaderBytecode>> versions; + Map<StringName, Ref<RDShaderSPIRV>> versions; String base_error; public: - void set_bytecode(const Ref<RDShaderBytecode> &p_bytecode, const StringName &p_version = StringName()) { + void set_bytecode(const Ref<RDShaderSPIRV> &p_bytecode, const StringName &p_version = StringName()) { ERR_FAIL_COND(p_bytecode.is_null()); versions[p_version] = p_bytecode; emit_changed(); } - Ref<RDShaderBytecode> get_bytecode(const StringName &p_version = StringName()) const { - ERR_FAIL_COND_V(!versions.has(p_version), Ref<RDShaderBytecode>()); + Ref<RDShaderSPIRV> get_spirv(const StringName &p_version = StringName()) const { + ERR_FAIL_COND_V(!versions.has(p_version), Ref<RDShaderSPIRV>()); return versions[p_version]; } + Vector<RD::ShaderStageSPIRVData> get_spirv_stages(const StringName &p_version = StringName()) const { + ERR_FAIL_COND_V(!versions.has(p_version), Vector<RD::ShaderStageSPIRVData>()); + return versions[p_version]->get_stages(); + } + Vector<StringName> get_version_list() const { Vector<StringName> vnames; - for (Map<StringName, Ref<RDShaderBytecode>>::Element *E = versions.front(); E; E = E->next()) { + for (Map<StringName, Ref<RDShaderSPIRV>>::Element *E = versions.front(); E; E = E->next()) { vnames.push_back(E->key()); } vnames.sort_custom<StringName::AlphCompare>(); @@ -353,7 +371,7 @@ public: if (base_error != "") { ERR_PRINT("Error parsing shader '" + p_file + "':\n\n" + base_error); } else { - for (Map<StringName, Ref<RDShaderBytecode>>::Element *E = versions.front(); E; E = E->next()) { + for (Map<StringName, Ref<RDShaderSPIRV>>::Element *E = versions.front(); E; E = E->next()) { for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String error = E->get()->get_stage_compile_error(RD::ShaderStage(i)); if (error != String()) { @@ -388,9 +406,9 @@ protected: versions.clear(); List<Variant> keys; p_versions.get_key_list(&keys); - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - StringName name = E->get(); - Ref<RDShaderBytecode> bc = p_versions[E->get()]; + for (const Variant &E : keys) { + StringName name = E; + Ref<RDShaderSPIRV> bc = p_versions[E]; ERR_CONTINUE(bc.is_null()); versions[name] = bc; } @@ -400,7 +418,7 @@ protected: static void _bind_methods() { ClassDB::bind_method(D_METHOD("set_bytecode", "bytecode", "version"), &RDShaderFile::set_bytecode, DEFVAL(StringName())); - ClassDB::bind_method(D_METHOD("get_bytecode", "version"), &RDShaderFile::get_bytecode, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("get_spirv", "version"), &RDShaderFile::get_spirv, DEFVAL(StringName())); ClassDB::bind_method(D_METHOD("get_version_list"), &RDShaderFile::get_version_list); ClassDB::bind_method(D_METHOD("set_base_error", "error"), &RDShaderFile::set_base_error); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 3b9aca200b..baa5381554 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -912,6 +912,8 @@ void ShaderLanguage::clear() { completion_class = SubClassTag::TAG_GLOBAL; completion_struct = StringName(); + unknown_varying_usages.clear(); + #ifdef DEBUG_ENABLED used_constants.clear(); used_varyings.clear(); @@ -2818,6 +2820,20 @@ bool ShaderLanguage::is_token_operator(TokenType p_type) { p_type == TK_COLON); } +bool ShaderLanguage::is_token_operator_assign(TokenType p_type) { + return (p_type == TK_OP_ASSIGN || + p_type == TK_OP_ASSIGN_ADD || + p_type == TK_OP_ASSIGN_SUB || + p_type == TK_OP_ASSIGN_MUL || + p_type == TK_OP_ASSIGN_DIV || + p_type == TK_OP_ASSIGN_MOD || + p_type == TK_OP_ASSIGN_SHIFT_LEFT || + p_type == TK_OP_ASSIGN_SHIFT_RIGHT || + p_type == TK_OP_ASSIGN_BIT_AND || + p_type == TK_OP_ASSIGN_BIT_OR || + p_type == TK_OP_ASSIGN_BIT_XOR); +} + bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) { if (p_constant->datatype == p_to_type) { if (p_value) { @@ -3324,8 +3340,7 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; } break; - case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT: - case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT: + case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: case ShaderNode::Varying::STAGE_VERTEX: if (current_function == varying_function_names.fragment) { *r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'."); @@ -3348,13 +3363,14 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) { switch (p_varying.stage) { case ShaderNode::Varying::STAGE_UNKNOWN: - *r_message = RTR("Varying must be assigned before using!"); - return false; + VaryingUsage usage; + usage.var = &p_varying; + usage.line = tk_line; + unknown_varying_usages.push_back(usage); + break; case ShaderNode::Varying::STAGE_VERTEX: - if (current_function == varying_function_names.fragment) { - p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT; - } else if (current_function == varying_function_names.light) { - p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT; + if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { + p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; } break; case ShaderNode::Varying::STAGE_FRAGMENT: @@ -3362,24 +3378,25 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; } break; - case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT: - if (current_function == varying_function_names.light) { - *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); - return false; - } - break; - case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT: - if (current_function == varying_function_names.fragment) { - *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); - return false; - } - break; default: break; } return true; } +bool ShaderLanguage::_check_varying_usages(int *r_error_line, String *r_error_message) const { + for (const List<ShaderLanguage::VaryingUsage>::Element *E = unknown_varying_usages.front(); E; E = E->next()) { + ShaderNode::Varying::Stage stage = E->get().var->stage; + if (stage != ShaderNode::Varying::STAGE_UNKNOWN && stage != ShaderNode::Varying::STAGE_VERTEX && stage != ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT) { + *r_error_line = E->get().line; + *r_error_message = RTR("Fragment-stage varying could not been accessed in custom function!"); + return false; + } + } + + return true; +} + bool ShaderLanguage::_check_node_constness(const Node *p_node) const { switch (p_node->type) { case Node::TYPE_OPERATOR: { @@ -4237,7 +4254,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Token next_token = _get_token(); _set_tkpos(prev_pos); String error; - if (next_token.type == TK_OP_ASSIGN) { + + if (is_token_operator_assign(next_token.type)) { if (!_validate_varying_assign(shader->varyings[identifier], &error)) { _set_error(error); return nullptr; @@ -4448,12 +4466,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String member_name = String(ident.ptr()); if (shader->structs.has(st)) { StructNode *n = shader->structs[st].shader_struct; - for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) { - if (String(E->get()->name) == member_name) { - member_type = E->get()->datatype; - array_size = E->get()->array_size; + for (const MemberNode *E : n->members) { + if (String(E->name) == member_name) { + member_type = E->datatype; + array_size = E->array_size; if (member_type == TYPE_STRUCT) { - member_struct_name = E->get()->struct_name; + member_struct_name = E->struct_name; } ok = true; break; @@ -4778,10 +4796,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String member_struct_name; if (expr->get_array_size() > 0) { - uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; - if (index_constant >= (uint32_t)expr->get_array_size()) { - _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1)); - return nullptr; + if (index->type == Node::TYPE_CONSTANT) { + uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; + if (index_constant >= (uint32_t)expr->get_array_size()) { + _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1)); + return nullptr; + } } member_type = expr->get_datatype(); if (member_type == TYPE_STRUCT) { @@ -7875,6 +7895,15 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } + + int error_line; + String error_message; + if (!_check_varying_usages(&error_line, &error_message)) { + _set_tkpos({ 0, error_line }); + _set_error(error_message); + return ERR_PARSE_ERROR; + } + return OK; } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index a91fa57a8e..c02d6c47ec 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -646,10 +646,9 @@ public: struct Varying { enum Stage { STAGE_UNKNOWN, - STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT or STAGE_VERTEX_TO_LIGHT, emits error if they are not used - STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits error if it's not used - STAGE_VERTEX_TO_FRAGMENT, - STAGE_VERTEX_TO_LIGHT, + STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT_LIGHT, emits warning if it's not used + STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits warning if it's not used + STAGE_VERTEX_TO_FRAGMENT_LIGHT, STAGE_FRAGMENT_TO_LIGHT, }; @@ -767,6 +766,7 @@ public: static String get_datatype_name(DataType p_type); static bool is_token_nonvoid_datatype(TokenType p_type); static bool is_token_operator(TokenType p_type); + static bool is_token_operator_assign(TokenType p_type); static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr); static DataType get_scalar_type(DataType p_type); @@ -876,6 +876,14 @@ private: VaryingFunctionNames varying_function_names; + struct VaryingUsage { + ShaderNode::Varying *var; + int line; + }; + List<VaryingUsage> unknown_varying_usages; + + bool _check_varying_usages(int *r_error_line, String *r_error_message) const; + TkPos _get_tkpos() { TkPos tkp; tkp.char_idx = char_idx; |