diff options
Diffstat (limited to 'servers')
-rw-r--r-- | servers/register_server_types.cpp | 1 | ||||
-rw-r--r-- | servers/rendering/dummy/storage/texture_storage.h | 2 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/effects/vrs.cpp | 22 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/effects/vrs.h | 7 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/effects/vrs.glsl | 46 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/texture_storage.cpp | 14 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/texture_storage.h | 3 | ||||
-rw-r--r-- | servers/rendering/renderer_viewport.cpp | 7 | ||||
-rw-r--r-- | servers/rendering/renderer_viewport.h | 1 | ||||
-rw-r--r-- | servers/rendering/rendering_device_commons.h | 2 | ||||
-rw-r--r-- | servers/rendering/rendering_server_default.h | 1 | ||||
-rw-r--r-- | servers/rendering/storage/texture_storage.h | 2 | ||||
-rw-r--r-- | servers/rendering_server.cpp | 8 | ||||
-rw-r--r-- | servers/rendering_server.h | 9 | ||||
-rw-r--r-- | servers/xr/xr_interface.cpp | 83 | ||||
-rw-r--r-- | servers/xr/xr_interface.h | 13 | ||||
-rw-r--r-- | servers/xr/xr_vrs.cpp | 151 | ||||
-rw-r--r-- | servers/xr/xr_vrs.h | 67 |
18 files changed, 327 insertions, 112 deletions
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 1a75614a4c..7a15d202a3 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -325,6 +325,7 @@ void register_server_types() { PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); GDREGISTER_ABSTRACT_CLASS(XRInterface); + GDREGISTER_CLASS(XRVRS); GDREGISTER_CLASS(XRBodyTracker); GDREGISTER_CLASS(XRControllerTracker); GDREGISTER_CLASS(XRFaceTracker); diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 1331ca72c2..43572b65e0 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -193,6 +193,8 @@ public: virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {} virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; } + virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) override {} + virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_UPDATE_DISABLED; } virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {} virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); } diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp index 30c318fb9a..94453bf95f 100644 --- a/servers/rendering/renderer_rd/effects/vrs.cpp +++ b/servers/rendering/renderer_rd/effects/vrs.cpp @@ -80,7 +80,16 @@ 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 })); - VRSMode mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT; + 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; + } else { + push_constant.max_texel_factor = 2.0; + } RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode); ERR_FAIL_COND(shader.is_null()); @@ -88,7 +97,7 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>()); 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_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); - // RD::get_singleton()->draw_list_set_push_constant(draw_list, &vrs_shader.push_constant, sizeof(VRSPushConstant)); + 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(); } @@ -111,12 +120,11 @@ Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const { void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) { TextureStorage *texture_storage = TextureStorage::get_singleton(); 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); - if (vrs_mode != RS::VIEWPORT_VRS_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"); - // TODO figure out if image has changed since it was last copied so we can save some resources.. - if (vrs_mode == RS::VIEWPORT_VRS_TEXTURE) { RID vrs_texture = texture_storage->render_target_get_vrs_texture(p_render_target); if (vrs_texture.is_valid()) { @@ -145,6 +153,10 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) { #endif // _3D_DISABLED } + if (vrs_update_mode == RS::VIEWPORT_VRS_UPDATE_ONCE) { + texture_storage->render_target_set_vrs_update_mode(p_render_target, RS::VIEWPORT_VRS_UPDATE_DISABLED); + } + RD::get_singleton()->draw_command_end_label(); } } diff --git a/servers/rendering/renderer_rd/effects/vrs.h b/servers/rendering/renderer_rd/effects/vrs.h index b18cf55791..94878e4661 100644 --- a/servers/rendering/renderer_rd/effects/vrs.h +++ b/servers/rendering/renderer_rd/effects/vrs.h @@ -47,11 +47,12 @@ private: VRS_MAX, }; - /* we have no push constant here (yet) struct VRSPushConstant { - + float max_texel_factor; // 4x8, 8x4 and 8x8 are only available on some GPUs. + float res1; + float res2; + float res3; }; - */ struct VRSShader { // VRSPushConstant push_constant; diff --git a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl index 23b0373eef..7ed3fa3348 100644 --- a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl @@ -19,6 +19,14 @@ layout(location = 0) out vec3 uv_interp; layout(location = 0) out vec2 uv_interp; #endif +layout(push_constant, std430) uniform Params { + float max_texel_factor; + float res1; + float res2; + float res3; +} +params; + void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); @@ -53,6 +61,14 @@ layout(set = 0, binding = 0) uniform sampler2D source_color; layout(location = 0) out uint frag_color; +layout(push_constant, std430) uniform Params { + float max_texel_factor; + float res1; + float res2; + float res3; +} +params; + void main() { #ifdef USE_MULTIVIEW vec3 uv = uv_interp; @@ -60,20 +76,22 @@ void main() { vec2 uv = uv_interp; #endif -#ifdef USE_MULTIVIEW + // Input is standardised. 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); - frag_color = uint(color.r * 255.0); -#else /* USE_MULTIVIEW */ - vec4 color = textureLod(source_color, uv, 0.0); - - // for user supplied VRS map we do a color mapping - color.r *= 3.0; - frag_color = int(color.r) << 2; - color.g *= 3.0; - frag_color += int(color.g); - - // note 1x4, 4x1, 1x8, 8x1, 2x8 and 8x2 are not supported - // 4x8, 8x4 and 8x8 are only available on some GPUs -#endif /* USE_MULTIVIEW */ + // 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); + + // Note 1x4, 4x1, 1x8, 8x1, 2x8 and 8x2 are not supported: + if (color.r < (color.g - 1.0)) { + color.r = color.g - 1.0; + } + if (color.g < (color.r - 1.0)) { + color.g = color.r - 1.0; + } + + // Encode to frag_color; + frag_color = int(color.r + 0.1) << 2; + frag_color += int(color.g + 0.1); } diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 76ff566b18..f844919df1 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -3960,6 +3960,20 @@ RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_targ return rt->vrs_mode; } +void TextureStorage::render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL(rt); + + rt->vrs_update_mode = p_mode; +} + +RS::ViewportVRSUpdateMode TextureStorage::render_target_get_vrs_update_mode(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL_V(rt, RS::VIEWPORT_VRS_UPDATE_DISABLED); + + return rt->vrs_update_mode; +} + void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 1304b284d5..704f5fb1bd 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -366,6 +366,7 @@ private: // VRS RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED; + RS::ViewportVRSUpdateMode vrs_update_mode = RS::VIEWPORT_VRS_UPDATE_ONCE; RID vrs_texture; // overridden textures @@ -746,6 +747,8 @@ public: virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override; virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override; + virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) override; + virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const override; virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override; virtual RID render_target_get_vrs_texture(RID p_render_target) const override; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 31d5a9074c..075df10e05 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1450,6 +1450,13 @@ void RendererViewport::viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode _configure_3d_render_buffers(viewport); } +void RendererViewport::viewport_set_vrs_update_mode(RID p_viewport, RS::ViewportVRSUpdateMode p_mode) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_NULL(viewport); + + RSG::texture_storage->render_target_set_vrs_update_mode(viewport->render_target, p_mode); +} + void RendererViewport::viewport_set_vrs_texture(RID p_viewport, RID p_texture) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_NULL(viewport); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 5107398c54..8bdce04c50 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -298,6 +298,7 @@ public: virtual RID viewport_find_from_screen_attachment(DisplayServer::WindowID p_id = DisplayServer::MAIN_WINDOW_ID) const; void viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode); + void viewport_set_vrs_update_mode(RID p_viewport, RS::ViewportVRSUpdateMode p_mode); void viewport_set_vrs_texture(RID p_viewport, RID p_texture); void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time); diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 28d641c879..918bf9b834 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -810,6 +810,8 @@ public: LIMIT_SUBGROUP_OPERATIONS, LIMIT_VRS_TEXEL_WIDTH, LIMIT_VRS_TEXEL_HEIGHT, + LIMIT_VRS_MAX_FRAGMENT_WIDTH, + LIMIT_VRS_MAX_FRAGMENT_HEIGHT, }; enum Features { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index e0049e3fa4..bb2f3d94ce 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -672,6 +672,7 @@ public: FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID) FUNC2(viewport_set_vrs_mode, RID, ViewportVRSMode) + FUNC2(viewport_set_vrs_update_mode, RID, ViewportVRSUpdateMode) FUNC2(viewport_set_vrs_texture, RID, RID) /* COMPOSITOR EFFECT */ diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index cf37fbfb4a..72c4dd305b 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -169,6 +169,8 @@ public: virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) = 0; virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const = 0; + virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) = 0; + virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const = 0; virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) = 0; virtual RID render_target_get_vrs_texture(RID p_render_target) const = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 60e8f18c19..ab82e42f43 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2824,6 +2824,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); ClassDB::bind_method(D_METHOD("viewport_set_vrs_mode", "viewport", "mode"), &RenderingServer::viewport_set_vrs_mode); + ClassDB::bind_method(D_METHOD("viewport_set_vrs_update_mode", "viewport", "mode"), &RenderingServer::viewport_set_vrs_update_mode); ClassDB::bind_method(D_METHOD("viewport_set_vrs_texture", "viewport", "texture"), &RenderingServer::viewport_set_vrs_texture); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); @@ -2832,7 +2833,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); - BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); // Then goes to disabled); must be manually updated. + BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); // Then goes to disabled, must be manually updated. BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); // Default BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS); @@ -2914,6 +2915,11 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR); BIND_ENUM_CONSTANT(VIEWPORT_VRS_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_UPDATE_DISABLED); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_UPDATE_ONCE); // Then goes to disabled, must be manually updated. + BIND_ENUM_CONSTANT(VIEWPORT_VRS_UPDATE_ALWAYS); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_UPDATE_MAX); + /* SKY API */ ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 240d82c90b..5bc028dfdd 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1056,7 +1056,15 @@ public: VIEWPORT_VRS_MAX, }; + enum ViewportVRSUpdateMode { + VIEWPORT_VRS_UPDATE_DISABLED, + VIEWPORT_VRS_UPDATE_ONCE, + VIEWPORT_VRS_UPDATE_ALWAYS, + VIEWPORT_VRS_UPDATE_MAX, + }; + virtual void viewport_set_vrs_mode(RID p_viewport, ViewportVRSMode p_mode) = 0; + virtual void viewport_set_vrs_update_mode(RID p_viewport, ViewportVRSUpdateMode p_mode) = 0; virtual void viewport_set_vrs_texture(RID p_viewport, RID p_texture) = 0; /* SKY API */ @@ -1815,6 +1823,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale); VARIANT_ENUM_CAST(RenderingServer::ViewportVRSMode); +VARIANT_ENUM_CAST(RenderingServer::ViewportVRSUpdateMode); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::CompositorEffectCallbackType); VARIANT_ENUM_CAST(RenderingServer::CompositorEffectFlags); diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 9ced28fd52..26f315a454 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -132,13 +132,7 @@ void XRInterface::set_primary(bool p_primary) { XRInterface::XRInterface() {} -XRInterface::~XRInterface() { - if (vrs.vrs_texture.is_valid()) { - ERR_FAIL_NULL(RenderingServer::get_singleton()); - RS::get_singleton()->free(vrs.vrs_texture); - vrs.vrs_texture = RID(); - } -} +XRInterface::~XRInterface() {} // query if this interface supports this play area mode bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { @@ -176,80 +170,7 @@ int XRInterface::get_camera_feed_id() { } RID XRInterface::get_vrs_texture() { - // Default logic will return a standard VRS image based on our target size and default projections. - // Note that this only gets called if VRS is supported on the hardware. - - 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); - int view_count = get_view_count(); - Size2 target_size = get_render_target_size(); - real_t aspect = target_size.x / target_size.y; // is this y/x ? - Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_width), round(0.5 + target_size.y / texel_height)); - real_t radius = vrs_size.length() * 0.5; - Size2 vrs_sizei = vrs_size; - - if (vrs.size != vrs_sizei) { - const uint8_t densities[] = { - 0, // 1x1 - 1, // 1x2 - // 2, // 1x4 - not supported - // 3, // 1x8 - not supported - // 4, // 2x1 - 5, // 2x2 - 6, // 2x4 - // 9, // 4x2 - 10, // 4x4 - }; - - // out with the old - if (vrs.vrs_texture.is_valid()) { - RS::get_singleton()->free(vrs.vrs_texture); - vrs.vrs_texture = RID(); - } - - // in with the new - Vector<Ref<Image>> images; - vrs.size = vrs_sizei; - - for (int i = 0; i < view_count && i < 2; i++) { - PackedByteArray data; - data.resize(vrs_sizei.x * vrs_sizei.y); - uint8_t *data_ptr = data.ptrw(); - - // Our near and far don't matter much for what we're doing here, but there are some interfaces that will remember this as the near and far and may fail as a result... - Projection cm = get_projection_for_view(i, aspect, 0.1, 1000.0); - Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0)); - - Vector2i view_center; - view_center.x = int(vrs_size.x * (center.x + 1.0) * 0.5); - view_center.y = int(vrs_size.y * (center.y + 1.0) * 0.5); - - int d = 0; - for (int y = 0; y < vrs_sizei.y; y++) { - for (int x = 0; x < vrs_sizei.x; x++) { - Vector2 offset = Vector2(x - view_center.x, y - view_center.y); - offset.y *= aspect; - real_t distance = offset.length(); - int idx = round(5.0 * distance / radius); - if (idx > 4) { - idx = 4; - } - uint8_t density = densities[idx]; - - data_ptr[d++] = density; - } - } - images.push_back(Image::create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_R8, data)); - } - - if (images.size() == 1) { - vrs.vrs_texture = RS::get_singleton()->texture_2d_create(images[0]); - } else { - vrs.vrs_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TEXTURE_LAYERED_2D_ARRAY); - } - } - - return vrs.vrs_texture; + return RID(); } /** these are optional, so we want dummies **/ diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 809800d8b9..7beec219bb 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -34,6 +34,7 @@ #include "core/math/projection.h" #include "core/os/thread_safe.h" #include "servers/xr_server.h" +#include "xr_vrs.h" // forward declaration struct BlitToScreen; @@ -133,7 +134,6 @@ public: // These methods are called from the rendering thread. virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */ virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */ - virtual RID get_vrs_texture(); /* obtain VRS texture */ virtual RID get_color_texture(); /* obtain color output texture (if applicable) */ virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */ virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */ @@ -149,19 +149,16 @@ public: virtual bool start_passthrough() { return false; } virtual void stop_passthrough() {} - /** environment blend mode. */ + /** environment blend mode **/ virtual Array get_supported_environment_blend_modes(); virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const { return XR_ENV_BLEND_MODE_OPAQUE; } virtual bool set_environment_blend_mode(EnvironmentBlendMode mode) { return false; } + /** VRS **/ + virtual RID get_vrs_texture(); /* obtain VRS texture */ + XRInterface(); ~XRInterface(); - -private: - struct VRSData { - RID vrs_texture; - Size2i size; - } vrs; }; VARIANT_ENUM_CAST(XRInterface::Capabilities); diff --git a/servers/xr/xr_vrs.cpp b/servers/xr/xr_vrs.cpp new file mode 100644 index 0000000000..9d1e2f2068 --- /dev/null +++ b/servers/xr/xr_vrs.cpp @@ -0,0 +1,151 @@ +/**************************************************************************/ +/* xr_vrs.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "xr_vrs.h" + +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering_server.h" + +void XRVRS::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &XRVRS::get_vrs_min_radius); + ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &XRVRS::set_vrs_min_radius); + + ClassDB::bind_method(D_METHOD("get_vrs_strength"), &XRVRS::get_vrs_strength); + ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &XRVRS::set_vrs_strength); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); + + ClassDB::bind_method(D_METHOD("make_vrs_texture", "target_size", "eye_foci"), &XRVRS::make_vrs_texture); +} + +XRVRS::~XRVRS() { + if (vrs_texture.is_valid()) { + ERR_FAIL_NULL(RS::get_singleton()); + RS::get_singleton()->free(vrs_texture); + vrs_texture = RID(); + } +} + +float XRVRS::get_vrs_min_radius() const { + return vrs_min_radius; +} + +void XRVRS::set_vrs_min_radius(float p_vrs_min_radius) { + if (p_vrs_min_radius < 1.0) { + WARN_PRINT_ONCE("VRS minimum radius can not be set below 1.0"); + vrs_min_radius = 1.0; + } else if (p_vrs_min_radius > 100.0) { + WARN_PRINT_ONCE("VRS minimum radius can not be set above 100.0"); + vrs_min_radius = 100.0; + } else { + vrs_min_radius = p_vrs_min_radius; + vrs_dirty = true; + } +} + +float XRVRS::get_vrs_strength() const { + return vrs_strength; +} + +void XRVRS::set_vrs_strength(float p_vrs_strength) { + if (p_vrs_strength < 0.1) { + WARN_PRINT_ONCE("VRS strength can not be set below 0.1"); + vrs_strength = 0.1; + } else if (p_vrs_strength > 10.0) { + WARN_PRINT_ONCE("VRS strength can not be set above 10.0"); + vrs_strength = 10.0; + } else { + vrs_strength = p_vrs_strength; + vrs_dirty = true; + } +} + +RID XRVRS::make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array &p_eye_foci) { + ERR_FAIL_COND_V(p_eye_foci.is_empty(), RID()); + + 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); + + Size2 vrs_size = Size2(0.5 + p_target_size.x / texel_width, 0.5 + p_target_size.y / texel_height).round(); + float max_radius = 0.5 * MIN(vrs_size.x, vrs_size.y); // Maximum radius that fits inside of our image + float min_radius = vrs_min_radius * max_radius / 100.0; // Minimum radius as a percentage of our size + real_t outer_radius = MAX(1.0, (max_radius - min_radius) / vrs_strength); + Size2 vrs_sizei = vrs_size; + + // Our density map is now unified, with a value of (0.0, 0.0) meaning a 1x1 texel size and (1.0, 1.0) an max texel size. + // For our standard VRS extension on Vulkan this means a maximum of 8x8. + // For the density map extension this scales depending on the max texel size. + + if (target_size != vrs_sizei || eye_foci != p_eye_foci || vrs_dirty) { + // Out with the old. + if (vrs_texture.is_valid()) { + RS::get_singleton()->free(vrs_texture); + vrs_texture = RID(); + } + + // In with the new. + Vector<Ref<Image>> images; + target_size = vrs_sizei; + eye_foci = p_eye_foci; + + for (int i = 0; i < eye_foci.size() && i < RendererSceneRender::MAX_RENDER_VIEWS; i++) { + PackedByteArray data; + data.resize(vrs_sizei.x * vrs_sizei.y * 2); + uint8_t *data_ptr = data.ptrw(); + + Vector2i view_center; + view_center.x = int(vrs_size.x * (eye_foci[i].x + 1.0) * 0.5); + view_center.y = int(vrs_size.y * (eye_foci[i].y + 1.0) * 0.5); + + int d = 0; + for (int y = 0; y < vrs_sizei.y; y++) { + for (int x = 0; x < vrs_sizei.x; x++) { + Vector2 offset = Vector2(x - view_center.x, y - view_center.y); + real_t density = 255.0 * MAX(0.0, (Math::abs(offset.x) - min_radius) / outer_radius); + data_ptr[d++] = MIN(255, density); + density = 255.0 * MAX(0.0, (Math::abs(offset.y) - min_radius) / outer_radius); + data_ptr[d++] = MIN(255, density); + } + } + images.push_back(Image::create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_RG8, data)); + } + + if (images.size() == 1) { + vrs_texture = RS::get_singleton()->texture_2d_create(images[0]); + } else { + vrs_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TEXTURE_LAYERED_2D_ARRAY); + } + + vrs_dirty = false; + } + + return vrs_texture; +} diff --git a/servers/xr/xr_vrs.h b/servers/xr/xr_vrs.h new file mode 100644 index 0000000000..35dfe55620 --- /dev/null +++ b/servers/xr/xr_vrs.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* xr_vrs.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef XR_VRS_H +#define XR_VRS_H + +#include "core/object/class_db.h" +#include "core/object/object.h" +#include "core/templates/rid.h" +#include "core/variant/variant.h" + +/* This is a helper class for generating stereoscopic VRS images */ + +class XRVRS : public Object { + GDCLASS(XRVRS, Object); + +private: + float vrs_min_radius = 20.0; + float vrs_strength = 1.0; + bool vrs_dirty = true; + + RID vrs_texture; + Size2i target_size; + PackedVector2Array eye_foci; + +protected: + static void _bind_methods(); + +public: + ~XRVRS(); + + float get_vrs_min_radius() const; + void set_vrs_min_radius(float p_vrs_min_radius); + float get_vrs_strength() const; + void set_vrs_strength(float p_vrs_strength); + + RID make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array &p_eye_foci); +}; + +#endif // XR_VRS_H |