Vulkan: Remove support for render passes

Vulkan 1.0 render passes have been replaced by dynamic rendering in 1.2.
Blender Vulkan backend was implemented with dynamic rendering in mind.
All our supported platforms support dynamic rendering. Render pass support
was added to try to work around an issue with legacy drivers. However these
drivers also fail with render passes.

Using render passes had several limitations (blending and some workbench
features were not supported).  As no GPU uses it and it is quite some code
to support it is better to remove it.

Pull Request: https://projects.blender.org/blender/blender/pulls/144149
This commit is contained in:
Jeroen Bakker
2025-08-08 08:08:58 +02:00
parent 73afa1c94f
commit 97f1aeb84c
23 changed files with 62 additions and 486 deletions

View File

@@ -329,9 +329,7 @@ class GHOST_DeviceVK {
VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = {};
dynamic_rendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
dynamic_rendering.dynamicRendering = VK_TRUE;
if (extension_enabled(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) {
feature_struct_ptr.push_back(&dynamic_rendering);
}
feature_struct_ptr.push_back(&dynamic_rendering);
VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT
dynamic_rendering_unused_attachments = {};
@@ -1241,7 +1239,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
#else
required_device_extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
#endif
optional_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
required_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
optional_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
optional_device_extensions.push_back(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
optional_device_extensions.push_back(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);

View File

@@ -246,15 +246,6 @@ void SceneState::init(const DRWContext *context,
shading.flag & V3D_SHADING_DEPTH_OF_FIELD;
draw_object_id = (draw_outline || draw_curvature);
/* Legacy Vulkan devices don't support gaps between color attachments. We disable outline
* drawing on these devices. There are situations outline drawing can just work, but we need to
* be sure transparency depth drawing isn't used. */
/* TODO(jbakker): Add support on legacy Vulkan devices by introducing specific depth shaders. */
if ((shading.type < OB_SOLID || xray_mode) && GPU_vulkan_render_pass_workaround()) {
draw_object_id = false;
draw_outline = false;
}
};
static const CustomData *get_loop_custom_data(const Mesh *mesh)

View File

@@ -53,8 +53,6 @@ bool GPU_use_main_context_workaround();
bool GPU_use_hq_normals_workaround();
bool GPU_crappy_amd_driver();
bool GPU_vulkan_render_pass_workaround();
bool GPU_geometry_shader_support();
bool GPU_shader_draw_parameters_support();
bool GPU_hdr_support();

View File

@@ -172,11 +172,6 @@ bool GPU_node_link_instancing_workaround()
return GCaps.node_link_instancing_workaround;
}
bool GPU_vulkan_render_pass_workaround()
{
return GCaps.render_pass_workaround;
}
bool GPU_geometry_shader_support()
{
return GCaps.geometry_shader_support;

View File

@@ -64,9 +64,6 @@ struct GPUCapabilities {
bool use_subprocess_shader_compilations = false;
/* Vulkan related workarounds. */
bool render_pass_workaround = false;
/* Metal related workarounds. */
/* Minimum per-vertex stride in bytes (For a vertex buffer). */
int minimum_per_vertex_stride = 1;

View File

@@ -21,7 +21,6 @@ struct VKBeginRenderingData {
VkRenderingAttachmentInfo depth_attachment;
VkRenderingAttachmentInfo stencil_attachment;
VkRenderingInfoKHR vk_rendering_info;
VkRenderPassBeginInfo vk_render_pass_begin_info;
};
struct VKBeginRenderingCreateInfo {
@@ -53,25 +52,19 @@ class VKBeginRenderingNode : public VKNodeInfo<VKNodeType::BEGIN_RENDERING,
template<typename Node, typename Storage>
void set_node_data(Node &node, Storage &storage, const CreateInfo &create_info)
{
const bool use_render_pass = create_info.node_data.vk_render_pass_begin_info.renderPass !=
VK_NULL_HANDLE;
UNUSED_VARS_NDEBUG(use_render_pass);
BLI_assert_msg(use_render_pass ||
ELEM(create_info.node_data.vk_rendering_info.pColorAttachments,
nullptr,
create_info.node_data.color_attachments),
BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pColorAttachments,
nullptr,
create_info.node_data.color_attachments),
"When create_info.node_data.vk_rendering_info.pColorAttachments points to "
"something, it should point to create_info.node_data.color_attachments.");
BLI_assert_msg(use_render_pass ||
ELEM(create_info.node_data.vk_rendering_info.pDepthAttachment,
nullptr,
&create_info.node_data.depth_attachment),
BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pDepthAttachment,
nullptr,
&create_info.node_data.depth_attachment),
"When create_info.node_data.vk_rendering_info.pDepthAttachment points to "
"something, it should point to create_info.node_data.depth_attachment.");
BLI_assert_msg(use_render_pass ||
ELEM(create_info.node_data.vk_rendering_info.pStencilAttachment,
nullptr,
&create_info.node_data.stencil_attachment),
BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pStencilAttachment,
nullptr,
&create_info.node_data.stencil_attachment),
"When create_info.node_data.vk_rendering_info.pStencilAttachment points to "
"something, it should point to create_info.node_data.stencil_attachment.");
node.storage_index = storage.begin_rendering.append_and_get_index(create_info.node_data);
@@ -97,25 +90,19 @@ class VKBeginRenderingNode : public VKNodeInfo<VKNodeType::BEGIN_RENDERING,
Data &data,
VKBoundPipelines & /*r_bound_pipelines*/) override
{
const bool is_dynamic_rendering = data.vk_render_pass_begin_info.renderPass == VK_NULL_HANDLE;
if (is_dynamic_rendering) {
/* Localize pointers just before sending to the command buffer. Pointer can (and will) change
* as they are stored in a union which is stored in a vector. When the vector reallocates,
* the pointers will become invalid. */
if (data.vk_rendering_info.pColorAttachments) {
data.vk_rendering_info.pColorAttachments = data.color_attachments;
}
if (data.vk_rendering_info.pDepthAttachment) {
data.vk_rendering_info.pDepthAttachment = &data.depth_attachment;
}
if (data.vk_rendering_info.pStencilAttachment) {
data.vk_rendering_info.pStencilAttachment = &data.stencil_attachment;
}
command_buffer.begin_rendering(&data.vk_rendering_info);
/* Localize pointers just before sending to the command buffer. Pointer can (and will) change
* as they are stored in a union which is stored in a vector. When the vector reallocates,
* the pointers will become invalid. */
if (data.vk_rendering_info.pColorAttachments) {
data.vk_rendering_info.pColorAttachments = data.color_attachments;
}
else {
command_buffer.begin_render_pass(&data.vk_render_pass_begin_info);
if (data.vk_rendering_info.pDepthAttachment) {
data.vk_rendering_info.pDepthAttachment = &data.depth_attachment;
}
if (data.vk_rendering_info.pStencilAttachment) {
data.vk_rendering_info.pStencilAttachment = &data.stencil_attachment;
}
command_buffer.begin_rendering(&data.vk_rendering_info);
}
};
} // namespace blender::gpu::render_graph

View File

@@ -15,10 +15,7 @@ namespace blender::gpu::render_graph {
/**
* Information stored inside the render graph node. See `VKRenderGraphNode`.
*/
struct VKEndRenderingData {
/* Render pass used (when dynamic rendering is not supported). */
VkRenderPass vk_render_pass;
};
struct VKEndRenderingData {};
/**
* End rendering node
@@ -59,16 +56,10 @@ class VKEndRenderingNode : public VKNodeInfo<VKNodeType::END_RENDERING,
* Build the commands and add them to the command_buffer.
*/
void build_commands(VKCommandBufferInterface &command_buffer,
Data &data,
Data & /*data*/,
VKBoundPipelines & /*r_bound_pipelines*/) override
{
const bool is_dynamic_rendering = data.vk_render_pass == VK_NULL_HANDLE;
if (is_dynamic_rendering) {
command_buffer.end_rendering();
}
else {
command_buffer.end_render_pass();
}
command_buffer.end_rendering();
}
};
} // namespace blender::gpu::render_graph

View File

@@ -342,9 +342,6 @@ TEST_P(VKRenderGraphTestRender, begin_draw_end__layered)
log[8]);
}
INSTANTIATE_TEST_SUITE_P(,
VKRenderGraphTestRender,
::testing::Values(std::make_tuple(true, true),
std::make_tuple(true, false)));
INSTANTIATE_TEST_SUITE_P(, VKRenderGraphTestRender, ::testing::Values(true, false));
} // namespace blender::gpu::render_graph

