|
|
|
@ -107,7 +107,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind |
|
|
|
state.draw.shader_program = 0; |
|
|
|
state.Apply(); |
|
|
|
|
|
|
|
LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here"); |
|
|
|
CheckExtensions(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -121,66 +120,41 @@ void RasterizerOpenGL::CheckExtensions() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
GLuint RasterizerOpenGL::SetupVertexFormat() { |
|
|
|
void RasterizerOpenGL::SetupVertexFormat() { |
|
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_VAO); |
|
|
|
|
|
|
|
auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); |
|
|
|
auto& vao_entry = iter->second; |
|
|
|
|
|
|
|
if (is_cache_miss) { |
|
|
|
vao_entry.Create(); |
|
|
|
const GLuint vao = vao_entry.handle; |
|
|
|
|
|
|
|
// Eventhough we are using DSA to create this vertex array, there is a bug on Intel's blob
|
|
|
|
// that fails to properly create the vertex array if it's not bound even after creating it
|
|
|
|
// with glCreateVertexArrays
|
|
|
|
state.draw.vertex_array = vao; |
|
|
|
state.ApplyVertexArrayState(); |
|
|
|
|
|
|
|
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
|
|
|
|
// Enables the first 16 vertex attributes always, as we don't know which ones are actually
|
|
|
|
// used until shader time. Note, Tegra technically supports 32, but we're capping this to 16
|
|
|
|
// for now to avoid OpenGL errors.
|
|
|
|
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. Enables
|
|
|
|
// the first 16 vertex attributes always, as we don't know which ones are actually used until
|
|
|
|
// shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now to
|
|
|
|
// avoid OpenGL errors.
|
|
|
|
// TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
|
|
|
|
// assume every shader uses them all.
|
|
|
|
for (u32 index = 0; index < 16; ++index) { |
|
|
|
const auto& attrib = regs.vertex_attrib_format[index]; |
|
|
|
|
|
|
|
// Ignore invalid attributes.
|
|
|
|
if (!attrib.IsValid()) |
|
|
|
if (!attrib.IsValid()) { |
|
|
|
glDisableVertexAttribArray(index); |
|
|
|
continue; |
|
|
|
} |
|
|
|
glEnableVertexAttribArray(index); |
|
|
|
|
|
|
|
const auto& buffer = regs.vertex_array[attrib.buffer]; |
|
|
|
LOG_TRACE(Render_OpenGL, |
|
|
|
"vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", |
|
|
|
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), |
|
|
|
attrib.offset.Value(), attrib.IsNormalized()); |
|
|
|
|
|
|
|
ASSERT(buffer.IsEnabled()); |
|
|
|
|
|
|
|
glEnableVertexArrayAttrib(vao, index); |
|
|
|
if (attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SignedInt || |
|
|
|
attrib.type == |
|
|
|
Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnsignedInt) { |
|
|
|
glVertexArrayAttribIFormat(vao, index, attrib.ComponentCount(), |
|
|
|
MaxwellToGL::VertexType(attrib), attrib.offset); |
|
|
|
if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt || |
|
|
|
attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) { |
|
|
|
glVertexAttribIFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), |
|
|
|
attrib.offset); |
|
|
|
} else { |
|
|
|
glVertexArrayAttribFormat( |
|
|
|
vao, index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), |
|
|
|
glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), |
|
|
|
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); |
|
|
|
} |
|
|
|
glVertexArrayAttribBinding(vao, index, attrib.buffer); |
|
|
|
} |
|
|
|
glVertexAttribBinding(index, attrib.buffer); |
|
|
|
} |
|
|
|
|
|
|
|
state.draw.vertex_array = vao_entry.handle; |
|
|
|
return vao_entry.handle; |
|
|
|
} |
|
|
|
|
|
|
|
void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
|
void RasterizerOpenGL::SetupVertexBuffer() { |
|
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
@ -189,8 +163,9 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
|
// Upload all guest vertex arrays sequentially to our buffer
|
|
|
|
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
|
|
|
const auto& vertex_array = regs.vertex_array[index]; |
|
|
|
if (!vertex_array.IsEnabled()) |
|
|
|
if (!vertex_array.IsEnabled()) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
const GPUVAddr start = vertex_array.StartAddress(); |
|
|
|
const GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); |
|
|
|
@ -205,15 +180,15 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
|
|
|
|
|
if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) { |
|
|
|
// Enable vertex buffer instancing with the specified divisor.
|
|
|
|
glVertexArrayBindingDivisor(vao, index, vertex_array.divisor); |
|
|
|
glVertexBindingDivisor(index, vertex_array.divisor); |
|
|
|
} else { |
|
|
|
// Disable the vertex buffer instancing.
|
|
|
|
glVertexArrayBindingDivisor(vao, index, 0); |
|
|
|
glVertexBindingDivisor(index, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void RasterizerOpenGL::SetupVertexInstances(GLuint vao) { |
|
|
|
void RasterizerOpenGL::SetupVertexInstances() { |
|
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
@ -222,10 +197,10 @@ void RasterizerOpenGL::SetupVertexInstances(GLuint vao) { |
|
|
|
if (regs.instanced_arrays.IsInstancingEnabled(index) && |
|
|
|
regs.vertex_array[index].divisor != 0) { |
|
|
|
// Enable vertex buffer instancing with the specified divisor.
|
|
|
|
glVertexArrayBindingDivisor(vao, index, regs.vertex_array[index].divisor); |
|
|
|
glVertexBindingDivisor(index, regs.vertex_array[index].divisor); |
|
|
|
} else { |
|
|
|
// Disable the vertex buffer instancing.
|
|
|
|
glVertexArrayBindingDivisor(vao, index, 0); |
|
|
|
glVertexBindingDivisor(index, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -559,13 +534,12 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { |
|
|
|
buffer_cache.Map(buffer_size); |
|
|
|
|
|
|
|
// Prepare vertex array format.
|
|
|
|
const GLuint vao = SetupVertexFormat(); |
|
|
|
vertex_array_pushbuffer.Setup(vao); |
|
|
|
SetupVertexFormat(); |
|
|
|
vertex_array_pushbuffer.Setup(); |
|
|
|
|
|
|
|
// Upload vertex and index data.
|
|
|
|
SetupVertexBuffer(vao); |
|
|
|
SetupVertexInstances(vao); |
|
|
|
|
|
|
|
SetupVertexBuffer(); |
|
|
|
SetupVertexInstances(); |
|
|
|
GLintptr index_buffer_offset; |
|
|
|
if (is_indexed) { |
|
|
|
index_buffer_offset = SetupIndexBuffer(); |
|
|
|
|