mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 21:36:54 +01:00
graphics: fix PS5 NGG vertex and instance draw offsets
Refs: https://github.com/KytyPS5/KytyPS5/issues/130
This commit is contained in:
@@ -76,7 +76,7 @@ public:
|
|||||||
void DrawIndex(uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
|
void DrawIndex(uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
|
||||||
uint32_t instance_count = 0, const void* object_ids = nullptr,
|
uint32_t instance_count = 0, const void* object_ids = nullptr,
|
||||||
uint32_t render_target_slice_offset = 0, int32_t vertex_offset_add = 0,
|
uint32_t render_target_slice_offset = 0, int32_t vertex_offset_add = 0,
|
||||||
uint32_t first_instance = 0);
|
uint32_t first_instance = 0, bool offsets_from_indirect_args = false);
|
||||||
void DrawIndexOffset(uint32_t index_offset, uint32_t index_count, uint32_t flags);
|
void DrawIndexOffset(uint32_t index_offset, uint32_t index_count, uint32_t flags);
|
||||||
void DrawIndexAuto(uint32_t index_count, uint32_t flags,
|
void DrawIndexAuto(uint32_t index_count, uint32_t flags,
|
||||||
uint32_t render_target_slice_offset = 0);
|
uint32_t render_target_slice_offset = 0);
|
||||||
@@ -151,7 +151,7 @@ private:
|
|||||||
void SuspendPm4();
|
void SuspendPm4();
|
||||||
void SubmitNonIndexedDraw(uint32_t vertex_count, uint32_t flags,
|
void SubmitNonIndexedDraw(uint32_t vertex_count, uint32_t flags,
|
||||||
uint32_t render_target_slice_offset, uint32_t first_vertex,
|
uint32_t render_target_slice_offset, uint32_t first_vertex,
|
||||||
uint32_t first_instance);
|
uint32_t first_instance, bool offsets_from_indirect_args = false);
|
||||||
|
|
||||||
CommandScheduler& GetScheduler() const { return m_renderer.GetCommandScheduler(); }
|
CommandScheduler& GetScheduler() const { return m_renderer.GetCommandScheduler(); }
|
||||||
CommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
|
CommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
|
||||||
|
|||||||
@@ -850,7 +850,7 @@ void CommandProcessor::SetPredication(uint32_t condition, uint32_t op, uint32_t
|
|||||||
void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, uint32_t flags,
|
void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, uint32_t flags,
|
||||||
uint32_t type, uint32_t instance_count, const void* object_ids,
|
uint32_t type, uint32_t instance_count, const void* object_ids,
|
||||||
uint32_t render_target_slice_offset, int32_t vertex_offset_add,
|
uint32_t render_target_slice_offset, int32_t vertex_offset_add,
|
||||||
uint32_t first_instance) {
|
uint32_t first_instance, bool offsets_from_indirect_args) {
|
||||||
CheckBuffer();
|
CheckBuffer();
|
||||||
|
|
||||||
if (instance_count == 0) {
|
if (instance_count == 0) {
|
||||||
@@ -868,9 +868,10 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u
|
|||||||
"\n",
|
"\n",
|
||||||
vertex_offset_add, first_instance);
|
vertex_offset_add, first_instance);
|
||||||
}
|
}
|
||||||
m_renderer.GetRenderExecutor().DrawIndex(
|
m_renderer.GetRenderExecutor().DrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size,
|
||||||
m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr, flags, type,
|
index_count, index_addr, flags, type, instance_count,
|
||||||
instance_count, render_target_slice_offset, vertex_offset_add, first_instance);
|
render_target_slice_offset, vertex_offset_add,
|
||||||
|
first_instance, offsets_from_indirect_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count,
|
void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count,
|
||||||
@@ -929,7 +930,7 @@ void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiato
|
|||||||
}
|
}
|
||||||
m_num_instances = args.instance_count;
|
m_num_instances = args.instance_count;
|
||||||
SubmitNonIndexedDraw(args.vertex_count_per_instance, 0, 0, args.start_vertex_location,
|
SubmitNonIndexedDraw(args.vertex_count_per_instance, 0, 0, args.start_vertex_location,
|
||||||
args.start_instance_location);
|
args.start_instance_location, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -971,7 +972,7 @@ void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiato
|
|||||||
|
|
||||||
m_num_instances = args.instance_count;
|
m_num_instances = args.instance_count;
|
||||||
DrawIndex(index_count, index_addr, 0, 1, args.instance_count, nullptr, 0,
|
DrawIndex(index_count, index_addr, 0, 1, args.instance_count, nullptr, 0,
|
||||||
static_cast<int32_t>(args.base_vertex_location), args.start_instance_location);
|
static_cast<int32_t>(args.base_vertex_location), args.start_instance_location, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_count_or_count,
|
void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_count_or_count,
|
||||||
@@ -1029,7 +1030,7 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun
|
|||||||
}
|
}
|
||||||
m_num_instances = args->instance_count;
|
m_num_instances = args->instance_count;
|
||||||
SubmitNonIndexedDraw(args->vertex_count_per_instance, 0, 0, args->start_vertex_location,
|
SubmitNonIndexedDraw(args->vertex_count_per_instance, 0, 0, args->start_vertex_location,
|
||||||
args->start_instance_location);
|
args->start_instance_location, true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,7 +1073,8 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun
|
|||||||
|
|
||||||
m_num_instances = args->instance_count;
|
m_num_instances = args->instance_count;
|
||||||
DrawIndex(index_count, index_addr, 0, 1, args->instance_count, nullptr, 0,
|
DrawIndex(index_count, index_addr, 0, 1, args->instance_count, nullptr, 0,
|
||||||
static_cast<int32_t>(args->base_vertex_location), args->start_instance_location);
|
static_cast<int32_t>(args->base_vertex_location), args->start_instance_location,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1170,12 +1172,13 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags,
|
|||||||
|
|
||||||
void CommandProcessor::SubmitNonIndexedDraw(uint32_t vertex_count, uint32_t flags,
|
void CommandProcessor::SubmitNonIndexedDraw(uint32_t vertex_count, uint32_t flags,
|
||||||
uint32_t render_target_slice_offset,
|
uint32_t render_target_slice_offset,
|
||||||
uint32_t first_vertex, uint32_t first_instance) {
|
uint32_t first_vertex, uint32_t first_instance,
|
||||||
|
bool offsets_from_indirect_args) {
|
||||||
CheckBuffer();
|
CheckBuffer();
|
||||||
|
|
||||||
m_renderer.GetRenderExecutor().DrawAuto(m_submit_id, CurrentBuffer(), vertex_count, flags,
|
m_renderer.GetRenderExecutor().DrawAuto(
|
||||||
render_target_slice_offset, m_num_instances,
|
m_submit_id, CurrentBuffer(), vertex_count, flags, render_target_slice_offset,
|
||||||
first_vertex, first_instance);
|
m_num_instances, first_vertex, first_instance, offsets_from_indirect_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) {
|
void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) {
|
||||||
|
|||||||
@@ -132,10 +132,12 @@ public:
|
|||||||
void DrawIndex(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_type_and_size,
|
void DrawIndex(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_type_and_size,
|
||||||
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
|
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
|
||||||
uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0,
|
uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0,
|
||||||
int32_t vertex_offset_add = 0, uint32_t first_instance = 0);
|
int32_t vertex_offset_add = 0, uint32_t first_instance = 0,
|
||||||
|
bool offsets_from_indirect_args = false);
|
||||||
void DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_count, uint32_t flags,
|
void DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_count, uint32_t flags,
|
||||||
uint32_t render_target_slice_offset = 0, uint32_t instance_count = 1,
|
uint32_t render_target_slice_offset = 0, uint32_t instance_count = 1,
|
||||||
uint32_t first_vertex = 0, uint32_t first_instance = 0);
|
uint32_t first_vertex = 0, uint32_t first_instance = 0,
|
||||||
|
bool offsets_from_indirect_args = false);
|
||||||
void DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, uint32_t thread_group_x,
|
void DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, uint32_t thread_group_x,
|
||||||
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
|
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,25 @@ int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo&
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ResolveInstanceOffset(const ShaderVertexInputInfo& vs_input_info) {
|
||||||
|
if (!vs_input_info.fetch_embedded) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXIT_IF(!vs_input_info.stage);
|
||||||
|
const auto& program = *vs_input_info.stage.program;
|
||||||
|
const auto& resources = vs_input_info.stage.resources;
|
||||||
|
if (program.info.instance_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
|
||||||
|
const auto index =
|
||||||
|
static_cast<uint32_t>(program.info.instance_offset_sgpr) - program.user_data_base;
|
||||||
|
if (index < resources.user_data.size()) {
|
||||||
|
return resources.user_data[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static std::atomic<uint32_t> g_draw_state_log_count = 0;
|
static std::atomic<uint32_t> g_draw_state_log_count = 0;
|
||||||
static std::atomic<uint32_t> g_draw_input_log_count = 0;
|
static std::atomic<uint32_t> g_draw_input_log_count = 0;
|
||||||
static std::atomic<uint32_t> g_mrt_state_log_count = 0;
|
static std::atomic<uint32_t> g_mrt_state_log_count = 0;
|
||||||
@@ -508,6 +527,7 @@ struct DrawCallInfo {
|
|||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
uint32_t instance_count = 0;
|
uint32_t instance_count = 0;
|
||||||
uint32_t first_instance = 0;
|
uint32_t first_instance = 0;
|
||||||
|
bool offsets_from_indirect_args = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool ResolveDccAttachmentClear(TextureCache& cache, const RenderColorInfo& target,
|
static bool ResolveDccAttachmentClear(TextureCache& cache, const RenderColorInfo& target,
|
||||||
@@ -747,6 +767,7 @@ struct DrawEmitInfo {
|
|||||||
bool indexed = false;
|
bool indexed = false;
|
||||||
int32_t vertex_offset = 0;
|
int32_t vertex_offset = 0;
|
||||||
uint32_t first_vertex = 0;
|
uint32_t first_vertex = 0;
|
||||||
|
uint32_t first_instance = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DrawIndexBufferSource {
|
struct DrawIndexBufferSource {
|
||||||
@@ -1124,10 +1145,10 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
|||||||
case Prospero::PrimitiveType::kRectList:
|
case Prospero::PrimitiveType::kRectList:
|
||||||
if (emit.indexed) {
|
if (emit.indexed) {
|
||||||
vk_buffer.drawIndexed(draw.index_count, draw.instance_count, 0, emit.vertex_offset,
|
vk_buffer.drawIndexed(draw.index_count, draw.instance_count, 0, emit.vertex_offset,
|
||||||
draw.first_instance);
|
emit.first_instance);
|
||||||
} else {
|
} else {
|
||||||
vk_buffer.draw(draw.index_count, draw.instance_count, emit.first_vertex,
|
vk_buffer.draw(draw.index_count, draw.instance_count, emit.first_vertex,
|
||||||
draw.first_instance);
|
emit.first_instance);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Prospero::PrimitiveType::kRectListLegacy:
|
case Prospero::PrimitiveType::kRectListLegacy:
|
||||||
@@ -1136,17 +1157,17 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
|||||||
}
|
}
|
||||||
// Sarah
|
// Sarah
|
||||||
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
|
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
|
||||||
vk_buffer.draw(4, draw.instance_count, emit.first_vertex, draw.first_instance);
|
vk_buffer.draw(4, draw.instance_count, emit.first_vertex, emit.first_instance);
|
||||||
break;
|
break;
|
||||||
case Prospero::PrimitiveType::kQuadListLegacy:
|
case Prospero::PrimitiveType::kQuadListLegacy:
|
||||||
EXIT_NOT_IMPLEMENTED((draw.index_count & 0x3u) != 0);
|
EXIT_NOT_IMPLEMENTED((draw.index_count & 0x3u) != 0);
|
||||||
for (uint32_t i = 0; i < draw.index_count; i += 4) {
|
for (uint32_t i = 0; i < draw.index_count; i += 4) {
|
||||||
if (emit.indexed) {
|
if (emit.indexed) {
|
||||||
vk_buffer.drawIndexed(4, draw.instance_count, i, emit.vertex_offset,
|
vk_buffer.drawIndexed(4, draw.instance_count, i, emit.vertex_offset,
|
||||||
draw.first_instance);
|
emit.first_instance);
|
||||||
} else {
|
} else {
|
||||||
vk_buffer.draw(4, draw.instance_count, i + emit.first_vertex,
|
vk_buffer.draw(4, draw.instance_count, i + emit.first_vertex,
|
||||||
draw.first_instance);
|
emit.first_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1242,7 +1263,8 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
uint32_t index_type_and_size, uint32_t index_count,
|
uint32_t index_type_and_size, uint32_t index_count,
|
||||||
const void* index_addr, uint32_t flags, uint32_t type,
|
const void* index_addr, uint32_t flags, uint32_t type,
|
||||||
uint32_t instance_count, uint32_t render_target_slice_offset,
|
uint32_t instance_count, uint32_t render_target_slice_offset,
|
||||||
int32_t vertex_offset_add, uint32_t first_instance) {
|
int32_t vertex_offset_add, uint32_t first_instance,
|
||||||
|
bool offsets_from_indirect_args) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
|
|
||||||
EXIT_IF(buffer.IsInvalid());
|
EXIT_IF(buffer.IsInvalid());
|
||||||
@@ -1328,7 +1350,8 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
EXIT_NOT_IMPLEMENTED(type != 1);
|
EXIT_NOT_IMPLEMENTED(type != 1);
|
||||||
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex,
|
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex,
|
||||||
index_count, flags,
|
index_count, flags,
|
||||||
instance_count, first_instance};
|
instance_count, first_instance,
|
||||||
|
offsets_from_indirect_args};
|
||||||
std::vector<uint16_t> expanded_indices;
|
std::vector<uint16_t> expanded_indices;
|
||||||
if (expand_index8_to_u16) {
|
if (expand_index8_to_u16) {
|
||||||
EXIT_NOT_IMPLEMENTED(index_addr == nullptr);
|
EXIT_NOT_IMPLEMENTED(index_addr == nullptr);
|
||||||
@@ -1359,11 +1382,16 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
LogDrawStateIfNeeded(buffer, draw, state, true, false, index_type_and_size, index_addr);
|
LogDrawStateIfNeeded(buffer, draw, state, true, false, index_type_and_size, index_addr);
|
||||||
|
|
||||||
const auto vertex_offset =
|
const auto vertex_offset =
|
||||||
ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
|
draw.offsets_from_indirect_args
|
||||||
|
? vertex_offset_add
|
||||||
|
: ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
|
||||||
|
|
||||||
DrawEmitInfo emit {};
|
DrawEmitInfo emit {};
|
||||||
emit.indexed = true;
|
emit.indexed = true;
|
||||||
emit.vertex_offset = vertex_offset;
|
emit.vertex_offset = vertex_offset;
|
||||||
|
emit.first_instance = draw.offsets_from_indirect_args
|
||||||
|
? draw.first_instance
|
||||||
|
: ResolveInstanceOffset(state.vs_input_info);
|
||||||
|
|
||||||
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source,
|
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source,
|
||||||
primitive_restart, true, true, false);
|
primitive_restart, true, true, false);
|
||||||
@@ -1374,7 +1402,7 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_count,
|
void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_t index_count,
|
||||||
uint32_t flags, uint32_t render_target_slice_offset,
|
uint32_t flags, uint32_t render_target_slice_offset,
|
||||||
uint32_t instance_count, uint32_t first_vertex,
|
uint32_t instance_count, uint32_t first_vertex,
|
||||||
uint32_t first_instance) {
|
uint32_t first_instance, bool offsets_from_indirect_args) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
|
|
||||||
EXIT_IF(buffer.IsInvalid());
|
EXIT_IF(buffer.IsInvalid());
|
||||||
@@ -1426,7 +1454,8 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_
|
|||||||
EXIT_NOT_IMPLEMENTED(flags != 0);
|
EXIT_NOT_IMPLEMENTED(flags != 0);
|
||||||
const DrawCallInfo draw {"DrawIndexAuto", CommandBufferDebugOp::DrawIndexAuto,
|
const DrawCallInfo draw {"DrawIndexAuto", CommandBufferDebugOp::DrawIndexAuto,
|
||||||
index_count, flags,
|
index_count, flags,
|
||||||
instance_count, first_instance};
|
instance_count, first_instance,
|
||||||
|
offsets_from_indirect_args};
|
||||||
|
|
||||||
DrawRenderState state {};
|
DrawRenderState state {};
|
||||||
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false,
|
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false,
|
||||||
@@ -1460,10 +1489,16 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, uint32_
|
|||||||
ucfg.GetPrimType() == Prospero::PrimitiveType::kRectListLegacy, 0,
|
ucfg.GetPrimType() == Prospero::PrimitiveType::kRectListLegacy, 0,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
|
const auto vertex_offset =
|
||||||
static_cast<int32_t>(first_vertex);
|
draw.offsets_from_indirect_args
|
||||||
|
? static_cast<int32_t>(first_vertex)
|
||||||
|
: ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
|
||||||
|
static_cast<int32_t>(first_vertex);
|
||||||
DrawEmitInfo emit {};
|
DrawEmitInfo emit {};
|
||||||
emit.first_vertex = static_cast<uint32_t>(vertex_offset);
|
emit.first_vertex = static_cast<uint32_t>(vertex_offset);
|
||||||
|
emit.first_instance = draw.offsets_from_indirect_args
|
||||||
|
? draw.first_instance
|
||||||
|
: ResolveInstanceOffset(state.vs_input_info);
|
||||||
|
|
||||||
DrawIndexBufferSource index_source {};
|
DrawIndexBufferSource index_source {};
|
||||||
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false,
|
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false,
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ namespace Libs::Graphics {
|
|||||||
|
|
||||||
struct ShaderVertexInputInfo;
|
struct ShaderVertexInputInfo;
|
||||||
|
|
||||||
[[nodiscard]] int32_t ResolveVertexOffset(uint32_t index_offset,
|
[[nodiscard]] int32_t ResolveVertexOffset(uint32_t index_offset,
|
||||||
const ShaderVertexInputInfo& vs_input_info);
|
const ShaderVertexInputInfo& vs_input_info);
|
||||||
|
[[nodiscard]] uint32_t ResolveInstanceOffset(const ShaderVertexInputInfo& vs_input_info);
|
||||||
|
|
||||||
} // namespace Libs::Graphics
|
} // namespace Libs::Graphics
|
||||||
|
|
||||||
|
|||||||
@@ -234,8 +234,10 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
uint32_t wave_size) {
|
uint32_t wave_size) {
|
||||||
EmbeddedFetchData data;
|
EmbeddedFetchData data;
|
||||||
data.loads.reserve(input_info->resources_num);
|
data.loads.reserve(input_info->resources_num);
|
||||||
int32_t offset_candidate = -1;
|
int32_t vertex_offset_candidate = -1;
|
||||||
bool offset_conflict = false;
|
int32_t instance_offset_candidate = -1;
|
||||||
|
bool vertex_offset_conflict = false;
|
||||||
|
bool instance_offset_conflict = false;
|
||||||
|
|
||||||
const int shift_regs = 8;
|
const int shift_regs = 8;
|
||||||
const int attrib_reg = input_info->fetch_attrib_reg + shift_regs;
|
const int attrib_reg = input_info->fetch_attrib_reg + shift_regs;
|
||||||
@@ -263,26 +265,34 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
|
|
||||||
for (const auto& inst: decoded.instructions) {
|
for (const auto& inst: decoded.instructions) {
|
||||||
// Fetch shaders accumulate the draw's vertex offset in v0. The PS5 NGG ABI
|
// Fetch shaders accumulate the draw's vertex offset in v0. The PS5 NGG ABI
|
||||||
// seeds S_NGG_VERTEX_INDEX in v5 and applies the same offset there before fetching.
|
// seeds S_NGG_VERTEX_INDEX in v5 and S_NGG_INSTANCE_INDEX in v8, then applies the
|
||||||
|
// corresponding direct-draw offsets before fetching.
|
||||||
const bool vertex_index_accumulator =
|
const bool vertex_index_accumulator =
|
||||||
IsDecodedVgpr(inst.dst) &&
|
IsDecodedVgpr(inst.dst) &&
|
||||||
(inst.dst.reg == 0 || (user_data_base == 8 && inst.dst.reg == 5));
|
(inst.dst.reg == 0 || (user_data_base == 8 && inst.dst.reg == 5));
|
||||||
|
const bool instance_index_accumulator =
|
||||||
|
IsDecodedVgpr(inst.dst) && (inst.dst.reg == (user_data_base == 8 ? 8u : 3u));
|
||||||
uint32_t sad_zero = 0;
|
uint32_t sad_zero = 0;
|
||||||
const bool vertex_offset_add =
|
const bool index_offset_add =
|
||||||
vertex_index_accumulator && IsDecodedSgpr(inst.src0) &&
|
(vertex_index_accumulator || instance_index_accumulator) &&
|
||||||
|
IsDecodedSgpr(inst.src0) &&
|
||||||
((inst.opcode == Decoder::Opcode::V_ADD_I32 && IsDecodedVgpr(inst.src1) &&
|
((inst.opcode == Decoder::Opcode::V_ADD_I32 && IsDecodedVgpr(inst.src1) &&
|
||||||
inst.src1.reg == inst.dst.reg) ||
|
inst.src1.reg == inst.dst.reg) ||
|
||||||
(user_data_base == 8 && inst.dst.reg == 5 &&
|
(user_data_base == 8 && (inst.dst.reg == 5 || inst.dst.reg == 8) &&
|
||||||
inst.opcode == Decoder::Opcode::V_SAD_U32 && IsDecodedVgpr(inst.src2) &&
|
inst.opcode == Decoder::Opcode::V_SAD_U32 && IsDecodedVgpr(inst.src2) &&
|
||||||
inst.src2.reg == inst.dst.reg &&
|
inst.src2.reg == inst.dst.reg &&
|
||||||
TryDecodedOperandConstant(sgprs, inst.src1, sad_zero) && sad_zero == 0));
|
TryDecodedOperandConstant(sgprs, inst.src1, sad_zero) && sad_zero == 0));
|
||||||
if (data.loads.empty() && vertex_offset_add) {
|
if (data.loads.empty() && index_offset_add) {
|
||||||
const auto reg = DecodedSgprReg(inst.src0);
|
const auto reg = DecodedSgprReg(inst.src0);
|
||||||
if (reg >= user_data_base && reg - user_data_base < user_data_count) {
|
if (reg >= user_data_base && reg - user_data_base < user_data_count) {
|
||||||
if (offset_candidate >= 0 && offset_candidate != static_cast<int32_t>(reg)) {
|
auto& candidate = vertex_index_accumulator ? vertex_offset_candidate
|
||||||
offset_conflict = true;
|
: instance_offset_candidate;
|
||||||
|
auto& conflict = vertex_index_accumulator ? vertex_offset_conflict
|
||||||
|
: instance_offset_conflict;
|
||||||
|
if (candidate >= 0 && candidate != static_cast<int32_t>(reg)) {
|
||||||
|
conflict = true;
|
||||||
} else {
|
} else {
|
||||||
offset_candidate = static_cast<int32_t>(reg);
|
candidate = static_cast<int32_t>(reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,8 +451,13 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
load.attrib_id = buffer.attrib_id;
|
load.attrib_id = buffer.attrib_id;
|
||||||
load.components = DecodedDstSize(inst);
|
load.components = DecodedDstSize(inst);
|
||||||
load.prolog_loads = buffer.prolog_loads;
|
load.prolog_loads = buffer.prolog_loads;
|
||||||
if (data.loads.empty() && !offset_conflict) {
|
if (data.loads.empty()) {
|
||||||
data.vertex_offset_sgpr = offset_candidate;
|
if (!vertex_offset_conflict) {
|
||||||
|
data.vertex_offset_sgpr = vertex_offset_candidate;
|
||||||
|
}
|
||||||
|
if (!instance_offset_conflict) {
|
||||||
|
data.instance_offset_sgpr = instance_offset_candidate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data.loads.push_back(load);
|
data.loads.push_back(load);
|
||||||
}
|
}
|
||||||
@@ -615,7 +630,8 @@ TranslateResult TranslateProgram(std::span<const uint32_t> code, const CompileOp
|
|||||||
IR::TrackResources(ir);
|
IR::TrackResources(ir);
|
||||||
IR::EliminateDeadCode(ir.blocks);
|
IR::EliminateDeadCode(ir.blocks);
|
||||||
if (options.stage == ShaderType::Vertex) {
|
if (options.stage == ShaderType::Vertex) {
|
||||||
ir.info.vertex_offset_sgpr = embedded_fetch.vertex_offset_sgpr;
|
ir.info.vertex_offset_sgpr = embedded_fetch.vertex_offset_sgpr;
|
||||||
|
ir.info.instance_offset_sgpr = embedded_fetch.instance_offset_sgpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslateResult result;
|
TranslateResult result;
|
||||||
|
|||||||
@@ -950,7 +950,8 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
|
|||||||
result.cfg_failure_kind = options.cfg_failure_kind;
|
result.cfg_failure_kind = options.cfg_failure_kind;
|
||||||
result.fallback_reason = options.fallback_reason;
|
result.fallback_reason = options.fallback_reason;
|
||||||
if (options.embedded_fetch != nullptr) {
|
if (options.embedded_fetch != nullptr) {
|
||||||
result.info.vertex_offset_sgpr = options.embedded_fetch->vertex_offset_sgpr;
|
result.info.vertex_offset_sgpr = options.embedded_fetch->vertex_offset_sgpr;
|
||||||
|
result.info.instance_offset_sgpr = options.embedded_fetch->instance_offset_sgpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t vector_limit = 1u;
|
uint32_t vector_limit = 1u;
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ struct EmbeddedFetchLoad {
|
|||||||
|
|
||||||
struct EmbeddedFetchPlan {
|
struct EmbeddedFetchPlan {
|
||||||
std::vector<EmbeddedFetchLoad> loads;
|
std::vector<EmbeddedFetchLoad> loads;
|
||||||
int32_t vertex_offset_sgpr = -1;
|
int32_t vertex_offset_sgpr = -1;
|
||||||
|
int32_t instance_offset_sgpr = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TranslateOptions {
|
struct TranslateOptions {
|
||||||
|
|||||||
@@ -418,6 +418,7 @@ struct ShaderInfo {
|
|||||||
std::vector<StageOutput> outputs;
|
std::vector<StageOutput> outputs;
|
||||||
std::array<uint8_t, 32> vertex_fetch_components {};
|
std::array<uint8_t, 32> vertex_fetch_components {};
|
||||||
int32_t vertex_offset_sgpr = -1;
|
int32_t vertex_offset_sgpr = -1;
|
||||||
|
int32_t instance_offset_sgpr = -1;
|
||||||
bool has_bitwise_xor = false;
|
bool has_bitwise_xor = false;
|
||||||
bool uses_dma = false;
|
bool uses_dma = false;
|
||||||
|
|
||||||
|
|||||||
@@ -21909,6 +21909,18 @@ void CheckEmbeddedFetchVertexOffset() {
|
|||||||
return ResolveVertexOffset(index_offset, vertex);
|
return ResolveVertexOffset(index_offset, vertex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const auto ResolveInstance = [](const CompiledShader &result) {
|
||||||
|
ShaderVertexInputInfo vertex;
|
||||||
|
vertex.fetch_embedded = true;
|
||||||
|
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
||||||
|
program.user_data_base = result.program.user_data_base;
|
||||||
|
program.info.instance_offset_sgpr =
|
||||||
|
result.program.info.instance_offset_sgpr;
|
||||||
|
vertex.stage.program = &program;
|
||||||
|
vertex.stage.resources = result.resources;
|
||||||
|
return ResolveInstanceOffset(vertex);
|
||||||
|
};
|
||||||
|
|
||||||
const auto valid =
|
const auto valid =
|
||||||
Compile("EmbeddedFetchVertexOffset", MakeFetch({{18, 0}}), 7);
|
Compile("EmbeddedFetchVertexOffset", MakeFetch({{18, 0}}), 7);
|
||||||
Require(
|
Require(
|
||||||
@@ -21928,6 +21940,33 @@ void CheckEmbeddedFetchVertexOffset() {
|
|||||||
"PS5 NGG vertex-index offset or register index-offset precedence is "
|
"PS5 NGG vertex-index offset or register index-offset precedence is "
|
||||||
"wrong");
|
"wrong");
|
||||||
|
|
||||||
|
const auto ngg_instance =
|
||||||
|
Compile("EmbeddedFetchNggInstanceOffset",
|
||||||
|
MakeFetch({{18, 8}}, {}, 8, true), 81);
|
||||||
|
Require("EmbeddedFetchNggInstanceOffset", "parse",
|
||||||
|
ngg_instance.program.info.vertex_offset_sgpr == -1 &&
|
||||||
|
ngg_instance.program.info.instance_offset_sgpr == 18 &&
|
||||||
|
ResolveInstance(ngg_instance) == 81,
|
||||||
|
"PS5 NGG instance-index offset was not detected or resolved");
|
||||||
|
|
||||||
|
const auto instance_conflict = Compile(
|
||||||
|
"EmbeddedFetchConflictingInstanceOffset",
|
||||||
|
MakeFetch({{17, 8}, {18, 8}}, {}, 8, true), 81);
|
||||||
|
const auto instance_malformed =
|
||||||
|
Compile("EmbeddedFetchMalformedInstanceOffset",
|
||||||
|
MakeFetch({{18, 7}}, {}, 7, true), 81);
|
||||||
|
const auto instance_outside =
|
||||||
|
Compile("EmbeddedFetchOutsideInstanceOffset",
|
||||||
|
MakeFetch({{19, 8}}, {}, 8, true), 81);
|
||||||
|
for (const auto *result :
|
||||||
|
{&instance_conflict, &instance_malformed, &instance_outside}) {
|
||||||
|
Require("EmbeddedFetchNggInstanceOffset", "fail closed",
|
||||||
|
result->program.info.instance_offset_sgpr == -1 &&
|
||||||
|
ResolveInstance(*result) == 0,
|
||||||
|
"conflicting, malformed, or out-of-window instance add was "
|
||||||
|
"classified");
|
||||||
|
}
|
||||||
|
|
||||||
const auto pointer = 0x5b7c5100u;
|
const auto pointer = 0x5b7c5100u;
|
||||||
const auto late = Compile("EmbeddedFetchLateOffset",
|
const auto late = Compile("EmbeddedFetchLateOffset",
|
||||||
MakeFetch({}, std::pair<u32, u32>{18, 0}), pointer);
|
MakeFetch({}, std::pair<u32, u32>{18, 0}), pointer);
|
||||||
|
|||||||
Reference in New Issue
Block a user