Skip to content

Commit

Permalink
Implement support for fragment density maps.
Browse files Browse the repository at this point in the history
Co-Authored-By: Bastiaan Olij <mux213@gmail.com>
  • Loading branch information
DarioSamo and BastiaanOlij committed Nov 22, 2024
1 parent 0f65e7d commit 6fda940
Show file tree
Hide file tree
Showing 18 changed files with 352 additions and 149 deletions.
2 changes: 1 addition & 1 deletion drivers/d3d12/rendering_device_driver_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
};

public:
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) override final;
virtual void render_pass_free(RenderPassID p_render_pass) override final;

// ----- COMMANDS -----
Expand Down
229 changes: 153 additions & 76 deletions drivers/vulkan/rendering_device_driver_vulkan.cpp

Large diffs are not rendered by default.

23 changes: 17 additions & 6 deletions drivers/vulkan/rendering_device_driver_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
String supported_operations_desc() const;
};

struct VRSCapabilities {
bool pipeline_vrs_supported = false; // We can specify our fragment rate on a pipeline level.
bool primitive_vrs_supported = false; // We can specify our fragment rate on each drawcall.
bool attachment_vrs_supported = false; // We can provide a density map attachment on our framebuffer.
struct FSRCapabilities {
bool pipeline_fsr_supported = false; // We can specify our fragment rate on a pipeline level.
bool primitive_fsr_supported = false; // We can specify our fragment rate on each drawcall.
bool attachment_fsr_supported = false; // We can provide a density map attachment on our framebuffer.

Size2i min_texel_size;
Size2i max_texel_size;
Expand All @@ -88,6 +88,16 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
Size2i texel_size; // The texel size we'll use
};

struct FDMCapabilities {
bool fragment_density_map = false;
bool fragment_density_map_dynamic = false;
bool fragment_density_map_non_submsampled_images = false;

Size2i min_fragment_density_texel_size;
Size2i max_fragment_density_texel_size;
bool fragment_density_invocations = false;
};

struct ShaderCapabilities {
bool shader_float16_is_supported = false;
bool shader_int8_is_supported = false;
Expand Down Expand Up @@ -135,7 +145,8 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
RDD::Capabilities device_capabilities;
SubgroupCapabilities subgroup_capabilities;
MultiviewCapabilities multiview_capabilities;
VRSCapabilities vrs_capabilities;
FSRCapabilities fsr_capabilities;
FDMCapabilities fdm_capabilities;
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
bool pipeline_cache_control_support = false;
Expand Down Expand Up @@ -560,7 +571,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {

// ----- SUBPASS -----

virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) override final;
virtual void render_pass_free(RenderPassID p_render_pass) override final;

// ----- COMMANDS -----
Expand Down
32 changes: 23 additions & 9 deletions servers/rendering/renderer_rd/effects/vrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ VRS::VRS() {
Vector<String> vrs_modes;
vrs_modes.push_back("\n"); // VRS_DEFAULT
vrs_modes.push_back("\n#define USE_MULTIVIEW\n"); // VRS_MULTIVIEW
vrs_modes.push_back("\n#define SPLIT_RG\n"); // VRS_RG
vrs_modes.push_back("\n#define SPLIT_RG\n#define USE_MULTIVIEW\n"); // VRS_RG_MULTIVIEW

vrs_shader.shader.initialize(vrs_modes);

Expand Down Expand Up @@ -80,15 +82,19 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi

RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));

int mode = 0;
VRSPushConstant push_constant = {};

int mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT;

// Set maximum texel factor based on maximum fragment size, some GPUs do not support 8x8 (fragment shading rate approach).
if (MIN(RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_WIDTH), RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_HEIGHT)) > 4) {
push_constant.max_texel_factor = 3.0;
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP)) {
mode = p_multiview ? VRS_RG_MULTIVIEW : VRS_RG;
} else {
push_constant.max_texel_factor = 2.0;
mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT;

// Set maximum texel factor based on maximum fragment size, some GPUs do not support 8x8 (fragment shading rate approach).
if (MIN(RD::get_singleton()->limit_get(RD::LIMIT_FRAGMENT_SHADING_RATE_MAX_FRAGMENT_WIDTH), RD::get_singleton()->limit_get(RD::LIMIT_FRAGMENT_SHADING_RATE_MAX_FRAGMENT_HEIGHT)) > 4) {
push_constant.max_texel_factor = 3.0;
} else {
push_constant.max_texel_factor = 2.0;
}
}

RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode);
Expand All @@ -103,8 +109,16 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
}

Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH);
int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT);
int32_t texel_width = 0;
int32_t texel_height = 0;
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP)) {
const int32_t PreferredTexelSize = 32;
texel_width = CLAMP(PreferredTexelSize, RD::get_singleton()->limit_get(RD::LIMIT_MIN_FRAGMENT_DENSITY_TEXEL_WIDTH), RD::get_singleton()->limit_get(RD::LIMIT_MAX_FRAGMENT_DENSITY_TEXEL_WIDTH));
texel_height = CLAMP(PreferredTexelSize, RD::get_singleton()->limit_get(RD::LIMIT_MIN_FRAGMENT_DENSITY_TEXEL_HEIGHT), RD::get_singleton()->limit_get(RD::LIMIT_MAX_FRAGMENT_DENSITY_TEXEL_HEIGHT));
} else {
texel_width = RD::get_singleton()->limit_get(RD::LIMIT_FRAGMENT_SHADING_RATE_TEXEL_WIDTH);
texel_height = RD::get_singleton()->limit_get(RD::LIMIT_FRAGMENT_SHADING_RATE_TEXEL_HEIGHT);
}

int width = p_base_size.x / texel_width;
if (p_base_size.x % texel_width != 0) {
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_rd/effects/vrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class VRS {
enum VRSMode {
VRS_DEFAULT,
VRS_MULTIVIEW,
VRS_RG,
VRS_RG_MULTIVIEW,
VRS_MAX,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb(

if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);

return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), color, depth, vrs_texture);
} else {
return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), color, depth);
Expand Down Expand Up @@ -173,7 +172,6 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb(

if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);

