Skip to content

Commit

Permalink
Add dynamic VRS option that generates VRS density map with a shader
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Dec 2, 2024
1 parent 206e8d6 commit f1dc20a
Show file tree
Hide file tree
Showing 15 changed files with 164 additions and 27 deletions.
9 changes: 1 addition & 8 deletions modules/mobile_vr/mobile_vr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,18 +574,11 @@ void MobileVRInterface::process() {
}

RID MobileVRInterface::get_vrs_texture() {
PackedVector2Array eye_foci;

Size2 target_size = get_render_target_size();
real_t aspect_ratio = target_size.x / target_size.y;
uint32_t view_count = get_view_count();

for (uint32_t v = 0; v < view_count; v++) {
Projection cm = get_projection_for_view(v, aspect_ratio, 0.1, 1000.0);
Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0));

eye_foci.push_back(Vector2(center.x, center.y));
}
PackedVector2Array eye_foci = get_vrs_eye_foci(aspect_ratio);

return xr_vrs.make_vrs_texture(target_size, eye_foci);
}
Expand Down
16 changes: 16 additions & 0 deletions modules/openxr/openxr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,22 @@ Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints
return Vector3();
}

PackedVector2Array OpenXRInterface::get_vrs_eye_foci(float p_aspect) {
PackedVector2Array ret;

if (!openxr_api) {
return ret;
}

uint32_t view_count = get_view_count();

for (uint32_t v = 0; v < view_count; v++) {
ret.push_back(openxr_api->get_eye_focus(v, p_aspect));
}

return ret;
}

RID OpenXRInterface::get_vrs_texture() {
if (!openxr_api) {
return RID();
Expand Down
1 change: 1 addition & 0 deletions modules/openxr/openxr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ class OpenXRInterface : public XRInterface {
Vector3 get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const;
Vector3 get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const;

virtual PackedVector2Array get_vrs_eye_foci(float p_aspect) override;
virtual RID get_vrs_texture() override;

OpenXRInterface();
Expand Down
8 changes: 6 additions & 2 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3672,6 +3672,9 @@ void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
case VRS_XR: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_XR);
} break;
case VRS_XR_DYNAMIC: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_XR_DYNAMIC);
} break;
default: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_DISABLED);
} break;
Expand Down Expand Up @@ -4831,7 +4834,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.001"), "set_texture_mipmap_bias", "get_texture_mipmap_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness");
ADD_GROUP("Variable Rate Shading", "vrs_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_mode", PROPERTY_HINT_ENUM, "Disabled,Texture,Depth buffer,XR"), "set_vrs_mode", "get_vrs_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_mode", PROPERTY_HINT_ENUM, "Disabled,Texture,Depth buffer,XR,XR Dynamic"), "set_vrs_mode", "get_vrs_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,Always"), "set_vrs_update_mode", "get_vrs_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "vrs_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_vrs_texture", "get_vrs_texture");
#endif
Expand Down Expand Up @@ -4955,6 +4958,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(VRS_DISABLED);
BIND_ENUM_CONSTANT(VRS_TEXTURE);
BIND_ENUM_CONSTANT(VRS_XR);
BIND_ENUM_CONSTANT(VRS_XR_DYNAMIC);
BIND_ENUM_CONSTANT(VRS_MAX);

BIND_ENUM_CONSTANT(VRS_UPDATE_DISABLED);
Expand All @@ -4968,7 +4972,7 @@ void Viewport::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}

if (vrs_mode == VRS_DISABLED && (p_property.name == "vrs_update_mode")) {
if ((vrs_mode == VRS_DISABLED || vrs_mode == VRS_XR_DYNAMIC) && (p_property.name == "vrs_update_mode")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
Expand Down
1 change: 1 addition & 0 deletions scene/main/viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class Viewport : public Node {
VRS_DISABLED,
VRS_TEXTURE,
VRS_XR,
VRS_XR_DYNAMIC,
VRS_MAX
};

Expand Down
77 changes: 73 additions & 4 deletions servers/rendering/renderer_rd/effects/vrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@ using namespace RendererRD;
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_modes.push_back("\n#define SOURCE_TEXTURE\n"); // VRS_DEFAULT
vrs_modes.push_back("\n#define SOURCE_TEXTURE\n#define USE_MULTIVIEW\n"); // VRS_MULTIVIEW
vrs_modes.push_back("\n#define SOURCE_TEXTURE\n#define SPLIT_RG\n"); // VRS_RG
vrs_modes.push_back("\n#define SOURCE_TEXTURE\n#define SPLIT_RG\n#define USE_MULTIVIEW\n"); // VRS_RG_MULTIVIEW
vrs_modes.push_back("\n"); // VRS_DYNAMIC
vrs_modes.push_back("\n#define USE_MULTIVIEW\n"); // VRS_DYNAMIC_MULTIVIEW
vrs_modes.push_back("\n#define SPLIT_RG\n"); // VRS_DYNAMIC_RG
vrs_modes.push_back("\n#define SPLIT_RG\n#define USE_MULTIVIEW\n"); // VRS_DYNAMIC_RG_MULTIVIEW

vrs_shader.shader.initialize(vrs_modes);

Expand Down Expand Up @@ -106,6 +110,46 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
RD::get_singleton()->draw_list_end();
}

void VRS::draw_vrs(RID p_dest_framebuffer, const Vector<Vector2> &p_eye_centers, const float p_min_radius, const float p_max_radius, const float p_aspect_ratio) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);

