This commit is contained in:
lizzie 2026-04-25 21:57:57 +00:00
parent 8ceef6ed3a
commit 4d3812ea61
5 changed files with 177 additions and 197 deletions

View file

@ -427,24 +427,17 @@ Id CasLoop(EmitContext& ctx, Operation operation, Id array_pointer, Id element_p
return func;
}
template <typename Desc>
std::string NameOf(Stage stage, const Desc& desc, std::string_view prefix) {
if (desc.count > 1) {
return fmt::format("{}_{}{}_{:02x}x{}", StageName(stage), prefix, desc.cbuf_index,
desc.cbuf_offset, desc.count);
} else {
return fmt::format("{}_{}{}_{:02x}", StageName(stage), prefix, desc.cbuf_index,
desc.cbuf_offset);
}
template <typename T>
std::string NameOf(Stage stage, const T& desc, std::string_view prefix) {
return fmt::format("{}_{}{}_{:02x}x{}", StageName(stage), prefix, desc.cbuf_index, desc.cbuf_offset, desc.count);
}
Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) {
if (count > 1) {
const Id array_type{ctx.TypeArray(sampled_type, ctx.Const(count))};
return ctx.TypePointer(spv::StorageClass::UniformConstant, array_type);
} else {
return pointer_type;
}
return pointer_type;
}
} // Anonymous namespace

View file