View File

@@ -1144,9 +1144,6 @@ TEST_P(VKRenderGraphTestScheduler, begin_draw_copy_to_attachment_draw_end)
EXPECT_EQ("end_rendering()", log[12]);
}
INSTANTIATE_TEST_SUITE_P(,
VKRenderGraphTestScheduler,
::testing::Values(std::make_tuple(true, true),
std::make_tuple(true, false)));
INSTANTIATE_TEST_SUITE_P(, VKRenderGraphTestScheduler, ::testing::Values(true, false));
} // namespace blender::gpu::render_graph

View File

@@ -29,12 +29,9 @@ class CommandBufferLog : public VKCommandBufferInterface {
bool is_recording_ = false;
public:
CommandBufferLog(Vector<std::string> &log,
bool use_dynamic_rendering_ = true,
bool use_dynamic_rendering_local_read_ = true)
CommandBufferLog(Vector<std::string> &log, bool use_dynamic_rendering_local_read_ = true)
: log_(log)
{
use_dynamic_rendering = use_dynamic_rendering_;
use_dynamic_rendering_local_read = use_dynamic_rendering_local_read_;
}
virtual ~CommandBufferLog() {}
@@ -497,11 +494,9 @@ class VKRenderGraphTest : public ::testing::Test {
public:
VKRenderGraphTest()
{
resources.use_dynamic_rendering = use_dynamic_rendering;
resources.use_dynamic_rendering_local_read = use_dynamic_rendering_local_read;
render_graph = std::make_unique<VKRenderGraph>(resources);
command_buffer = std::make_unique<CommandBufferLog>(
log, use_dynamic_rendering, use_dynamic_rendering_local_read);
command_buffer = std::make_unique<CommandBufferLog>(log, use_dynamic_rendering_local_read);
}
protected:
@@ -509,21 +504,17 @@ class VKRenderGraphTest : public ::testing::Test {
VKResourceStateTracker resources;
std::unique_ptr<VKRenderGraph> render_graph;
std::unique_ptr<CommandBufferLog> command_buffer;
bool use_dynamic_rendering = true;
bool use_dynamic_rendering_local_read = true;
};
class VKRenderGraphTest_P : public ::testing::TestWithParam<std::tuple<bool, bool>> {
class VKRenderGraphTest_P : public ::testing::TestWithParam<std::tuple<bool>> {
public:
VKRenderGraphTest_P()
{
use_dynamic_rendering = std::get<0>(GetParam());
use_dynamic_rendering_local_read = std::get<1>(GetParam());
resources.use_dynamic_rendering = use_dynamic_rendering;
use_dynamic_rendering_local_read = std::get<0>(GetParam());
resources.use_dynamic_rendering_local_read = use_dynamic_rendering_local_read;
render_graph = std::make_unique<VKRenderGraph>(resources);
command_buffer = std::make_unique<CommandBufferLog>(
log, use_dynamic_rendering, use_dynamic_rendering_local_read);
command_buffer = std::make_unique<CommandBufferLog>(log, use_dynamic_rendering_local_read);
}
protected:

View File

@@ -15,7 +15,6 @@ VKCommandBufferWrapper::VKCommandBufferWrapper(VkCommandBuffer vk_command_buffer
const VKExtensions &extensions)
: vk_command_buffer_(vk_command_buffer)
{
use_dynamic_rendering = extensions.dynamic_rendering;
use_dynamic_rendering_local_read = extensions.dynamic_rendering_local_read;
}

View File

@@ -256,7 +256,6 @@ class VKResourceStateTracker {
return resources_.lookup(resource_handle).type;
}
bool use_dynamic_rendering = true;
bool use_dynamic_rendering_local_read = true;
void debug_print() const;

View File

@@ -175,6 +175,9 @@ static Vector<StringRefNull> missing_capabilities_get(VkPhysicalDevice vk_physic
if (!extensions.contains(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
missing_capabilities.append(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
if (!extensions.contains(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) {
missing_capabilities.append(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
}
#ifndef __APPLE__
/* Metal doesn't support provoking vertex. */
if (!extensions.contains(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME)) {
@@ -403,13 +406,10 @@ void VKBackend::detect_workarounds(VKDevice &device)
extensions.shader_output_layer = false;
extensions.shader_output_viewport_index = false;
extensions.fragment_shader_barycentric = false;
extensions.dynamic_rendering = false;
extensions.dynamic_rendering_local_read = false;
extensions.dynamic_rendering_unused_attachments = false;
extensions.descriptor_buffer = false;
GCaps.render_pass_workaround = true;
device.workarounds_ = workarounds;
device.extensions_ = extensions;
return;
@@ -421,8 +421,6 @@ void VKBackend::detect_workarounds(VKDevice &device)
device.physical_device_vulkan_12_features_get().shaderOutputViewportIndex;
extensions.fragment_shader_barycentric = device.supports_extension(
VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
extensions.dynamic_rendering = device.supports_extension(
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
extensions.dynamic_rendering_local_read = device.supports_extension(
VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
extensions.dynamic_rendering_unused_attachments = device.supports_extension(
@@ -491,8 +489,6 @@ void VKBackend::detect_workarounds(VKDevice &device)
workarounds.vertex_formats.r8g8b8 = (format_properties.bufferFeatures &
VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0;
GCaps.render_pass_workaround = !extensions.dynamic_rendering;
#ifdef __APPLE__
/* Due to a limitation in MoltenVK, attachments should be sequential even when using
* dynamic rendering. MoltenVK internally uses render passes to simulate dynamic rendering and

View File

@@ -167,7 +167,6 @@ void VKDescriptorSetUpdator::bind_input_attachment_resource(
}
}
else {
bool supports_dynamic_rendering = device.extensions_get().dynamic_rendering;
const BindSpaceTextures::Elem *elem_ptr = state_manager.textures_.get(
resource_binding.binding);
if (!elem_ptr) {
@@ -179,39 +178,20 @@ void VKDescriptorSetUpdator::bind_input_attachment_resource(
VKTexture *texture = static_cast<VKTexture *>(elem.resource);
BLI_assert(texture);
BLI_assert(elem.resource_type == BindSpaceTextures::Type::Texture);
if (supports_dynamic_rendering) {
const VKSampler &sampler = device.samplers().get(elem.sampler);
bind_image(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
sampler.vk_handle(),
texture->image_view_get(resource_binding.arrayed, VKImageViewFlags::DEFAULT).vk_handle(),
VK_IMAGE_LAYOUT_GENERAL,
resource_binding.location);
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({vk_image,
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
}
else {
/* Fall back to render-passes / sub-passes. */
bind_image(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
VK_NULL_HANDLE,
texture->image_view_get(resource_binding.arrayed, VKImageViewFlags::NO_SWIZZLING)
.vk_handle(),
VK_IMAGE_LAYOUT_GENERAL,
resource_binding.location);
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({vk_image,
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
const VKSampler &sampler = device.samplers().get(elem.sampler);
bind_image(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
sampler.vk_handle(),
texture->image_view_get(resource_binding.arrayed, VKImageViewFlags::DEFAULT).vk_handle(),
VK_IMAGE_LAYOUT_GENERAL,
resource_binding.location);
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({vk_image,
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
}
}

View File

@@ -39,7 +39,6 @@ void VKExtensions::log() const
" - [%c] fragment shader barycentric\n"
"Device extensions\n"
" - [%c] descriptor buffer\n"
" - [%c] dynamic rendering\n"
" - [%c] dynamic rendering local read\n"
" - [%c] dynamic rendering unused attachments\n"
" - [%c] external memory\n"
@@ -48,7 +47,6 @@ void VKExtensions::log() const
shader_output_layer ? 'X' : ' ',
fragment_shader_barycentric ? 'X' : ' ',
descriptor_buffer ? 'X' : ' ',
dynamic_rendering ? 'X' : ' ',
dynamic_rendering_local_read ? 'X' : ' ',
dynamic_rendering_unused_attachments ? 'X' : ' ',
external_memory ? 'X' : ' ',
@@ -139,7 +137,6 @@ void VKDevice::init(void *ghost_context)
debug::object_label(vk_queue_, "GenericQueue");
init_glsl_patch();
resources.use_dynamic_rendering = extensions_.dynamic_rendering;
resources.use_dynamic_rendering_local_read = extensions_.dynamic_rendering_local_read;
orphaned_data.timeline_ = 0;

View File

@@ -39,12 +39,6 @@ struct VKExtensions {
* VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR::fragmentShaderBarycentric.
*/
bool fragment_shader_barycentric = false;
/**
* Does the device support VK_KHR_dynamic_rendering enabled.
*
* We should assume that this is always supported. Option will be removed later in 5.0.
*/
bool dynamic_rendering = false;
/**
* Does the device support VK_KHR_dynamic_rendering_local_read enabled.

View File

@@ -42,20 +42,6 @@ VKFrameBuffer::~VKFrameBuffer()
if (context && context->active_framebuffer_get() == this) {
context->deactivate_framebuffer();
}
render_pass_free();
}
void VKFrameBuffer::render_pass_free()
{
VKDiscardPool &discard_pool = VKDiscardPool::discard_pool_get();
if (vk_framebuffer != VK_NULL_HANDLE) {
discard_pool.discard_framebuffer(vk_framebuffer);
vk_framebuffer = VK_NULL_HANDLE;
}
if (vk_render_pass != VK_NULL_HANDLE) {
discard_pool.discard_render_pass(vk_render_pass);
vk_render_pass = VK_NULL_HANDLE;
}
}
/** \} */
@@ -563,237 +549,6 @@ void VKFrameBuffer::rendering_reset()
is_rendering_ = false;
}
void VKFrameBuffer::rendering_ensure_render_pass(VKContext &context)
{
render_pass_free();
depth_attachment_format_ = VK_FORMAT_UNDEFINED;
stencil_attachment_format_ = VK_FORMAT_UNDEFINED;
render_graph::VKResourceAccessInfo access_info;
Vector<VkAttachmentDescription> vk_attachment_descriptions;
Vector<VkAttachmentReference> color_attachments;
Vector<VkAttachmentReference> input_attachments;
Vector<VkImageView> vk_image_views;
uint32_t max_layer_count = 1;
/* Color attachments */
VkAttachmentReference depth_attachment_reference = {0u};
for (int color_attachment_index :
IndexRange(GPU_FB_COLOR_ATTACHMENT0, GPU_FB_MAX_COLOR_ATTACHMENT))
{
const GPUAttachment &attachment = attachments_[color_attachment_index];
if (attachment.tex == nullptr) {
continue;
}
VKTexture &color_texture = *unwrap(unwrap(attachment.tex));
BLI_assert_msg(color_texture.usage_get() & GPU_TEXTURE_USAGE_ATTACHMENT,
"Texture is used as an attachment, but doesn't have the "
"GPU_TEXTURE_USAGE_ATTACHMENT flag.");
GPUAttachmentState attachment_state = attachment_states_[color_attachment_index];
uint32_t layer_base = max_ii(attachment.layer, 0);
int layer_count = color_texture.layer_count();
if (attachment.layer == -1 && layer_count != 1) {
max_layer_count = max_ii(max_layer_count, layer_count);
}
VKImageViewInfo image_view_info = {
eImageViewUsage::Attachment,
IndexRange(layer_base,
layer_count != 1 ? max_ii(layer_count - layer_base, 1) : layer_count),
IndexRange(attachment.mip, 1),
{{'r', 'g', 'b', 'a'}},
false,
srgb_ && enabled_srgb_,
VKImageViewArrayed::DONT_CARE};
const VKImageView &image_view = color_texture.image_view_get(image_view_info);
/* TODO: Use VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for read-only attachments. */
VkImageLayout vk_image_layout = (attachment_state == GPU_ATTACHMENT_READ) ?
VK_IMAGE_LAYOUT_GENERAL :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
uint32_t attachment_reference = color_attachment_index - GPU_FB_COLOR_ATTACHMENT0;
/* Depth attachment should always be right after the last color attachment. If not shaders
* cannot be reused between frame-buffers with and without depth/stencil attachment. */
depth_attachment_reference.attachment = attachment_reference + 1;
VkAttachmentDescription vk_attachment_description = {};
vk_attachment_description.format = image_view.vk_format();
vk_attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
vk_attachment_description.initialLayout = vk_image_layout;
vk_attachment_description.finalLayout = vk_image_layout;
vk_attachment_descriptions.append(std::move(vk_attachment_description));
vk_image_views.append(image_view.vk_handle());
switch (attachment_state) {
case GPU_ATTACHMENT_WRITE: {
color_attachments.append({attachment_reference, vk_image_layout});
access_info.images.append(
{color_texture.vk_image_handle(),
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT,
layer_base});
break;
}
case GPU_ATTACHMENT_READ: {
input_attachments.append({attachment_reference, vk_image_layout});
access_info.images.append({color_texture.vk_image_handle(),
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT,
layer_base});
break;
}
case GPU_ATTACHMENT_IGNORE: {
input_attachments.append({VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});
break;
}
}
}
/* Update the color attachment size attribute. This is used to generate the correct amount of
* color blend states in the graphics pipeline. */
color_attachment_size = color_attachments.size();
/* Depth attachment */
bool has_depth_attachment = false;
for (int depth_attachment_index : IndexRange(GPU_FB_DEPTH_ATTACHMENT, 2)) {
const GPUAttachment &attachment = attachments_[depth_attachment_index];
if (attachment.tex == nullptr) {
continue;
}
has_depth_attachment = true;
bool is_stencil_attachment = depth_attachment_index == GPU_FB_DEPTH_STENCIL_ATTACHMENT;
VKTexture &depth_texture = *unwrap(unwrap(attachment.tex));
BLI_assert_msg(depth_texture.usage_get() & GPU_TEXTURE_USAGE_ATTACHMENT,
"Texture is used as an attachment, but doesn't have the "
"GPU_TEXTURE_USAGE_ATTACHMENT flag.");
VkImageAspectFlags depth_texture_aspect = to_vk_image_aspect_flag_bits(
depth_texture.device_format_get());
bool is_depth_stencil_attachment = depth_texture_aspect & VK_IMAGE_ASPECT_STENCIL_BIT;
VkImageLayout vk_image_layout = is_depth_stencil_attachment ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
GPUAttachmentState attachment_state = attachment_states_[GPU_FB_DEPTH_ATTACHMENT];
VkImageView depth_image_view = VK_NULL_HANDLE;
uint32_t layer_base = max_ii(attachment.layer, 0);
if (attachment_state == GPU_ATTACHMENT_WRITE) {
VKImageViewInfo image_view_info = {eImageViewUsage::Attachment,
IndexRange(layer_base, 1),
IndexRange(attachment.mip, 1),
{{'r', 'g', 'b', 'a'}},
is_stencil_attachment,
false,
VKImageViewArrayed::DONT_CARE};
depth_image_view = depth_texture.image_view_get(image_view_info).vk_handle();
}
VkAttachmentDescription vk_attachment_description = {};
vk_attachment_description.format = to_vk_format(depth_texture.device_format_get());
vk_attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
vk_attachment_description.initialLayout = vk_image_layout;
vk_attachment_description.finalLayout = vk_image_layout;
vk_attachment_descriptions.append(std::move(vk_attachment_description));
depth_attachment_reference.layout = vk_image_layout;
vk_image_views.append(depth_image_view);
access_info.images.append({depth_texture.vk_image_handle(),
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
is_stencil_attachment ?
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT |
VK_IMAGE_ASPECT_STENCIL_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT),
0});
VkFormat vk_format = to_vk_format(depth_texture.device_format_get());
depth_attachment_format_ = vk_format;
if (is_stencil_attachment) {
stencil_attachment_format_ = vk_format;
}
}
/* Sub-pass description. */
VkSubpassDescription vk_subpass_description = {};
vk_subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
vk_subpass_description.colorAttachmentCount = color_attachments.size();
vk_subpass_description.pColorAttachments = color_attachments.data();
vk_subpass_description.inputAttachmentCount = input_attachments.size();
vk_subpass_description.pInputAttachments = input_attachments.data();
if (has_depth_attachment) {
vk_subpass_description.pDepthStencilAttachment = &depth_attachment_reference;
}
VKDevice &device = VKBackend::get().device;
/* Render-pass create info. */
VkRenderPassCreateInfo vk_render_pass_create_info = {};
vk_render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
vk_render_pass_create_info.subpassCount = 1;
vk_render_pass_create_info.pSubpasses = &vk_subpass_description;
vk_render_pass_create_info.attachmentCount = vk_attachment_descriptions.size();
vk_render_pass_create_info.pAttachments = vk_attachment_descriptions.data();
vkCreateRenderPass(device.vk_handle(), &vk_render_pass_create_info, nullptr, &vk_render_pass);
debug::object_label(vk_render_pass, name_);
/* Frame buffer create info */
VkFramebufferCreateInfo vk_framebuffer_create_info = {};
vk_framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
vk_framebuffer_create_info.renderPass = vk_render_pass;
vk_framebuffer_create_info.attachmentCount = vk_image_views.size();
vk_framebuffer_create_info.pAttachments = vk_image_views.data();
vk_framebuffer_create_info.width = width_;
vk_framebuffer_create_info.height = height_;
vk_framebuffer_create_info.layers = max_layer_count;
vkCreateFramebuffer(device.vk_handle(), &vk_framebuffer_create_info, nullptr, &vk_framebuffer);
debug::object_label(vk_framebuffer, name_);
/* Begin rendering */
render_graph::VKBeginRenderingNode::CreateInfo begin_rendering(access_info);
VkRenderPassBeginInfo &begin_info = begin_rendering.node_data.vk_render_pass_begin_info;
begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
begin_info.renderPass = vk_render_pass;
begin_info.framebuffer = vk_framebuffer;
render_area_update(begin_info.renderArea);
context.render_graph().add_node(begin_rendering);
/* Load store operations are not supported inside a render pass.
* It requires duplicating render passes and frame-buffers to support suspend/resume rendering.
* After suspension all the graphics pipelines needs to be created using the resume handles.
* Due to command reordering it is unclear when this switch needs to be made and would require
* to double the graphics pipelines.
*
* This all adds a lot of complexity just to support clearing ops on legacy platforms. An easier
* solution is to use #vkCmdClearAttachments right after the begin rendering.
*/
if (use_explicit_load_store_) {
render_graph::VKClearAttachmentsNode::CreateInfo clear_attachments = {};
for (int attachment_index : IndexRange(GPU_FB_MAX_ATTACHMENT)) {
GPULoadStore &load_store = load_stores[attachment_index];
if (load_store.load_action != GPU_LOADACTION_CLEAR) {
continue;
}
bool is_depth = attachment_index < GPU_FB_COLOR_ATTACHMENT0;
if (is_depth) {
build_clear_attachments_depth_stencil(
GPU_DEPTH_BIT, load_store.clear_value[0], 0, clear_attachments);
}
else {
build_clear_attachments_color(&load_store.clear_value, false, clear_attachments);
}
}
if (clear_attachments.attachment_count != 0) {
render_area_update(clear_attachments.vk_clear_rect.rect);
clear_attachments.vk_clear_rect.baseArrayLayer = 0;
clear_attachments.vk_clear_rect.layerCount = 1;
context.render_graph().add_node(clear_attachments);
}
}
}
void VKFrameBuffer::rendering_ensure_dynamic_rendering(VKContext &context,
const VKExtensions &extensions)
{
@@ -969,12 +724,7 @@ void VKFrameBuffer::rendering_ensure(VKContext &context)
const VKExtensions &extensions = VKBackend::get().device.extensions_get();
is_rendering_ = true;
if (extensions.dynamic_rendering) {
rendering_ensure_dynamic_rendering(context, extensions);
}
else {
rendering_ensure_render_pass(context);
}
rendering_ensure_dynamic_rendering(context, extensions);
dirty_attachments_ = false;
dirty_state_ = false;
}
@@ -999,13 +749,7 @@ void VKFrameBuffer::rendering_end(VKContext &context)
}
if (is_rendering_) {
const VKExtensions &extensions = VKBackend::get().device.extensions_get();
render_graph::VKEndRenderingNode::CreateInfo end_rendering = {};
end_rendering.vk_render_pass = VK_NULL_HANDLE;
if (!extensions.dynamic_rendering) {
BLI_assert(vk_render_pass);
end_rendering.vk_render_pass = vk_render_pass;
}
context.render_graph().add_node(end_rendering);
is_rendering_ = false;
}

View File

@@ -36,11 +36,7 @@ class VKFrameBuffer : public FrameBuffer {
Array<GPULoadStore, GPU_FB_MAX_ATTACHMENT> load_stores;
Array<GPUAttachmentState, GPU_FB_MAX_ATTACHMENT> attachment_states_;
/* Render pass workaround when dynamic rendering isn't supported. */
VkFramebuffer vk_framebuffer = VK_NULL_HANDLE;
public:
VkRenderPass vk_render_pass = VK_NULL_HANDLE;
uint32_t color_attachment_size = 0u;
/**
@@ -116,7 +112,6 @@ class VKFrameBuffer : public FrameBuffer {
*/
void rendering_ensure(VKContext &context);
void rendering_ensure_dynamic_rendering(VKContext &context, const VKExtensions &extensions);
void rendering_ensure_render_pass(VKContext &context);
/**
* End the rendering on this framebuffer.
@@ -139,13 +134,6 @@ class VKFrameBuffer : public FrameBuffer {
int color_attachments_resource_size() const;
private:
/**
* Discard both the render pass and framebuffer
*
* TODO: render pass could be reusable.
*/
void render_pass_free();
/* Clearing attachments */
void build_clear_attachments_depth_stencil(
eGPUFrameBufferBits buffers,

View File

@@ -565,22 +565,14 @@ VkPipeline VKPipelinePool::get_or_create_graphics_pipeline(VKGraphicsInfo &graph
}
/* VK_KHR_dynamic_rendering */
if (extensions.dynamic_rendering) {
vk_pipeline_rendering_create_info_.depthAttachmentFormat =
graphics_info.fragment_out.depth_attachment_format;
vk_pipeline_rendering_create_info_.stencilAttachmentFormat =
graphics_info.fragment_out.stencil_attachment_format;
vk_pipeline_rendering_create_info_.colorAttachmentCount =
graphics_info.fragment_out.color_attachment_formats.size();
vk_pipeline_rendering_create_info_.pColorAttachmentFormats =
graphics_info.fragment_out.color_attachment_formats.data();
}
else {
BLI_assert(ELEM(
vk_graphics_pipeline_create_info_.pNext, &vk_pipeline_rendering_create_info_, nullptr));
vk_graphics_pipeline_create_info_.pNext = nullptr;
vk_graphics_pipeline_create_info_.renderPass = graphics_info.fragment_out.vk_render_pass;
}
vk_pipeline_rendering_create_info_.depthAttachmentFormat =
graphics_info.fragment_out.depth_attachment_format;
vk_pipeline_rendering_create_info_.stencilAttachmentFormat =
graphics_info.fragment_out.stencil_attachment_format;
vk_pipeline_rendering_create_info_.colorAttachmentCount =
graphics_info.fragment_out.color_attachment_formats.size();
vk_pipeline_rendering_create_info_.pColorAttachmentFormats =
graphics_info.fragment_out.color_attachment_formats.data();
/* Common values */
vk_graphics_pipeline_create_info_.layout = graphics_info.vk_pipeline_layout;
@@ -610,7 +602,6 @@ VkPipeline VKPipelinePool::get_or_create_graphics_pipeline(VKGraphicsInfo &graph
vk_graphics_pipeline_create_info_.stageCount = 0;
vk_graphics_pipeline_create_info_.layout = VK_NULL_HANDLE;
vk_graphics_pipeline_create_info_.basePipelineHandle = VK_NULL_HANDLE;
vk_graphics_pipeline_create_info_.renderPass = VK_NULL_HANDLE;
for (VkPipelineShaderStageCreateInfo &info :
MutableSpan<VkPipelineShaderStageCreateInfo>(vk_pipeline_shader_stage_create_info_, 3))
{

View File

@@ -144,8 +144,6 @@ struct VKGraphicsInfo {
VkFormat depth_attachment_format;
VkFormat stencil_attachment_format;
Vector<VkFormat> color_attachment_formats;
/* Render pass rendering */
VkRenderPass vk_render_pass;
bool operator==(const FragmentOut &other) const
{
@@ -172,8 +170,7 @@ struct VKGraphicsInfo {
uint64_t hash() const
{
uint64_t hash = uint64_t(vk_render_pass);
hash = hash * 33 ^ uint64_t(depth_attachment_format);
uint64_t hash = uint64_t(depth_attachment_format);
hash = hash * 33 ^ uint64_t(stencil_attachment_format);
hash = hash * 33 ^ XXH3_64bits(color_attachment_formats.data(),
color_attachment_formats.size() * sizeof(VkFormat));

View File

@@ -991,7 +991,6 @@ std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo
ss << "\n/* Sub-pass Inputs. */\n";
const VKShaderInterface &interface = interface_get();
const bool use_local_read = extensions.dynamic_rendering_local_read;
const bool use_dynamic_rendering = extensions.dynamic_rendering;
if (use_local_read) {
uint32_t subpass_input_binding_index = 0;
@@ -1029,7 +1028,7 @@ std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo
pre_main += ss_pre.str();
}
}
else if (use_dynamic_rendering) {
else {
for (const ShaderCreateInfo::SubpassIn &input : info.subpass_inputs_) {
std::string image_name = "gpu_subpass_img_";
image_name += std::to_string(input.index);
@@ -1071,57 +1070,10 @@ std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo
pre_main += ss_pre.str();
}
}
else {
/* Use subpass passes input attachments when dynamic rendering isn't available. */
for (const ShaderCreateInfo::SubpassIn &input : info.subpass_inputs_) {
using Resource = ShaderCreateInfo::Resource;
Resource res(Resource::BindType::SAMPLER, input.index);
const VKDescriptorSet::Location location = interface.descriptor_set_location(res);
std::string image_name = "gpu_subpass_img_" + std::to_string(input.index);
/* Declare global for input. */
ss << to_string(input.type) << " " << input.name << ";\n";
/* Declare subpass input. */
ss << "layout(input_attachment_index=" << input.index << ", set=0, binding=" << location
<< ") uniform ";
switch (to_component_type(input.type)) {
case Type::int_t:
ss << "isubpassInput";
break;
case Type::uint_t:
ss << "usubpassInput";
break;
case Type::float_t:
default:
ss << "subpassInput";
break;
}
ss << " " << image_name << ";";
/* Read data from subpass input. */
char swizzle[] = "xyzw";
swizzle[to_component_count(input.type)] = '\0';
std::stringstream ss_pre;
ss_pre << " " << input.name << " = subpassLoad(" << image_name << ")." << swizzle << ";\n";
pre_main += ss_pre.str();
}
}
ss << "\n/* Outputs. */\n";
int fragment_out_location = 0;
for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
/* When using dynamic rendering the attachment location doesn't change. When using render
* passes and sub-passes the location refers to the color attachment of the sub-pass.
*
* LIMITATION: dual source blending cannot be used together with sub-passes.
*/
const bool use_dual_blending = output.blend != DualBlend::NONE;
BLI_assert_msg(!(use_dual_blending && !info.subpass_inputs_.is_empty()),
"Dual source blending are not supported with subpass inputs when using render "
"passes. It can be supported, but wasn't for code readability.");
const int location = (use_dynamic_rendering || use_dual_blending) ? output.index :
fragment_out_location++;
const int location = output.index;
ss << "layout(location = " << location;
switch (output.blend) {
case DualBlend::SRC_0:
@@ -1378,7 +1330,6 @@ VkPipeline VKShader::ensure_and_get_graphics_pipeline(GPUPrimType primitive,
graphics_info.fragment_shader.scissors.clear();
framebuffer.vk_render_areas_append(graphics_info.fragment_shader.scissors);
graphics_info.fragment_out.vk_render_pass = framebuffer.vk_render_pass;
graphics_info.fragment_out.depth_attachment_format = framebuffer.depth_attachment_format_get();
graphics_info.fragment_out.stencil_attachment_format =
framebuffer.stencil_attachment_format_get();

View File

@@ -424,7 +424,6 @@ void VKShaderInterface::init_descriptor_set_layout_info(
UNUSED_VARS(index);
// TODO: clean up remove negation.
descriptor_set_layout_info_.bindings.append_n_times(
!extensions.dynamic_rendering ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT :
!extensions.dynamic_rendering_local_read ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER :
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
info.subpass_inputs_.size());

View File

@@ -485,7 +485,6 @@ static VkImageUsageFlags to_vk_image_usage(const eGPUTextureUsage usage,
{
const VKDevice &device = VKBackend::get().device;
const bool supports_local_read = device.extensions_get().dynamic_rendering_local_read;
const bool supports_dynamic_rendering = device.extensions_get().dynamic_rendering;
VkImageUsageFlags result = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
@@ -506,7 +505,7 @@ static VkImageUsageFlags to_vk_image_usage(const eGPUTextureUsage usage,
}
else {
result |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (supports_local_read || (!supports_dynamic_rendering)) {
if (supports_local_read) {
result |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
}