diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 8612a758f7..a2d231bf39 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -286,6 +286,38 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); + PrimitiveAssembler& primitive_assembler = g_state.primitive_assembler; + + bool accelerate_draw = VideoCore::g_hw_shader_enabled && primitive_assembler.IsEmpty(); + + if (regs.pipeline.use_gs == PipelineRegs::UseGS::No) { + auto topology = primitive_assembler.GetTopology(); + if (topology == PipelineRegs::TriangleTopology::Shader || + topology == PipelineRegs::TriangleTopology::List) { + accelerate_draw = accelerate_draw && (regs.pipeline.num_vertices % 3) == 0; + } + // TODO (wwylele): for Strip/Fan topology, if the primitive assember is not restarted + // after this draw call, the buffered vertex from this draw should "leak" to the next + // draw, in which case we should buffer the vertex into the software primitive assember, + // or disable accelerate draw completely. However, there is not game found yet that does + // this, so this is left unimplemented for now. Revisit this when an issue is found in + // games. + } else { + if (VideoCore::g_hw_shader_accurate_gs) { + accelerate_draw = false; + } + } + + bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); + + if (accelerate_draw && + VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed)) { + if (g_debug_context) { + g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); + } + break; + } + // Processes information about internal vertex attributes to figure out how a vertex is // loaded. // Later, these can be compiled and cached. @@ -294,15 +326,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { Shader::OutputVertex::ValidateSemantics(regs.rasterizer); // Load vertices - bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); - const auto& index_info = regs.pipeline.index_array; const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); const u16* index_address_16 = reinterpret_cast(index_address_8); bool index_u16 = index_info.format != 0; - PrimitiveAssembler& primitive_assembler = g_state.primitive_assembler; - if (g_debug_context && g_debug_context->recorder) { for (int i = 0; i < 3; ++i) { const auto texture = regs.texturing.GetTextures()[i]; diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h index 5c1d6f5d46..fd5445aa8e 100644 --- a/src/video_core/primitive_assembly.h +++ b/src/video_core/primitive_assembly.h @@ -46,12 +46,12 @@ struct PrimitiveAssembler { void Reconfigure(PipelineRegs::TriangleTopology topology); /** - * Is our internal state empty? + * Returns whether the PrimitiveAssembler has an empty internal buffer. */ bool IsEmpty() const; /** - * What is our triangle topology? + * Returns the current topology. */ PipelineRegs::TriangleTopology GetTopology() const;