mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-08 20:58:41 +00:00
* 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`
154 lines
5.0 KiB
C++
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
|