Adding Variable Rate Shading support to Godot

Improve GI renderer and add VRS support
Implement render device has_feature and move subgroup settings to limit_get
This commit is contained in:
Bastiaan Olij 2022-02-11 22:33:54 +11:00
parent e3a8ab68ce
commit d139131aab
44 changed files with 1574 additions and 466 deletions

View File

@ -1968,6 +1968,12 @@
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm. This algorithm is only supported on desktop platforms and consoles.
[b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor (see [member application/config/use_hidden_project_data_directory]).
</member>
<member name="rendering/vrs/mode" type="int" setter="" getter="" default="0">
Set the default Variable Rate Shading (VRS) mode for the main viewport. See [member Viewport.vrs_mode] to change this at runtime, and [enum Viewport.VRSMode] for possible values.
</member>
<member name="rendering/vrs/texture" type="String" setter="" getter="" default="&quot;&quot;">
If [member rendering/vrs/mode] is set to texture, this is the path to default texture loaded as the VRS image.
</member>
<member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
</member>
<member name="rendering/vulkan/rendering/back_end" type="int" setter="" getter="" default="0">

View File

@ -395,7 +395,7 @@
<description>
</description>
</method>
<method name="limit_get">
<method name="limit_get" qualifiers="const">
<return type="int" />
<argument index="0" name="limit" type="int" enum="RenderingDevice.Limit" />
<description>

View File

@ -3357,6 +3357,22 @@
If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [XRInterface].
</description>
</method>
<method name="viewport_set_vrs_mode">
<return type="void" />
<argument index="0" name="viewport" type="RID" />
<argument index="1" name="mode" type="int" enum="RenderingServer.ViewportVRSMode" />
<description>
Sets the Variable Rate Shading (VRS) mode for the viewport. Note, if hardware does not support VRS this property is ignored.
</description>
</method>
<method name="viewport_set_vrs_texture">
<return type="void" />
<argument index="0" name="viewport" type="RID" />
<argument index="1" name="texture" type="RID" />
<description>
Texture to use when the VRS mode is set to [constant RenderingServer.VIEWPORT_VRS_TEXTURE].
</description>
</method>
<method name="visibility_notifier_create">
<return type="RID" />
<description>
@ -4116,6 +4132,18 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_MOTION_VECTORS" value="25" enum="ViewportDebugDraw">
</constant>
<constant name="VIEWPORT_VRS_DISABLED" value="0" enum="ViewportVRSMode">
VRS is disabled.
</constant>
<constant name="VIEWPORT_VRS_TEXTURE" value="1" enum="ViewportVRSMode">
VRS uses a texture. Note, for stereoscopic use a texture atlas with a texture for each view.
</constant>
<constant name="VIEWPORT_VRS_XR" value="2" enum="ViewportVRSMode">
VRS texture is supplied by the primary [XRInterface].
</constant>
<constant name="VIEWPORT_VRS_MAX" value="3" enum="ViewportVRSMode">
Represents the size of the [enum ViewportVRSMode] enum.
</constant>
<constant name="SKY_MODE_AUTOMATIC" value="0" enum="SkyMode">
</constant>
<constant name="SKY_MODE_QUALITY" value="1" enum="SkyMode">

View File

@ -286,6 +286,12 @@
<member name="use_xr" type="bool" setter="set_use_xr" getter="is_using_xr" default="false">
If [code]true[/code], the viewport will use the primary XR interface to render XR output. When applicable this can result in a stereoscopic image and the resulting render being output to a headset.
</member>
<member name="vrs_mode" type="int" setter="set_vrs_mode" getter="get_vrs_mode" enum="Viewport.VRSMode" default="0">
The Variable Rate Shading (VRS) mode that is used for this viewport. Note, if hardware does not support VRS this property is ignored.
</member>
<member name="vrs_texture" type="Texture2D" setter="set_vrs_texture" getter="get_vrs_texture">
Texture to use when [member vrs_mode] is set to [constant Viewport.VRS_TEXTURE].
</member>
<member name="world_2d" type="World2D" setter="set_world_2d" getter="get_world_2d">
The custom [World2D] which can be used as 2D environment source.
</member>
@ -492,5 +498,17 @@
</constant>
<constant name="SDF_SCALE_MAX" value="3" enum="SDFScale">
</constant>
<constant name="VRS_DISABLED" value="0" enum="VRSMode">
VRS is disabled.
</constant>
<constant name="VRS_TEXTURE" value="1" enum="VRSMode">
VRS uses a texture. Note, for stereoscopic use a texture atlas with a texture for each view.
</constant>
<constant name="VRS_XR" value="2" enum="VRSMode">
VRS texture is supplied by the primary [XRInterface].
</constant>
<constant name="VRS_MAX" value="3" enum="VRSMode">
Represents the size of the [enum VRSMode] enum.
</constant>
</constants>
</class>

View File

@ -106,6 +106,11 @@
Returns the number of views this interface requires, 1 for mono, 2 for stereoscopic.
</description>
</method>
<method name="_get_vrs_texture" qualifiers="virtual">
<return type="RID" />
<description>
</description>
</method>
<method name="_initialize" qualifiers="virtual">
<return type="bool" />
<description>

View File

@ -546,6 +546,16 @@ public:
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region);
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{};
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{};
void bind_framebuffer(GLuint framebuffer) {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
}
void bind_framebuffer_system() {
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
}
String get_framebuffer_error(GLenum p_status);
};

View File

@ -106,7 +106,7 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
return buffer;
}
static void update_external_dependency_for_store(VkSubpassDependency &dependency, bool is_sampled, bool is_storage, bool is_depth) {
static void update_external_dependency_for_store(VkSubpassDependency2KHR &dependency, bool is_sampled, bool is_storage, bool is_depth) {
// Transitioning from write to read, protect the shaders that may use this next
// Allow for copies/image layout transitions
dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
@ -1758,6 +1758,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
}
if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
@ -3362,17 +3366,24 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; // From Section 7.1 of Vulkan API Spec v1.1.148
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
VkSubpassDependency dependencies[2] = { { VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0 },
{ 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0 } };
VkSubpassDependency &dependency_from_external = dependencies[0];
VkSubpassDependency &dependency_to_external = dependencies[1];
VkSubpassDependency2KHR dependencies[2] = {
{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0, 0 },
{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0, 0 }
};
VkSubpassDependency2KHR &dependency_from_external = dependencies[0];
VkSubpassDependency2KHR &dependency_to_external = dependencies[1];
LocalVector<int32_t> attachment_last_pass;
attachment_last_pass.resize(p_attachments.size());
Vector<VkAttachmentDescription> attachments;
// These are only used if we use multiview but we need to define them in scope.
const uint32_t view_mask = (1 << p_view_count) - 1;
const uint32_t correlation_mask = (1 << p_view_count) - 1;
Vector<VkAttachmentDescription2KHR> attachments;
Vector<int> attachment_remap;
for (int i = 0; i < p_attachments.size(); i++) {
@ -3383,10 +3394,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE);
ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE);
ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)),
ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)),
VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set.");
VkAttachmentDescription description = {};
VkAttachmentDescription2KHR description = {};
description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
description.pNext = nullptr;
description.flags = 0;
description.format = vulkan_formats[p_attachments[i].format];
description.samples = rasterization_sample_count[p_attachments[i].samples];
@ -3395,6 +3408,17 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
// We can setup a framebuffer where we write to our VRS texture to set it up.
// We make the assumption here that if our texture is actually used as our VRS attachment,
// it is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
if (is_vrs) {
// For VRS we only read, there is no writing to this texture
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
} else {
// For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write
// Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs.
// the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
@ -3474,6 +3498,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
}
}
}
bool used_last = false;
@ -3485,6 +3510,10 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
if (p_passes[last_pass].depth_attachment == i) {
used_last = true;
}
} else if (is_vrs) {
if (p_passes[last_pass].vrs_attachment == i) {
used_last = true;
}
} else {
if (p_passes[last_pass].resolve_attachments.size()) {
//if using resolve attachments, check resolve attachments
@ -3526,6 +3555,16 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
}
if (is_vrs) {
// We don't change our VRS texture during this process
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// TODO do we need to update our external dependency ?
// update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
} else {
switch (is_depth ? final_depth_action : final_action) {
case FINAL_ACTION_READ: {
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
@ -3555,9 +3594,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
}
} break;
case FINAL_ACTION_CONTINUE: {
@ -3570,9 +3609,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
}
} break;
@ -3580,18 +3619,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
}
}
}
attachment_last_pass[i] = -1;
attachment_remap.push_back(attachments.size());
attachments.push_back(description);
}
LocalVector<VkSubpassDescription> subpasses;
LocalVector<LocalVector<VkAttachmentReference>> color_reference_array;
LocalVector<LocalVector<VkAttachmentReference>> input_reference_array;
LocalVector<LocalVector<VkAttachmentReference>> resolve_reference_array;
LocalVector<VkSubpassDescription2KHR> subpasses;
LocalVector<LocalVector<VkAttachmentReference2KHR>> color_reference_array;
LocalVector<LocalVector<VkAttachmentReference2KHR>> input_reference_array;
LocalVector<LocalVector<VkAttachmentReference2KHR>> resolve_reference_array;
LocalVector<LocalVector<uint32_t>> preserve_reference_array;
LocalVector<VkAttachmentReference> depth_reference_array;
LocalVector<VkAttachmentReference2KHR> depth_reference_array;
LocalVector<VkAttachmentReference2KHR> vrs_reference_array;
LocalVector<VkFragmentShadingRateAttachmentInfoKHR> vrs_attachment_info_array;
subpasses.resize(p_passes.size());
color_reference_array.resize(p_passes.size());
@ -3599,20 +3641,25 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
resolve_reference_array.resize(p_passes.size());
preserve_reference_array.resize(p_passes.size());
depth_reference_array.resize(p_passes.size());
vrs_reference_array.resize(p_passes.size());
vrs_attachment_info_array.resize(p_passes.size());
LocalVector<VkSubpassDependency> subpass_dependencies;
LocalVector<VkSubpassDependency2KHR> subpass_dependencies;
for (int i = 0; i < p_passes.size(); i++) {
const FramebufferPass *pass = &p_passes[i];
LocalVector<VkAttachmentReference> &color_references = color_reference_array[i];
LocalVector<VkAttachmentReference2KHR> &color_references = color_reference_array[i];
TextureSamples texture_samples = TEXTURE_SAMPLES_1;
bool is_multisample_first = true;
void *subpass_nextptr = nullptr;
for (int j = 0; j < pass->color_attachments.size(); j++) {
int32_t attachment = pass->color_attachments[j];
VkAttachmentReference reference;
VkAttachmentReference2KHR reference;
reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -3631,14 +3678,17 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_last_pass[attachment] = i;
}
reference.aspectMask = 0;
color_references.push_back(reference);
}
LocalVector<VkAttachmentReference> &input_references = input_reference_array[i];
LocalVector<VkAttachmentReference2KHR> &input_references = input_reference_array[i];
for (int j = 0; j < pass->input_attachments.size(); j++) {
int32_t attachment = pass->input_attachments[j];
VkAttachmentReference reference;
VkAttachmentReference2KHR reference;
reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -3650,10 +3700,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
reference.aspectMask = 0; // TODO we need to set this here, possibly VK_IMAGE_ASPECT_COLOR_BIT ??
input_references.push_back(reference);
}
LocalVector<VkAttachmentReference> &resolve_references = resolve_reference_array[i];
LocalVector<VkAttachmentReference2KHR> &resolve_references = resolve_reference_array[i];
if (pass->resolve_attachments.size() > 0) {
ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ").");
@ -3661,7 +3712,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
for (int j = 0; j < pass->resolve_attachments.size(); j++) {
int32_t attachment = pass->resolve_attachments[j];
VkAttachmentReference reference;
VkAttachmentReference2KHR reference;
reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -3676,10 +3729,13 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
reference.aspectMask = 0;
resolve_references.push_back(reference);
}
VkAttachmentReference &depth_stencil_reference = depth_reference_array[i];
VkAttachmentReference2KHR &depth_stencil_reference = depth_reference_array[i];
depth_stencil_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
depth_stencil_reference.pNext = nullptr;
if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
int32_t attachment = pass->depth_attachment;
@ -3688,6 +3744,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
depth_stencil_reference.attachment = attachment_remap[attachment];
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_stencil_reference.aspectMask = 0;
attachment_last_pass[attachment] = i;
if (is_multisample_first) {
@ -3702,6 +3759,32 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
int32_t attachment = pass->vrs_attachment;
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as vrs, but it's not a vrs attachment.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer vrs attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i];
vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
vrs_reference.pNext = nullptr;
vrs_reference.attachment = attachment_remap[attachment];
vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
vrs_reference.aspectMask = 0;
Size2i texel_size = context->get_vrs_capabilities().max_texel_size;
VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i];
vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
vrs_attachment_info.pNext = nullptr;
vrs_attachment_info.pFragmentShadingRateAttachment = &vrs_reference;
vrs_attachment_info.shadingRateAttachmentTexelSize = { uint32_t(texel_size.x), uint32_t(texel_size.y) };
attachment_last_pass[attachment] = i;
subpass_nextptr = &vrs_attachment_info;
}
LocalVector<uint32_t> &preserve_references = preserve_reference_array[i];
for (int j = 0; j < pass->preserve_attachments.size(); j++) {
@ -3718,9 +3801,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
}
VkSubpassDescription &subpass = subpasses[i];
VkSubpassDescription2KHR &subpass = subpasses[i];
subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
subpass.pNext = subpass_nextptr;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.viewMask = view_mask;
subpass.inputAttachmentCount = input_references.size();
if (input_references.size()) {
subpass.pInputAttachments = input_references.ptr();
@ -3757,7 +3843,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
if (i > 0) {
VkSubpassDependency dependency;
VkSubpassDependency2KHR dependency;
dependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
dependency.pNext = nullptr;
dependency.srcSubpass = i - 1;
dependency.dstSubpass = i;
dependency.srcStageMask = 0;
@ -3767,6 +3855,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependency.viewOffset = 0;
subpass_dependencies.push_back(dependency);
}
/*
@ -3784,10 +3873,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
*/
}
VkRenderPassCreateInfo render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
VkRenderPassCreateInfo2KHR render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = attachments.size();
render_pass_create_info.pAttachments = attachments.ptr();
render_pass_create_info.subpassCount = subpasses.size();
@ -3804,13 +3894,15 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
render_pass_create_info.pDependencies = nullptr;
}
// These are only used if we use multiview but we need to define them in scope.
const uint32_t view_mask = (1 << p_view_count) - 1;
const uint32_t correlation_mask = (1 << p_view_count) - 1;
render_pass_create_info.correlatedViewMaskCount = 1;
render_pass_create_info.pCorrelatedViewMasks = &correlation_mask;
Vector<uint32_t> view_masks;
VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
if (p_view_count > 1) {
// this may no longer be needed with the new settings already including this
const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
// For now this only works with multiview!
@ -3837,8 +3929,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
VkRenderPass render_pass;
VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + ".");
VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass2KHR failed with error " + itos(res) + ".");
return render_pass;
}
@ -3899,7 +3991,9 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
return E->get();
}
VkSubpassDescription subpass;
VkSubpassDescription2KHR subpass;
subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
subpass.pNext = nullptr;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = 0; //unsupported for now
@ -3911,8 +4005,8 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
VkRenderPassCreateInfo render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
VkRenderPassCreateInfo2KHR render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = 0;
@ -3923,9 +4017,9 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
render_pass_create_info.pDependencies = nullptr;
VkRenderPass render_pass;
VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass for empty fb failed with error " + itos(res) + ".");
ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + ".");
if (render_pass == VK_NULL_HANDLE) { //was likely invalid
return INVALID_ID;
@ -3978,6 +4072,8 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
pass.depth_attachment = i;
} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
pass.vrs_attachment = i;
} else {
pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
}
@ -4008,6 +4104,10 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
size.width = texture->width;
size.height = texture->height;
size_set = true;
} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
// If this is not the first attachement we assume this is used as the VRS attachment
// in this case this texture will be 1/16th the size of the color attachement.
// So we skip the size check
} else {
ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
"All textures in a framebuffer should be the same size.");
@ -6552,11 +6652,28 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
dynamic_state_create_info.dynamicStateCount = dynamic_states.size();
dynamic_state_create_info.pDynamicStates = dynamic_states.ptr();
void *graphics_pipeline_nextptr = nullptr;
VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info;
if (context->get_vrs_capabilities().attachment_vrs_supported) {
// If VRS is used, this defines how the different VRS types are combined.
// combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS
// combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS
vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR;
vrs_create_info.pNext = nullptr;
vrs_create_info.fragmentSize = { 4, 4 };
vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter
vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // always use the outcome of attachment VRS if enabled
graphics_pipeline_nextptr = &vrs_create_info;
}
//finally, pipeline create info
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info;
graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
graphics_pipeline_create_info.pNext = nullptr;
graphics_pipeline_create_info.pNext = graphics_pipeline_nextptr;
graphics_pipeline_create_info.flags = 0;
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages;
@ -6721,7 +6838,7 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
if (psc.constant_id == sc.constant.constant_id) {
ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
data_ptr[i] = sc.constant.int_value;
data_ptr[i] = psc.int_value;
break;
}
}
@ -6905,10 +7022,12 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
if (texture) {
attachments.push_back(texture->view);
if (!(texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) { // VRS attachment will be a different size.
ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG);
ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG);
}
}
}
framebuffer_create_info.attachmentCount = attachments.size();
framebuffer_create_info.pAttachments = attachments.ptr();
framebuffer_create_info.width = p_framebuffer->size.width;
@ -7134,7 +7253,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
// We only check for our VRS usage bit if this is not the first texture id.
// If it is the first we're likely populating our VRS texture.
// Bit dirty but..
if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) {
color_count++;
}
}
@ -8995,17 +9117,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
{
device_capabilities.version_major = p_context->get_vulkan_major();
device_capabilities.version_minor = p_context->get_vulkan_minor();
// get info about subgroups
VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
device_capabilities.subgroup_size = subgroup_capabilities.size;
device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
// get info about further features
VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
device_capabilities.supports_fsr_half_float = p_context->get_shader_capabilities().shader_float16_is_supported && p_context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
}
context = p_context;
@ -9354,7 +9465,7 @@ String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) cons
return frames[frame].timestamp_result_names[p_index];
}
uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) {
uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
switch (p_limit) {
case LIMIT_MAX_BOUND_UNIFORM_SETS:
return limits.maxBoundDescriptorSets;
@ -9424,7 +9535,18 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) {
return limits.maxComputeWorkGroupSize[1];
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
return limits.maxComputeWorkGroupSize[2];
case LIMIT_SUBGROUP_SIZE: {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.size;
}
case LIMIT_SUBGROUP_IN_SHADERS: {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.supported_stages_flags_rd();
}
case LIMIT_SUBGROUP_OPERATIONS: {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.supported_operations_flags_rd();
}
default:
ERR_FAIL_V(0);
}
@ -9524,6 +9646,25 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
return rd;
}
bool RenderingDeviceVulkan::has_feature(const Features p_feature) const {
switch (p_feature) {
case SUPPORTS_MULTIVIEW: {
VulkanContext::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities();
return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
} break;
case SUPPORTS_FSR_HALF_FLOAT: {
return context->get_shader_capabilities().shader_float16_is_supported && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
} break;
case SUPPORTS_ATTACHMENT_VRS: {
VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
return vrs_capabilities.attachment_vrs_supported;
} break;
default: {
return false;
}
}
}
RenderingDeviceVulkan::RenderingDeviceVulkan() {
device_capabilities.device_family = DEVICE_VULKAN;
}

View File

