added support for cubemap arrays

This commit is contained in:
psucien 2024-09-18 22:08:33 +02:00
parent 223a7e4eef
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:
return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, sampled, format);
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:
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.mod = getMimgModifier(m_instruction.opcode);
ASSERT(m_instruction.control.mimg.r128 == 0);
}
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.explicit_lod.Assign(explicit_lod);
info.has_derivatives.Assign(has_derivatives);
info.is_array.Assign(mimg.da);
// Issue IR instruction, leaving unknown fields blank to patch later.
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.explicit_lod.Assign(explicit_lod);
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.
const IR::Value texel = [&]() -> IR::Value {

View file

@ -64,9 +64,10 @@ struct ImageResource {
u32 dword_offset;
AmdGpu::ImageType type;
AmdGpu::NumberFormat nfmt;
bool is_storage;
bool is_depth;
bool is_storage{};
bool is_depth{};
bool is_atomic{};
bool is_array{};
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_depth = bool(inst_info.is_depth),
.is_atomic = IsImageAtomicInstruction(inst),
.is_array = bool(inst_info.is_array),
});
// 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<6, 2, u32> gather_comp;
BitField<8, 1, u32> has_derivatives;
BitField<9, 1, u32> is_array;
};
union BufferInstInfo {

View file

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

View file

@ -3,6 +3,7 @@
#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_pipeline_common.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,
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;
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);
auto& image = texture_cache.GetImage(image_id);
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 {
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())) {
@ -42,7 +43,7 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
}
// 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 (instance.IsNullDescriptorSupported()) {
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)) {
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);
image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view,
texture_cache.GetImage(image_id).last_state.layout);
@ -69,8 +70,8 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
.dstBinding = binding++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType =
is_storage ? vk::DescriptorType::eStorageImage : vk::DescriptorType::eSampledImage,
.descriptorType = desc.is_storage ? vk::DescriptorType::eStorageImage
: vk::DescriptorType::eSampledImage,
.pImageInfo = &image_infos.back(),
});
}

View file

@ -44,7 +44,6 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(
case 0xc81ad50e:
case 0xb7c39078:
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;
default:
break;

View file

@ -200,11 +200,13 @@ boost::container::small_vector<vk::ImageMemoryBarrier2, 32> Image::GetBarriers(
// resource transition for the next time.
const auto mips =
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);
const auto layers =
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);
for (u32 mip : mips) {

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "shader_recompiler/info.h"
#include "video_core/amdgpu/resource.h"
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/renderer_vulkan/vk_instance.h"
@ -66,8 +67,8 @@ vk::Format TrySwizzleFormat(vk::Format format, u32 dst_sel) {
return format;
}
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, bool is_storage_) noexcept
: is_storage{is_storage_} {
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept
: is_storage{desc.is_storage} {
const auto dfmt = image.GetDataFmt();
auto nfmt = image.GetNumberFmt();
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);
range.base.level = image.base_level;
range.base.layer = image.base_array;
range.extent.levels = image.last_level + 1;
range.extent.layers = image.last_array + 1;
range.extent.levels = image.last_level - image.base_level + 1;
range.extent.layers = image.last_array - image.base_array + 1;
type = ConvertImageViewType(image.GetType());
// Adjust view type for partial cubemaps and arrays
if (image.IsPartialCubemap()) {
type = vk::ImageViewType::e2DArray;
}
if (type == vk::ImageViewType::eCube && range.extent.layers > 6) {
type = vk::ImageViewType::eCubeArray;
if (type == vk::ImageViewType::eCube) {
if (desc.is_array) {
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) {
// 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;
}
@ -116,7 +122,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer,
const auto base_format =
Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.info.format, col_buffer.NumFormat());
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(
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);
is_storage = ctl.depth_write_enable;
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,
@ -160,9 +166,9 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
.subresourceRange{
.aspectMask = aspect,
.baseMipLevel = info.range.base.level,
.levelCount = info.range.extent.levels - info.range.base.level,
.levelCount = info.range.extent.levels,
.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);

View file

@ -3,6 +3,7 @@
#pragma once
#include "shader_recompiler/info.h"
#include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/resource.h"
#include "video_core/renderer_vulkan/vk_common.h"
@ -17,7 +18,7 @@ namespace VideoCore {
struct ImageViewInfo {
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::DepthBuffer& depth_buffer,
AmdGpu::Liverpool::DepthView view, AmdGpu::Liverpool::DepthControl ctl);