bool multiview = p_eye_centers.size() > 1;

int mode = 0;
VRSPushConstant push_constant = {};
bool uses_rg_format = RD::get_singleton()->vrs_get_format() == RD::DATA_FORMAT_R8G8_UNORM;
if (uses_rg_format) {
mode = multiview ? VRS_DYNAMIC_RG_MULTIVIEW : VRS_DYNAMIC_RG;
} else {
mode = multiview ? VRS_DYNAMIC_MULTIVIEW : VRS_DYNAMIC;

// Default to 4x4 as it's not possible to query the max fragment size from RenderingDevice. This can be improved to use the largest size
// available if this code is moved over to RenderingDevice at some point.
push_constant.max_texel_factor = 2.0;
}

push_constant.min_radius = p_min_radius;
push_constant.max_radius = p_max_radius;
push_constant.aspect_ratio = p_aspect_ratio;

int i = 0;
for (const Vector2 &eye_center : p_eye_centers) {
push_constant.eye_center[i][0] = eye_center.x * 0.5 + 0.5;
push_constant.eye_center[i][1] = eye_center.y * 0.5 + 0.5;
i++;
}

RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode);
ERR_FAIL_COND(shader.is_null());

RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(VRSPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}

Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
Size2i vrs_texel_size = RD::get_singleton()->vrs_get_texel_size();
return Size2i((p_base_size.x + vrs_texel_size.x - 1) / vrs_texel_size.x, (p_base_size.y + vrs_texel_size.y - 1) / vrs_texel_size.y);
Expand All @@ -116,6 +160,13 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target);
RS::ViewportVRSUpdateMode vrs_update_mode = texture_storage->render_target_get_vrs_update_mode(p_render_target);

#ifndef _3D_DISABLED
if (vrs_mode == RS::VIEWPORT_VRS_XR_DYNAMIC) {
// We're not copying but generating, so always do this!
vrs_update_mode = RS::VIEWPORT_VRS_UPDATE_ALWAYS;
}
#endif // _3D_DISABLED

if (vrs_mode != RS::VIEWPORT_VRS_DISABLED && vrs_update_mode != RS::VIEWPORT_VRS_UPDATE_DISABLED) {
RD::get_singleton()->draw_command_begin_label("VRS Setup");

Expand Down Expand Up @@ -144,6 +195,24 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
}
}
}
} else if (vrs_mode == RS::VIEWPORT_VRS_XR_DYNAMIC) {
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
if (interface.is_valid()) {
Size2 size = texture_storage->render_target_get_size(p_render_target);
float aspect_ratio = size.x / size.y;

// Need to get these from our interface:
PackedVector2Array eye_centers = interface->get_vrs_eye_foci(aspect_ratio);

// Need to vary these based on performance:
float min_radius = 0.1;
float max_radius = 0.3;

// TODO: should check if any of the above has changed since last frame,
// or VRS texture was marked dirty. Skip draw if neither is the case.

draw_vrs(p_vrs_fb, eye_centers, min_radius, max_radius, aspect_ratio);
}
#endif // _3D_DISABLED
}

Expand Down
12 changes: 9 additions & 3 deletions servers/rendering/renderer_rd/effects/vrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,19 @@ class VRS {
VRS_MULTIVIEW,
VRS_RG,
VRS_RG_MULTIVIEW,
VRS_DYNAMIC,
VRS_DYNAMIC_MULTIVIEW,
VRS_DYNAMIC_RG,
VRS_DYNAMIC_RG_MULTIVIEW,
VRS_MAX,
};

struct VRSPushConstant {
float eye_center[2][2];
float max_texel_factor; // 4x8, 8x4 and 8x8 are only available on some GPUs.
float res1;
float res2;
float res3;
float min_radius;
float max_radius;
float aspect_ratio;
};

struct VRSShader {
Expand All @@ -68,6 +73,7 @@ class VRS {
~VRS();

void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false);
void draw_vrs(RID p_dest_framebuffer, const Vector<Vector2> &p_eye_centers, const float p_min_radius, const float p_max_radius, const float p_aspect_ratio);

Size2i get_vrs_texture_size(const Size2i p_base_size) const;
void update_vrs_texture(RID p_vrs_fb, RID p_render_target);
Expand Down
34 changes: 27 additions & 7 deletions servers/rendering/renderer_rd/shaders/effects/vrs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ layout(location = 0) out vec2 uv_interp;
#endif

layout(push_constant, std430) uniform Params {
vec2 eye_center[2];
float max_texel_factor;
float res1;
float res2;
float res3;
float min_radius;
float max_radius;
float aspect_ratio;
}
params;

Expand All @@ -49,14 +50,22 @@ void main() {
#else // has_VK_KHR_multiview
#define ViewIndex 0
#endif // has_VK_KHR_multiview
#else // USE_MULTIVIEW
#define ViewIndex 0
#endif //USE_MULTIVIEW

#ifdef USE_MULTIVIEW
layout(location = 0) in vec3 uv_interp;

#ifdef SOURCE_TEXTURE
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
#endif /* SOURCE_TEXTURE */
#else /* USE_MULTIVIEW */
layout(location = 0) in vec2 uv_interp;

#ifdef SOURCE_TEXTURE
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif /* SOURCE_TEXTURE */
#endif /* USE_MULTIVIEW */

#ifdef SPLIT_RG
Expand All @@ -66,10 +75,11 @@ layout(location = 0) out uint frag_color;
#endif

layout(push_constant, std430) uniform Params {
vec2 eye_center[2];
float max_texel_factor;
float res1;
float res2;
float res3;
float min_radius;
float max_radius;
float aspect_ratio;
}
params;

Expand All @@ -80,8 +90,18 @@ void main() {
vec2 uv = uv_interp;
#endif

vec2 color;
#ifdef SOURCE_TEXTURE
// 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);
color = textureLod(source_color, uv, 0.0).rg;
#else
vec2 offset = uv.xy - params.eye_center[ViewIndex]; // Q: Might need to invert y?
offset.y /= params.aspect_ratio; // Q: or *= ??
float dist = length(offset);
float density = clamp((dist - params.min_radius) / (params.max_radius - params.min_radius), 0.0, 1.0);

color = vec2(density);
#endif // SOURCE_TEXTURE

#ifdef SPLIT_RG
// Density map for VRS according to VK_EXT_fragment_density_map, we can use as is.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,10 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co

// Create our color buffer.
const bool resolve_target = msaa_3d != RS::VIEWPORT_MSAA_DISABLED;
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, get_color_usage_bits(resolve_target, false, can_be_storage));
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, get_color_usage_bits(resolve_target, false, can_be_storage), RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);

// Create our depth buffer.
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, get_depth_format(resolve_target, false, can_be_storage), get_depth_usage_bits(resolve_target, false, can_be_storage));
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, get_depth_format(resolve_target, false, can_be_storage), get_depth_usage_bits(resolve_target, false, can_be_storage), RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);

// Create our MSAA buffers.
if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2941,6 +2941,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_VRS_DISABLED);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_TEXTURE);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR_DYNAMIC);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_MAX);

BIND_ENUM_CONSTANT(VIEWPORT_VRS_UPDATE_DISABLED);
Expand Down
3 changes: 2 additions & 1 deletion servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,7 @@ class RenderingServer : public Object {
VIEWPORT_VRS_DISABLED,
VIEWPORT_VRS_TEXTURE,
VIEWPORT_VRS_XR,
VIEWPORT_VRS_XR_DYNAMIC,
VIEWPORT_VRS_MAX,
};

Expand Down Expand Up @@ -1761,7 +1762,7 @@ class RenderingServer : public Object {

#ifndef DISABLE_DEPRECATED
// Never actually used, should be removed when we can break compatibility.
enum Features {
enum Features{
FEATURE_SHADERS,
FEATURE_MULTITHREADED,
};
Expand Down
13 changes: 13 additions & 0 deletions servers/xr/xr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,19 @@ int XRInterface::get_camera_feed_id() {
return 0;
}

PackedVector2Array XRInterface::get_vrs_eye_foci(float p_aspect) {
PackedVector2Array eye_foci;

for (uint32_t v = 0; v < get_view_count(); v++) {
Projection cm = get_projection_for_view(v, p_aspect, 0.1, 1000.0);
Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0));

eye_foci.push_back(Vector2(center.x, center.y));
}

return eye_foci;
}

RID XRInterface::get_vrs_texture() {
return RID();
}
Expand Down
1 change: 1 addition & 0 deletions servers/xr/xr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class XRInterface : public RefCounted {
virtual bool set_environment_blend_mode(EnvironmentBlendMode mode) { return false; }

/** VRS **/
virtual PackedVector2Array get_vrs_eye_foci(float p_aspect); /* obtain eye foci, used with VRS_XR_DYNAMIC */
virtual RID get_vrs_texture(); /* obtain VRS texture */

XRInterface();
Expand Down
9 changes: 9 additions & 0 deletions servers/xr/xr_interface_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,15 @@ Projection XRInterfaceExtension::get_projection_for_view(uint32_t p_view, double
return Projection();
}

PackedVector2Array XRInterfaceExtension::get_vrs_eye_foci(float p_aspect) {
PackedVector2Array vrs_eye_foci;
if (GDVIRTUAL_CALL(_get_vrs_eye_foci, p_aspect, vrs_eye_foci)) {
return vrs_eye_foci;
} else {
return XRInterface::get_vrs_eye_foci(p_aspect);
}
}

RID XRInterfaceExtension::get_vrs_texture() {
RID vrs_texture;
if (GDVIRTUAL_CALL(_get_vrs_texture, vrs_texture)) {
Expand Down
Loading

0 comments on commit f1dc20a

Please sign in to comment.