@ -241,6 +241,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Vector<AttachmentFormat> attachments;
Vector<FramebufferPass> passes;
uint32_t view_count = 1;
bool operator<(const FramebufferFormatKey &p_key) const {
if (view_count != p_key.view_count) {
return view_count < p_key.view_count;
@ -1203,7 +1204,7 @@ public:
/**** Limits ****/
/****************/
virtual uint64_t limit_get(Limit p_limit);
virtual uint64_t limit_get(Limit p_limit) const;
virtual void prepare_screen_for_drawing();
void initialize(VulkanContext *p_context, bool p_local_device = false);
@ -1234,6 +1235,8 @@ public:
virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
virtual bool has_feature(const Features p_feature) const;
RenderingDeviceVulkan();
~RenderingDeviceVulkan();
};

View File

@ -48,6 +48,18 @@
VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
if (fpCreateRenderPass2KHR == nullptr) {
fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetInstanceProcAddr(inst, "vkCreateRenderPass2KHR");
}
if (fpCreateRenderPass2KHR == nullptr) {
return VK_ERROR_EXTENSION_NOT_PRESENT;
} else {
return (fpCreateRenderPass2KHR)(device, pCreateInfo, pAllocator, pRenderPass);
}
}
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
@ -507,6 +519,9 @@ Error VulkanContext::_check_capabilities() {
// (note that the desktop loader does a better job here but the android loader doesn't)
// assume not supported until proven otherwise
vrs_capabilities.pipeline_vrs_supported = false;
vrs_capabilities.primitive_vrs_supported = false;
vrs_capabilities.attachment_vrs_supported = false;
multiview_capabilities.is_supported = false;
multiview_capabilities.geometry_shader_is_supported = false;
multiview_capabilities.tessellation_shader_is_supported = false;
@ -531,9 +546,17 @@ Error VulkanContext::_check_capabilities() {
}
if (vkGetPhysicalDeviceFeatures2_func != nullptr) {
// check our extended features
VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {
/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR,
/*pNext*/ nullptr,
/*pipelineFragmentShadingRate*/ false,
/*primitiveFragmentShadingRate*/ false,
/*attachmentFragmentShadingRate*/ false,
};
VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
/*pNext*/ nullptr,
/*pNext*/ &vrs_features,
/*shaderFloat16*/ false,
/*shaderInt8*/ false,
};
@ -561,6 +584,10 @@ Error VulkanContext::_check_capabilities() {
vkGetPhysicalDeviceFeatures2_func(gpu, &device_features);
vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
multiview_capabilities.is_supported = multiview_features.multiview;
multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
@ -581,24 +608,33 @@ Error VulkanContext::_check_capabilities() {
device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
}
if (device_properties_func != nullptr) {
VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties;
VkPhysicalDeviceMultiviewProperties multiviewProperties;
VkPhysicalDeviceSubgroupProperties subgroupProperties;
VkPhysicalDeviceProperties2 physicalDeviceProperties;
void *nextptr = nullptr;
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
subgroupProperties.pNext = nullptr;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
subgroupProperties.pNext = nextptr;
nextptr = &subgroupProperties;
if (multiview_capabilities.is_supported) {
multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
multiviewProperties.pNext = &subgroupProperties;
multiviewProperties.pNext = nextptr;
physicalDeviceProperties.pNext = &multiviewProperties;
} else {
physicalDeviceProperties.pNext = &subgroupProperties;
nextptr = &multiviewProperties;
}
if (vrs_capabilities.attachment_vrs_supported) {
vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
vrsProperties.pNext = nextptr;
nextptr = &vrsProperties;
}
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = nextptr;
device_properties_func(gpu, &physicalDeviceProperties);
subgroup_capabilities.size = subgroupProperties.subgroupSize;
@ -609,6 +645,28 @@ Error VulkanContext::_check_capabilities() {
// - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
print_verbose("- Vulkan Varying Shading Rates supported:");
if (vrs_capabilities.pipeline_vrs_supported) {
print_verbose(" Pipeline fragment shading rate");
}
if (vrs_capabilities.primitive_vrs_supported) {
print_verbose(" Primitive fragment shading rate");
}
if (vrs_capabilities.attachment_vrs_supported) {
// TODO expose these somehow to the end user
vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width;
vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height;
vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height;
print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")"));
}
} else {
print_verbose("- Vulkan Varying Shading Rates not supported");
}
if (multiview_capabilities.is_supported) {
multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
@ -999,6 +1057,13 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
// if multiview is supported, enable it
extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, device_extensions[i].extensionName)) {
// if shading rate image is supported, enable it
extension_names[enabled_extension_count++] = VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME;
}
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(device_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
@ -1110,6 +1175,18 @@ Error VulkanContext::_create_device() {
};
nextptr = &shader_features;
VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features;
if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
// insert into our chain to enable these features if they are available
vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
vrs_features.pNext = nextptr;
vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported;
vrs_features.primitiveFragmentShadingRate = vrs_capabilities.primitive_vrs_supported;
vrs_features.attachmentFragmentShadingRate = vrs_capabilities.attachment_vrs_supported;
nextptr = &vrs_features;
}
VkPhysicalDeviceVulkan11Features vulkan11features;
VkPhysicalDevice16BitStorageFeaturesKHR storage_feature;
VkPhysicalDeviceMultiviewFeatures multiview_features;
@ -1725,7 +1802,9 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/******** FRAMEBUFFER ************/
{
const VkAttachmentDescription attachment = {
const VkAttachmentDescription2KHR attachment = {
/*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR,
/*pNext*/ nullptr,
/*flags*/ 0,
/*format*/ format,
/*samples*/ VK_SAMPLE_COUNT_1_BIT,
@ -1737,14 +1816,20 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
};
const VkAttachmentReference color_reference = {
const VkAttachmentReference2KHR color_reference = {
/*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR,
/*pNext*/ nullptr,
/*attachment*/ 0,
/*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*aspectMask*/ 0,
};
const VkSubpassDescription subpass = {
const VkSubpassDescription2KHR subpass = {
/*sType*/ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR,
/*pNext*/ nullptr,
/*flags*/ 0,
/*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS,
/*viewMask*/ 1,
/*inputAttachmentCount*/ 0,
/*pInputAttachments*/ nullptr,
/*colorAttachmentCount*/ 1,
@ -1754,8 +1839,10 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*preserveAttachmentCount*/ 0,
/*pPreserveAttachments*/ nullptr,
};
const VkRenderPassCreateInfo rp_info = {
/*sTyp*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
uint32_t view_masks = 1;
const VkRenderPassCreateInfo2KHR rp_info = {
/*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR,
/*pNext*/ nullptr,
/*flags*/ 0,
/*attachmentCount*/ 1,
@ -1764,9 +1851,11 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*pSubpasses*/ &subpass,
/*dependencyCount*/ 0,
/*pDependencies*/ nullptr,
/*correlatedViewMaskCount*/ 1,
/*pCorrelatedViewMasks*/ &view_masks,
};
err = vkCreateRenderPass(device, &rp_info, nullptr, &window->render_pass);
err = vkCreateRenderPass2KHR(device, &rp_info, nullptr, &window->render_pass);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
for (uint32_t i = 0; i < swapchainImageCount; i++) {

View File

@ -69,6 +69,15 @@ public:
uint32_t max_instance_count;
};
struct VRSCapabilities {
bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level
bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall
bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer
Size2i min_texel_size;
Size2i max_texel_size;
};
struct ShaderCapabilities {
bool shader_float16_is_supported;
bool shader_int8_is_supported;
@ -104,6 +113,7 @@ private:
uint32_t vulkan_patch = 0;
SubgroupCapabilities subgroup_capabilities;
MultiviewCapabilities multiview_capabilities;
VRSCapabilities vrs_capabilities;
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
@ -206,6 +216,7 @@ private:
PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr;
PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr;
PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr;
PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr;
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
@ -256,10 +267,14 @@ protected:
Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
public:
// Extension calls
VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
VRSCapabilities get_vrs_capabilities() const { return vrs_capabilities; };
ShaderCapabilities get_shader_capabilities() const { return shader_capabilities; };
StorageBufferCapabilities get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };

View File

@ -38,7 +38,8 @@
#include <glslang/Public/ShaderLang.h>
#include <glslang/SPIRV/GlslangToSpv.h>
static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice::Capabilities *p_capabilities) {
static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device) {
const RD::Capabilities *capabilities = p_render_device->get_device_capabilities();
Vector<uint8_t> ret;
ERR_FAIL_COND_V(p_language == RenderingDevice::SHADER_LANGUAGE_HLSL, ret);
@ -58,12 +59,12 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
glslang::TShader::ForbidIncluder includer;
if (p_capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 0) {
if (capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
if (capabilities->version_major == 1 && capabilities->version_minor == 0) {
ClientVersion = glslang::EShTargetVulkan_1_0;
TargetVersion = glslang::EShTargetSpv_1_0;
check_subgroup_support = false; // subgroups are not supported in Vulkan 1.0
} else if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 1) {
} else if (capabilities->version_major == 1 && capabilities->version_minor == 1) {
ClientVersion = glslang::EShTargetVulkan_1_1;
TargetVersion = glslang::EShTargetSpv_1_3;
} else {
@ -90,34 +91,36 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
if (check_subgroup_support) {
uint32_t stage_bit = 1 << p_stage;
if ((p_capabilities->subgroup_in_shaders & stage_bit) == stage_bit) {
uint32_t subgroup_in_shaders = uint32_t(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS));
uint32_t subgroup_operations = uint32_t(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS));
if ((subgroup_in_shaders & stage_bit) == stage_bit) {
// stage supports subgroups
preamble += "#define has_GL_KHR_shader_subgroup_basic 1\n";
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_VOTE_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_VOTE_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_vote 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_ARITHMETIC_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_ARITHMETIC_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_arithmetic 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_BALLOT_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_BALLOT_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_ballot 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_shuffle 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_RELATIVE_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_RELATIVE_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_shuffle_relative 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_CLUSTERED_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_CLUSTERED_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_clustered 1\n";
}
if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_QUAD_BIT) {
if (subgroup_operations & RenderingDevice::SUBGROUP_QUAD_BIT) {
preamble += "#define has_GL_KHR_shader_subgroup_quad 1\n";
}
}
}
if (p_capabilities->supports_multiview) {
if (p_render_device->has_feature(RD::SUPPORTS_MULTIVIEW)) {
preamble += "#define has_VK_KHR_multiview 1\n";
}
@ -184,9 +187,10 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
return ret;
}
static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *p_capabilities) {
static String _get_cache_key_function_glsl(const RenderingDevice *p_render_device) {
const RD::Capabilities *capabilities = p_render_device->get_device_capabilities();
String version;
version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(p_capabilities->version_major) + ", minor=" + itos(p_capabilities->version_minor) + " , subgroup_size=" + itos(p_capabilities->subgroup_operations) + " , subgroup_ops=" + itos(p_capabilities->subgroup_operations) + " , subgroup_in_shaders=" + itos(p_capabilities->subgroup_in_shaders);
version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(capabilities->version_major) + ", minor=" + itos(capabilities->version_minor) + " , subgroup_size=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_SIZE)) + " , subgroup_ops=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS)) + " , subgroup_in_shaders=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS));
return version;
}

View File

@ -34,6 +34,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
#include "core/io/dir_access.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/multiplayer/multiplayer_api.h"
@ -1446,6 +1447,29 @@ SceneTree::SceneTree() {
bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false);
root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
// We setup VRS for the main viewport here, in the editor this will have little effect.
const int vrs_mode = GLOBAL_DEF("rendering/vrs/mode", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/mode", PropertyInfo(Variant::INT, "rendering/vrs/mode", PROPERTY_HINT_ENUM, String::utf8("Disabled,Texture,XR")));
root->set_vrs_mode(Viewport::VRSMode(vrs_mode));
const String vrs_texture_path = String(GLOBAL_DEF("rendering/vrs/texture", String())).strip_edges();
ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/texture",
PropertyInfo(Variant::STRING,
"rendering/vrs/texture",
PROPERTY_HINT_FILE, "*.png"));
if (vrs_mode == 1 && !vrs_texture_path.is_empty()) {
Ref<Image> vrs_image;
vrs_image.instantiate();
Error load_err = ImageLoader::load_image(vrs_texture_path, vrs_image);
if (load_err) {
ERR_PRINT("Non-existing or invalid VRS texture at '" + vrs_texture_path + "'.");
} else {
Ref<ImageTexture> vrs_texture;
vrs_texture.instantiate();
vrs_texture->create_from_image(vrs_image);
root->set_vrs_texture(vrs_texture);
}
}
int shadowmap_size = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size", 4096);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"));
GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size.mobile", 2048);

View File

