mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
graphics: store vertex attribute bindings without duplicated arrays
This commit is contained in:
@@ -761,24 +761,20 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
|
||||
vs_input_info.resources_num > ShaderVertexInputInfo::RES_MAX);
|
||||
key.vertex_input.binding_count = static_cast<uint8_t>(vs_input_info.buffers_num);
|
||||
key.vertex_input.attribute_count = static_cast<uint8_t>(vs_input_info.resources_num);
|
||||
uint32_t attributes_num = 0;
|
||||
for (int binding = 0; binding < vs_input_info.buffers_num; binding++) {
|
||||
const auto& buffer = vs_input_info.buffers[binding];
|
||||
EXIT_IF(buffer.attr_num < 0 || buffer.attr_num > ShaderVertexInputBuffer::ATTR_MAX);
|
||||
attributes_num += static_cast<uint32_t>(buffer.attr_num);
|
||||
EXIT_IF(attributes_num > static_cast<uint32_t>(vs_input_info.resources_num));
|
||||
key.vertex_input.bindings[binding] = {.stride = buffer.stride,
|
||||
.instance = buffer.fetch_index != 0};
|
||||
for (int attribute = 0; attribute < buffer.attr_num; attribute++) {
|
||||
const auto index = buffer.attr_indices[attribute];
|
||||
EXIT_IF(index < 0 || index >= vs_input_info.resources_num);
|
||||
key.vertex_input.attributes[index] = {
|
||||
.offset = buffer.attr_offsets[attribute],
|
||||
.binding = static_cast<uint8_t>(binding),
|
||||
};
|
||||
}
|
||||
}
|
||||
EXIT_IF(attributes_num != static_cast<uint32_t>(vs_input_info.resources_num));
|
||||
for (int attribute = 0; attribute < vs_input_info.resources_num; attribute++) {
|
||||
const auto binding = vs_input_info.resources_dst[attribute].buffer_index;
|
||||
EXIT_IF(binding < 0 || binding >= vs_input_info.buffers_num);
|
||||
key.vertex_input.attributes[attribute] = {
|
||||
.offset = static_cast<uint32_t>(vs_input_info.resources[attribute].Base48() -
|
||||
vs_input_info.buffers[binding].addr),
|
||||
.binding = static_cast<uint8_t>(binding),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (auto iter = m_graphics_pipelines.find(key); iter != m_graphics_pipelines.end()) {
|
||||
|
||||
@@ -249,8 +249,8 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo
|
||||
for (int bi = 0; bi < vs_input_info.buffers_num; bi++) {
|
||||
const auto& b = vs_input_info.buffers[bi];
|
||||
LOGF("DrawInputState[%u]: vb[%d] addr=0x%010" PRIx64
|
||||
" stride=%u records=%u fetch_index=%u attr_num=%d\n",
|
||||
log_id, bi, b.addr, b.stride, b.num_records, b.fetch_index, b.attr_num);
|
||||
" stride=%u records=%u fetch_index=%u\n",
|
||||
log_id, bi, b.addr, b.stride, b.num_records, b.fetch_index);
|
||||
|
||||
const auto* bytes = reinterpret_cast<const uint8_t*>(b.addr);
|
||||
if (bytes != nullptr && b.stride != 0) {
|
||||
@@ -272,11 +272,13 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo
|
||||
raw[5], raw[6], raw[7], raw[8], flt[0], flt[1], flt[2], flt[3], flt[4], flt[5],
|
||||
flt[6], flt[7], flt[8]);
|
||||
|
||||
for (int ai = 0; ai < b.attr_num; ai++) {
|
||||
const auto res_index = b.attr_indices[ai];
|
||||
const auto& r = vs_input_info.resources[res_index];
|
||||
const auto& rd = vs_input_info.resources_dst[res_index];
|
||||
const auto offset = b.attr_offsets[ai];
|
||||
for (int ai = 0; ai < vs_input_info.resources_num; ai++) {
|
||||
const auto& r = vs_input_info.resources[ai];
|
||||
const auto& rd = vs_input_info.resources_dst[ai];
|
||||
if (rd.buffer_index != bi) {
|
||||
continue;
|
||||
}
|
||||
const auto offset = static_cast<uint32_t>(r.Base48() - b.addr);
|
||||
if (offset + 4u <= b.stride &&
|
||||
r.Format() == Prospero::BufferFormat::k8_8_8_8UNorm) {
|
||||
uint32_t packed = 0;
|
||||
@@ -296,14 +298,16 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo
|
||||
}
|
||||
}
|
||||
|
||||
for (int ai = 0; ai < b.attr_num; ai++) {
|
||||
const auto res_index = b.attr_indices[ai];
|
||||
const auto& r = vs_input_info.resources[res_index];
|
||||
const auto& rd = vs_input_info.resources_dst[res_index];
|
||||
LOGF("DrawInputState[%u]: attr[%d] res=%d offset=%u dst=v%d regs=%d fetch_index=%u "
|
||||
for (int ai = 0; ai < vs_input_info.resources_num; ai++) {
|
||||
const auto& r = vs_input_info.resources[ai];
|
||||
const auto& rd = vs_input_info.resources_dst[ai];
|
||||
if (rd.buffer_index != bi) {
|
||||
continue;
|
||||
}
|
||||
LOGF("DrawInputState[%u]: attr[%d] offset=%u dst=v%d regs=%d fetch_index=%u "
|
||||
"sharp=%08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n",
|
||||
log_id, ai, res_index, b.attr_offsets[ai], rd.register_start, rd.registers_num,
|
||||
rd.fetch_index, r.fields[0], r.fields[1], r.fields[2], r.fields[3]);
|
||||
log_id, ai, static_cast<uint32_t>(r.Base48() - b.addr), rd.register_start,
|
||||
rd.registers_num, rd.fetch_index, r.fields[0], r.fields[1], r.fields[2], r.fields[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -630,19 +634,22 @@ struct PreparedIndexBuffer {
|
||||
vk::IndexType type = vk::IndexType::eUint16;
|
||||
};
|
||||
|
||||
static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer,
|
||||
const ShaderVertexInputInfo& info) {
|
||||
static uint64_t VertexBufferDescriptorSize(int binding, const ShaderVertexInputInfo& info) {
|
||||
const auto& buffer = info.buffers[binding];
|
||||
if (buffer.stride != 0 || buffer.num_records == 0) {
|
||||
return static_cast<uint64_t>(buffer.stride) * buffer.num_records;
|
||||
}
|
||||
|
||||
uint64_t size = 0;
|
||||
for (int i = 0; i < buffer.attr_num; i++) {
|
||||
const auto& resource = info.resources[buffer.attr_indices[i]];
|
||||
for (int i = 0; i < info.resources_num; i++) {
|
||||
if (info.resources_dst[i].buffer_index != binding) {
|
||||
continue;
|
||||
}
|
||||
const auto& resource = info.resources[i];
|
||||
// RDNA2 OOB_SELECT=2 only checks NumRecords != 0. A constant attribute still
|
||||
// fetches its entire format; NumRecords is not a byte count in this mode.
|
||||
const uint64_t extent = resource.OutOfBounds() == 2
|
||||
? static_cast<uint64_t>(buffer.attr_offsets[i]) +
|
||||
? resource.Base48() - buffer.addr +
|
||||
ShaderRecompiler::Format::GetFormatInfo(resource.Format()).byte_size
|
||||
: buffer.num_records;
|
||||
size = std::max(size, extent);
|
||||
@@ -679,7 +686,7 @@ static PreparedVertexBuffers AcquireVertexBuffers(CommandBuffer& b
|
||||
uint32_t range_count = 0;
|
||||
for (int i = 0; i < vs_input_info.buffers_num; i++) {
|
||||
const auto& vertex = vs_input_info.buffers[i];
|
||||
const auto size = VertexBufferDescriptorSize(vertex, vs_input_info);
|
||||
const auto size = VertexBufferDescriptorSize(i, vs_input_info);
|
||||
sizes[i] = size;
|
||||
if (size == 0) {
|
||||
continue;
|
||||
|
||||
@@ -336,14 +336,15 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo& info) {
|
||||
for (int ri = 0; ri < info.resources_num; ri++) {
|
||||
const auto& r = info.resources[ri];
|
||||
|
||||
bool merged = false;
|
||||
for (int bi = 0; bi < info.buffers_num; bi++) {
|
||||
auto& destination = info.resources_dst[ri];
|
||||
int bi = 0;
|
||||
for (; bi < info.buffers_num; bi++) {
|
||||
auto& b = info.buffers[bi];
|
||||
|
||||
uint64_t stride = b.stride;
|
||||
|
||||
if (stride == r.Stride() &&
|
||||
b.fetch_index == static_cast<uint32_t>(info.resources_dst[ri].fetch_index)) {
|
||||
b.fetch_index == destination.fetch_index) {
|
||||
uint64_t rbase = r.Base48();
|
||||
uint64_t base = std::min(rbase, b.addr);
|
||||
uint64_t offset1 = rbase - base;
|
||||
@@ -352,31 +353,20 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo& info) {
|
||||
if (offset1 < stride && offset2 < stride) {
|
||||
EXIT_NOT_IMPLEMENTED(b.num_records != r.NumRecords());
|
||||
b.addr = base;
|
||||
EXIT_NOT_IMPLEMENTED(b.attr_num >= ShaderVertexInputBuffer::ATTR_MAX);
|
||||
b.attr_indices[b.attr_num++] = ri;
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!merged) {
|
||||
if (bi == info.buffers_num) {
|
||||
EXIT_NOT_IMPLEMENTED(info.buffers_num >= ShaderVertexInputInfo::RES_MAX);
|
||||
int bi = info.buffers_num++;
|
||||
info.buffers[bi].addr = r.Base48();
|
||||
info.buffers[bi].stride = r.Stride();
|
||||
info.buffers[bi].num_records = r.NumRecords();
|
||||
info.buffers[bi].fetch_index = info.resources_dst[ri].fetch_index;
|
||||
info.buffers[bi].attr_num = 1;
|
||||
info.buffers[bi].attr_indices[0] = ri;
|
||||
}
|
||||
}
|
||||
|
||||
for (int bi = 0; bi < info.buffers_num; bi++) {
|
||||
auto& b = info.buffers[bi];
|
||||
for (int ri = 0; ri < b.attr_num; ri++) {
|
||||
b.attr_offsets[ri] = info.resources[b.attr_indices[ri]].Base48() - b.addr;
|
||||
info.buffers[bi] = {.addr = r.Base48(),
|
||||
.stride = r.Stride(),
|
||||
.num_records = r.NumRecords(),
|
||||
.fetch_index = destination.fetch_index};
|
||||
info.buffers_num++;
|
||||
}
|
||||
destination.buffer_index = bi;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,8 +897,9 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info) {
|
||||
|
||||
LOGF("\t\t register_start = %d\n"
|
||||
"\t\t registers_num = %d\n"
|
||||
"\t\t fetch_index = %" PRIu32 "\n",
|
||||
rd.register_start, rd.registers_num, rd.fetch_index);
|
||||
"\t\t fetch_index = %" PRIu32 "\n"
|
||||
"\t\t buffer_index = %d\n",
|
||||
rd.register_start, rd.registers_num, rd.fetch_index, rd.buffer_index);
|
||||
LOGF("\t\t fields = %08" PRIx32 "%08" PRIx32 "%08" PRIx32 "%08" PRIx32 "\n",
|
||||
r.fields[3], r.fields[2], r.fields[1], r.fields[0]);
|
||||
LOGF("\t\t Base() = %" PRIx64 "\n"
|
||||
@@ -934,14 +925,8 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info) {
|
||||
LOGF("\t\t addr = %" PRIx64 "\n"
|
||||
"\t\t stride = %" PRIu32 "\n"
|
||||
"\t\t num_records = %" PRIu32 "\n"
|
||||
"\t\t fetch_index = %" PRIu32 "\n"
|
||||
"\t\t attr_num = %" PRId32 "\n",
|
||||
r.addr, r.stride, r.num_records, r.fetch_index, r.attr_num);
|
||||
for (int j = 0; j < r.attr_num; j++) {
|
||||
LOGF("\t\t attr_indices[%d] = %d\n"
|
||||
"\t\t attr_offsets[%d] = %u\n",
|
||||
j, r.attr_indices[j], j, r.attr_offsets[j]);
|
||||
}
|
||||
"\t\t fetch_index = %" PRIu32 "\n",
|
||||
r.addr, r.stride, r.num_records, r.fetch_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,15 +174,10 @@ struct ShaderSamplerResource {
|
||||
};
|
||||
|
||||
struct ShaderVertexInputBuffer {
|
||||
static constexpr int ATTR_MAX = 32;
|
||||
|
||||
uint64_t addr = 0;
|
||||
uint32_t stride = 0;
|
||||
uint32_t num_records = 0;
|
||||
uint32_t fetch_index = 0;
|
||||
int attr_num = 0;
|
||||
int attr_indices[ATTR_MAX] = {0};
|
||||
uint32_t attr_offsets[ATTR_MAX] = {0};
|
||||
uint64_t addr = 0;
|
||||
uint32_t stride = 0;
|
||||
uint32_t num_records = 0;
|
||||
uint32_t fetch_index = 0;
|
||||
};
|
||||
|
||||
struct ShaderVertexDestination {
|
||||
@@ -190,6 +185,7 @@ struct ShaderVertexDestination {
|
||||
int registers_num = 0;
|
||||
int attr_id = -1;
|
||||
uint32_t fetch_index = 0;
|
||||
int buffer_index = 0;
|
||||
};
|
||||
|
||||
enum class ShaderStorageUsage {
|
||||
|
||||
@@ -14062,9 +14062,7 @@ public:
|
||||
vertex.resources_num = 2;
|
||||
vertex.buffers_num = 1;
|
||||
vertex.buffers[0].stride = 6 * sizeof(float);
|
||||
vertex.buffers[0].attr_num = 2;
|
||||
vertex.buffers[0].attr_indices[1] = 1;
|
||||
vertex.buffers[0].attr_offsets[1] = 2 * sizeof(float);
|
||||
vertex.resources[1].UpdateAddress48(2 * sizeof(float));
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
const auto format = i == 0 ? Prospero::BufferFormat::k32_32Float
|
||||
: packed_vertex_color ? Prospero::BufferFormat::k11_11_10Float
|
||||
|
||||
@@ -1702,6 +1702,61 @@ void TestShaderStageBarriers() {
|
||||
"independent vertex invocations retained a workgroup barrier");
|
||||
}
|
||||
|
||||
void TestVertexBufferGrouping() {
|
||||
const uint32_t shader[] = {EncodeSopp(0x01)};
|
||||
std::array<uint16_t, static_cast<size_t>(AgcDirectResourceType::Last) + 1> offsets;
|
||||
offsets.fill(AGC_ILLEGAL_DIRECT_OFFSET);
|
||||
offsets[static_cast<size_t>(AgcDirectResourceType::PtrVertexBufferTable)] = 0;
|
||||
offsets[static_cast<size_t>(AgcDirectResourceType::PtrVertexAttribDescTable)] = 2;
|
||||
ShaderUserData user_data{};
|
||||
user_data.direct_resource_count = offsets.size();
|
||||
user_data.direct_resource_offset = offsets.data();
|
||||
std::array<ShaderSemantic, 4> semantics{};
|
||||
for (uint32_t i = 0; i < semantics.size(); i++) {
|
||||
semantics[i].semantic = i;
|
||||
semantics[i].hardware_mapping = i;
|
||||
semantics[i].size_in_elements = 1;
|
||||
}
|
||||
ShaderMappedData mapped{};
|
||||
mapped.user_data = &user_data;
|
||||
mapped.code_size_bytes = sizeof(shader);
|
||||
mapped.input_semantics = semantics.data();
|
||||
mapped.num_input_semantics = semantics.size();
|
||||
HW::VertexShaderInfo regs{};
|
||||
regs.es_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||
regs.gs_regs.rsrc2.user_sgpr = 4;
|
||||
ShaderMapUserData(regs.es_regs.data_addr, mapped);
|
||||
std::array<ShaderBufferResource, 4> descriptors{};
|
||||
const std::array<uint32_t, 4> attributes{0, 1u | (1u << 26u), 2, 3};
|
||||
const std::array<uint64_t, 2> pointers{
|
||||
reinterpret_cast<uint64_t>(descriptors.data()),
|
||||
reinterpret_cast<uint64_t>(attributes.data())};
|
||||
std::memcpy(regs.gs_user_sgpr.value, pointers.data(), sizeof(pointers));
|
||||
ShaderVertexInputInfo input{};
|
||||
for (const uint64_t base : {0x1000u, 0x3000u}) {
|
||||
for (auto &descriptor : descriptors) {
|
||||
descriptor.fields[1] = 16u << 16u;
|
||||
descriptor.fields[2] = 8;
|
||||
descriptor.UpdateAddress48(base);
|
||||
}
|
||||
descriptors[0].UpdateAddress48(base + 8);
|
||||
descriptors[1].UpdateAddress48(base + 4);
|
||||
descriptors[3].fields[1] = 0; // Constant attributes use their own buffer.
|
||||
(void)PrepareProgram(regs, HW::Context{}, HW::UserConfig{}, input);
|
||||
Check(input.resources_num == 4 && input.buffers_num == 3 &&
|
||||
input.resources_dst[0].buffer_index == 0 &&
|
||||
input.resources_dst[1].buffer_index == 1 &&
|
||||
input.resources_dst[2].buffer_index == 0 &&
|
||||
input.resources_dst[3].buffer_index == 2,
|
||||
"interleaved vertex attributes lost their stride or instance-rate binding");
|
||||
Check(input.buffers[0].addr == base && input.buffers[1].addr == base + 4 &&
|
||||
input.buffers[1].fetch_index == 1 && input.buffers[2].stride == 0 &&
|
||||
input.resources[0].Base48() - input.buffers[0].addr == 8 &&
|
||||
input.resources[2].Base48() == input.buffers[0].addr,
|
||||
"a later lower-address attribute or changed table left stale vertex offsets");
|
||||
}
|
||||
}
|
||||
|
||||
void TestNggVertexEntryState() {
|
||||
using namespace ShaderRecompiler;
|
||||
// PPSA03309 shader 5a39eb2021a5d2c1: retain its NGG prologue and replace
|
||||
@@ -10571,13 +10626,11 @@ void TestNewShaderRecompilerClipDisabledPosition() {
|
||||
ShaderVertexInputInfo layout_a{};
|
||||
layout_a.resources_num = 1;
|
||||
layout_a.buffers_num = 1;
|
||||
layout_a.buffers[0].attr_num = 1;
|
||||
layout_a.buffers[0].attr_indices[0] = 0;
|
||||
layout_a.buffers[0].stride = 16;
|
||||
auto layout_b = layout_a;
|
||||
layout_b.buffers[0].stride = 32;
|
||||
layout_b.buffers[0].fetch_index = 1;
|
||||
layout_b.buffers[0].attr_offsets[0] = 4;
|
||||
layout_b.resources[0].UpdateAddress48(4);
|
||||
Check(MakeStageStaticKey(layout_a) == MakeStageStaticKey(layout_b),
|
||||
"pipeline-only vertex layout fragmented the shader module cache key");
|
||||
}
|
||||
@@ -13855,6 +13908,7 @@ int main() {
|
||||
TestDemandDrivenSpirvDeclarations();
|
||||
TestNewShaderRecompilerSMovB32();
|
||||
TestShaderStageBarriers();
|
||||
TestVertexBufferGrouping();
|
||||
TestNggVertexEntryState();
|
||||
TestNewShaderRecompilerClipDisabledPosition();
|
||||
TestNewShaderRecompilerAuxPositionExports();
|
||||
|
||||
Reference in New Issue
Block a user