[vk] Fix Validation Errors In Texture, Blit, and render passes
Some checks failed
eden-license / license-header (pull_request) Failing after 24s

This commit is contained in:
Ribbit 2025-09-26 23:07:52 -07:00 committed by crueter
parent 020ad29a8c
commit 21e6f9a1cc
10 changed files with 170 additions and 63 deletions

View file

@ -275,11 +275,12 @@ constexpr std::array<VkPipelineShaderStageCreateInfo, 2> MakeStages(
} }
void UpdateOneTextureDescriptorSet(const Device& device, VkDescriptorSet descriptor_set, void UpdateOneTextureDescriptorSet(const Device& device, VkDescriptorSet descriptor_set,
VkSampler sampler, VkImageView image_view) { VkSampler sampler, VkImageView image_view,
VkImageLayout image_layout = VK_IMAGE_LAYOUT_GENERAL) {
const VkDescriptorImageInfo image_info{ const VkDescriptorImageInfo image_info{
.sampler = sampler, .sampler = sampler,
.imageView = image_view, .imageView = image_view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL, .imageLayout = image_layout,
}; };
const VkWriteDescriptorSet write_descriptor_set{ const VkWriteDescriptorSet write_descriptor_set{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
@ -408,9 +409,9 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
.subresourceRange{ .subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
}; };
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
@ -512,7 +513,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
} }
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view, void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
VkImage src_image, VkSampler src_sampler, VkImage src_image, VkSampler sampler,
const Region2D& dst_region, const Region2D& src_region, const Region2D& dst_region, const Region2D& src_region,
const Extent3D& src_size) { const Extent3D& src_size) {
const BlitImagePipelineKey key{ const BlitImagePipelineKey key{
@ -522,12 +523,12 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key); const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region, scheduler.Record([this, dst_framebuffer, src_image_view, src_image, sampler, dst_region,
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) { src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
BeginRenderPass(cmdbuf, dst_framebuffer); BeginRenderPass(cmdbuf, dst_framebuffer);
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view); UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
nullptr); nullptr);
@ -1005,7 +1006,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
if (pipeline) { if (pipeline) {
return; return;
} }
VkShaderModule frag_shader = *convert_depth_to_float_frag; VkShaderModule frag_shader = *convert_float_to_depth_frag;
const std::array stages = MakeStages(*full_screen_vert, frag_shader); const std::array stages = MakeStages(*full_screen_vert, frag_shader);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline({ pipeline = device.GetLogical().CreateGraphicsPipeline({
@ -1021,7 +1022,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = *one_texture_pipeline_layout, .layout = *one_texture_pipeline_layout,
.renderPass = renderpass, .renderPass = renderpass,
@ -1039,6 +1040,9 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
} }
const std::array stages = MakeStages(*full_screen_vert, *module); const std::array stages = MakeStages(*full_screen_vert, *module);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
const VkPipelineColorBlendStateCreateInfo* const color_blend_state =
is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
: &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO;
pipeline = device.GetLogical().CreateGraphicsPipeline({ pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -1052,7 +1056,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, .pColorBlendState = color_blend_state,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
.renderPass = renderpass, .renderPass = renderpass,

View file

@ -193,8 +193,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()}; !image_view.SupportsAnisotropy()};
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() const bool enable_compare =
: sampler.Handle()}; sampler.DepthCompareEnabled() && image_view.SupportsDepthCompare();
const VkSampler vk_sampler =
sampler.HandleForUsage(use_fallback_sampler, enable_compare);
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler); guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
rescaling.PushTexture(texture_cache.IsRescaling(image_view)); rescaling.PushTexture(texture_cache.IsRescaling(image_view));
} }

View file

@ -65,7 +65,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
}; };
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,

View file

@ -667,6 +667,22 @@ vk::Buffer BufferCacheRuntime::CreateNullBuffer() {
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) { scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) {
cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0);
const VkBufferMemoryBarrier vis{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffer,
.offset = 0,
.size = VK_WHOLE_SIZE,
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
0, vis);
}); });
return ret; return ret;

View file

