Vulkan: Support for Framebuffer with Missing Attachments #113141

Merged
Jeroen Bakker merged 9 commits from Jeroen-Bakker/blender:vulkan/wireframe-shading-mode into main 2023-10-10 09:27:14 +02:00
6 changed files with 75 additions and 14 deletions

View File

@ -55,6 +55,7 @@ void VKContext::sync_backbuffer()
command_buffer_.init(device);
command_buffer_.begin_recording();
device.init_dummy_buffer(*this);
device.init_dummy_color_attachment();
}
device.descriptor_pools_get().reset();
}

View File

@ -27,6 +27,10 @@ void VKDevice::deinit()
vkDestroyCommandPool(vk_device_, vk_command_pool_, vk_allocation_callbacks);
dummy_buffer_.free();
if (dummy_color_attachment_.has_value()) {
delete &(*dummy_color_attachment_).get();
dummy_color_attachment_.reset();
}
sampler_.free();
destroy_discarded_resources();
vmaDestroyAllocator(mem_allocator_);
@ -135,6 +139,19 @@ void VKDevice::init_dummy_buffer(VKContext &context)
dummy_buffer_.clear(context, 0);
}
void VKDevice::init_dummy_color_attachment()
{
if (dummy_color_attachment_.has_value()) {
return;
}
GPUTexture *texture = GPU_texture_create_2d(
"dummy_attachment", 1, 1, 1, GPU_R32F, GPU_TEXTURE_USAGE_ATTACHMENT, nullptr);
BLI_assert(texture);
VKTexture &vk_texture = *unwrap(unwrap(texture));
dummy_color_attachment_ = std::make_optional(std::reference_wrapper(vk_texture));
}
/* -------------------------------------------------------------------- */
/** \name Platform/driver/device information
* \{ */

View File

@ -72,6 +72,7 @@ class VKDevice : public NonCopyable {
/** Buffer to bind to unbound resource locations. */
VKBuffer dummy_buffer_;
std::optional<std::reference_wrapper<VKTexture>> dummy_color_attachment_;
Vector<std::pair<VkImage, VmaAllocation>> discarded_images_;
Vector<std::pair<VkBuffer, VmaAllocation>> discarded_buffers_;
@ -158,6 +159,7 @@ class VKDevice : public NonCopyable {
* Dummy buffer can only be initialized after the command buffer of the context is retrieved.
*/
void init_dummy_buffer(VKContext &context);
void init_dummy_color_attachment();
void deinit();
eGPUDeviceType device_type() const;
@ -183,6 +185,12 @@ class VKDevice : public NonCopyable {
return dummy_buffer_;
}
VKTexture &dummy_color_attachment_get() const
{
BLI_assert(dummy_color_attachment_.has_value());
return (*dummy_color_attachment_).get();
}
void discard_image(VkImage vk_image, VmaAllocation vma_allocation);
void discard_image_view(VkImageView vk_image_view);
void discard_buffer(VkBuffer vk_buffer, VmaAllocation vma_allocation);

View File

@ -413,6 +413,8 @@ void VKFrameBuffer::render_pass_create()
bool has_depth_attachment = false;
bool found_attachment = false;
const VKImageView &dummy_attachment =
VKBackend::get().device_get().dummy_color_attachment_get().image_view_get();
int depth_location = -1;
for (int type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; type--) {
@ -436,8 +438,14 @@ void VKFrameBuffer::render_pass_create()
int attachment_location = type >= GPU_FB_COLOR_ATTACHMENT0 ? type - GPU_FB_COLOR_ATTACHMENT0 :
depth_location;
const bool is_depth_attachment = ELEM(
type, GPU_FB_DEPTH_ATTACHMENT, GPU_FB_DEPTH_STENCIL_ATTACHMENT);
if (attachment.tex) {
BLI_assert_msg(!is_depth_attachment || !has_depth_attachment,
"There can only be one depth/stencil attachment.");
has_depth_attachment |= is_depth_attachment;
/* Ensure texture is allocated to ensure the image view. */
VKTexture &texture = *static_cast<VKTexture *>(unwrap(attachment.tex));
image_views_.append(VKImageView(texture,
@ -461,18 +469,31 @@ void VKFrameBuffer::render_pass_create()
attachment_description.finalLayout = texture.current_layout_get();
/* Create the attachment reference. */
const bool is_depth_attachment = ELEM(
type, GPU_FB_DEPTH_ATTACHMENT, GPU_FB_DEPTH_STENCIL_ATTACHMENT);
BLI_assert_msg(!is_depth_attachment || !has_depth_attachment,
"There can only be one depth/stencil attachment.");
has_depth_attachment |= is_depth_attachment;
VkAttachmentReference &attachment_reference = attachment_references[attachment_location];
attachment_reference.attachment = attachment_location;
attachment_reference.layout = is_depth_attachment ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
VK_IMAGE_LAYOUT_GENERAL;
}
else if (!is_depth_attachment) {
image_views[attachment_location] = dummy_attachment.vk_handle();
VkAttachmentDescription &attachment_description =
attachment_descriptions[attachment_location];
attachment_description.flags = 0;
attachment_description.format = VK_FORMAT_R32_SFLOAT;
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment_description.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachment_description.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference &attachment_reference = attachment_references[attachment_location];
attachment_reference.attachment = VK_ATTACHMENT_UNUSED;
attachment_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
}
/* Update the size, viewport & scissor based on the first attachment. */
@ -492,7 +513,6 @@ void VKFrameBuffer::render_pass_create()
scissor_reset();
/* Create render pass. */
const int attachment_len = has_depth_attachment ? depth_location + 1 : depth_location;
const int color_attachment_len = depth_location;
VkSubpassDescription subpass = {};
@ -594,6 +614,17 @@ void VKFrameBuffer::update_size()
size_set(1, 1);
}
int VKFrameBuffer::color_attachments_resource_size() const
{
int size = 0;
for (int color_slot : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) {
if (color_tex(color_slot) != nullptr) {
size = max_ii(color_slot + 1, size);
}
}
return size;
}
/** \} */
} // namespace blender::gpu

View File

@ -109,6 +109,15 @@ class VKFrameBuffer : public FrameBuffer {
*/
void update_size();
/**
* Return the number of color attachments of this frame buffer, including unused color
* attachments.
*
* Framebuffers can have unused attachments. When higher attachment slots are being used, unused
* lower attachment slots will be counted as they are required resources in renderpasses.
*/
int color_attachments_resource_size() const;
private:
void update_attachments();
void render_pass_free();

View File

@ -78,13 +78,8 @@ void VKPipelineStateManager::force_state(const GPUState &state,
void VKPipelineStateManager::finalize_color_blend_state(const VKFrameBuffer &framebuffer)
{
color_blend_attachments.clear();
for (int color_slot = 0; color_slot < GPU_FB_MAX_COLOR_ATTACHMENT; color_slot++) {
VKTexture *texture = unwrap(unwrap(framebuffer.color_tex(color_slot)));
if (texture) {
color_blend_attachments.append(color_blend_attachment_template);
}
}
color_blend_attachments.append_n_times(color_blend_attachment_template,
framebuffer.color_attachments_resource_size());
pipeline_color_blend_state.attachmentCount = color_blend_attachments.size();
pipeline_color_blend_state.pAttachments = color_blend_attachments.data();
}