@ -3080,6 +3080,41 @@ Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_textu
return default_canvas_item_texture_repeat;
}
void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
// Note, set this even if not supported on this hardware, it will only be used if it is but we want to save the value as set by the user.
vrs_mode = p_vrs_mode;
switch (p_vrs_mode) {
case VRS_TEXTURE: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_TEXTURE);
} break;
case VRS_XR: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_XR);
} break;
default: {
RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_DISABLED);
} break;
}
notify_property_list_changed();
}
Viewport::VRSMode Viewport::get_vrs_mode() const {
return vrs_mode;
}
void Viewport::set_vrs_texture(Ref<Texture2D> p_texture) {
vrs_texture = p_texture;
// TODO need to add something here in case the RID changes
RID tex = p_texture.is_valid() ? p_texture->get_rid() : RID();
RS::get_singleton()->viewport_set_vrs_texture(viewport, tex);
}
Ref<Texture2D> Viewport::get_vrs_texture() const {
return vrs_texture;
}
DisplayServer::WindowID Viewport::get_window_id() const {
return DisplayServer::MAIN_WINDOW_ID;
}
@ -3741,6 +3776,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fsr_mipmap_bias", "fsr_mipmap_bias"), &Viewport::set_fsr_mipmap_bias);
ClassDB::bind_method(D_METHOD("get_fsr_mipmap_bias"), &Viewport::get_fsr_mipmap_bias);
ClassDB::bind_method(D_METHOD("set_vrs_mode", "mode"), &Viewport::set_vrs_mode);
ClassDB::bind_method(D_METHOD("get_vrs_mode"), &Viewport::get_vrs_mode);
ClassDB::bind_method(D_METHOD("set_vrs_texture", "texture"), &Viewport::set_vrs_texture);
ClassDB::bind_method(D_METHOD("get_vrs_texture"), &Viewport::get_vrs_texture);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
@ -3766,6 +3807,9 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.1"), "set_fsr_mipmap_bias", "get_fsr_mipmap_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness");
#endif
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::OBJECT, "vrs_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_vrs_texture", "get_vrs_texture");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
@ -3876,6 +3920,17 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SDF_SCALE_50_PERCENT);
BIND_ENUM_CONSTANT(SDF_SCALE_25_PERCENT);
BIND_ENUM_CONSTANT(SDF_SCALE_MAX);
BIND_ENUM_CONSTANT(VRS_DISABLED);
BIND_ENUM_CONSTANT(VRS_TEXTURE);
BIND_ENUM_CONSTANT(VRS_XR);
BIND_ENUM_CONSTANT(VRS_MAX);
}
void Viewport::_validate_property(PropertyInfo &property) const {
if (vrs_mode != VRS_TEXTURE && (property.name == "vrs_texture")) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
Viewport::Viewport() {

View File

@ -197,6 +197,13 @@ public:
SUBWINDOW_CANVAS_LAYER = 1024
};
enum VRSMode {
VRS_DISABLED,
VRS_TEXTURE,
VRS_XR,
VRS_MAX
};
private:
friend class ViewportTexture;
@ -333,6 +340,10 @@ private:
RID canvas_item;
};
// VRS
VRSMode vrs_mode = VRS_DISABLED;
Ref<Texture2D> vrs_texture;
struct GUI {
// info used when this is a window
@ -604,6 +615,14 @@ public:
void set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat);
DefaultCanvasItemTextureRepeat get_default_canvas_item_texture_repeat() const;
// VRS
void set_vrs_mode(VRSMode p_vrs_mode);
VRSMode get_vrs_mode() const;
void set_vrs_texture(Ref<Texture2D> p_texture);
Ref<Texture2D> get_vrs_texture() const;
virtual DisplayServer::WindowID get_window_id() const = 0;
void set_embedding_subwindows(bool p_embed);
@ -690,6 +709,7 @@ public:
bool is_using_xr();
#endif // _3D_DISABLED
virtual void _validate_property(PropertyInfo &property) const override;
Viewport();
~Viewport();
};
@ -752,6 +772,7 @@ VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
VARIANT_ENUM_CAST(Viewport::SDFScale);
VARIANT_ENUM_CAST(Viewport::SDFOversize);
VARIANT_ENUM_CAST(Viewport::VRSMode);
VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::RenderInfoType);

View File

@ -169,6 +169,9 @@ public:
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {}
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {}
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{};
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{};
};
} // namespace RendererDummy

View File

@ -100,11 +100,11 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
{
Vector<String> copy_modes;
copy_modes.push_back("\n");
copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");
copy_modes.push_back("\n#define MODE_TWO_SOURCES\n");
copy_modes.push_back("\n#define MULTIVIEW\n");
copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n");
copy_modes.push_back("\n"); // COPY_TO_FB_COPY
copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); // COPY_TO_FB_COPY_PANORAMA_TO_DP
copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_COPY2
copy_modes.push_back("\n#define MULTIVIEW\n"); // COPY_TO_FB_MULTIVIEW
copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_MULTIVIEW_WITH_DEPTH
copy_to_fb.shader.initialize(copy_modes);

View File

@ -0,0 +1,171 @@
/*************************************************************************/
/* vrs.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "vrs.h"
#include "../renderer_compositor_rd.h"
#include "../storage_rd/texture_storage.h"
#include "../uniform_set_cache_rd.h"
#include "servers/xr_server.h"
using namespace RendererRD;
VRS::VRS() {
{
Vector<String> vrs_modes;
vrs_modes.push_back("\n"); // VRS_DEFAULT
vrs_modes.push_back("\n#define MULTIVIEW\n"); // VRS_MULTIVIEW
vrs_shader.shader.initialize(vrs_modes);
if (!RendererCompositorRD::singleton->is_xr_enabled()) {
vrs_shader.shader.set_variant_enabled(VRS_MULTIVIEW, false);
}
vrs_shader.shader_version = vrs_shader.shader.version_create();
//use additive
for (int i = 0; i < VRS_MAX; i++) {
if (vrs_shader.shader.is_variant_enabled(i)) {
vrs_shader.pipelines[i].setup(vrs_shader.shader.version_get_shader(vrs_shader.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
} else {
vrs_shader.pipelines[i].clear();
}
}
}
}
VRS::~VRS() {
vrs_shader.shader.version_free(vrs_shader.shader_version);
}
void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
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;
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::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, 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_bind_index_array(draw_list, material_storage->get_quad_index_array());
// RD::get_singleton()->draw_list_set_push_constant(draw_list, &vrs_shader.push_constant, sizeof(VRSPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
void VRS::create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb) {
// TODO find a way to skip this if VRS is not supported, but we don't have access to VulkanContext here, even though we're in vulkan.. hmmm
// TODO we should find some way to store this properly, we're assuming 16x16 as this seems to be the standard but in our vrs_capacities we
// obtain a minimum and maximum size, and we should choose something within this range and then make sure that is consistantly set when creating
// our frame buffer. Also it is important that we make the resulting size we calculate down below available to the end user so they know the size
// of the VRS buffer to supply.
Size2i texel_size = Size2i(16, 16);
RD::TextureFormat tf;
if (p_view_count > 1) {
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
} else {
tf.texture_type = RD::TEXTURE_TYPE_2D;
}
tf.format = RD::DATA_FORMAT_R8_UINT;
tf.width = p_base_width / texel_size.x;
if (p_base_width % texel_size.x != 0) {
tf.width++;
}
tf.height = p_base_height / texel_size.y;
if (p_base_height % texel_size.y != 0) {
tf.height++;
}
tf.array_layers = p_view_count; // create a layer for every view
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
tf.samples = RD::TEXTURE_SAMPLES_1;
p_vrs_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
// by default VRS is assumed to be our VRS attachment, but if we need to write into it, we need a bit more control
Vector<RID> fb;
fb.push_back(p_vrs_texture);
RD::FramebufferPass pass;
pass.color_attachments.push_back(0);
Vector<RD::FramebufferPass> passes;
passes.push_back(pass);
p_vrs_fb = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, p_view_count);
}
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);
if (vrs_mode != RS::VIEWPORT_VRS_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()) {
Texture *texture = texture_storage->get_texture(vrs_texture);
if (texture) {
// Copy into our density buffer
copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1);
}
}
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
if (interface.is_valid()) {
RID vrs_texture = interface->get_vrs_texture();
if (vrs_texture.is_valid()) {
Texture *texture = texture_storage->get_texture(vrs_texture);
if (texture) {
// Copy into our density buffer
copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1);
}
}
}
}
RD::get_singleton()->draw_command_end_label();
}
}

View File

@ -0,0 +1,75 @@
/*************************************************************************/
/* vrs.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 VRS_RD_H
#define VRS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/vrs.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class VRS {
private:
enum VRSMode {
VRS_DEFAULT,
VRS_MULTIVIEW,
VRS_MAX,
};
/* we have no push constant here (yet)
struct VRSPushConstant {
};
*/
struct VRSShader {
// VRSPushConstant push_constant;
VrsShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[VRS_MAX];
} vrs_shader;
public:
VRS();
~VRS();
void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false);
void create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb);
void update_vrs_texture(RID p_vrs_fb, RID p_render_target);
};
} // namespace RendererRD
#endif // !VRS_RD_H

View File

@ -1309,7 +1309,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
#else
// Everyone else can use normal mode when available.
if (RD::get_singleton()->get_device_capabilities()->supports_fsr_half_float) {
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FSR_HALF_FLOAT)) {
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
} else {
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");

View File

@ -109,6 +109,7 @@ void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xfo
Vector<Vector<uint8_t>> s;
s.push_back(p_distance_field);
voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s);
RD::get_singleton()->set_resource_name(voxel_gi->sdf_texture, "VoxelGI SDF Texture");
}
#if 0
{
@ -122,6 +123,7 @@ void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xfo
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(voxel_gi->sdf_texture, "VoxelGI SDF Texture");
}
RID shared_tex;
{
@ -402,29 +404,38 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
RD::TextureFormat tf_render = tf_sdf;
tf_render.format = RD::DATA_FORMAT_R16_UINT;
render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_albedo, "VoxelGI Render Albedo");
tf_render.format = RD::DATA_FORMAT_R32_UINT;
render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_emission, "VoxelGI Render Emission");
render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_emission_aniso, "VoxelGI Render Emission Aniso");
tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize
for (int i = 0; i < 8; i++) {
render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_occlusion[i], String("VoxelGI Render Occlusion ") + itos(i));
}
tf_render.format = RD::DATA_FORMAT_R32_UINT;
render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_geom_facing, "VoxelGI Render Geometry Facing");
tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT;
render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_sdf[0], "VoxelGI Render SDF 0");
render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_sdf[1], "VoxelGI Render SDF 1");
tf_render.width /= 2;
tf_render.height /= 2;
tf_render.depth /= 2;
render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_sdf_half[0], "VoxelGI Render SDF Half 0");
render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
RD::get_singleton()->set_resource_name(render_sdf_half[1], "VoxelGI Render SDF Half 1");
}
RD::TextureFormat tf_occlusion = tf_sdf;
@ -465,7 +476,9 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D;
lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
RD::get_singleton()->set_resource_name(lightprobe_history_scroll, "VoxelGI LightProbe History Scroll");
lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
RD::get_singleton()->set_resource_name(lightprobe_average_scroll, "VoxelGI LightProbe Average Scroll");
{
//octahedral lightprobes
@ -479,6 +492,7 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
//lightprobe texture is an octahedral texture
lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView());
RD::get_singleton()->set_resource_name(lightprobe_data, "VoxelGI LightProbe Data");
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, lightprobe_data);
@ -492,11 +506,13 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
//lightprobe texture is an octahedral texture
ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
RD::get_singleton()->set_resource_name(ambient_texture, "VoxelGI Ambient Texture");
}
cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView());
RD::get_singleton()->set_resource_name(occlusion_data, "VoxelGI Occlusion Data");
{
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
@ -509,11 +525,15 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
/* 3D Textures */
cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.sdf_tex, "VoxelGI Cascade SDF Texture");
cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.light_data, "VoxelGI Cascade Light Data");
cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.light_aniso_0_tex, "VoxelGI Cascade Light Aniso 0 Texture");
cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.light_aniso_1_tex, "VoxelGI Cascade Light Aniso 1 Texture");
{
RD::TextureView tv;
@ -540,9 +560,11 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world
/* Probe History */
cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.lightprobe_history_tex, "VoxelGI Cascade LightProbe History Texture");
RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work
cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
RD::get_singleton()->set_resource_name(cascade.lightprobe_average_tex, "VoxelGI Cascade LightProbe Average Texture");
RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work
/* Buffers */
@ -2444,6 +2466,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(texture, "VoxelGI Instance Texture");
RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1);
@ -2573,6 +2596,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.texture, "VoxelGI Instance DMap Texture");
if (dynamic_maps.size() == 0) {
// Render depth for first one.
@ -2580,6 +2604,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.fb_depth, "VoxelGI Instance DMap FB Depth");
}
//just use depth as-is
@ -2587,13 +2612,17 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.depth, "VoxelGI Instance DMap Depth");
if (dynamic_maps.size() == 0) {
dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.albedo, "VoxelGI Instance DMap Albedo");
dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.normal, "VoxelGI Instance DMap Normal");
dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
RD::get_singleton()->set_resource_name(dmap.orm, "VoxelGI Instance DMap ORM");
Vector<RID> fb;
fb.push_back(dmap.albedo);
@ -3342,37 +3371,40 @@ void GI::init(RendererSceneSkyRD *p_sky) {
//calculate tables
String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
Vector<String> gi_modes;
gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_VOXEL_GI
gi_modes.push_back("\n#define USE_SDFGI\n"); // MODE_SDFGI
gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_COMBINED
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_HALF_RES_VOXEL_GI
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); // MODE_HALF_RES_SDFGI
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_HALF_RES_COMBINED
gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_VOXEL_GI_MULTIVIEW
gi_modes.push_back("\n#define USE_SDFGI\n#define USE_MULTIVIEW\n"); // MODE_SDFGI_MULTIVIEW
gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_COMBINED_MULTIVIEW
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_VOXEL_GI_MULTIVIEW
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_SDFGI_MULTIVIEW
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_COMBINED_MULTIVIEW
shader.initialize(gi_modes, defines);
shader_version = shader.version_create();
if (!RendererCompositorRD::singleton->is_xr_enabled()) {
shader.set_variant_enabled(MODE_VOXEL_GI_MULTIVIEW, false);
shader.set_variant_enabled(MODE_SDFGI_MULTIVIEW, false);
shader.set_variant_enabled(MODE_COMBINED_MULTIVIEW, false);
shader.set_variant_enabled(MODE_HALF_RES_VOXEL_GI_MULTIVIEW, false);
shader.set_variant_enabled(MODE_HALF_RES_SDFGI_MULTIVIEW, false);
shader.set_variant_enabled(MODE_HALF_RES_COMBINED_MULTIVIEW, false);
Vector<RD::PipelineSpecializationConstant> specialization_constants;
{
RD::PipelineSpecializationConstant sc;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = 0; // SHADER_SPECIALIZATION_HALF_RES
sc.bool_value = false;
specialization_constants.push_back(sc);
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = 1; // SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX
sc.bool_value = false;
specialization_constants.push_back(sc);
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = 2; // SHADER_SPECIALIZATION_USE_VRS
sc.bool_value = false;
specialization_constants.push_back(sc);
}
shader_version = shader.version_create();
for (int v = 0; v < SHADER_SPECIALIZATION_VARIATIONS; v++) {
specialization_constants.ptrw()[0].bool_value = (v & SHADER_SPECIALIZATION_HALF_RES) ? true : false;
specialization_constants.ptrw()[1].bool_value = (v & SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX) ? true : false;
specialization_constants.ptrw()[2].bool_value = (v & SHADER_SPECIALIZATION_USE_VRS) ? true : false;
for (int i = 0; i < MODE_MAX; i++) {
if (shader.is_variant_enabled(i)) {
pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i));
} else {
pipelines[i] = RID();
pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i), specialization_constants);
}
}
@ -3564,25 +3596,17 @@ void GI::RenderBuffersGI::free() {
}
if (ambient_buffer.is_valid()) {
if (view_count == 1) {
// Only one view? then these are copies of our main buffers.
ambient_view[0] = RID();
reflection_view[0] = RID();
} else {
// Multiple views? free our slices.
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(ambient_view[v]);
RD::get_singleton()->free(reflection_view[v]);
ambient_view[v] = RID();
reflection_view[v] = RID();
}
}
// Now we can free our buffers.
RD::get_singleton()->free(ambient_buffer);
RD::get_singleton()->free(reflection_buffer);
ambient_buffer = RID();
reflection_buffer = RID();
// these are automatically freed when we free the textures, so just reset..
for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
ambient_slice[v] = RID();
reflection_slice[v] = RID();
}
view_count = 0;
}
@ -3592,7 +3616,7 @@ void GI::RenderBuffersGI::free() {
}
}
void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) {
void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@ -3606,14 +3630,13 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
if (rb->rbgi.ambient_buffer.is_null() || rb->rbgi.using_half_size_gi != half_resolution || rb->rbgi.view_count != p_view_count) {
// Free our old buffer if applicable
if (rb->rbgi.ambient_buffer.is_valid()) {
if (rb->rbgi.view_count > 1) {
for (uint32_t v = 0; v < rb->rbgi.view_count; v++) {
RD::get_singleton()->free(rb->rbgi.ambient_view[v]);
RD::get_singleton()->free(rb->rbgi.reflection_view[v]);
}
}
RD::get_singleton()->free(rb->rbgi.ambient_buffer);
RD::get_singleton()->free(rb->rbgi.reflection_buffer);
for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
rb->rbgi.ambient_slice[v] = RID();
rb->rbgi.reflection_slice[v] = RID();
}
}
// Remember the view count we're using
@ -3637,18 +3660,19 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
}
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->rbgi.ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->rbgi.ambient_buffer, "GI Ambient Buffer");
rb->rbgi.reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->rbgi.reflection_buffer, "GI Reflection Buffer");
rb->rbgi.using_half_size_gi = half_resolution;
if (p_view_count == 1) {
// Just one view? Copy our buffers
rb->rbgi.ambient_view[0] = rb->rbgi.ambient_buffer;
rb->rbgi.reflection_view[0] = rb->rbgi.reflection_buffer;
// Just copy, we don't need to create slices
rb->rbgi.ambient_slice[0] = rb->rbgi.ambient_buffer;
rb->rbgi.reflection_slice[0] = rb->rbgi.reflection_buffer;
} else {
// More then one view? Create slices for each view
for (uint32_t v = 0; v < p_view_count; v++) {
rb->rbgi.ambient_view[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.ambient_buffer, v, 0);
rb->rbgi.reflection_view[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.reflection_buffer, v, 0);
rb->rbgi.ambient_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.ambient_buffer, v, 0);
rb->rbgi.reflection_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.reflection_buffer, v, 0);
}
}
}
@ -3681,7 +3705,6 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
// Now compute the contents of our buffers.
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
for (uint32_t v = 0; v < p_view_count; v++) {
// Render each eye seperately.
// We need to look into whether we can make our compute shader use Multiview but not sure that works or makes a difference..
@ -3689,22 +3712,39 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
PushConstant push_constant;
push_constant.view_index = v;
push_constant.orthogonal = p_projections[v].is_orthogonal();
push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size());
push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH;
push_constant.z_near = p_projections[v].get_z_near();
push_constant.z_far = p_projections[v].get_z_far();
// these should be the same for all views
push_constant.orthogonal = p_projections[0].is_orthogonal();
push_constant.z_near = p_projections[0].get_z_near();
push_constant.z_far = p_projections[0].get_z_far();
push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projections[v].matrix[0][0]);
push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projections[v].matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
// these are only used if we have 1 view, else we use the projections in our scene data
push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projections[0].matrix[0][0]);
push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projections[0].matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projections[0].matrix[0][2]) / p_projections[0].matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projections[0].matrix[1][2]) / p_projections[0].matrix[1][1];
bool use_sdfgi = rb->sdfgi != nullptr;
bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
uint32_t pipeline_specialization = 0;
if (rb->rbgi.using_half_size_gi) {
pipeline_specialization |= SHADER_SPECIALIZATION_HALF_RES;
}
if (p_view_count > 1) {
pipeline_specialization |= SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX;
}
if (p_vrs_slices[0].is_valid()) {
pipeline_specialization |= SHADER_SPECIALIZATION_USE_VRS;
}
Mode mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI);
for (uint32_t v = 0; v < p_view_count; v++) {
push_constant.view_index = v;
// setup our uniform set
if (rb->rbgi.uniform_set[v].is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->rbgi.uniform_set[v])) {
Vector<RD::Uniform> uniforms;
@ -3790,7 +3830,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 9;
u.append_id(rb->rbgi.ambient_view[v]);
u.append_id(rb->rbgi.ambient_slice[v]);
uniforms.push_back(u);
}
@ -3798,7 +3838,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 10;
u.append_id(rb->rbgi.reflection_view[v]);
u.append_id(rb->rbgi.reflection_slice[v]);
uniforms.push_back(u);
}
@ -3824,7 +3864,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 13;
u.append_id(p_normal_roughness_views[v]);
u.append_id(p_normal_roughness_slices[v]);
uniforms.push_back(u);
}
{
@ -3865,27 +3905,19 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v
u.append_id(rb->rbgi.scene_data_ubo);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 19;
RID buffer = p_vrs_slices[v].is_valid() ? p_vrs_slices[v] : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_VRS);
u.append_id(buffer);
uniforms.push_back(u);
}
rb->rbgi.uniform_set[v] = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
}
Mode mode;
if (p_view_count > 1) {
if (rb->rbgi.using_half_size_gi) {
mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED_MULTIVIEW : (use_sdfgi ? MODE_HALF_RES_SDFGI_MULTIVIEW : MODE_HALF_RES_VOXEL_GI_MULTIVIEW);
} else {
mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED_MULTIVIEW : (use_sdfgi ? MODE_SDFGI_MULTIVIEW : MODE_VOXEL_GI_MULTIVIEW);
}
} else {
if (rb->rbgi.using_half_size_gi) {
mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_VOXEL_GI);
} else {
mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI);
}
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[pipeline_specialization][mode]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->rbgi.uniform_set[v], 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));

View File

@ -660,13 +660,13 @@ public:
/* GI buffers */
RID ambient_buffer;
RID ambient_slice[RendererSceneRender::MAX_RENDER_VIEWS];
RID reflection_buffer;
RID ambient_view[RendererSceneRender::MAX_RENDER_VIEWS];
RID reflection_view[RendererSceneRender::MAX_RENDER_VIEWS];
RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
RID reflection_slice[RendererSceneRender::MAX_RENDER_VIEWS];
bool using_half_size_gi = false;
uint32_t view_count = 1;
RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
RID scene_data_ubo;
void free();
@ -729,44 +729,41 @@ public:
};
struct PushConstant {
uint32_t view_index;
uint32_t max_voxel_gi_instances;
uint32_t high_quality_vct;
uint32_t orthogonal;
uint32_t view_index;
float proj_info[4];
float z_near;
float z_far;
float pad1;
float pad2;
float pad3;
};
RID sdfgi_ubo;
enum Mode {
MODE_VOXEL_GI,
MODE_SDFGI,
MODE_COMBINED,
MODE_HALF_RES_VOXEL_GI,
MODE_HALF_RES_SDFGI,
MODE_HALF_RES_COMBINED,
MODE_VOXEL_GI_MULTIVIEW,
MODE_SDFGI_MULTIVIEW,
MODE_COMBINED_MULTIVIEW,
MODE_HALF_RES_VOXEL_GI_MULTIVIEW,
MODE_HALF_RES_SDFGI_MULTIVIEW,
MODE_HALF_RES_COMBINED_MULTIVIEW,
MODE_MAX
};
enum ShaderSpecializations {
SHADER_SPECIALIZATION_HALF_RES = 1 << 0,
SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX = 1 << 1,
SHADER_SPECIALIZATION_USE_VRS = 1 << 2,
SHADER_SPECIALIZATION_VARIATIONS = 0x07,
};
RID default_voxel_gi_buffer;
bool half_resolution = false;
GiShaderRD shader;
RID shader_version;
RID pipelines[MODE_MAX];
RID pipelines[SHADER_SPECIALIZATION_VARIATIONS][MODE_MAX];
GI();
~GI();
@ -777,7 +774,7 @@ public:
SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
void process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render);
void process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render);
RID voxel_gi_instance_create(RID p_base);
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);

