gl_rasterizer: Implement indexed vertex mode.
This commit is contained in:
		
							parent
							
								
									44e09ba807
								
							
						
					
					
						commit
						1a1af3fda3
					
				@ -165,6 +165,7 @@ void Maxwell3D::ProcessQueryGet() {
 | 
			
		||||
void Maxwell3D::DrawArrays() {
 | 
			
		||||
    LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(),
 | 
			
		||||
              regs.vertex_buffer.count);
 | 
			
		||||
    ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
 | 
			
		||||
 | 
			
		||||
    auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
 | 
			
		||||
 | 
			
		||||
@ -176,7 +177,8 @@ void Maxwell3D::DrawArrays() {
 | 
			
		||||
        debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/);
 | 
			
		||||
    const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
 | 
			
		||||
    VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
 | 
			
		||||
 | 
			
		||||
@ -248,6 +248,12 @@ public:
 | 
			
		||||
            Patches = 0xe,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        enum class IndexFormat : u32 {
 | 
			
		||||
            UnsignedByte = 0x0,
 | 
			
		||||
            UnsignedShort = 0x1,
 | 
			
		||||
            UnsignedInt = 0x2,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        union {
 | 
			
		||||
            struct {
 | 
			
		||||
                INSERT_PADDING_WORDS(0x200);
 | 
			
		||||
@ -375,7 +381,42 @@ public:
 | 
			
		||||
                    };
 | 
			
		||||
                } draw;
 | 
			
		||||
 | 
			
		||||
                INSERT_PADDING_WORDS(0x139);
 | 
			
		||||
                INSERT_PADDING_WORDS(0x6B);
 | 
			
		||||
 | 
			
		||||
                struct {
 | 
			
		||||
                    u32 start_addr_high;
 | 
			
		||||
                    u32 start_addr_low;
 | 
			
		||||
                    u32 end_addr_high;
 | 
			
		||||
                    u32 end_addr_low;
 | 
			
		||||
                    IndexFormat format;
 | 
			
		||||
                    u32 first;
 | 
			
		||||
                    u32 count;
 | 
			
		||||
 | 
			
		||||
                    unsigned FormatSizeInBytes() const {
 | 
			
		||||
                        switch (format) {
 | 
			
		||||
                        case IndexFormat::UnsignedByte:
 | 
			
		||||
                            return 1;
 | 
			
		||||
                        case IndexFormat::UnsignedShort:
 | 
			
		||||
                            return 2;
 | 
			
		||||
                        case IndexFormat::UnsignedInt:
 | 
			
		||||
                            return 4;
 | 
			
		||||
                        }
 | 
			
		||||
                        UNREACHABLE();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    GPUVAddr StartAddress() const {
 | 
			
		||||
                        return static_cast<GPUVAddr>(
 | 
			
		||||
                            (static_cast<GPUVAddr>(start_addr_high) << 32) | start_addr_low);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    GPUVAddr EndAddress() const {
 | 
			
		||||
                        return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) |
 | 
			
		||||
                                                     end_addr_low);
 | 
			
		||||
                    }
 | 
			
		||||
                } index_array;
 | 
			
		||||
 | 
			
		||||
                INSERT_PADDING_WORDS(0xC7);
 | 
			
		||||
 | 
			
		||||
                struct {
 | 
			
		||||
                    u32 query_address_high;
 | 
			
		||||
                    u32 query_address_low;
 | 
			
		||||
@ -572,6 +613,7 @@ ASSERT_REG_POSITION(tsc, 0x557);
 | 
			
		||||
ASSERT_REG_POSITION(tic, 0x55D);
 | 
			
		||||
ASSERT_REG_POSITION(code_address, 0x582);
 | 
			
		||||
ASSERT_REG_POSITION(draw, 0x585);
 | 
			
		||||
ASSERT_REG_POSITION(index_array, 0x5F2);
 | 
			
		||||
ASSERT_REG_POSITION(query, 0x6C0);
 | 
			
		||||
ASSERT_REG_POSITION(vertex_array[0], 0x700);
 | 
			
		||||
ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
 | 
			
		||||
 | 
			
		||||
@ -97,7 +97,6 @@ RasterizerOpenGL::RasterizerOpenGL() {
 | 
			
		||||
    state.draw.vertex_buffer = stream_buffer->GetHandle();
 | 
			
		||||
 | 
			
		||||
    shader_program_manager = std::make_unique<GLShader::ProgramManager>();
 | 
			
		||||
 | 
			
		||||
    state.draw.shader_program = 0;
 | 
			
		||||
    state.draw.vertex_array = hw_vao.handle;
 | 
			
		||||
    state.Apply();
 | 
			
		||||
@ -128,17 +127,6 @@ RasterizerOpenGL::~RasterizerOpenGL() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) {
 | 
			
		||||
    const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
 | 
			
		||||
 | 
			
		||||
    if (is_indexed) {
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): Add support for 1+ vertex arrays
 | 
			
		||||
    vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_VAO);
 | 
			
		||||
    const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
 | 
			
		||||
@ -150,6 +138,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): Add support for 1+ vertex arrays
 | 
			
		||||
    const auto& vertex_array{regs.vertex_array[0]};
 | 
			
		||||
    const auto& vertex_array_limit{regs.vertex_array_limit[0]};
 | 
			
		||||
    ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?");
 | 
			
		||||
    ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!");
 | 
			
		||||
    for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) {
 | 
			
		||||
@ -162,6 +151,10 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    // to avoid OpenGL errors.
 | 
			
		||||
    for (unsigned index = 0; index < 16; ++index) {
 | 
			
		||||
        auto& attrib = regs.vertex_attrib_format[index];
 | 
			
		||||
        LOG_DEBUG(HW_GPU, "vertex attrib %d, count=%d, size=%s, type=%s, offset=%d, normalize=%d",
 | 
			
		||||
                  index, attrib.ComponentCount(), attrib.SizeString().c_str(),
 | 
			
		||||
                  attrib.TypeString().c_str(), attrib.offset.Value(), attrib.IsNormalized());
 | 
			
		||||
 | 
			
		||||
        glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
 | 
			
		||||
                              attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride,
 | 
			
		||||
                              reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset));
 | 
			
		||||
@ -170,7 +163,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Copy vertex array data
 | 
			
		||||
    const u32 data_size{vertex_array.stride * regs.vertex_buffer.count};
 | 
			
		||||
    const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1};
 | 
			
		||||
    const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())};
 | 
			
		||||
    res_cache.FlushRegion(data_addr, data_size, nullptr);
 | 
			
		||||
    Memory::ReadBlock(data_addr, array_ptr, data_size);
 | 
			
		||||
