Files
shadPS4/src/shader_recompiler/resource.h
psucien a9f8eaf778 video_core: Initial implementation of pipeline cache (#3816)
* Initial implementation

* Fix for crash caused by stale stages data; cosmetics applied

* Someone mentioned the assert

* Async blob writer

* Fix for memory leak

* Remain stuff

* Async changed to `packaged_task`
2025-11-29 11:52:08 +02:00

154 lines
5.0 KiB
C++

// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include "shader_recompiler/ir/type.h"
#include "video_core/amdgpu/resource.h"
#include <boost/container/static_vector.hpp>
namespace Shader {
static constexpr u32 NUM_USER_DATA_REGS = 16;
static constexpr u32 NUM_IMAGES = 64;
static constexpr u32 NUM_BUFFERS = 40;
static constexpr u32 NUM_SAMPLERS = 16;
static constexpr u32 NUM_FMASKS = 8;
enum class BufferType : u32 {
Guest,
Flatbuf,
BdaPagetable,
FaultBuffer,
GdsBuffer,
SharedMemory,
};
struct Info;
struct BufferResource {
u32 sharp_idx;
IR::Type used_types;
AmdGpu::Buffer inline_cbuf;
BufferType buffer_type;
u8 instance_attrib{};
bool is_written{};
bool is_formatted{};
bool IsSpecial() const noexcept {
return buffer_type != BufferType::Guest;
}
bool IsStorage([[maybe_unused]] const AmdGpu::Buffer buffer) const noexcept {
// When using uniform buffers, a size is required at compilation time, so we need to
// either compile a lot of shader specializations to handle each size or just force it to
// the maximum possible size always. However, for some vendors the shader-supplied size is
// used for bounds checking uniform buffer accesses, so the latter would effectively turn
// off buffer robustness behavior. Instead, force storage buffers which are bounds checked
// using the actual buffer size. We are assuming the performance hit from this is
// acceptable.
return true; // buffer.GetSize() > profile.max_ubo_size || is_written;
}
constexpr AmdGpu::Buffer GetSharp(const auto& info) const noexcept {
AmdGpu::Buffer buffer{};
if (inline_cbuf) {
buffer = inline_cbuf;
if (inline_cbuf.base_address > 1) {
buffer.base_address += info.pgm_base; // address fixup
}
} else {
buffer = info.template ReadUdSharp<AmdGpu::Buffer>(sharp_idx);
}
if (!buffer.Valid()) {
LOG_DEBUG(Render, "Encountered invalid buffer sharp");
return AmdGpu::Buffer::Null();
}
return buffer;
}
};
using BufferResourceList = boost::container::static_vector<BufferResource, NUM_BUFFERS>;
struct ImageResource {
u32 sharp_idx;
bool is_depth{};
bool is_atomic{};
bool is_array{};
bool is_written{};
bool is_r128{};
constexpr AmdGpu::Image GetSharp(const auto& info) const noexcept {
AmdGpu::Image image{};
if (!is_r128) {
image = info.template ReadUdSharp<AmdGpu::Image>(sharp_idx);
} else {
const auto raw = info.template ReadUdSharp<u128>(sharp_idx);
std::memcpy(&image, &raw, sizeof(raw));
}
if (!image.Valid()) {
LOG_DEBUG(Render_Vulkan, "Encountered invalid image sharp");
image = AmdGpu::Image::Null(is_depth);
} else if (is_depth) {
const auto data_fmt = image.GetDataFmt();
if (data_fmt != AmdGpu::DataFormat::Format16 &&
data_fmt != AmdGpu::DataFormat::Format32) {
LOG_DEBUG(Render_Vulkan,
"Encountered non-depth image used with depth instruction!");
image = AmdGpu::Image::Null(true);
}
}
return image;
}
};
using ImageResourceList = boost::container::static_vector<ImageResource, NUM_IMAGES>;
struct SamplerResource {
u32 sharp_idx;
AmdGpu::Sampler inline_sampler;
u32 is_inline_sampler : 1;
u32 associated_image : 4;
u32 disable_aniso : 1;
constexpr AmdGpu::Sampler GetSharp(const auto& info) const noexcept {
return is_inline_sampler ? inline_sampler
: info.template ReadUdSharp<AmdGpu::Sampler>(sharp_idx);
}
};
using SamplerResourceList = boost::container::static_vector<SamplerResource, NUM_SAMPLERS>;
struct FMaskResource {
u32 sharp_idx;
constexpr AmdGpu::Image GetSharp(const auto& info) const noexcept {
return info.template ReadUdSharp<AmdGpu::Image>(sharp_idx);
}
};
using FMaskResourceList = boost::container::static_vector<FMaskResource, NUM_FMASKS>;
struct PushData {
static constexpr u32 XOffsetIndex = 0;
static constexpr u32 YOffsetIndex = 1;
static constexpr u32 XScaleIndex = 2;
static constexpr u32 YScaleIndex = 3;
static constexpr u32 UdRegsIndex = 4;
static constexpr u32 BufOffsetIndex = UdRegsIndex + NUM_USER_DATA_REGS / 4;
float xoffset;
float yoffset;
float xscale;
float yscale;
std::array<u32, NUM_USER_DATA_REGS> ud_regs;
std::array<u8, NUM_BUFFERS> buf_offsets;
void AddOffset(u32 binding, u32 offset) {
ASSERT(offset < 256 && binding < buf_offsets.size());
buf_offsets[binding] = offset;
}
};
static_assert(sizeof(PushData) <= 128,
"PushData size is greater than minimum size guaranteed by Vulkan spec");
} // namespace Shader