View File

@ -171,29 +171,24 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi()
}
void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
// note, slices are freed automatically when the parent texture is freed so we just clear them.
for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
color_views[v] = RID();
depth_views[v] = RID();
color_msaa_views[v] = RID();
depth_msaa_views[v] = RID();
normal_roughness_views[v] = RID();
normal_roughness_msaa_views[v] = RID();
voxelgi_views[v] = RID();
voxelgi_msaa_views[v] = RID();
vrs_views[v] = RID();
}
if (voxelgi_buffer != RID()) {
RD::get_singleton()->free(voxelgi_buffer);
voxelgi_buffer = RID();
if (view_count == 1) {
voxelgi_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(voxelgi_views[v]);
voxelgi_views[v] = RID();
}
}
if (voxelgi_buffer_msaa.is_valid()) {
if (view_count == 1) {
voxelgi_msaa_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(voxelgi_msaa_views[v]);
voxelgi_msaa_views[v] = RID();
}
}
RD::get_singleton()->free(voxelgi_buffer_msaa);
voxelgi_buffer_msaa = RID();
}
@ -202,35 +197,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
if (color_msaa.is_valid()) {
if (view_count == 1) {
color_views[0] = RID();
color_msaa_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(color_views[v]);
RD::get_singleton()->free(color_msaa_views[v]);
color_views[v] = RID();
color_msaa_views[v] = RID();
}
}
RD::get_singleton()->free(color_msaa);
color_msaa = RID();
}
if (depth_msaa.is_valid()) {
if (view_count == 1) {
depth_views[0] = RID();
depth_msaa_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(depth_views[v]);
RD::get_singleton()->free(depth_msaa_views[v]);
depth_views[v] = RID();
depth_msaa_views[v] = RID();
}
}
RD::get_singleton()->free(depth_msaa);
depth_msaa = RID();
}
@ -245,33 +216,17 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
color = RID();
color_only_fb = RID();
depth = RID();
depth_fb = RID();
color_framebuffers.clear(); // Color pass framebuffers are freed automatically by their dependency relations
if (normal_roughness_buffer.is_valid()) {
if (view_count == 1) {
normal_roughness_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(normal_roughness_views[v]);
normal_roughness_views[v] = RID();
}
}
RD::get_singleton()->free(normal_roughness_buffer);
normal_roughness_buffer = RID();
if (normal_roughness_buffer_msaa.is_valid()) {
if (view_count == 1) {
normal_roughness_msaa_views[0] = RID();
} else {
for (uint32_t v = 0; v < view_count; v++) {
RD::get_singleton()->free(normal_roughness_msaa_views[v]);
normal_roughness_msaa_views[v] = RID();
}
}
RD::get_singleton()->free(normal_roughness_buffer_msaa);
normal_roughness_buffer_msaa = RID();
}
@ -294,11 +249,12 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
}
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) {
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) {
clear();
msaa = p_msaa;
use_taa = p_use_taa;
vrs = p_vrs_texture;
width = p_width;
height = p_height;
@ -307,11 +263,26 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c
color = p_color_buffer;
depth = p_depth_buffer;
if (vrs.is_valid()) {
if (view_count == 1) {
// just reuse
vrs_views[0] = vrs;
} else {
// create slices
for (uint32_t v = 0; v < view_count; v++) {
vrs_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), vrs, v, 0);
}
}
}
if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
{
Vector<RID> fb;
fb.push_back(p_color_buffer);
fb.push_back(depth);
if (vrs.is_valid()) {
fb.push_back(vrs);
}
color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
}
@ -371,6 +342,9 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c
Vector<RID> fb;
fb.push_back(color_msaa);
fb.push_back(depth_msaa);
if (vrs.is_valid()) {
fb.push_back(vrs);
}
color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
}
@ -409,6 +383,10 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb(
fb.push_back(use_msaa ? depth_msaa : depth);
if (vrs.is_valid()) {
fb.push_back(vrs);
}
int v_count = (p_color_pass_flags & COLOR_PASS_FLAG_MULTIVIEW) ? view_count : 1;
RID framebuffer = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, v_count);
color_framebuffers[p_color_pass_flags] = framebuffer;
@ -1673,8 +1651,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
continue_depth = !finish_depth;
}
RID null_rids[2];
_pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_views : null_rids, render_buffer ? render_buffer->voxelgi_buffer : RID());
RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
_pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_views : nullrids, render_buffer ? render_buffer->voxelgi_buffer : RID(), render_buffer ? render_buffer->vrs_views : nullrids);
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");

View File

@ -107,11 +107,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID depth_normal_roughness_voxelgi_fb;
RID color_only_fb;
RID specular_only_fb;
RID vrs;
int width, height;
HashMap<uint32_t, RID> color_framebuffers;
// for multiview
uint32_t view_count;
uint32_t view_count = 1;
RID color_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
RID depth_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
RID color_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
@ -120,13 +123,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID normal_roughness_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
RID voxelgi_views[RendererSceneRender::MAX_RENDER_VIEWS];
RID voxelgi_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
RID vrs_views[RendererSceneRender::MAX_RENDER_VIEWS];
RID render_sdfgi_uniform_set;
void ensure_specular();
void ensure_voxelgi();
void ensure_velocity();
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count);
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture);
RID get_color_pass_fb(uint32_t p_color_pass_flags);
~RenderBufferDataForwardClustered();

View File

@ -87,10 +87,11 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
}
}
void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) {
void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) {
clear();
msaa = p_msaa;
vrs = p_vrs_texture;
Size2i target_size = RD::get_singleton()->texture_size(p_target_buffer);
@ -108,6 +109,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
Vector<RID> fb;
fb.push_back(p_color_buffer); // 0 - color buffer
fb.push_back(depth); // 1 - depth buffer
if (vrs.is_valid()) {
fb.push_back(vrs); // 2 - vrs texture
}
// Now define our subpasses
Vector<RD::FramebufferPass> passes;
@ -116,6 +120,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
// re-using the same attachments
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
if (vrs.is_valid()) {
pass.vrs_attachment = 2;
}
// - opaque pass
passes.push_back(pass);
@ -131,12 +138,13 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
if (!is_scaled) {
// - add blit to 2D pass
fb.push_back(p_target_buffer); // 2 - target buffer
int target_buffer_id = fb.size();
fb.push_back(p_target_buffer); // 2/3 - target buffer
RD::FramebufferPass blit_pass;
blit_pass.color_attachments.push_back(2);
blit_pass.color_attachments.push_back(target_buffer_id);
blit_pass.input_attachments.push_back(0);
passes.push_back(blit_pass);
passes.push_back(blit_pass); // this doesn't need VRS
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
} else {
@ -179,6 +187,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
Vector<RID> fb;
fb.push_back(color_msaa); // 0 - msaa color buffer
fb.push_back(depth_msaa); // 1 - msaa depth buffer
if (vrs.is_valid()) {
fb.push_back(vrs); // 2 - vrs texture
}
// Now define our subpasses
Vector<RD::FramebufferPass> passes;
@ -187,18 +198,22 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
// re-using the same attachments
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
if (vrs.is_valid()) {
pass.vrs_attachment = 2;
}
// - opaque pass
passes.push_back(pass);
// - add sky pass
fb.push_back(color); // 2 - color buffer
int color_buffer_id = fb.size();
fb.push_back(color); // color buffer
passes.push_back(pass); // without resolve for our 3 + 4 subpass config
{
// but with resolve for our 2 subpass config
Vector<RD::FramebufferPass> two_passes;
two_passes.push_back(pass); // opaque subpass without resolve
pass.resolve_attachments.push_back(2);
pass.resolve_attachments.push_back(color_buffer_id);
two_passes.push_back(pass); // sky subpass with resolve
color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count);
@ -217,10 +232,11 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
if (!is_scaled) {
// - add blit to 2D pass
fb.push_back(p_target_buffer); // 3 - target buffer
int target_buffer_id = fb.size();
fb.push_back(p_target_buffer); // target buffer
RD::FramebufferPass blit_pass;
blit_pass.color_attachments.push_back(3);
blit_pass.input_attachments.push_back(2);
blit_pass.color_attachments.push_back(target_buffer_id);
blit_pass.input_attachments.push_back(color_buffer_id);
passes.push_back(blit_pass);
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
@ -675,8 +691,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
}
RID null_rids[2];
_pre_opaque_render(p_render_data, false, false, false, null_rids, RID());
RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
_pre_opaque_render(p_render_data, false, false, false, nullrids, RID(), nullrids);
uint32_t spec_constant_base_flags = 0;

View File

@ -131,12 +131,14 @@ protected:
RID depth_msaa;
// RID normal_roughness_buffer_msaa;
RID vrs;
RID color_fbs[FB_CONFIG_MAX];
int width, height;
uint32_t view_count;
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count);
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture);
~RenderBufferDataForwardMobile();
};

View File

