summaryrefslogtreecommitdiffstats
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.h44
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp50
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h34
5 files changed, 105 insertions, 28 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 98ed11ec5..0e1d6d785 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -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) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 1fae41cb2..2b45ffed7 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -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);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 28abc563a..75b4031a7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -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];
+ NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
+ index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
+ 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
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 548ce0453..fb5d99ba2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -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;
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 7909dcfc3..aa5026cce 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -31,7 +31,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return GL_UNSIGNED_BYTE;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str());
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
UNREACHABLE();
return {};
}
@@ -40,7 +40,21 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return GL_FLOAT;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str());
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
+ UNREACHABLE();
+ 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;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format));
UNREACHABLE();
return {};
}
@@ -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);
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology));
UNREACHABLE();
return {};
}
@@ -64,18 +78,26 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) {
case Tegra::Texture::TextureFilter::Nearest:
return GL_NEAREST;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u",
- static_cast<u32>(filter_mode));
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
+ static_cast<u32>(filter_mode));
UNREACHABLE();
return {};
}
inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
switch (wrap_mode) {
+ case Tegra::Texture::WrapMode::Wrap:
+ return GL_REPEAT;
case Tegra::Texture::WrapMode::ClampToEdge:
return GL_CLAMP_TO_EDGE;
+ case Tegra::Texture::WrapMode::ClampOGL:
+ // TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use
+ // GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to
+ // manually mix them. However the shader part of this is not yet implemented.
+ return GL_CLAMP_TO_BORDER;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode));
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}",
+ static_cast<u32>(wrap_mode));
UNREACHABLE();
return {};
}