Vulkan: Support for Framebuffer with Missing Attachments #113141
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue