yuzu-emu
/
yuzu
Archived
1
0
Fork 0

video_core: Optimize maxwell drawing trigger mechanism

This commit is contained in:
FengChen 2022-11-21 23:38:37 +08:00 committed by Feng Chen
parent aab68674c0
commit 1d57851fc7
2 changed files with 63 additions and 61 deletions

View File

@ -126,6 +126,7 @@ void Maxwell3D::InitializeRegisterDefaults() {
draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;
draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;
draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true;
draw_command[MAXWELL3D_REG_INDEX(draw.instance_id)] = true;
} }
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
@ -288,31 +289,58 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < Regs::NUM_REGS, ASSERT_MSG(method < Regs::NUM_REGS,
"Invalid Maxwell3D register, increase the size of the Regs structure"); "Invalid Maxwell3D register, increase the size of the Regs structure");
const u32 argument = ProcessShadowRam(method, method_argument);
ProcessDirtyRegisters(method, argument);
if (draw_command[method]) { if (draw_command[method]) {
regs.reg_array[method] = method_argument; regs.reg_array[method] = method_argument;
deferred_draw_method.push_back(method); deferred_draw_method.push_back(method);
auto u32_to_u8 = [&](const u32 argument) { auto update_inline_index = [&](const u32 index) {
inline_index_draw_indexes.push_back(static_cast<u8>(argument & 0x000000ff)); inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x0000ff00) >> 8)); inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x00ff0000) >> 16)); inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0xff000000) >> 24)); inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
draw_mode = DrawMode::InlineIndex;
}; };
if (MAXWELL3D_REG_INDEX(draw_inline_index) == method) { switch (method) {
u32_to_u8(method_argument); case MAXWELL3D_REG_INDEX(draw.end):
} else if (MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method) { switch (draw_mode) {
u32_to_u8(regs.inline_index_2x16.even); case DrawMode::General:
u32_to_u8(regs.inline_index_2x16.odd); ProcessDraw(1);
} else if (MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { break;
u32_to_u8(regs.inline_index_4x8.index0); case DrawMode::InlineIndex:
u32_to_u8(regs.inline_index_4x8.index1); regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
u32_to_u8(regs.inline_index_4x8.index2); regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
u32_to_u8(regs.inline_index_4x8.index3); ProcessDraw(1);
inline_index_draw_indexes.clear();
break;
case DrawMode::Instance:
break;
}
break;
case MAXWELL3D_REG_INDEX(draw_inline_index):
update_inline_index(method_argument);
break;
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
update_inline_index(regs.inline_index_2x16.even);
update_inline_index(regs.inline_index_2x16.odd);
break;
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
update_inline_index(regs.inline_index_4x8.index0);
update_inline_index(regs.inline_index_4x8.index1);
update_inline_index(regs.inline_index_4x8.index2);
update_inline_index(regs.inline_index_4x8.index3);
break;
case MAXWELL3D_REG_INDEX(draw.instance_id):
draw_mode =
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
? DrawMode::Instance
: DrawMode::General;
break;
} }
} else { } else {
ProcessDeferredDraw(); ProcessDeferredDraw();
const u32 argument = ProcessShadowRam(method, method_argument);
ProcessDirtyRegisters(method, argument);
ProcessMethodCall(method, argument, method_argument, is_last_call); ProcessMethodCall(method, argument, method_argument, is_last_call);
} }
} }
@ -626,57 +654,27 @@ void Maxwell3D::ProcessDraw(u32 instance_count) {
} }
void Maxwell3D::ProcessDeferredDraw() { void Maxwell3D::ProcessDeferredDraw() {
if (deferred_draw_method.empty()) { if (draw_mode != DrawMode::Instance || deferred_draw_method.empty()) {
return; return;
} }
enum class DrawMode {
Undefined,
General,
Instance,
};
DrawMode draw_mode{DrawMode::Undefined};
u32 method_count = static_cast<u32>(deferred_draw_method.size()); u32 method_count = static_cast<u32>(deferred_draw_method.size());
u32 method = deferred_draw_method[method_count - 1]; u32 instance_count = 1;
if (MAXWELL3D_REG_INDEX(draw.end) != method) { u32 vertex_buffer_count = 0;
return; u32 index_buffer_count = 0;
} for (u32 index = 0; index < method_count; ++index) {
draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || u32 method = deferred_draw_method[index];
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) {
? DrawMode::Instance instance_count = ++vertex_buffer_count;
: DrawMode::General; } else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
u32 instance_count = 0; instance_count = ++index_buffer_count;
if (draw_mode == DrawMode::Instance) {
u32 vertex_buffer_count = 0;
u32 index_buffer_count = 0;
for (u32 index = 0; index < method_count; ++index) {
method = deferred_draw_method[index];
if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) {
instance_count = ++vertex_buffer_count;
} else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
instance_count = ++index_buffer_count;
}
}
ASSERT_MSG(!(vertex_buffer_count && index_buffer_count),
"Instance both indexed and direct?");
} else {
instance_count = 1;
for (u32 index = 0; index < method_count; ++index) {
method = deferred_draw_method[index];
if (MAXWELL3D_REG_INDEX(draw_inline_index) == method ||
MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method ||
MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) {
regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
break;
}
} }
} }
ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?");
ProcessDraw(instance_count); ProcessDraw(instance_count);
deferred_draw_method.clear(); deferred_draw_method.clear();
inline_index_draw_indexes.clear();
} }
} // namespace Tegra::Engines } // namespace Tegra::Engines

View File

@ -3148,10 +3148,12 @@ private:
/// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
void ProcessTopologyOverride(); void ProcessTopologyOverride();
void ProcessDraw(u32 instance_count = 1); /// Handles deferred draw(e.g., instance draw).
void ProcessDeferredDraw(); void ProcessDeferredDraw();
/// Handles a draw.
void ProcessDraw(u32 instance_count = 1);
/// Returns a query's value or an empty object if the value will be deferred through a cache. /// Returns a query's value or an empty object if the value will be deferred through a cache.
std::optional<u64> GetQueryResult(); std::optional<u64> GetQueryResult();
@ -3178,6 +3180,8 @@ private:
std::array<bool, Regs::NUM_REGS> draw_command{}; std::array<bool, Regs::NUM_REGS> draw_command{};
std::vector<u32> deferred_draw_method; std::vector<u32> deferred_draw_method;
enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
DrawMode draw_mode{DrawMode::General};
}; };
#define ASSERT_REG_POSITION(field_name, position) \ #define ASSERT_REG_POSITION(field_name, position) \