@ -333,13 +326,18 @@ void RasterizerOpenGL::DrawArrays() {
 | 
			
		||||
 | 
			
		||||
    // Draw the vertex batch
 | 
			
		||||
    const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
 | 
			
		||||
    AnalyzeVertexArray(is_indexed);
 | 
			
		||||
    const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
 | 
			
		||||
    const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): Add support for 1+ vertex arrays
 | 
			
		||||
    vs_input_size = vertex_num * regs.vertex_array[0].stride;
 | 
			
		||||
 | 
			
		||||
    state.draw.vertex_buffer = stream_buffer->GetHandle();
 | 
			
		||||
    state.Apply();
 | 
			
		||||
 | 
			
		||||
    size_t buffer_size = static_cast<size_t>(vs_input_size);
 | 
			
		||||
    if (is_indexed) {
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Uniform space for the 5 shader stages
 | 
			
		||||
@ -354,9 +352,18 @@ void RasterizerOpenGL::DrawArrays() {
 | 
			
		||||
    SetupVertexArray(buffer_ptr, buffer_offset);
 | 
			
		||||
    ptr_pos += vs_input_size;
 | 
			
		||||
 | 
			
		||||
    // If indexed mode, copy the index buffer
 | 
			
		||||
    GLintptr index_buffer_offset = 0;
 | 
			
		||||
    if (is_indexed) {
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        ptr_pos = Common::AlignUp(ptr_pos, 4);
 | 
			
		||||
 | 
			
		||||
        const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
 | 
			
		||||
        const VAddr index_data_addr{
 | 
			
		||||
            memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())};
 | 
			
		||||
        Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size);
 | 
			
		||||
 | 
			
		||||
        index_buffer_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
 | 
			
		||||
        ptr_pos += index_buffer_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SetupShaders(buffer_ptr, buffer_offset, ptr_pos);
 | 
			
		||||
@ -366,11 +373,16 @@ void RasterizerOpenGL::DrawArrays() {
 | 
			
		||||
    shader_program_manager->ApplyTo(state);
 | 
			
		||||
    state.Apply();
 | 
			
		||||
 | 
			
		||||
    const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)};
 | 
			
		||||
    if (is_indexed) {
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        const GLint index_min{static_cast<GLint>(regs.index_array.first)};
 | 
			
		||||
        const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)};
 | 
			
		||||
        glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count,
 | 
			
		||||
                                      MaxwellToGL::IndexFormat(regs.index_array.format),
 | 
			
		||||
                                      reinterpret_cast<const void*>(index_buffer_offset),
 | 
			
		||||
                                      -index_min);
 | 
			
		||||
    } else {
 | 
			
		||||
        glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0,
 | 
			
		||||
                     regs.vertex_buffer.count);
 | 
			
		||||
        glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Disable scissor test
 | 
			
		||||
 | 
			
		||||
@ -155,7 +155,6 @@ private:
 | 
			
		||||
 | 
			
		||||
    GLsizeiptr vs_input_size;
 | 
			
		||||
 | 
			
		||||
    void AnalyzeVertexArray(bool is_indexed);
 | 
			
		||||
    void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset);
 | 
			
		||||
 | 
			
		||||
    std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,20 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline GLenum IndexFormat(Maxwell::IndexFormat index_format) {
 | 
			
		||||
    switch (index_format) {
 | 
			
		||||
    case Maxwell::IndexFormat::UnsignedByte:
 | 
			
		||||
        return GL_UNSIGNED_BYTE;
 | 
			
		||||
    case Maxwell::IndexFormat::UnsignedShort:
 | 
			
		||||
        return GL_UNSIGNED_SHORT;
 | 
			
		||||
    case Maxwell::IndexFormat::UnsignedInt:
 | 
			
		||||
        return GL_UNSIGNED_INT;
 | 
			
		||||
    }
 | 
			
		||||
    LOG_CRITICAL(Render_OpenGL, "Unimplemented index_format=%d", index_format);
 | 
			
		||||
    UNREACHABLE();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
 | 
			
		||||
    switch (topology) {
 | 
			
		||||
    case Maxwell::PrimitiveTopology::Triangles:
 | 
			
		||||
@ -52,7 +66,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
 | 
			
		||||
    case Maxwell::PrimitiveTopology::TriangleStrip:
 | 
			
		||||
        return GL_TRIANGLE_STRIP;
 | 
			
		||||
    }
 | 
			
		||||
    LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology);
 | 
			
		||||
    LOG_CRITICAL(Render_OpenGL, "Unimplemented topology=%d", topology);
 | 
			
		||||
    UNREACHABLE();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user