Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic fast filtering implementation #36588

Merged
merged 1 commit into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1037,23 +1037,28 @@
Lower-end override for [member rendering/quality/intended_usage/framebuffer_allocation] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/reflection_atlas/reflection_count" type="int" setter="" getter="" default="64">
Number of cubemaps to store in the reflection atlas. The number of [ReflectionProbe]s in a scene will be limited by this amount. A higher number requires more VRAM.
</member>
<member name="rendering/quality/reflection_atlas/reflection_size" type="int" setter="" getter="" default="256">
<member name="rendering/quality/reflection_atlas/reflection_size" type="int" setter="" getter="" default="128">
Size of cubemap faces for [ReflectionProbe]s. A higher number requires more VRAM and may make reflection probe updating slower.
</member>
<member name="rendering/quality/reflection_atlas/reflection_size.mobile" type="int" setter="" getter="" default="128">
Lower-end override for [member rendering/quality/reflection_atlas/reflection_size] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/reflections/fast_filter_high_quality" type="bool" setter="" getter="" default="false">
Use a higher quality variant of the fast filtering algorithm. Significantly slower than using default quality, but results in smoother reflections. Should only be used when the scene is especially detailed.
</member>
<member name="rendering/quality/reflections/ggx_samples" type="int" setter="" getter="" default="1024">
Sets the number of samples to take when using importance sampling for [Sky]s and [ReflectionProbe]s. A higher value will result in smoother, higher quality reflections, but increases time to calculate radiance maps. In general, fewer samples are needed for simpler, low dynamic range environments while more samples are needed for HDR environments and environments with a high level of detail.
</member>
<member name="rendering/quality/reflections/ggx_samples.mobile" type="int" setter="" getter="" default="128">
</member>
<member name="rendering/quality/reflections/ggx_samples_realtime" type="int" setter="" getter="" default="64">
</member>
<member name="rendering/quality/reflections/ggx_samples_realtime.mobile" type="int" setter="" getter="" default="16">
Lower-end override for [member rendering/quality/reflections/ggx_samples] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/reflections/roughness_layers" type="int" setter="" getter="" default="6">
Limits the number of layers to use in radiance maps when using importance sampling. A lower number will be slightly faster and take up less VRAM.
</member>
<member name="rendering/quality/reflections/texture_array_reflections" type="bool" setter="" getter="" default="true">
If [code]true[/code], uses texture arrays instead of mipmaps for reflection probes and panorama backgrounds (sky). This reduces jitter noise on reflections, but costs more performance and memory.
If [code]true[/code], uses texture arrays instead of mipmaps for reflection probes and panorama backgrounds (sky). This reduces jitter noise and upscaling artifacts on reflections, but is significantly slower to compute and uses [member rendering/quality/reflections/roughness_layers] times more memory.
</member>
<member name="rendering/quality/reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
Lower-end override for [member rendering/quality/reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
Expand Down
4 changes: 2 additions & 2 deletions doc/classes/ReflectionProbe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Captures its surroundings to create reflections.
</brief_description>
<description>
Capture its surroundings as a dual parabolid image, and stores versions of it with increasing levels of blur to simulate different material roughnesses.
Captures its surroundings as a cubemap, and stores versions of it with increasing levels of blur to simulate different material roughnesses.
The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [GIProbe]s and Screen Space Reflections to achieve high quality reflections. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them.
</description>
<tutorials>
Expand Down Expand Up @@ -52,7 +52,7 @@
</members>
<constants>
<constant name="UPDATE_ONCE" value="0" enum="UpdateMode">
Update the probe once on the next frame.
Update the probe once on the next frame. The corresponding radiance map will be generated over the following six frames. This is slower to update than [constant UPDATE_ALWAYS] but can result in higher quality reflections.
</constant>
<constant name="UPDATE_ALWAYS" value="1" enum="UpdateMode">
Update the probe every frame. This is needed when you want to capture dynamic objects. However, it results in an increased render time. Use [constant UPDATE_ONCE] whenever possible.
Expand Down
4 changes: 4 additions & 0 deletions doc/classes/Sky.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</methods>
<members>
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Sky.ProcessMode" default="0">
Sets the method for generating the radiance map from the sky. The radiance map is a cubemap with increasingly blurry versions of the sky corresponding to different levels of roughness. Radiance maps can be expensive to calculate. See [enum ProcessMode] for options.
</member>
<member name="radiance_size" type="int" setter="set_radiance_size" getter="get_radiance_size" enum="Sky.RadianceSize" default="2">
The [Sky]'s radiance map size. The higher the radiance map size, the more detailed the lighting from the [Sky] will be.
Expand Down Expand Up @@ -45,8 +46,11 @@
Represents the size of the [enum RadianceSize] enum.
</constant>
<constant name="PROCESS_MODE_QUALITY" value="0" enum="ProcessMode">
Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime.
</constant>
<constant name="PROCESS_MODE_REALTIME" value="1" enum="ProcessMode">
Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
[b]Note:[/b] The fast filtering algorithm is limited to 128x128 cubemaps, so [member radiance_size] must be set to [constant RADIANCE_SIZE_128].
</constant>
</constants>
</class>
28 changes: 28 additions & 0 deletions servers/visual/rasterizer_rd/cubemap_coeffs.h

Large diffs are not rendered by default.

94 changes: 93 additions & 1 deletion servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#include "rasterizer_effects_rd.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "cubemap_coeffs.h"

static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
p_array[0] = p_basis.elements[0][0];
Expand Down Expand Up @@ -750,6 +752,44 @@ void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness,
RD::get_singleton()->compute_list_end();
}