@ -437,7 +437,7 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT, .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
}; };
const VkDescriptorSet set = descriptor_allocator.Commit(); const VkDescriptorSet set = descriptor_allocator.Commit();
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
@ -448,7 +448,7 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {}); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
cmdbuf.Dispatch(1, 1, 1); cmdbuf.Dispatch(1, 1, 1);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0, write_barrier); VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
}); });
} }
@ -497,11 +497,7 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT |
VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
}; };
const QueriesPrefixScanPushConstants uniforms{ const QueriesPrefixScanPushConstants uniforms{
.min_accumulation_base = static_cast<u32>(min_accumulation_limit), .min_accumulation_base = static_cast<u32>(min_accumulation_limit),
@ -519,7 +515,7 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms); cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
cmdbuf.Dispatch(1, 1, 1); cmdbuf.Dispatch(1, 1, 1);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
write_barrier); write_barrier);
}); });
} }
@ -701,8 +697,30 @@ void MSAACopyPass::CopyImage(Image& dst_image, Image& src_image,
copy.extent.depth, copy.extent.depth,
}; };
scheduler.Record([this, dst = dst_image.Handle(), msaa_pipeline, num_dispatches, scheduler.Record([this, src = src_image.Handle(), dst = dst_image.Handle(), msaa_pipeline, num_dispatches,
descriptor_data](vk::CommandBuffer cmdbuf) { descriptor_data](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
const VkDescriptorSet set = descriptor_allocator.Commit(); const VkDescriptorSet set = descriptor_allocator.Commit();
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, msaa_pipeline); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, msaa_pipeline);

View file

@ -132,20 +132,10 @@ RenderPassKey MakeRenderPassKey(const FixedPipelineState& state) {
key.depth_format = PixelFormat::Invalid; key.depth_format = PixelFormat::Invalid;
} }
key.samples = MaxwellToVK::MsaaMode(state.msaa_mode); key.samples = MaxwellToVK::MsaaMode(state.msaa_mode);
key.color_attachment_count = static_cast<u8>(Maxwell::NumRenderTargets);
return key; return key;
} }
size_t NumAttachments(const FixedPipelineState& state) {
size_t num{};
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
const auto format{static_cast<Tegra::RenderTargetFormat>(state.color_formats[index])};
if (format != Tegra::RenderTargetFormat::NONE) {
num = index + 1;
}
}
return num;
}
template <typename Spec> template <typename Spec>
bool Passes(const std::array<vk::ShaderModule, NUM_STAGES>& modules, bool Passes(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
const std::array<Shader::Info, NUM_STAGES>& stage_infos) { const std::array<Shader::Info, NUM_STAGES>& stage_infos) {
@ -770,30 +760,45 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
LOG_WARNING(Render_Vulkan, "Depth bounds is enabled but not supported"); LOG_WARNING(Render_Vulkan, "Depth bounds is enabled but not supported");
} }
static_vector<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; static_vector<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments;
const size_t num_attachments{NumAttachments(key.state)}; for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
for (size_t index = 0; index < num_attachments; ++index) {
static constexpr std::array mask_table{ static constexpr std::array mask_table{
VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_R_BIT,
VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_G_BIT,
VK_COLOR_COMPONENT_B_BIT, VK_COLOR_COMPONENT_B_BIT,
VK_COLOR_COMPONENT_A_BIT, VK_COLOR_COMPONENT_A_BIT,
}; };
const auto& blend{key.state.attachments[index]}; VkPipelineColorBlendAttachmentState attachment{};
const std::array mask{blend.Mask()}; const auto format{static_cast<Tegra::RenderTargetFormat>(key.state.color_formats[index])};
VkColorComponentFlags write_mask{}; if (format != Tegra::RenderTargetFormat::NONE) {
for (size_t i = 0; i < mask_table.size(); ++i) { const auto& blend{key.state.attachments[index]};
write_mask |= mask[i] ? mask_table[i] : 0; const std::array mask{blend.Mask()};
VkColorComponentFlags write_mask{};
for (size_t i = 0; i < mask_table.size(); ++i) {
write_mask |= mask[i] ? mask_table[i] : 0;
}
attachment = VkPipelineColorBlendAttachmentState{
.blendEnable = blend.enable != 0,
.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()),
.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()),
.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()),
.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()),
.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()),
.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()),
.colorWriteMask = write_mask,
};
} else {
attachment = VkPipelineColorBlendAttachmentState{
.blendEnable = VK_FALSE,
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = 0,
};
} }
cb_attachments.push_back({ cb_attachments.push_back(attachment);
.blendEnable = blend.enable != 0,
.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()),
.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()),
.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()),
.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()),
.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()),
.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()),
.colorWriteMask = write_mask,
});
} }
const VkPipelineColorBlendStateCreateInfo color_blend_ci{ const VkPipelineColorBlendStateCreateInfo color_blend_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,

View file

@ -6,6 +6,7 @@
#include <unordered_map> #include <unordered_map>
#include <algorithm>
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "video_core/renderer_vulkan/maxwell_to_vk.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h"
@ -77,9 +78,10 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
} }
boost::container::static_vector<VkAttachmentDescription, 9> descriptions; boost::container::static_vector<VkAttachmentDescription, 9> descriptions;
std::array<VkAttachmentReference, 8> references{}; std::array<VkAttachmentReference, 8> references{};
u32 num_attachments{}; const u32 total_color_slots =
std::min<u32>(key.color_attachment_count, static_cast<u32>(key.color_formats.size()));
u32 num_colors{}; u32 num_colors{};
for (size_t index = 0; index < key.color_formats.size(); ++index) { for (u32 index = 0; index < total_color_slots; ++index) {
const PixelFormat format{key.color_formats[index]}; const PixelFormat format{key.color_formats[index]};
const bool is_valid{format != PixelFormat::Invalid}; const bool is_valid{format != PixelFormat::Invalid};
references[index] = VkAttachmentReference{ references[index] = VkAttachmentReference{
@ -88,10 +90,10 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
}; };
if (is_valid) { if (is_valid) {
descriptions.push_back(AttachmentDescription(*device, format, key.samples)); descriptions.push_back(AttachmentDescription(*device, format, key.samples));
num_attachments = static_cast<u32>(index + 1);
++num_colors; ++num_colors;
} }
} }
const u32 num_attachments = total_color_slots;
const bool has_depth{key.depth_format != PixelFormat::Invalid}; const bool has_depth{key.depth_format != PixelFormat::Invalid};
VkAttachmentReference depth_reference{}; VkAttachmentReference depth_reference{};
if (key.depth_format != PixelFormat::Invalid) { if (key.depth_format != PixelFormat::Invalid) {

View file

@ -6,6 +6,7 @@
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
#include "common/common_types.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
@ -17,6 +18,7 @@ struct RenderPassKey {
std::array<VideoCore::Surface::PixelFormat, 8> color_formats; std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
VideoCore::Surface::PixelFormat depth_format; VideoCore::Surface::PixelFormat depth_format;
VkSampleCountFlagBits samples; VkSampleCountFlagBits samples;
u8 color_attachment_count{};
}; };
} // namespace Vulkan } // namespace Vulkan
@ -27,6 +29,7 @@ struct hash<Vulkan::RenderPassKey> {
[[nodiscard]] size_t operator()(const Vulkan::RenderPassKey& key) const noexcept { [[nodiscard]] size_t operator()(const Vulkan::RenderPassKey& key) const noexcept {
size_t value = static_cast<size_t>(key.depth_format) << 48; size_t value = static_cast<size_t>(key.depth_format) << 48;
value ^= static_cast<size_t>(key.samples) << 52; value ^= static_cast<size_t>(key.samples) << 52;
value ^= static_cast<size_t>(key.color_attachment_count) << 56;
for (size_t i = 0; i < key.color_formats.size(); ++i) { for (size_t i = 0; i < key.color_formats.size(); ++i) {
value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6); value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6);
} }

View file

@ -2026,15 +2026,27 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
} }
} }
const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
if (ImageUsageFlags(format_info, format) != image.UsageFlags()) { VkImageUsageFlags view_usage = ImageUsageFlags(format_info, format);
const VkImageUsageFlags image_usage = image.UsageFlags();
const VkImageUsageFlags original_view_usage = view_usage;
const VkImageUsageFlags unsupported_usage = view_usage & ~image_usage;
if (unsupported_usage != 0) {
LOG_WARNING(Render_Vulkan, LOG_WARNING(Render_Vulkan,
"Image view format {} has different usage flags than image format {}", format, "Clamping image view usage 0x{:X} for format {} to match image format {} (0x{:X})",
image.info.format); static_cast<unsigned>(original_view_usage), format, image.info.format,
static_cast<unsigned>(image_usage));
view_usage &= image_usage;
}
if (view_usage == 0) {
LOG_WARNING(Render_Vulkan,
"Image view usage for format {} became 0 after clamping; falling back to image usage 0x{:X}",
format, static_cast<unsigned>(image_usage));
view_usage = image_usage;
} }
const VkImageViewUsageCreateInfo image_view_usage{ const VkImageViewUsageCreateInfo image_view_usage{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.usage = ImageUsageFlags(format_info, format), .usage = view_usage,
}; };
const VkImageViewCreateInfo create_info{ const VkImageViewCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -2188,6 +2200,11 @@ bool ImageView::IsRescaled() const noexcept {
return src_image.IsRescaled(); return src_image.IsRescaled();
} }
bool ImageView::SupportsDepthCompare() const noexcept {
const auto surface_type = VideoCore::Surface::GetFormatType(format);
return surface_type == SurfaceType::Depth || surface_type == SurfaceType::DepthStencil;
}
vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) { vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {
return device->GetLogical().CreateImageView({ return device->GetLogical().CreateImageView({
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -2235,7 +2252,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
// Some games have samplers with garbage. Sanitize them here. // Some games have samplers with garbage. Sanitize them here.
const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
const auto create_sampler = [&](const f32 anisotropy) { const auto create_sampler = [&](const f32 anisotropy, bool compare_enabled) {
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = pnext, .pNext = pnext,
@ -2249,7 +2266,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
.mipLodBias = tsc.LodBias(), .mipLodBias = tsc.LodBias(),
.anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE), .anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = anisotropy, .maxAnisotropy = anisotropy,
.compareEnable = tsc.depth_compare_enabled, .compareEnable = compare_enabled ? VK_TRUE : VK_FALSE,
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
@ -2259,12 +2276,41 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
}); });
}; };
sampler = create_sampler(max_anisotropy); depth_compare_enabled = tsc.depth_compare_enabled != 0;
sampler = create_sampler(max_anisotropy, depth_compare_enabled);
const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy); const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy);
if (max_anisotropy > max_anisotropy_default) { const bool needs_default_anisotropy = max_anisotropy > max_anisotropy_default;
sampler_default_anisotropy = create_sampler(max_anisotropy_default); if (needs_default_anisotropy) {
sampler_default_anisotropy = create_sampler(max_anisotropy_default, depth_compare_enabled);
} }
if (depth_compare_enabled) {
sampler_no_compare = create_sampler(max_anisotropy, false);
if (needs_default_anisotropy) {
sampler_no_compare_default_anisotropy = create_sampler(max_anisotropy_default, false);
}
}
}
VkSampler Sampler::HandleForUsage(bool use_default_anisotropy, bool enable_compare) const noexcept {
const bool wants_default = use_default_anisotropy && HasAddedAnisotropy();
if (enable_compare || !depth_compare_enabled) {
if (wants_default && sampler_default_anisotropy) {
return *sampler_default_anisotropy;
}
return *sampler;
}
if (wants_default) {
if (sampler_no_compare_default_anisotropy) {
return *sampler_no_compare_default_anisotropy;
}
if (sampler_default_anisotropy) {
return *sampler_default_anisotropy;
}
} else if (sampler_no_compare) {
return *sampler_no_compare;
}
return wants_default && sampler_default_anisotropy ? *sampler_default_anisotropy : *sampler;
} }
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers, Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
@ -2293,6 +2339,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
ImageView* depth_buffer, bool is_rescaled_) { ImageView* depth_buffer, bool is_rescaled_) {
boost::container::small_vector<VkImageView, NUM_RT + 1> attachments; boost::container::small_vector<VkImageView, NUM_RT + 1> attachments;
RenderPassKey renderpass_key{}; RenderPassKey renderpass_key{};
renderpass_key.color_attachment_count = static_cast<u8>(NUM_RT);
s32 num_layers = 1; s32 num_layers = 1;
is_rescaled = is_rescaled_; is_rescaled = is_rescaled_;

View file

@ -237,6 +237,7 @@ public:
Shader::ImageFormat image_format); Shader::ImageFormat image_format);
[[nodiscard]] bool IsRescaled() const noexcept; [[nodiscard]] bool IsRescaled() const noexcept;
[[nodiscard]] bool SupportsDepthCompare() const noexcept;
[[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept { [[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
return *image_views[static_cast<size_t>(texture_type)]; return *image_views[static_cast<size_t>(texture_type)];
@ -303,9 +304,18 @@ public:
return static_cast<bool>(sampler_default_anisotropy); return static_cast<bool>(sampler_default_anisotropy);
} }
[[nodiscard]] bool DepthCompareEnabled() const noexcept {
return depth_compare_enabled;
}
[[nodiscard]] VkSampler HandleForUsage(bool use_default_anisotropy, bool enable_compare) const noexcept;
private: private:
vk::Sampler sampler; vk::Sampler sampler;
vk::Sampler sampler_default_anisotropy; vk::Sampler sampler_default_anisotropy;
vk::Sampler sampler_no_compare;
vk::Sampler sampler_no_compare_default_anisotropy;
bool depth_compare_enabled = false;
}; };
class Framebuffer { class Framebuffer {