added support for cubemap arrays

This commit is contained in:
psucien 2024-09-18 22:08:33 +02:00
commit 0c7fa82c02
12 changed files with 42 additions and 25 deletions

View file

@ -510,7 +510,8 @@ Id ImageType(EmitContext& ctx, const ImageResource& desc, Id sampled_type) {
case AmdGpu::ImageType::Color3D: case AmdGpu::ImageType::Color3D:
return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, sampled, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, sampled, format);
case AmdGpu::ImageType::Cube: case AmdGpu::ImageType::Cube:
return ctx.TypeImage(sampled_type, spv::Dim::Cube, false, false, false, sampled, format); return ctx.TypeImage(sampled_type, spv::Dim::Cube, false, desc.is_array, false, sampled,
format);
default: default:
break; break;
} }

View file

@ -1032,6 +1032,7 @@ void GcnDecodeContext::decodeInstructionMIMG(uint64_t hexInstruction) {
m_instruction.control.mimg = *reinterpret_cast<InstControlMIMG*>(&hexInstruction); m_instruction.control.mimg = *reinterpret_cast<InstControlMIMG*>(&hexInstruction);
m_instruction.control.mimg.mod = getMimgModifier(m_instruction.opcode); m_instruction.control.mimg.mod = getMimgModifier(m_instruction.opcode);
ASSERT(m_instruction.control.mimg.r128 == 0);
} }
void GcnDecodeContext::decodeInstructionDS(uint64_t hexInstruction) { void GcnDecodeContext::decodeInstructionDS(uint64_t hexInstruction) {

View file

@ -546,6 +546,7 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
info.has_offset.Assign(flags.test(MimgModifier::Offset)); info.has_offset.Assign(flags.test(MimgModifier::Offset));
info.explicit_lod.Assign(explicit_lod); info.explicit_lod.Assign(explicit_lod);
info.has_derivatives.Assign(has_derivatives); info.has_derivatives.Assign(has_derivatives);
info.is_array.Assign(mimg.da);
// Issue IR instruction, leaving unknown fields blank to patch later. // Issue IR instruction, leaving unknown fields blank to patch later.
const IR::Value texel = [&]() -> IR::Value { const IR::Value texel = [&]() -> IR::Value {
@ -630,6 +631,7 @@ void Translator::IMAGE_GATHER(const GcnInst& inst) {
info.has_offset.Assign(flags.test(MimgModifier::Offset)); info.has_offset.Assign(flags.test(MimgModifier::Offset));
// info.explicit_lod.Assign(explicit_lod); // info.explicit_lod.Assign(explicit_lod);
info.gather_comp.Assign(std::bit_width(mimg.dmask) - 1); info.gather_comp.Assign(std::bit_width(mimg.dmask) - 1);
info.is_array.Assign(mimg.da);
// Issue IR instruction, leaving unknown fields blank to patch later. // Issue IR instruction, leaving unknown fields blank to patch later.
const IR::Value texel = [&]() -> IR::Value { const IR::Value texel = [&]() -> IR::Value {

View file

@ -64,9 +64,10 @@ struct ImageResource {
u32 dword_offset; u32 dword_offset;
AmdGpu::ImageType type; AmdGpu::ImageType type;
AmdGpu::NumberFormat nfmt; AmdGpu::NumberFormat nfmt;
bool is_storage; bool is_storage{};
bool is_depth; bool is_depth{};
bool is_atomic{}; bool is_atomic{};
bool is_array{};
constexpr AmdGpu::Image GetSharp(const Info& info) const noexcept; constexpr AmdGpu::Image GetSharp(const Info& info) const noexcept;
}; };

View file

@ -491,6 +491,7 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
.is_storage = is_storage, .is_storage = is_storage,
.is_depth = bool(inst_info.is_depth), .is_depth = bool(inst_info.is_depth),
.is_atomic = IsImageAtomicInstruction(inst), .is_atomic = IsImageAtomicInstruction(inst),
.is_array = bool(inst_info.is_array),
}); });
// Read sampler sharp. This doesn't exist for IMAGE_LOAD/IMAGE_STORE instructions // Read sampler sharp. This doesn't exist for IMAGE_LOAD/IMAGE_STORE instructions

View file

@ -59,6 +59,7 @@ union TextureInstInfo {
BitField<5, 1, u32> has_offset; BitField<5, 1, u32> has_offset;
BitField<6, 2, u32> gather_comp; BitField<6, 2, u32> gather_comp;
BitField<8, 1, u32> has_derivatives; BitField<8, 1, u32> has_derivatives;
BitField<9, 1, u32> is_array;
}; };
union BufferInstInfo { union BufferInstInfo {

View file

@ -282,6 +282,7 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceFeatures2{ vk::PhysicalDeviceFeatures2{
.features{ .features{
.robustBufferAccess = features.robustBufferAccess, .robustBufferAccess = features.robustBufferAccess,
.imageCubeArray = features.imageCubeArray,
.independentBlend = features.independentBlend, .independentBlend = features.independentBlend,
.geometryShader = features.geometryShader, .geometryShader = features.geometryShader,
.logicOp = features.logicOp, .logicOp = features.logicOp,

View file

@ -3,6 +3,7 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "shader_recompiler/info.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_pipeline_common.h" #include "video_core/renderer_vulkan/vk_pipeline_common.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -21,7 +22,7 @@ Pipeline::~Pipeline() = default;
void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage, void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
u32& binding, DescriptorWrites& set_writes) const { u32& binding, DescriptorWrites& set_writes) const {
using ImageBindingInfo = std::tuple<VideoCore::ImageId, AmdGpu::Image, bool>; using ImageBindingInfo = std::tuple<VideoCore::ImageId, AmdGpu::Image, Shader::ImageResource>;
boost::container::static_vector<ImageBindingInfo, 32> image_bindings; boost::container::static_vector<ImageBindingInfo, 32> image_bindings;
for (const auto& image_desc : stage.images) { for (const auto& image_desc : stage.images) {
@ -31,9 +32,9 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
const auto image_id = texture_cache.FindImage(image_info); const auto image_id = texture_cache.FindImage(image_info);
auto& image = texture_cache.GetImage(image_id); auto& image = texture_cache.GetImage(image_id);
image.flags |= VideoCore::ImageFlagBits::Bound; image.flags |= VideoCore::ImageFlagBits::Bound;
image_bindings.emplace_back(image_id, tsharp, image_desc.is_storage); image_bindings.emplace_back(image_id, tsharp, image_desc);
} else { } else {
image_bindings.emplace_back(VideoCore::ImageId{}, tsharp, image_desc.is_storage); image_bindings.emplace_back(VideoCore::ImageId{}, tsharp, image_desc);
} }
if (texture_cache.IsMeta(tsharp.Address())) { if (texture_cache.IsMeta(tsharp.Address())) {
@ -42,7 +43,7 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
} }
// Second pass to re-bind images that were updated after binding // Second pass to re-bind images that were updated after binding
for (auto [image_id, tsharp, is_storage] : image_bindings) { for (auto [image_id, tsharp, desc] : image_bindings) {
if (!image_id) { if (!image_id) {
if (instance.IsNullDescriptorSupported()) { if (instance.IsNullDescriptorSupported()) {
image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
@ -56,7 +57,7 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
if (True(image.flags & VideoCore::ImageFlagBits::NeedsRebind)) { if (True(image.flags & VideoCore::ImageFlagBits::NeedsRebind)) {
image_id = texture_cache.FindImage(image.info); image_id = texture_cache.FindImage(image.info);
} }
VideoCore::ImageViewInfo view_info{tsharp, is_storage}; VideoCore::ImageViewInfo view_info{tsharp, desc};
auto& image_view = texture_cache.FindTexture(image_id, view_info); auto& image_view = texture_cache.FindTexture(image_id, view_info);
image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view,
texture_cache.GetImage(image_id).last_state.layout); texture_cache.GetImage(image_id).last_state.layout);
@ -69,8 +70,8 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
.dstBinding = binding++, .dstBinding = binding++,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = .descriptorType = desc.is_storage ? vk::DescriptorType::eStorageImage
is_storage ? vk::DescriptorType::eStorageImage : vk::DescriptorType::eSampledImage, : vk::DescriptorType::eSampledImage,
.pImageInfo = &image_infos.back(), .pImageInfo = &image_infos.back(),
}); });
} }

View file

@ -44,7 +44,6 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(
case 0xc81ad50e: case 0xc81ad50e:
case 0xb7c39078: case 0xb7c39078:
case 0x32868fde: // vkCreateBufferView(): pCreateInfo->range does not equal VK_WHOLE_SIZE case 0x32868fde: // vkCreateBufferView(): pCreateInfo->range does not equal VK_WHOLE_SIZE
case 0x92d66fc1: // `pMultisampleState is NULL` for depth only passes (confirmed VL error)
return VK_FALSE; return VK_FALSE;
default: default:
break; break;

View file

@ -200,11 +200,13 @@ boost::container::small_vector<vk::ImageMemoryBarrier2, 32> Image::GetBarriers(
// resource transition for the next time. // resource transition for the next time.
const auto mips = const auto mips =
needs_partial_transition needs_partial_transition
? std::ranges::views::iota(subres_range->base.level, subres_range->extent.levels) ? std::ranges::views::iota(subres_range->base.level,
subres_range->base.level + subres_range->extent.levels)
: std::views::iota(0u, info.resources.levels); : std::views::iota(0u, info.resources.levels);
const auto layers = const auto layers =
needs_partial_transition needs_partial_transition
? std::ranges::views::iota(subres_range->base.layer, subres_range->extent.layers) ? std::ranges::views::iota(subres_range->base.layer,
subres_range->base.layer + subres_range->extent.layers)
: std::views::iota(0u, info.resources.layers); : std::views::iota(0u, info.resources.layers);
for (u32 mip : mips) { for (u32 mip : mips) {

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h" #include "common/logging/log.h"
#include "shader_recompiler/info.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
@ -66,8 +67,8 @@ vk::Format TrySwizzleFormat(vk::Format format, u32 dst_sel) {
return format; return format;
} }
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, bool is_storage_) noexcept ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept
: is_storage{is_storage_} { : is_storage{desc.is_storage} {
const auto dfmt = image.GetDataFmt(); const auto dfmt = image.GetDataFmt();
auto nfmt = image.GetNumberFmt(); auto nfmt = image.GetNumberFmt();
if (is_storage && nfmt == AmdGpu::NumberFormat::Srgb) { if (is_storage && nfmt == AmdGpu::NumberFormat::Srgb) {
@ -76,19 +77,24 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, bool is_storage_) noexc
format = Vulkan::LiverpoolToVK::SurfaceFormat(dfmt, nfmt); format = Vulkan::LiverpoolToVK::SurfaceFormat(dfmt, nfmt);
range.base.level = image.base_level; range.base.level = image.base_level;
range.base.layer = image.base_array; range.base.layer = image.base_array;
range.extent.levels = image.last_level + 1; range.extent.levels = image.last_level - image.base_level + 1;
range.extent.layers = image.last_array + 1; range.extent.layers = image.last_array - image.base_array + 1;
type = ConvertImageViewType(image.GetType()); type = ConvertImageViewType(image.GetType());
// Adjust view type for partial cubemaps and arrays // Adjust view type for partial cubemaps and arrays
if (image.IsPartialCubemap()) { if (image.IsPartialCubemap()) {
type = vk::ImageViewType::e2DArray; type = vk::ImageViewType::e2DArray;
} }
if (type == vk::ImageViewType::eCube && range.extent.layers > 6) { if (type == vk::ImageViewType::eCube) {
if (desc.is_array) {
type = vk::ImageViewType::eCubeArray; type = vk::ImageViewType::eCubeArray;
} else {
// Some games try to bind an array of cubemaps while shader reads only single one.
range.extent.layers = std::min(range.extent.layers, 6u);
}
} }
if (type == vk::ImageViewType::e3D && range.extent.layers > 1) { if (type == vk::ImageViewType::e3D && range.extent.layers > 1) {
// Some games pass incorrect layer count for 3D textures so we need to fixup it // Some games pass incorrect layer count for 3D textures so we need to fixup it.
range.extent.layers = 1; range.extent.layers = 1;
} }
@ -116,7 +122,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer,
const auto base_format = const auto base_format =
Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.info.format, col_buffer.NumFormat()); Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.info.format, col_buffer.NumFormat());
range.base.layer = col_buffer.view.slice_start; range.base.layer = col_buffer.view.slice_start;
range.extent.layers = col_buffer.NumSlices(); range.extent.layers = col_buffer.NumSlices() - range.base.layer;
format = Vulkan::LiverpoolToVK::AdjustColorBufferFormat( format = Vulkan::LiverpoolToVK::AdjustColorBufferFormat(
base_format, col_buffer.info.comp_swap.Value(), is_vo_surface); base_format, col_buffer.info.comp_swap.Value(), is_vo_surface);
} }
@ -128,7 +134,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,
depth_buffer.stencil_info.format); depth_buffer.stencil_info.format);
is_storage = ctl.depth_write_enable; is_storage = ctl.depth_write_enable;
range.base.layer = view.slice_start; range.base.layer = view.slice_start;
range.extent.layers = view.NumSlices(); range.extent.layers = view.NumSlices() - range.base.layer;
} }
ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info_, Image& image, ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info_, Image& image,
@ -160,9 +166,9 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = info.range.base.level, .baseMipLevel = info.range.base.level,
.levelCount = info.range.extent.levels - info.range.base.level, .levelCount = info.range.extent.levels,
.baseArrayLayer = info.range.base.layer, .baseArrayLayer = info.range.base.layer,
.layerCount = info.range.extent.layers - info.range.base.layer, .layerCount = info.range.extent.layers,
}, },
}; };
image_view = instance.GetDevice().createImageViewUnique(image_view_ci); image_view = instance.GetDevice().createImageViewUnique(image_view_ci);

View file

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "shader_recompiler/info.h"
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"
@ -17,7 +18,7 @@ namespace VideoCore {
struct ImageViewInfo { struct ImageViewInfo {
ImageViewInfo() = default; ImageViewInfo() = default;
ImageViewInfo(const AmdGpu::Image& image, bool is_storage) noexcept; ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept;
ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer, bool is_vo_surface) noexcept; ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer, bool is_vo_surface) noexcept;
ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer, ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,
AmdGpu::Liverpool::DepthView view, AmdGpu::Liverpool::DepthControl ctl); AmdGpu::Liverpool::DepthView view, AmdGpu::Liverpool::DepthControl ctl);