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:
parent
e3a8ab68ce
commit
d139131aab
|
@ -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="""">
|
||||
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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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,83 +3408,95 @@ 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;
|
||||
|
||||
// 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
|
||||
// stage
|
||||
// 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;
|
||||
|
||||
switch (is_depth ? p_initial_depth_action : p_initial_action) {
|
||||
case INITIAL_ACTION_CLEAR_REGION:
|
||||
case INITIAL_ACTION_CLEAR: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
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
|
||||
// stage
|
||||
|
||||
switch (is_depth ? p_initial_depth_action : p_initial_action) {
|
||||
case INITIAL_ACTION_CLEAR_REGION:
|
||||
case INITIAL_ACTION_CLEAR: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_KEEP: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_DROP: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_CLEAR_REGION_CONTINUE:
|
||||
case INITIAL_ACTION_CONTINUE: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_KEEP: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_DROP: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
case INITIAL_ACTION_CLEAR_REGION_CONTINUE:
|
||||
case INITIAL_ACTION_CONTINUE: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
} 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
|
||||
dependency_from_external.srcStageMask |= reading_stages;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,58 +3555,69 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
|
|||
}
|
||||
}
|
||||
|
||||
switch (is_depth ? final_depth_action : final_action) {
|
||||
case FINAL_ACTION_READ: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
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_COLOR_ATTACHMENT_OPTIMAL);
|
||||
update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true);
|
||||
} 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
|
||||
// TODO: What does this mean about the next usage (and thus appropriate dependency masks
|
||||
}
|
||||
} break;
|
||||
case FINAL_ACTION_DISCARD: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
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_COLOR_ATTACHMENT_OPTIMAL);
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
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
|
||||
}
|
||||
} break;
|
||||
case FINAL_ACTION_CONTINUE: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
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
|
||||
}
|
||||
if (is_vrs) {
|
||||
// We don't change our VRS texture during this process
|
||||
|
||||
} break;
|
||||
default: {
|
||||
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
|
||||
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) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
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_COLOR_ATTACHMENT_OPTIMAL);
|
||||
update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true);
|
||||
} 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
|
||||
// TODO: What does this mean about the next usage (and thus appropriate dependency masks
|
||||
}
|
||||
} break;
|
||||
case FINAL_ACTION_DISCARD: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
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_COLOR_ATTACHMENT_OPTIMAL);
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
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.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: {
|
||||
if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
} else {
|
||||
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;
|
||||
default: {
|
||||
ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3586,12 +3626,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
|
|||
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,8 +7022,10 @@ 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);
|
||||
ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG);
|
||||
ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG);
|
||||
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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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; };
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
@ -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 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();
|
||||
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++) {
|
||||
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,29 +3705,45 @@ 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);
|
||||
|
||||
// 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..
|
||||
|
||||
// setup our push constant
|
||||
|
||||
PushConstant push_constant;
|
||||
|
||||
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;
|
||||
|
||||
// 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();
|
||||
|
||||
// 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++) {
|
||||
// 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..
|
||||
|
||||
// setup our push constant
|
||||
|
||||
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();
|
||||
|
||||
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];
|
||||
|
||||
bool use_sdfgi = rb->sdfgi != nullptr;
|
||||
bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
|
||||
|
||||
// setup our uniform set
|
||||
if (rb->rbgi.uniform_set[v].is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->rbgi.uniform_set[v])) {
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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,34 +148,34 @@ vec4 blend_color(vec4 src, vec4 dst) {
|
|||
}
|
||||
|
||||
vec3 reconstruct_position(ivec2 screen_pos) {
|
||||
#ifdef USE_MULTIVIEW
|
||||
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;
|
||||
pos.w = 1.0;
|
||||
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;
|
||||
pos.w = 1.0;
|
||||
|
||||
pos = scene_data.inv_projection[params.view_index] * pos;
|
||||
pos = scene_data.inv_projection[params.view_index] * pos;
|
||||
|
||||
return pos.xyz / pos.w;
|
||||
#else
|
||||
vec3 pos;
|
||||
pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r;
|
||||
|
||||
pos.z = pos.z * 2.0 - 1.0;
|
||||
if (params.orthogonal) {
|
||||
pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
|
||||
return pos.xyz / pos.w;
|
||||
} else {
|
||||
pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near));
|
||||
}
|
||||
pos.z = -pos.z;
|
||||
vec3 pos;
|
||||
pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r;
|
||||
|
||||
pos.xy = vec2(screen_pos) * params.proj_info.xy + params.proj_info.zw;
|
||||
if (!params.orthogonal) {
|
||||
pos.xy *= pos.z;
|
||||
}
|
||||
pos.z = pos.z * 2.0 - 1.0;
|
||||
if (params.orthogonal) {
|
||||
pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
|
||||
} else {
|
||||
pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near));
|
||||
}
|
||||
pos.z = -pos.z;
|
||||
|
||||
return pos;
|
||||
#endif
|
||||
pos.xy = vec2(screen_pos) * params.proj_info.xy + params.proj_info.zw;
|
||||
if (!params.orthogonal) {
|
||||
pos.xy *= pos.z;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
pos <<= 1;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
pos >>= 1;
|
||||
#endif
|
||||
if (sc_half_res) {
|
||||
pos >>= 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue