1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-07 12:30:27 +00:00

Add color pass flags to Forward Clustered renderer

This commit removes a lot of enum values related to the color render pass in favor of a new flag-bases approach. This means instead of hard-coding all the possible option combinations into enums, we can write our logic by checking a bit-mask.

The changes in rendering_device_vulkan.cpp add support for unused attachments. That means RenderingDeviceVulkan::framebuffer_create() can take null RIDs in the attachments vector, which will result in VK_ATTACHMENT_UNUSED entries in the render pass.

This is used in this same PR to establish fixed locations for the color pass attachments (only color and separate specular so far, but TAA will add motion vectors as well). This way the attachment locations in the shader can stay the same regardless of which attachments are actually used.

Right now all the combinations of flags are generated, but we will need to add a way to limit the amount of combinations in the future.
This commit is contained in:
jfons
2022-02-17 10:56:22 +01:00
parent 4263f02f28
commit e69d762dd0
7 changed files with 337 additions and 248 deletions

View File

@@ -3364,8 +3364,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
attachment_last_pass.resize(p_attachments.size());
Vector<VkAttachmentDescription> attachments;
Vector<int> attachment_remap;
for (int i = 0; i < p_attachments.size(); i++) {
if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {
attachment_remap.push_back(VK_ATTACHMENT_UNUSED);
continue;
}
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)),
@@ -3567,7 +3573,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
attachment_last_pass[i] = -1;
attachment_remap.push_back(attachments.size());
attachments.push_back(description);
}
@@ -3612,7 +3618,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples.");
}
reference.attachment = attachment;
reference.attachment = attachment_remap[attachment];
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_last_pass[attachment] = i;
}
@@ -3631,7 +3637,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
reference.attachment = attachment;
reference.attachment = attachment_remap[attachment];
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
@@ -3657,7 +3663,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;
ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
reference.attachment = attachment;
reference.attachment = attachment_remap[attachment];
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
@@ -3671,7 +3677,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
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_DEPTH_STENCIL_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment.");
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;
depth_stencil_reference.attachment = attachment_remap[attachment];
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachment_last_pass[attachment] = i;
@@ -3958,14 +3964,13 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
for (int i = 0; i < p_texture_attachments.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
pass.depth_attachment = i;
} else {
pass.color_attachments.push_back(i);
pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
}
}
@@ -3979,29 +3984,35 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
_THREAD_SAFE_METHOD_
Vector<AttachmentFormat> attachments;
attachments.resize(p_texture_attachments.size());
Size2i size;
bool size_set = false;
for (int i = 0; i < p_texture_attachments.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
if (i == 0) {
size.width = texture->width;
size.height = texture->height;
} 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.");
}
AttachmentFormat af;
af.format = texture->format;
af.samples = texture->samples;
af.usage_flags = texture->usage_flags;
attachments.push_back(af);
Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
if (!texture) {
af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;
} else {
ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
if (!size_set) {
size.width = texture->width;
size.height = texture->height;
size_set = true;
} 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.");
}
af.format = texture->format;
af.samples = texture->samples;
af.usage_flags = texture->usage_flags;
}
attachments.write[i] = af;
}
ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");
FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count);
if (format_id == INVALID_ID) {
return RID();
@@ -4019,7 +4030,9 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
RID id = framebuffer_owner.make_rid(framebuffer);
for (int i = 0; i < p_texture_attachments.size(); i++) {
_add_dependency(id, p_texture_attachments[i]);
if (p_texture_attachments[i].is_valid()) {
_add_dependency(id, p_texture_attachments[i]);
}
}
return id;
@@ -6417,49 +6430,55 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
Vector<VkPipelineColorBlendAttachmentState> attachment_states;
{
const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
attachment_states.resize(pass.color_attachments.size());
ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());
for (int i = 0; i < pass.color_attachments.size(); i++) {
if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) {
int idx = attachment_states.size();
VkPipelineColorBlendAttachmentState state;
if (pass.color_attachments[i] == FramebufferPass::ATTACHMENT_UNUSED) {
state.blendEnable = false;
ERR_FAIL_INDEX_V(idx, p_blend_state.attachments.size(), RID());
VkPipelineColorBlendAttachmentState state;
state.blendEnable = p_blend_state.attachments[idx].enable_blend;
state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
state.colorBlendOp = VK_BLEND_OP_ADD;
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[idx].src_color_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_color_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].color_blend_op, BLEND_OP_MAX, RID());
state.colorBlendOp = blend_operations[p_blend_state.attachments[idx].color_blend_op];
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].src_alpha_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_alpha_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].alpha_blend_op, BLEND_OP_MAX, RID());
state.alphaBlendOp = blend_operations[p_blend_state.attachments[idx].alpha_blend_op];
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
state.alphaBlendOp = VK_BLEND_OP_ADD;
state.colorWriteMask = 0;
if (p_blend_state.attachments[idx].write_r) {
} else {
state.blendEnable = p_blend_state.attachments[i].enable_blend;
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());
state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op];
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor];
ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());
state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op];
state.colorWriteMask = 0;
if (p_blend_state.attachments[i].write_r) {
state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
}
if (p_blend_state.attachments[idx].write_g) {
if (p_blend_state.attachments[i].write_g) {
state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
}
if (p_blend_state.attachments[idx].write_b) {
if (p_blend_state.attachments[i].write_b) {
state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
}
if (p_blend_state.attachments[idx].write_a) {
if (p_blend_state.attachments[i].write_a) {
state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
}
attachment_states.push_back(state);
idx++;
}
attachment_states.write[i] = state;
}
ERR_FAIL_COND_V(attachment_states.size() != p_blend_state.attachments.size(), RID());
}
color_blend_state_create_info.attachmentCount = attachment_states.size();
@@ -6863,10 +6882,11 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
Vector<VkImageView> attachments;
for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
ERR_FAIL_COND_V(!texture, ERR_BUG);
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) {
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);
}
}
framebuffer_create_info.attachmentCount = attachments.size();
framebuffer_create_info.pAttachments = attachments.ptr();
@@ -6910,13 +6930,18 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
Vector<VkClearValue> clear_values;
clear_values.resize(framebuffer->texture_ids.size());
int clear_values_count = 0;
{
int color_index = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
VkClearValue clear_value;
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
if (!texture) {
color_index++;
continue;
}
if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug
Color clear_color = p_clear_colors[color_index];
@@ -6934,15 +6959,18 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
clear_value.color.float32[2] = 0;
clear_value.color.float32[3] = 0;
}
clear_values.write[i] = clear_value;
clear_values.write[clear_values_count++] = clear_value;
}
}
render_pass_begin.clearValueCount = clear_values.size();
render_pass_begin.clearValueCount = clear_values_count;
render_pass_begin.pClearValues = clear_values.ptr();
for (int i = 0; i < p_storage_textures.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_storage_textures[i]);
if (!texture) {
continue;
}
ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage.");
if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
@@ -6981,6 +7009,9 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
if (!texture) {
continue;
}
texture->bound = true;
draw_list_bound_textures.push_back(framebuffer->texture_ids[i]);
}
@@ -6989,15 +7020,21 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
}
void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
ERR_FAIL_COND_MSG(p_clear_color && p_clear_colors.size() != framebuffer->texture_ids.size(), "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(framebuffer->texture_ids.size()) + ").");
Vector<VkClearAttachment> clear_attachments;
int color_index = 0;
int texture_index = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
VkClearAttachment clear_at = {};
if (!texture) {
texture_index++;
continue;
}
VkClearAttachment clear_at = {};
if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug
Color clear_color = p_clear_colors[color_index];
Color clear_color = p_clear_colors[texture_index++];
clear_at.clearValue.color.float32[0] = clear_color.r;
clear_at.clearValue.color.float32[1] = clear_color.g;
clear_at.clearValue.color.float32[2] = clear_color.b;
@@ -7073,18 +7110,14 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
}
if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values
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->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
color_count++;
}
}
ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID,
"Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
}
VkFramebuffer vkframebuffer;
@@ -7176,7 +7209,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
color_count++;
}
}