return FramebufferCacheRD::get_singleton()->get_cache_multiview(v_count, color, specular, velocity_buffer, depth, vrs_texture);
} else {
return FramebufferCacheRD::get_singleton()->get_cache_multiview(v_count, color, specular, velocity_buffer, depth);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe

uint32_t view_count = render_buffers->get_view_count();

bool vrs_uses_fdm = RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP);
RID vrs_texture;
if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
Expand Down Expand Up @@ -199,8 +200,8 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
RD::FramebufferPass pass;
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
if (vrs_texture.is_valid()) {
pass.vrs_attachment = 2;
if (!vrs_uses_fdm && vrs_texture.is_valid()) {
pass.fragment_shading_rate_attachment = 2;
}

if (use_msaa) {
Expand All @@ -222,8 +223,8 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
RD::FramebufferPass pass;
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
if (vrs_texture.is_valid()) {
pass.vrs_attachment = 2;
if (!vrs_uses_fdm && vrs_texture.is_valid()) {
pass.fragment_shading_rate_attachment = 2;
}

if (use_msaa) {
Expand Down Expand Up @@ -2864,8 +2865,9 @@ static RD::FramebufferFormatID _get_color_framebuffer_format_for_pipeline(RD::Da
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;

if (p_vrs) {
pass.vrs_attachment = 2;
bool vrs_uses_fdm = RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP);
if (!vrs_uses_fdm && p_vrs) {
pass.fragment_shading_rate_attachment = 2;
}

if (multisampling) {
Expand Down Expand Up @@ -2893,7 +2895,7 @@ static RD::FramebufferFormatID _get_color_framebuffer_format_for_pipeline(RD::Da
passes.push_back(blit_pass);
}

return RD::get_singleton()->framebuffer_format_create_multipass(attachments, passes, p_view_count);
return RD::get_singleton()->framebuffer_format_create_multipass(attachments, passes, p_view_count, vrs_uses_fdm ? 2 : -1);
}

static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline() {
Expand Down
4 changes: 2 additions & 2 deletions servers/rendering/renderer_rd/framebuffer_cache_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class FramebufferCacheRD : public Object {

static _FORCE_INLINE_ uint32_t _hash_pass(const RD::FramebufferPass &p, uint32_t h) {
h = hash_murmur3_one_32(p.depth_attachment, h);
h = hash_murmur3_one_32(p.vrs_attachment, h);
h = hash_murmur3_one_32(p.fragment_shading_rate_attachment, h);

h = hash_murmur3_one_32(p.color_attachments.size(), h);
for (int i = 0; i < p.color_attachments.size(); i++) {
Expand All @@ -84,7 +84,7 @@ class FramebufferCacheRD : public Object {
return false;
}

if (a.vrs_attachment != b.vrs_attachment) {
if (a.fragment_shading_rate_attachment != b.fragment_shading_rate_attachment) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_positi
RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr;

bool RendererSceneRenderRD::is_vrs_supported() const {
return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS);
return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_FRAGMENT_SHADING_RATE) || RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP);
}

bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
Expand Down
11 changes: 11 additions & 0 deletions servers/rendering/renderer_rd/shaders/effects/vrs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ layout(location = 0) in vec2 uv_interp;
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif /* USE_MULTIVIEW */

#ifdef SPLIT_RG
layout(location = 0) out vec2 frag_color;
#else
layout(location = 0) out uint frag_color;
#endif

layout(push_constant, std430) uniform Params {
float max_texel_factor;
Expand All @@ -79,6 +83,12 @@ void main() {
// Input is standardized. R for X, G for Y, 0.0 (0) = 1, 0.33 (85) = 2, 0.66 (170) = 3, 1.0 (255) = 8
vec4 color = textureLod(source_color, uv, 0.0);

#ifdef SPLIT_RG
// Density map for VRS according to VK_EXT_fragment_density_map, we can use as is.
// TODO: The format is different than was was described in the comment. Discuss with Baastian if we should
// bother doing a conversion here or just generate it differently on the CPU instead.
frag_color = max(vec2(1.0f) - color.rg, vec2(1.0f / 255.0f));
#else
// Output image shading rate image for VRS according to VK_KHR_fragment_shading_rate.
color.r = clamp(floor(color.r * params.max_texel_factor + 0.1), 0.0, params.max_texel_factor);
color.g = clamp(floor(color.g * params.max_texel_factor + 0.1), 0.0, params.max_texel_factor);
Expand All @@ -94,4 +104,5 @@ void main() {
// Encode to frag_color;
frag_color = int(color.r + 0.1) << 2;
frag_color += int(color.g + 0.1);
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,17 @@ uint32_t RenderSceneBuffersRD::get_velocity_usage_bits(bool p_resolve, bool p_ms
}

RD::DataFormat RenderSceneBuffersRD::get_vrs_format() {
return RD::DATA_FORMAT_R8_UINT;
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP)) {
return RD::DATA_FORMAT_R8G8_UNORM;
} else {
return RD::DATA_FORMAT_R8_UINT;
}
}

uint32_t RenderSceneBuffersRD::get_vrs_usage_bits() {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP)) {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_FRAGMENT_DENSITY_MAP_BIT;
} else {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT;
}
}
31 changes: 29 additions & 2 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,9 @@ TextureStorage::TextureStorage() {
tformat.format = RD::DATA_FORMAT_R8_UINT;
tformat.width = 4;
tformat.height = 4;
tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT;
tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT;
tformat.texture_type = RD::TEXTURE_TYPE_2D;
if (!RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS)) {
if (!RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_FRAGMENT_SHADING_RATE)) {
tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
}

Expand All @@ -501,6 +501,33 @@ TextureStorage::TextureStorage() {
}
}

{
// Create default fragment density map.
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R8G8_UNORM;
tformat.width = 4;
tformat.height = 4;
tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
tformat.texture_type = RD::TEXTURE_TYPE_2D;

if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_DENSITY_MAP)) {
// Only request the usage bits if we know the feature is supported.
tformat.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_FRAGMENT_DENSITY_MAP_BIT;
}

Vector<uint8_t> pv;
pv.resize(4 * 4);
for (int i = 0; i < 4 * 4; i++) {
pv.set(i, 0);
}

{
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);
default_rd_textures[DEFAULT_RD_TEXTURE_FDM] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
}

{
Vector<String> sdf_modes;
sdf_modes.push_back("\n#define MODE_LOAD\n");
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class TextureStorage : public RendererTextureStorage {
DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH,
DEFAULT_RD_TEXTURE_2D_UINT,
DEFAULT_RD_TEXTURE_VRS,
DEFAULT_RD_TEXTURE_FDM,
DEFAULT_RD_TEXTURE_MAX
};

Expand Down
Loading

0 comments on commit 6fda940

Please sign in to comment.