@ -577,38 +577,38 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
boost::container::static_vector<VkBuffer, VideoCommon::NUM_VERTEX_BUFFERS> buffer_handles(bindings.buffers.size());
VkBuffer null_buffer_handle = VK_NULL_HANDLE;
if (!device.HasNullDescriptor()) {
ReserveNullBuffer();
null_buffer_handle = *null_buffer;
}
for (u32 i = 0; i < bindings.buffers.size(); ++i) {
auto handle = bindings.buffers[i]->Handle();
if (handle == VK_NULL_HANDLE) {
if (auto handle = bindings.buffers[i]->Handle(); handle != VK_NULL_HANDLE) {
buffer_handles[i] = handle;
} else {
bindings.offsets[i] = 0;
bindings.sizes[i] = VK_WHOLE_SIZE;
if (!device.HasNullDescriptor()) {
ReserveNullBuffer();
handle = *null_buffer;
}
buffer_handles[i] = null_buffer_handle;
}
buffer_handles[i] = handle;
}
const u32 device_max = device.GetMaxVertexInputBindings();
const u32 min_binding = (std::min)(bindings.min_index, device_max);
const u32 max_binding = (std::min)(bindings.max_index, device_max);
const u32 binding_count = max_binding - min_binding;
if (binding_count == 0) {
return;
}
if (device.IsExtExtendedDynamicStateSupported()) {
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
});
} else {
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data());
});
if (binding_count > 0) {
if (device.IsExtExtendedDynamicStateSupported()) {
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
});
} else {
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data());
});
}
}
}
void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset,
u32 size) {
void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size) {
if (!device.IsExtTransformFeedbackSupported()) {
// Already logged in the rasterizer
return;

View file

@ -51,6 +51,10 @@ using VideoCore::Surface::IsPixelFormatInteger;
using VideoCore::Surface::SurfaceType;
namespace {
[[nodiscard]] u32 GetMaxMipLevel(u32 w, u32 h, u32 d) {
return Common::Log2Floor32((std::max)((std::max)(w, h), d)) + 1;
}
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
if (color == std::array<float, 4>{0, 0, 0, 0}) {
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
@ -143,7 +147,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
.height = info.size.height >> samples_y,
.depth = info.size.depth,
};
auto const max_mipmap_levels = Common::Log2Floor32(std::max(std::max(extent.width, extent.height), extent.depth)) + 1;
auto const max_mipmap_levels = GetMaxMipLevel(extent.width, extent.height, extent.depth);
auto mipmap_levels = u32(info.resources.levels);
if (mipmap_levels > max_mipmap_levels) {
LOG_WARNING(HW_GPU, "texture with too many mipmaps? {}, {}", mipmap_levels, max_mipmap_levels);
@ -156,7 +160,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
.imageType = ConvertImageType(info.type),
.format = format_info.format,
.extent = extent,
.mipLevels = u32(info.resources.levels),
.mipLevels = mipmap_levels,
.arrayLayers = u32(info.resources.layers),
.samples = ConvertSampleCount(info.num_samples),
.tiling = VK_IMAGE_TILING_OPTIMAL,
@ -354,13 +358,12 @@ void SanitizeDepthStencilSwizzle(std::array<SwizzleSource, 4>& swizzle,
return VK_IMAGE_VIEW_TYPE_2D;
}
[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers(
VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) {
[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers(VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask, u32 max_miplevel) {
return VkImageSubresourceLayers{
.aspectMask = aspect_mask,
.mipLevel = static_cast<u32>(subresource.base_level),
.baseArrayLayer = static_cast<u32>(subresource.base_layer),
.layerCount = static_cast<u32>(subresource.num_layers),
.mipLevel = (std::min)(max_miplevel, u32(subresource.base_level)),
.baseArrayLayer = u32(subresource.base_layer),
.layerCount = u32(subresource.num_layers),
};
}
@ -374,31 +377,28 @@ void SanitizeDepthStencilSwizzle(std::array<SwizzleSource, 4>& swizzle,
[[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) {
return VkExtent3D{
.width = static_cast<u32>(extent3d.width),
.height = static_cast<u32>(extent3d.height),
.depth = static_cast<u32>(extent3d.depth),
.width = u32(extent3d.width),
.height = u32(extent3d.height),
.depth = u32(extent3d.depth),
};
}
[[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy,
VkImageAspectFlags aspect_mask) noexcept {
[[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy, VkImageAspectFlags aspect_mask) noexcept {
return VkImageCopy{
.srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask),
.srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask, GetMaxMipLevel(copy.extent.width, copy.extent.height, copy.extent.depth)),
.srcOffset = MakeOffset3D(copy.src_offset),
.dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask),
.dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask, GetMaxMipLevel(copy.extent.width, copy.extent.height, copy.extent.depth)),
.dstOffset = MakeOffset3D(copy.dst_offset),
.extent = MakeExtent3D(copy.extent),
};
}
[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src,
VkImageAspectFlags aspect_mask) noexcept {
[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src, VkImageAspectFlags aspect_mask) noexcept {
return VkBufferImageCopy{
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource = MakeImageSubresourceLayers(
is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask),
.imageSubresource = MakeImageSubresourceLayers(is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask, GetMaxMipLevel(copy.extent.width, copy.extent.height, copy.extent.depth)),
.imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset),
.imageExtent = MakeExtent3D(copy.extent),
};
@ -410,9 +410,9 @@ TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t bu
std::ranges::transform(
copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) {
return VkBufferCopy{
.srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset),
.dstOffset = static_cast<VkDeviceSize>(copy.dst_offset),
.size = static_cast<VkDeviceSize>(copy.size),
.srcOffset = VkDeviceSize(copy.src_offset + buffer_offset),
.dstOffset = VkDeviceSize(copy.dst_offset),
.size = VkDeviceSize(copy.size),
};
});
return result;
@ -426,25 +426,22 @@ TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t bu
.bufferOffset = copy.buffer_offset + buffer_offset,
.bufferRowLength = copy.buffer_row_length,
.bufferImageHeight = copy.buffer_image_height,
.imageSubresource =
{
.aspectMask = aspect_mask,
.mipLevel = static_cast<u32>(copy.image_subresource.base_level),
.baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer),
.layerCount = static_cast<u32>(copy.image_subresource.num_layers),
},
.imageOffset =
{
.x = copy.image_offset.x,
.y = copy.image_offset.y,
.z = copy.image_offset.z,
},
.imageExtent =
{
.width = copy.image_extent.width,
.height = copy.image_extent.height,
.depth = copy.image_extent.depth,
},
.imageSubresource = {
.aspectMask = aspect_mask,
.mipLevel = (std::min)(u32(copy.image_subresource.base_level), GetMaxMipLevel(copy.image_extent.width, copy.image_extent.height, copy.image_extent.depth)),
.baseArrayLayer = u32(copy.image_subresource.base_layer),
.layerCount = u32(copy.image_subresource.num_layers),
},
.imageOffset = {
.x = copy.image_offset.x,
.y = copy.image_offset.y,
.z = copy.image_offset.z,
},
.imageExtent = {
.width = copy.image_extent.width,
.height = copy.image_extent.height,
.depth = copy.image_extent.depth,
},
};
}
size_t buffer_offset;
@ -464,14 +461,13 @@ TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t bu
}
}
[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask,
const SubresourceRange& range) {
[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask, const SubresourceRange& range) {
return VkImageSubresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = static_cast<u32>(range.base.level),
.levelCount = static_cast<u32>(range.extent.levels),
.baseArrayLayer = static_cast<u32>(range.base.layer),
.layerCount = static_cast<u32>(range.extent.layers),
.baseMipLevel = u32(range.base.level),
.levelCount = u32(range.extent.levels),
.baseArrayLayer = u32(range.base.layer),
.layerCount = u32(range.extent.layers),
};
}
@ -483,15 +479,16 @@ TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t bu
range.base.layer = 0;
range.extent.layers = 1;
}
range.extent.levels = (std::min)(range.extent.levels, s32(GetMaxMipLevel(image_view->size.width, image_view->size.height, image_view->size.depth)));
return MakeSubresourceRange(ImageAspectMask(image_view->format), range);
}
[[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) {
return VkImageSubresourceLayers{
.aspectMask = ImageAspectMask(image_view->format),
.mipLevel = static_cast<u32>(image_view->range.base.level),
.baseArrayLayer = static_cast<u32>(image_view->range.base.layer),
.layerCount = static_cast<u32>(image_view->range.extent.layers),
.mipLevel = (std::min)(u32(image_view->range.base.level), GetMaxMipLevel(image_view->size.width, image_view->size.height, image_view->size.depth)),
.baseArrayLayer = u32(image_view->range.base.layer),
.layerCount = u32(image_view->range.extent.layers),
};
}
@ -546,11 +543,14 @@ struct RangedBarrierRange {
u32 min_layer = (std::numeric_limits<u32>::max)();
u32 max_layer = (std::numeric_limits<u32>::min)();
void AddLayers(const VkImageSubresourceLayers& layers) {
void AddLayers(const VkImageSubresourceLayers& layers, u32 max_miplevel) {
min_mip = (std::min)(min_mip, layers.mipLevel);
max_mip = (std::max)(max_mip, layers.mipLevel + 1);
min_layer = (std::min)(min_layer, layers.baseArrayLayer);
max_layer = (std::max)(max_layer, layers.baseArrayLayer + layers.layerCount);
// clamp to proper so we dont access too many layers :)
min_mip = (std::min)(min_mip, max_miplevel);
max_mip = (std::min)(max_mip, max_miplevel);
}
VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
@ -563,47 +563,45 @@ struct RangedBarrierRange {
};
}
};
void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
VkImageAspectFlags aspect_mask, bool is_initialized,
std::span<const VkBufferImageCopy> copies) {
static constexpr VkAccessFlags WRITE_ACCESS_FLAGS =
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
static constexpr VkAccessFlags READ_ACCESS_FLAGS = VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image, VkImageAspectFlags aspect_mask, bool is_initialized, std::span<const VkBufferImageCopy> copies) {
static constexpr VkAccessFlags WRITE_ACCESS_FLAGS = VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
static constexpr VkAccessFlags READ_ACCESS_FLAGS = VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
// Compute exact mip/layer range being written to
RangedBarrierRange range;
for (const auto& region : copies) {
range.AddLayers(region.imageSubresource);
for (const auto& copy : copies) {
range.AddLayers(copy.imageSubresource, GetMaxMipLevel(copy.imageExtent.width, copy.imageExtent.height, copy.imageExtent.depth));
}
const VkImageSubresourceRange subresource_range = range.SubresourceRange(aspect_mask);
const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = WRITE_ACCESS_FLAGS,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = WRITE_ACCESS_FLAGS,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
};
const VkImageMemoryBarrier write_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
@ -750,59 +748,51 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
const VkFilter vk_filter = is_bilinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d,
vk_filter, up_scaling](vk::CommandBuffer cmdbuf) {
scheduler.Record([depth = info.size.depth, dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, vk_filter, up_scaling](vk::CommandBuffer cmdbuf) {
const VkOffset2D src_size{
.x = static_cast<s32>(up_scaling ? extent.width : resolution.ScaleUp(extent.width)),
.y = static_cast<s32>(is_2d && up_scaling ? extent.height
: resolution.ScaleUp(extent.height)),
.x = s32(up_scaling ? extent.width : resolution.ScaleUp(extent.width)),
.y = s32(is_2d && up_scaling ? extent.height : resolution.ScaleUp(extent.height)),
};
const VkOffset2D dst_size{
.x = static_cast<s32>(up_scaling ? resolution.ScaleUp(extent.width) : extent.width),
.y = static_cast<s32>(is_2d && up_scaling ? resolution.ScaleUp(extent.height)
: extent.height),
.x = s32(up_scaling ? resolution.ScaleUp(extent.width) : extent.width),
.y = s32(is_2d && up_scaling ? resolution.ScaleUp(extent.height) : extent.height),
};
boost::container::small_vector<VkImageBlit, 4> regions;
regions.reserve(resources.levels);
for (s32 level = 0; level < resources.levels; level++) {
regions.push_back({
u32 const src_levels = (std::min)(resources.levels, s32(GetMaxMipLevel(src_size.x, src_size.y, depth)));
u32 const dst_levels = (std::min)(resources.levels, s32(GetMaxMipLevel(dst_size.x, dst_size.y, depth)));
u32 const max_levels = (std::max)(src_levels, dst_levels);
std::array<VkImageBlit, 16> regions;
ASSERT(regions.size() >= max_levels);
for (u32 i = 0; i < max_levels; ++i) {
regions[i] = VkImageBlit{
.srcSubresource{
.aspectMask = aspect_mask,
.mipLevel = static_cast<u32>(level),
.mipLevel = (std::min)(i, src_levels),
.baseArrayLayer = 0,
.layerCount = static_cast<u32>(resources.layers),
.layerCount = u32(resources.layers),
},
.srcOffsets{
{ .x = 0, .y = 0, .z = 0, },
{
.x = 0,
.y = 0,
.z = 0,
},
{
.x = (std::max)(1, src_size.x >> level),
.y = (std::max)(1, src_size.y >> level),
.x = (std::max)(1, src_size.x >> s32(i)),
.y = (std::max)(1, src_size.y >> s32(i)),
.z = 1,
},
},
.dstSubresource{
.aspectMask = aspect_mask,
.mipLevel = static_cast<u32>(level),
.mipLevel = (std::min)(i, dst_levels),
.baseArrayLayer = 0,
.layerCount = static_cast<u32>(resources.layers),
.layerCount = u32(resources.layers),
},
.dstOffsets{
{ .x = 0, .y = 0, .z = 0, },
{
.x = 0,
.y = 0,
.z = 0,
},
{
.x = (std::max)(1, dst_size.x >> level),
.y = (std::max)(1, dst_size.y >> level),
.x = (std::max)(1, dst_size.x >> s32(i)),
.y = (std::max)(1, dst_size.y >> s32(i)),
.z = 1,
},
},
});
};
}
const VkImageSubresourceRange subresource_range{
.aspectMask = aspect_mask,
@ -827,9 +817,9 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFER_WRITE_BIT,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
| VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, // Discard contents
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
@ -865,12 +855,9 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
.subresourceRange = subresource_range,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, read_barriers);
cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions, vk_filter);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, nullptr, nullptr, write_barriers);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr, read_barriers);
cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk::Span(regions.data(), max_levels), vk_filter);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, nullptr, nullptr, write_barriers);
});
}
} // Anonymous namespace
@ -1046,10 +1033,10 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
RangedBarrierRange dst_range;
RangedBarrierRange src_range;
for (const VkBufferImageCopy& copy : vk_in_copies) {
src_range.AddLayers(copy.imageSubresource);
src_range.AddLayers(copy.imageSubresource, GetMaxMipLevel(copy.imageExtent.width, copy.imageExtent.height, copy.imageExtent.depth));
}
for (const VkBufferImageCopy& copy : vk_out_copies) {
dst_range.AddLayers(copy.imageSubresource);
dst_range.AddLayers(copy.imageSubresource, GetMaxMipLevel(copy.imageExtent.width, copy.imageExtent.height, copy.imageExtent.depth));
}
static constexpr VkMemoryBarrier READ_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
@ -1482,11 +1469,10 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
const VkImage src_image = src.Handle();
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
RangedBarrierRange dst_range;
RangedBarrierRange src_range;
RangedBarrierRange dst_range, src_range;
for (const VkImageCopy& copy : vk_copies) {
dst_range.AddLayers(copy.dstSubresource);
src_range.AddLayers(copy.srcSubresource);
dst_range.AddLayers(copy.dstSubresource, GetMaxMipLevel(copy.extent.width, copy.extent.height, copy.extent.depth));
src_range.AddLayers(copy.srcSubresource, GetMaxMipLevel(copy.extent.width, copy.extent.height, copy.extent.depth));
}
const std::array pre_barriers{
VkImageMemoryBarrier{
@ -1726,8 +1712,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
const VkImage temp_vk_image = *temp_wrapper->original_image;
const VkImageAspectFlags vk_aspect_mask = temp_wrapper->aspect_mask;
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies,
keep = temp_wrapper](vk::CommandBuffer cmdbuf) {
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies, keep = temp_wrapper](vk::CommandBuffer cmdbuf) {
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, VideoCommon::FixSmallVectorADL(vk_copies));
});
@ -2123,11 +2108,11 @@ bool Image::NeedsScaleHelper() const {
return needs_blit_helper;
}
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr},
device{&runtime.device}, image_handle{image.Handle()},
samples(ConvertSampleCount(image.info.num_samples)) {
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr}
, device{&runtime.device}, image_handle{image.Handle()}
, samples(ConvertSampleCount(image.info.num_samples))
{
using Shader::TextureType;
const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
@ -2139,9 +2124,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
};
if (!info.IsRenderTarget()) {
swizzle = info.Swizzle();
TryTransformSwizzleIfNeeded(format, swizzle,
device->MustEmulateBGR565(),
!device->IsExt4444FormatsSupported());
TryTransformSwizzleIfNeeded(format, swizzle, device->MustEmulateBGR565(), !device->IsExt4444FormatsSupported());
if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed);
SanitizeDepthStencilSwizzle(swizzle, device->SupportsDepthStencilSwizzleOne());
@ -2156,6 +2139,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.pNext = nullptr,
.usage = clamped_view_usage,
};
SubresourceRange range = info.range;
range.extent.levels = (std::min)(range.extent.levels, s32(GetMaxMipLevel(image.info.size.width, image.info.size.height, image.info.size.depth)));
const VkImageViewCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = &image_view_usage,
@ -2169,7 +2154,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.b = ComponentSwizzle(swizzle[2]),
.a = ComponentSwizzle(swizzle[3]),
},
.subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
.subresourceRange = MakeSubresourceRange(aspect_mask, range),
};
const auto create = [&](TextureType tex_type, std::optional<u32> num_layers) {
VkImageViewCreateInfo ci{create_info};
@ -2301,6 +2286,8 @@ bool ImageView::IsRescaled() const noexcept {
}
vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {
auto subresource_range = MakeSubresourceRange(aspect_mask, range);
subresource_range.levelCount = (std::min)(subresource_range.levelCount, GetMaxMipLevel(size.width, size.height, size.depth));
return device->GetLogical().CreateImageView({
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
@ -2314,7 +2301,7 @@ vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange = MakeSubresourceRange(aspect_mask, range),
.subresourceRange = subresource_range,
});
}
@ -2369,7 +2356,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
.mipLodBias = tsc.LodBias(),
.anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = anisotropy,
.compareEnable = tsc.depth_compare_enabled,
.compareEnable = false,//tsc.depth_compare_enabled,
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@ -19,15 +19,18 @@ namespace VideoCommon {
ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info,
ImageId image_id_, GPUVAddr addr)
: image_id{image_id_}, gpu_addr{addr}, format{info.format}, type{info.type}, range{info.range},
size{
.width = (std::max)(image_info.size.width >> range.base.level, 1u),
.height = (std::max)(image_info.size.height >> range.base.level, 1u),
.depth = (std::max)(image_info.size.depth >> range.base.level, 1u),
} {
ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false, true),
"Image view format {} is incompatible with image format {}", info.format,
image_info.format);
: image_id{image_id_}
, gpu_addr{addr}
, format{info.format}
, type{info.type}
, range{info.range}
, size{
.width = (std::max)(image_info.size.width >> range.base.level, 1u),
.height = (std::max)(image_info.size.height >> range.base.level, 1u),
.depth = (std::max)(image_info.size.depth >> range.base.level, 1u),
}
{
ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false, true), "Image view format {} is incompatible with image format {}", info.format, image_info.format);
if (image_info.forced_flushed) {
flags |= ImageViewFlagBits::PreemtiveDownload;
}
@ -37,12 +40,13 @@ ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_i
}
ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info, GPUVAddr addr)
: image_id{NULL_IMAGE_ID}, gpu_addr{addr}, format{info.format}, type{ImageViewType::Buffer},
size{
.width = info.size.width,
.height = 1,
.depth = 1,
} {
: image_id{NULL_IMAGE_ID}, gpu_addr{addr}, format{info.format}, type{ImageViewType::Buffer}
, size{
.width = info.size.width,
.height = 1,
.depth = 1,
}
{
ASSERT_MSG(view_info.type == ImageViewType::Buffer, "Expected texture buffer");
}

View file

@ -20,16 +20,12 @@ namespace Vulkan::vk {
namespace {
template <typename Func>
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
Func&& func) {
// Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap
// functions.
std::stable_sort(devices.begin(), devices.end(),
[&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
return func(vk::PhysicalDevice(lhs, dld).GetProperties(),
vk::PhysicalDevice(rhs, dld).GetProperties());
});
template <typename F>
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld, F&& func) {
// Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap functions.
std::stable_sort(devices.begin(), devices.end(), [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
return func(vk::PhysicalDevice(lhs, dld).GetProperties(), vk::PhysicalDevice(rhs, dld).GetProperties());
});
}
void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,