@ -1827,6 +1827,16 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
rb->sss_texture = RID();
}
if (rb->vrs_fb.is_valid()) {
RD::get_singleton()->free(rb->vrs_fb);
rb->vrs_fb = RID();
}
if (rb->vrs_texture.is_valid()) {
RD::get_singleton()->free(rb->vrs_texture);
rb->vrs_texture = RID();
}
for (int i = 0; i < 2; i++) {
for (int l = 0; l < rb->blur[i].layers.size(); l++) {
for (int m = 0; m < rb->blur[i].layers[l].mipmaps.size(); m++) {
@ -3151,8 +3161,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
}
}
RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->render_target);
if (is_vrs_supported() && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
vrs->create_vrs_texture(p_internal_width, p_internal_height, p_view_count, rb->vrs_texture, rb->vrs_fb);
}
RID target_texture = texture_storage->render_target_get_rd_texture(rb->render_target);
rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_use_taa, p_view_count);
rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_use_taa, p_view_count, rb->vrs_texture);
if (is_clustered_enabled()) {
rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture);
@ -4929,7 +4944,7 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo
}
}
void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID *p_normal_roughness_views, RID p_voxel_gi_buffer) {
void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices) {
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
@ -5004,7 +5019,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//start GI
if (render_gi) {
gi.process_gi(p_render_data->render_buffers, p_normal_roughness_views, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this);
gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_vrs_slices, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this);
}
//Do shadow rendering (in parallel with GI)
@ -5045,13 +5060,13 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
if (p_use_ssao) {
// TODO make these proper stereo and thus use p_normal_roughness_views correctly
_process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_views[0], p_render_data->cam_projection);
// TODO make these proper stereo
_process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection);
}
if (p_use_ssil) {
// TODO make these proper stereo and thus use p_normal_roughness_views correctly
_process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_views[0], p_render_data->cam_projection, p_render_data->cam_transform);
// TODO make these proper stereo
_process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection, p_render_data->cam_transform);
}
}
@ -5240,6 +5255,11 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
}
if (rb != nullptr && rb->vrs_fb.is_valid()) {
// vrs_fb will only be valid if vrs is enabled
vrs->update_vrs_texture(rb->vrs_fb, rb->render_target);
}
_render_scene(&render_data, clear_color);
if (p_render_buffers.is_valid()) {
@ -5736,6 +5756,10 @@ int RendererSceneRenderRD::get_max_directional_lights() const {
return cluster.max_directional_lights;
}
bool RendererSceneRenderRD::is_vrs_supported() const {
return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS);
}
bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
// usable by default (unless low end = true)
return true;
@ -5975,6 +5999,7 @@ void fog() {
bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage));
copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage));
tone_mapper = memnew(RendererRD::ToneMapper);
vrs = memnew(RendererRD::VRS);
}
RendererSceneRenderRD::~RendererSceneRenderRD() {
@ -5989,6 +6014,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (tone_mapper) {
memdelete(tone_mapper);
}
if (vrs) {
memdelete(vrs);
}
for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) {
RD::get_singleton()->free(E.value.cubemap);

View File

@ -38,6 +38,7 @@
#include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
@ -104,11 +105,12 @@ protected:
RendererRD::BokehDOF *bokeh_dof = nullptr;
RendererRD::CopyEffects *copy_effects = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
RendererRD::VRS *vrs = nullptr;
double time = 0.0;
double time_step = 0.0;
struct RenderBufferData {
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) = 0;
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) = 0;
virtual ~RenderBufferData() {}
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
@ -149,7 +151,7 @@ protected:
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID *p_normal_roughness_views, RID p_voxel_gi_buffer);
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices);
void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
@ -492,6 +494,8 @@ private:
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!!!
RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling)
RID vrs_texture; // texture for vrs.
RID vrs_fb; // framebuffer to write to our vrs texture
// Access to the layers for each of our views (specifically needed for applying post effects on stereoscopic images)
struct View {
@ -1503,6 +1507,7 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
virtual bool is_vrs_supported() const;
virtual bool is_dynamic_gi_supported() const;
virtual bool is_clustered_enabled() const;
virtual bool is_volumetric_supported() const;

View File

@ -88,7 +88,7 @@ layout(set = 0, binding = 0) uniform sampler2DArray source_color;
layout(set = 1, binding = 0) uniform sampler2DArray source_depth;
layout(location = 1) out float depth;
#endif /* MODE_TWO_SOURCES */
#else
#else /* MULTIVIEW */
layout(set = 0, binding = 0) uniform sampler2D source_color;
#ifdef MODE_TWO_SOURCES
layout(set = 1, binding = 0) uniform sampler2D source_color2;
@ -139,7 +139,7 @@ void main() {
//uv.y = 1.0 - uv.y;
uv = 1.0 - uv;
}
#endif
#endif /* MODE_PANORAMA_TO_DP */
#ifdef MULTIVIEW
vec4 color = textureLod(source_color, uv, 0.0);
@ -148,12 +148,13 @@ void main() {
depth = textureLod(source_depth, uv, 0.0).r;
#endif /* MODE_TWO_SOURCES */
#else
#else /* MULTIVIEW */
vec4 color = textureLod(source_color, uv, 0.0);
#ifdef MODE_TWO_SOURCES
color += textureLod(source_color2, uv, 0.0);
#endif /* MODE_TWO_SOURCES */
#endif /* MULTIVIEW */
if (params.force_luminance) {
color.rgb = vec3(max(max(color.r, color.g), color.b));
}
@ -163,5 +164,6 @@ void main() {
if (params.srgb) {
color.rgb = linear_to_srgb(color.rgb);
}
frag_color = color;
}

View File

@ -0,0 +1,72 @@
#[vertex]
#version 450
#VERSION_DEFINES
#ifdef MULTIVIEW
#ifdef has_VK_KHR_multiview
#extension GL_EXT_multiview : enable
#define ViewIndex gl_ViewIndex
#else // has_VK_KHR_multiview
#define ViewIndex 0
#endif // has_VK_KHR_multiview
#endif //MULTIVIEW
#ifdef MULTIVIEW
layout(location = 0) out vec3 uv_interp;
#else
layout(location = 0) out vec2 uv_interp;
#endif
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.xy = base_arr[gl_VertexIndex];
#ifdef MULTIVIEW
uv_interp.z = ViewIndex;
#endif
gl_Position = vec4(uv_interp.xy * 2.0 - 1.0, 0.0, 1.0);
}
#[fragment]
#version 450
#VERSION_DEFINES
#ifdef MULTIVIEW
#ifdef has_VK_KHR_multiview
#extension GL_EXT_multiview : enable
#define ViewIndex gl_ViewIndex
#else // has_VK_KHR_multiview
#define ViewIndex 0
#endif // has_VK_KHR_multiview
#endif //MULTIVIEW
#ifdef MULTIVIEW
layout(location = 0) in vec3 uv_interp;
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
#else /* MULTIVIEW */
layout(location = 0) in vec2 uv_interp;
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif /* MULTIVIEW */
layout(location = 0) out uint frag_color;
void main() {
#ifdef MULTIVIEW
vec3 uv = uv_interp;
#else
vec2 uv = uv_interp;
#endif
#ifdef MULTIVIEW
vec4 color = textureLod(source_color, uv, 0.0);
#else /* MULTIVIEW */
vec4 color = textureLod(source_color, uv, 0.0);
#endif /* MULTIVIEW */
// See if we can change the sampler to one that returns int...
frag_color = uint(color.r * 256.0);
}

View File

@ -8,6 +8,12 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#define M_PI 3.141592
/* Specialization Constants (Toggles) */
layout(constant_id = 0) const bool sc_half_res = false;
layout(constant_id = 1) const bool sc_use_full_projection_matrix = false;
layout(constant_id = 2) const bool sc_use_vrs = false;
#define SDFGI_MAX_CASCADES 8
//set 0 for SDFGI and render buffers
@ -97,18 +103,20 @@ layout(set = 0, binding = 18, std140) uniform SceneData {
}
scene_data;
layout(r8ui, set = 0, binding = 19) uniform restrict readonly uimage2D vrs_buffer;
layout(push_constant, std430) uniform Params {
uint view_index;
uint max_voxel_gi_instances;
bool high_quality_vct;
bool orthogonal;
uint view_index;
vec4 proj_info;
float z_near;
float z_far;
float pad1;
float pad2;
float pad3;
}
params;
@ -140,7 +148,7 @@ vec4 blend_color(vec4 src, vec4 dst) {
}
vec3 reconstruct_position(ivec2 screen_pos) {
#ifdef USE_MULTIVIEW
if (sc_use_full_projection_matrix) {
vec4 pos;
pos.xy = (2.0 * vec2(screen_pos) / vec2(scene_data.screen_size)) - 1.0;
pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r * 2.0 - 1.0;
@ -149,7 +157,7 @@ vec3 reconstruct_position(ivec2 screen_pos) {
pos = scene_data.inv_projection[params.view_index] * pos;
return pos.xyz / pos.w;
#else
} else {
vec3 pos;
pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r;
@ -167,7 +175,7 @@ vec3 reconstruct_position(ivec2 screen_pos) {
}
return pos;
#endif
}
}
void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
@ -587,7 +595,6 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
vec4 fetch_normal_and_roughness(ivec2 pos) {
vec4 normal_roughness = texelFetch(sampler2D(normal_roughness_buffer, linear_sampler), pos, 0);
normal_roughness.xyz = normalize(normal_roughness.xyz * 2.0 - 1.0);
return normal_roughness;
}
@ -600,7 +607,7 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
if (normal.length() > 0.5) {
//valid normal, can do GI
float roughness = normal_roughness.w;
vec3 view = -normalize(mat3(scene_data.cam_transform) * (vertex - scene_data.eye_offset[params.view_index].xyz));
vec3 view = -normalize(mat3(scene_data.cam_transform) * (vertex - scene_data.eye_offset[gl_GlobalInvocationID.z].xyz));
vertex = mat3(scene_data.cam_transform) * vertex;
normal = normalize(mat3(scene_data.cam_transform) * normal);
vec3 reflection = normalize(reflect(-view, normal));
@ -648,9 +655,35 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
void main() {
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
#ifdef MODE_HALF_RES
uint vrs_x, vrs_y;
if (sc_use_vrs) {
ivec2 vrs_pos;
// Currenty we use a 16x16 texel, possibly some day make this configurable.
if (sc_half_res) {
vrs_pos = pos >> 3;
} else {
vrs_pos = pos >> 4;
}
uint vrs_texel = imageLoad(vrs_buffer, vrs_pos).r;
// note, valid values for vrs_x and vrs_y are 1, 2 and 4.
vrs_x = 1 << ((vrs_texel >> 2) & 3);
vrs_y = 1 << (vrs_texel & 3);
if (mod(pos.x, vrs_x) != 0) {
return;
}
if (mod(pos.y, vrs_y) != 0) {
return;
}
}
if (sc_half_res) {
pos <<= 1;
#endif
}
if (any(greaterThanEqual(pos, scene_data.screen_size))) { //too large, do nothing
return;
}
@ -663,10 +696,69 @@ void main() {
process_gi(pos, vertex, ambient_light, reflection_light);
#ifdef MODE_HALF_RES
if (sc_half_res) {
pos >>= 1;
#endif
}
imageStore(ambient_buffer, pos, ambient_light);
imageStore(reflection_buffer, pos, reflection_light);
if (sc_use_vrs) {
if (vrs_x > 1) {
imageStore(ambient_buffer, pos + ivec2(1, 0), ambient_light);
imageStore(reflection_buffer, pos + ivec2(1, 0), reflection_light);
}
if (vrs_x > 2) {
imageStore(ambient_buffer, pos + ivec2(2, 0), ambient_light);
imageStore(reflection_buffer, pos + ivec2(2, 0), reflection_light);
imageStore(ambient_buffer, pos + ivec2(3, 0), ambient_light);
imageStore(reflection_buffer, pos + ivec2(3, 0), reflection_light);
}
if (vrs_y > 1) {
imageStore(ambient_buffer, pos + ivec2(0, 1), ambient_light);
imageStore(reflection_buffer, pos + ivec2(0, 1), reflection_light);
}
if (vrs_y > 1 && vrs_x > 1) {
imageStore(ambient_buffer, pos + ivec2(1, 1), ambient_light);
imageStore(reflection_buffer, pos + ivec2(1, 1), reflection_light);
}
if (vrs_y > 1 && vrs_x > 2) {
imageStore(ambient_buffer, pos + ivec2(2, 1), ambient_light);
imageStore(reflection_buffer, pos + ivec2(2, 1), reflection_light);
imageStore(ambient_buffer, pos + ivec2(3, 1), ambient_light);
imageStore(reflection_buffer, pos + ivec2(3, 1), reflection_light);
}
if (vrs_y > 2) {
imageStore(ambient_buffer, pos + ivec2(0, 2), ambient_light);
imageStore(reflection_buffer, pos + ivec2(0, 2), reflection_light);
imageStore(ambient_buffer, pos + ivec2(0, 3), ambient_light);
imageStore(reflection_buffer, pos + ivec2(0, 3), reflection_light);
}
if (vrs_y > 2 && vrs_x > 1) {
imageStore(ambient_buffer, pos + ivec2(1, 2), ambient_light);
imageStore(reflection_buffer, pos + ivec2(1, 2), reflection_light);
imageStore(ambient_buffer, pos + ivec2(1, 3), ambient_light);
imageStore(reflection_buffer, pos + ivec2(1, 3), reflection_light);
}
if (vrs_y > 2 && vrs_x > 2) {
imageStore(ambient_buffer, pos + ivec2(2, 2), ambient_light);
imageStore(reflection_buffer, pos + ivec2(2, 2), reflection_light);
imageStore(ambient_buffer, pos + ivec2(2, 3), ambient_light);
imageStore(reflection_buffer, pos + ivec2(2, 3), reflection_light);
imageStore(ambient_buffer, pos + ivec2(3, 2), ambient_light);
imageStore(reflection_buffer, pos + ivec2(3, 2), reflection_light);
imageStore(ambient_buffer, pos + ivec2(3, 3), ambient_light);
imageStore(reflection_buffer, pos + ivec2(3, 3), reflection_light);
}
}
}

View File

@ -349,7 +349,6 @@ TextureStorage::TextureStorage() {
Vector<uint8_t> pv;
pv.resize(16 * 4);
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 0);
pv.set(i * 4 + 1, 0);
@ -358,7 +357,6 @@ TextureStorage::TextureStorage() {
}
{
//take the chance and initialize decal atlas to something
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);
decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
@ -366,6 +364,29 @@ TextureStorage::TextureStorage() {
}
}
{ //create default VRS
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R8_UINT;
tformat.width = 4;
tformat.height = 4;
tformat.array_layers = 1;
tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
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_VRS] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
}
{
Vector<String> sdf_modes;
sdf_modes.push_back("\n#define MODE_LOAD\n");
@ -2751,3 +2772,31 @@ void TextureStorage::render_target_set_backbuffer_uniform_set(RID p_render_targe
ERR_FAIL_COND(!rt);
rt->backbuffer_uniform_set = p_uniform_set;
}
void TextureStorage::render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->vrs_mode = p_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_COND(!rt);
rt->vrs_texture = p_texture;
}
RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED);
return rt->vrs_mode;
}
RID TextureStorage::render_target_get_vrs_texture(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->vrs_texture;
}