void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, bool p_source_is_panorama, RID p_dest_cubemap, const Size2i &p_size) {

cubemap_downsampler.push_constant.face_size = p_size.x;

RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipelines[p_source_is_panorama ? CUBEMAP_DOWNSAMPLER_SOURCE_PANORAMA : CUBEMAP_DOWNSAMPLER_SOURCE_CUBEMAP]);
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);

int x_groups = (p_size.x - 1) / 8 + 1;
int y_groups = (p_size.y - 1) / 8 + 1;

RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));

RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face

RD::get_singleton()->compute_list_end();
}

void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {

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_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);
for (int i = 0; i < p_dest_cubemap.size(); i++) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap[i]), i + 2);
}

int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64

RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face

RD::get_singleton()->compute_list_end();
}

RasterizerEffectsRD::RasterizerEffectsRD() {

{
Expand Down Expand Up @@ -930,7 +970,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
}

{
// Initialize copier
// Initialize roughness limiter
Vector<String> shader_modes;
shader_modes.push_back("");

Expand All @@ -941,6 +981,55 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0));
}

{
//Initialize cubemap downsampler
Vector<String> cubemap_downsampler_modes;
cubemap_downsampler_modes.push_back("\n#define MODE_SOURCE_PANORAMA\n");
cubemap_downsampler_modes.push_back("\n#define MODE_SOURCE_CUBEMAP\n");
cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);

cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();

for (int i = 0; i < CUBEMAP_DOWNSAMPLER_SOURCE_MAX; i++) {
cubemap_downsampler.pipelines[i] = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, i));
}
}

{
// Initialize cubemap filter
filter.use_high_quality = GLOBAL_GET("rendering/quality/reflections/fast_filter_high_quality");

Vector<String> cubemap_filter_modes;
cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
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));
RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0], false);
} else {
filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs));
RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0], false);
}

Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.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.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
}

RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
Expand Down Expand Up @@ -987,4 +1076,7 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {
ssao.gather_shader.version_free(ssao.gather_shader_version);
ssao.blur_shader.version_free(ssao.blur_shader_version);
roughness_limiter.shader.version_free(roughness_limiter.shader_version);
cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
filter.shader.version_free(filter.shader_version);
RD::get_singleton()->free(filter.coefficient_buffer);
}
43 changes: 43 additions & 0 deletions servers/visual/rasterizer_rd/rasterizer_effects_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "servers/visual/rasterizer_rd/shaders/blur.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/copy.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h"
#include "servers/visual/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h"
Expand Down Expand Up @@ -355,6 +357,45 @@ class RasterizerEffectsRD {

} roughness_limiter;

enum CubemapDownsamplerSource {
CUBEMAP_DOWNSAMPLER_SOURCE_PANORAMA,
CUBEMAP_DOWNSAMPLER_SOURCE_CUBEMAP,
CUBEMAP_DOWNSAMPLER_SOURCE_MAX
};

struct CubemapDownsamplerPushConstant {
uint32_t face_size;
float pad[3];
};

struct CubemapDownsampler {

CubemapDownsamplerPushConstant push_constant;
CubemapDownsamplerShaderRD shader;
RID shader_version;
RID pipelines[CUBEMAP_DOWNSAMPLER_SOURCE_MAX];

} cubemap_downsampler;

enum CubemapFilterMode {
FILTER_MODE_HIGH_QUALITY,
FILTER_MODE_LOW_QUALITY,
FILTER_MODE_HIGH_QUALITY_ARRAY,
FILTER_MODE_LOW_QUALITY_ARRAY,
FILTER_MODE_MAX,
};

struct CubemapFilter {

CubemapFilterShaderRD shader;
RID shader_version;
RID pipelines[FILTER_MODE_MAX];
RID uniform_set;
RID coefficient_buffer;
bool use_high_quality;

} filter;

RID default_sampler;
RID default_mipmap_sampler;
RID index_buffer;
Expand Down Expand Up @@ -424,6 +465,8 @@ class RasterizerEffectsRD {
void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness);

void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
void cubemap_downsample(RID p_source_cubemap, bool p_source_is_panorama, RID p_dest_cubemap, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);

RasterizerEffectsRD();
~RasterizerEffectsRD();
Expand Down
Loading