View File

@ -52,6 +52,7 @@ enum DefaultRDTexture {
DEFAULT_RD_TEXTURE_3D_BLACK,
DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
DEFAULT_RD_TEXTURE_2D_UINT,
DEFAULT_RD_TEXTURE_VRS,
DEFAULT_RD_TEXTURE_MAX
};
@ -229,6 +230,10 @@ struct RenderTarget {
RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
Size2i process_size;
// VRS
RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED;
RID vrs_texture;
//texture generated for this owner (nor RD).
RID texture;
bool was_used;
@ -549,6 +554,12 @@ public:
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
bool render_target_is_sdf_enabled(RID p_render_target) const;
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override;
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override;
RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const;
RID render_target_get_vrs_texture(RID p_render_target) const;
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
RID render_target_get_rd_texture(RID p_render_target);

View File

@ -1207,6 +1207,22 @@ RID RendererViewport::viewport_find_from_screen_attachment(DisplayServer::Window
return RID();
}
void RendererViewport::viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
RSG::texture_storage->render_target_set_vrs_mode(viewport->render_target, p_mode);
_configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_vrs_texture(RID p_viewport, RID p_texture) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
RSG::texture_storage->render_target_set_vrs_texture(viewport->render_target, p_texture);
_configure_3d_render_buffers(viewport);
}
bool RendererViewport::free(RID p_rid) {
if (viewport_owner.owns(p_rid)) {
Viewport *viewport = viewport_owner.get_or_null(p_rid);

View File

@ -284,6 +284,9 @@ 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_texture(RID p_viewport, RID p_texture);
void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time);
void set_default_clear_color(const Color &p_color);

View File

@ -64,12 +64,12 @@ Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_
ERR_FAIL_COND_V(!compile_to_spirv_function, Vector<uint8_t>());
return compile_to_spirv_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, this);
}
String RenderingDevice::shader_get_spirv_cache_key() const {
if (get_spirv_cache_key_function) {
return get_spirv_cache_key_function(&device_capabilities);
return get_spirv_cache_key_function(this);
}
return String();
}
@ -279,6 +279,7 @@ static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constan
}
return ret;
}
RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {
PipelineRasterizationState rasterization_state;
if (p_rasterization_state.is_valid()) {

View File

@ -123,19 +123,10 @@ public:
DeviceFamily device_family = DEVICE_UNKNOWN;
uint32_t version_major = 1.0;
uint32_t version_minor = 0.0;
// subgroup capabilities
uint32_t subgroup_size = 0;
uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations
// features
bool supports_multiview = false; // If true this device supports multiview options
bool supports_fsr_half_float = false; // If true this device supports FSR scaling 3D in half float mode, otherwise use the fallback mode
};
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 String (*ShaderSPIRVGetCacheKeyFunction)(const RenderingDevice *p_render_device);
typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
private:
@ -444,6 +435,7 @@ public:
TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9),
TEXTURE_USAGE_VRS_ATTACHMENT_BIT = (1 << 10),
};
enum TextureSwizzle {
@ -552,6 +544,7 @@ public:
Vector<int32_t> resolve_attachments;
Vector<int32_t> preserve_attachments;
int32_t depth_attachment = ATTACHMENT_UNUSED;
int32_t vrs_attachment = ATTACHMENT_UNUSED; // density map for VRS, only used if supported
};
virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0;
@ -675,6 +668,13 @@ public:
const Capabilities *get_device_capabilities() const { return &device_capabilities; };
enum Features {
SUPPORTS_MULTIVIEW,
SUPPORTS_FSR_HALF_FLOAT,
SUPPORTS_ATTACHMENT_VRS,
};
virtual bool has_feature(const Features p_feature) const = 0;
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;
@ -1221,9 +1221,12 @@ public:
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X,
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y,
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z,
LIMIT_SUBGROUP_SIZE,
LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
LIMIT_SUBGROUP_OPERATIONS,
};
virtual uint64_t limit_get(Limit p_limit) = 0;
virtual uint64_t limit_get(Limit p_limit) const = 0;
//methods below not exposed, used by RenderingDeviceRD
virtual void prepare_screen_for_drawing() = 0;
@ -1324,6 +1327,7 @@ VARIANT_ENUM_CAST(RenderingDevice::InitialAction)
VARIANT_ENUM_CAST(RenderingDevice::FinalAction)
VARIANT_ENUM_CAST(RenderingDevice::Limit)
VARIANT_ENUM_CAST(RenderingDevice::MemoryType)
VARIANT_ENUM_CAST(RenderingDevice::Features)
typedef RenderingDevice RD;

View File

@ -637,6 +637,9 @@ public:
FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID)
FUNC2(viewport_set_vrs_mode, RID, ViewportVRSMode)
FUNC2(viewport_set_vrs_texture, RID, RID)
/* ENVIRONMENT API */
#undef server_name

View File

@ -143,6 +143,9 @@ public:
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0;
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0;
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0;
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) = 0;
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) = 0;
};
#endif // !TEXTURE_STORAGE_H

View File

@ -2225,6 +2225,9 @@ 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_texture", "viewport", "texture"), &RenderingServer::viewport_set_vrs_texture);
BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR);
BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR);
BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX);
@ -2300,6 +2303,11 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS);
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_MOTION_VECTORS);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_DISABLED);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_TEXTURE);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR);
BIND_ENUM_CONSTANT(VIEWPORT_VRS_MAX);
/* SKY API */
ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create);

View File

@ -946,6 +946,16 @@ public:
virtual RID viewport_find_from_screen_attachment(DisplayServer::WindowID p_id = DisplayServer::MAIN_WINDOW_ID) const = 0;
enum ViewportVRSMode {
VIEWPORT_VRS_DISABLED,
VIEWPORT_VRS_TEXTURE,
VIEWPORT_VRS_XR,
VIEWPORT_VRS_MAX,
};
virtual void viewport_set_vrs_mode(RID p_viewport, ViewportVRSMode p_mode) = 0;
virtual void viewport_set_vrs_texture(RID p_viewport, RID p_texture) = 0;
/* SKY API */
enum SkyMode {
@ -1609,6 +1619,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw);
VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality);
VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize);
VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale);
VARIANT_ENUM_CAST(RenderingServer::ViewportVRSMode);
VARIANT_ENUM_CAST(RenderingServer::SkyMode);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource);

View File

@ -29,7 +29,7 @@
/*************************************************************************/
#include "xr_interface.h"
// #include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_compositor.h"
void XRInterface::_bind_methods() {
ADD_SIGNAL(MethodInfo("play_area_changed", PropertyInfo(Variant::INT, "mode")));
@ -114,7 +114,12 @@ void XRInterface::set_primary(bool p_primary) {
XRInterface::XRInterface() {}
XRInterface::~XRInterface() {}
XRInterface::~XRInterface() {
if (vrs.vrs_texture.is_valid()) {
RS::get_singleton()->free(vrs.vrs_texture);
vrs.vrs_texture = RID();
}
}
// query if this interface supports this play area mode
bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
@ -151,6 +156,85 @@ int XRInterface::get_camera_feed_id() {
return 0;
}
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.
Size2 texel_size = Size2(16.0, 16.0); // For now we assume we always use 16x16 texels, seems to be the standard.
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_size.x), round(0.5 + target_size.y / texel_size.y));
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
// 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...
CameraMatrix 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;
}
}
Ref<Image> image;
image.instantiate();
image->create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_R8, data);
images.push_back(image);
}
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;
}
/** these are optional, so we want dummies **/
PackedStringArray XRInterface::get_suggested_tracker_names() const {
PackedStringArray arr;

View File

@ -120,6 +120,7 @@ public:
virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
virtual CameraMatrix 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 */
// note, external color/depth/vrs texture support will be added here soon.
@ -133,6 +134,12 @@ public:
XRInterface();
~XRInterface();
private:
struct VRSData {
RID vrs_texture;
Size2i size;
} vrs;
};
VARIANT_ENUM_CAST(XRInterface::Capabilities);

View File

@ -50,6 +50,7 @@ void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_camera_transform);
GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform");
GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far");
GDVIRTUAL_BIND(_get_vrs_texture);
GDVIRTUAL_BIND(_process);
GDVIRTUAL_BIND(_pre_render);
@ -273,6 +274,15 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, doub
return CameraMatrix();
}
RID XRInterfaceExtension::get_vrs_texture() {
RID vrs_texture;
if (GDVIRTUAL_CALL(_get_vrs_texture, vrs_texture)) {
return vrs_texture;
} else {
return XRInterface::get_vrs_texture();
}
}
void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) {
BlitToScreen blit;

View File

@ -101,12 +101,14 @@ public:
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
virtual RID get_vrs_texture() override;
GDVIRTUAL0R(Size2, _get_render_target_size);
GDVIRTUAL0R(uint32_t, _get_view_count);
GDVIRTUAL0R(Transform3D, _get_camera_transform);
GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double);
GDVIRTUAL0R(RID, _get_vrs_texture);
void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0);