gl_state: Remove VAO cache and tracking

This commit is contained in:
ReinUsesLisp 2019-12-26 00:16:52 -03:00
parent 2a662fea36
commit d5ab0358b6
10 changed files with 52 additions and 152 deletions

View File

@ -107,7 +107,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
state.draw.shader_program = 0; state.draw.shader_program = 0;
state.Apply(); state.Apply();
LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here");
CheckExtensions(); CheckExtensions();
} }
@ -121,66 +120,41 @@ void RasterizerOpenGL::CheckExtensions() {
} }
} }
GLuint RasterizerOpenGL::SetupVertexFormat() { void RasterizerOpenGL::SetupVertexFormat() {
auto& gpu = system.GPU().Maxwell3D(); auto& gpu = system.GPU().Maxwell3D();
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
MICROPROFILE_SCOPE(OpenGL_VAO); MICROPROFILE_SCOPE(OpenGL_VAO);
auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. Enables
auto& vao_entry = iter->second; // 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
if (is_cache_miss) { // avoid OpenGL errors.
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.
// TODO(Subv): Analyze the shader to identify which attributes are actually used and don't // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
// assume every shader uses them all. // assume every shader uses them all.
for (u32 index = 0; index < 16; ++index) { for (u32 index = 0; index < 16; ++index) {
const auto& attrib = regs.vertex_attrib_format[index]; const auto& attrib = regs.vertex_attrib_format[index];
// Ignore invalid attributes. // Ignore invalid attributes.
if (!attrib.IsValid()) if (!attrib.IsValid()) {
glDisableVertexAttribArray(index);
continue; continue;
}
glEnableVertexAttribArray(index);
const auto& buffer = regs.vertex_array[attrib.buffer]; if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt ||
LOG_TRACE(Render_OpenGL, attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) {
"vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", glVertexAttribIFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), attrib.offset);
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);
} else { } else {
glVertexArrayAttribFormat( glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
vao, index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); 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(); auto& gpu = system.GPU().Maxwell3D();
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
@ -189,8 +163,9 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) {
// Upload all guest vertex arrays sequentially to our buffer // Upload all guest vertex arrays sequentially to our buffer
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
const auto& vertex_array = regs.vertex_array[index]; const auto& vertex_array = regs.vertex_array[index];
if (!vertex_array.IsEnabled()) if (!vertex_array.IsEnabled()) {
continue; continue;
}
const GPUVAddr start = vertex_array.StartAddress(); const GPUVAddr start = vertex_array.StartAddress();
const GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); 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) { if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) {
// Enable vertex buffer instancing with the specified divisor. // Enable vertex buffer instancing with the specified divisor.
glVertexArrayBindingDivisor(vao, index, vertex_array.divisor); glVertexBindingDivisor(index, vertex_array.divisor);
} else { } else {
// Disable the vertex buffer instancing. // 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(); auto& gpu = system.GPU().Maxwell3D();
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
@ -222,10 +197,10 @@ void RasterizerOpenGL::SetupVertexInstances(GLuint vao) {
if (regs.instanced_arrays.IsInstancingEnabled(index) && if (regs.instanced_arrays.IsInstancingEnabled(index) &&
regs.vertex_array[index].divisor != 0) { regs.vertex_array[index].divisor != 0) {
// Enable vertex buffer instancing with the specified divisor. // Enable vertex buffer instancing with the specified divisor.
glVertexArrayBindingDivisor(vao, index, regs.vertex_array[index].divisor); glVertexBindingDivisor(index, regs.vertex_array[index].divisor);
} else { } else {
// Disable the vertex buffer instancing. // 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); buffer_cache.Map(buffer_size);
// Prepare vertex array format. // Prepare vertex array format.
const GLuint vao = SetupVertexFormat(); SetupVertexFormat();
vertex_array_pushbuffer.Setup(vao); vertex_array_pushbuffer.Setup();
// Upload vertex and index data. // Upload vertex and index data.
SetupVertexBuffer(vao); SetupVertexBuffer();
SetupVertexInstances(vao); SetupVertexInstances();
GLintptr index_buffer_offset; GLintptr index_buffer_offset;
if (is_indexed) { if (is_indexed) {
index_buffer_offset = SetupIndexBuffer(); index_buffer_offset = SetupIndexBuffer();

View File

@ -194,11 +194,11 @@ private:
std::size_t CalculateIndexBufferSize() const; std::size_t CalculateIndexBufferSize() const;
/// Updates and returns a vertex array object representing current vertex format /// Updates the current vertex format
GLuint SetupVertexFormat(); void SetupVertexFormat();
void SetupVertexBuffer(GLuint vao); void SetupVertexBuffer();
void SetupVertexInstances(GLuint vao); void SetupVertexInstances();
GLintptr SetupIndexBuffer(); GLintptr SetupIndexBuffer();
@ -217,10 +217,6 @@ private:
ScreenInfo& screen_info; ScreenInfo& screen_info;
std::unique_ptr<GLShader::ProgramManager> shader_program_manager; std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
std::map<std::array<Tegra::Engines::Maxwell3D::Regs::VertexAttribute,
Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes>,
OGLVertexArray>
vertex_array_cache;
static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
OGLBufferCache buffer_cache; OGLBufferCache buffer_cache;

View File

@ -189,24 +189,6 @@ void OGLSync::Release() {
handle = 0; handle = 0;
} }
void OGLVertexArray::Create() {
if (handle != 0)
return;
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glCreateVertexArrays(1, &handle);
}
void OGLVertexArray::Release() {
if (handle == 0)
return;
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteVertexArrays(1, &handle);
OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
handle = 0;
}
void OGLFramebuffer::Create() { void OGLFramebuffer::Create() {
if (handle != 0) if (handle != 0)
return; return;

View File

@ -241,31 +241,6 @@ public:
GLsync handle = 0; GLsync handle = 0;
}; };
class OGLVertexArray : private NonCopyable {
public:
OGLVertexArray() = default;
OGLVertexArray(OGLVertexArray&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLVertexArray() {
Release();
}
OGLVertexArray& operator=(OGLVertexArray&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
}
/// Creates a new internal OpenGL resource and stores the handle
void Create();
/// Deletes the internal OpenGL resource
void Release();
GLuint handle = 0;
};
class OGLFramebuffer : private NonCopyable { class OGLFramebuffer : private NonCopyable {
public: public:
OGLFramebuffer() = default; OGLFramebuffer() = default;

View File

@ -98,12 +98,6 @@ void OpenGLState::ApplyFramebufferState() {
} }
} }
void OpenGLState::ApplyVertexArrayState() {
if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) {
glBindVertexArray(draw.vertex_array);
}
}
void OpenGLState::ApplyShaderProgram() { void OpenGLState::ApplyShaderProgram() {
if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) { if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) {
glUseProgram(draw.shader_program); glUseProgram(draw.shader_program);
@ -338,7 +332,6 @@ void OpenGLState::ApplyImages() {
void OpenGLState::Apply() { void OpenGLState::Apply() {
MICROPROFILE_SCOPE(OpenGL_State); MICROPROFILE_SCOPE(OpenGL_State);
ApplyFramebufferState(); ApplyFramebufferState();
ApplyVertexArrayState();
ApplyShaderProgram(); ApplyShaderProgram();
ApplyProgramPipeline(); ApplyProgramPipeline();
ApplyClipDistances(); ApplyClipDistances();
@ -411,13 +404,6 @@ OpenGLState& OpenGLState::ResetPipeline(GLuint handle) {
return *this; return *this;
} }
OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) {
if (draw.vertex_array == handle) {
draw.vertex_array = 0;
}
return *this;
}
OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) { OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) {
if (draw.read_framebuffer == handle) { if (draw.read_framebuffer == handle) {
draw.read_framebuffer = 0; draw.read_framebuffer = 0;

View File

@ -74,7 +74,6 @@ public:
struct { struct {
GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING
GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING
GLuint vertex_array = 0; // GL_VERTEX_ARRAY_BINDING
GLuint shader_program = 0; // GL_CURRENT_PROGRAM GLuint shader_program = 0; // GL_CURRENT_PROGRAM
GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING
} draw; } draw;
@ -117,7 +116,6 @@ public:
void Apply(); void Apply();
void ApplyFramebufferState(); void ApplyFramebufferState();
void ApplyVertexArrayState();
void ApplyShaderProgram(); void ApplyShaderProgram();
void ApplyProgramPipeline(); void ApplyProgramPipeline();
void ApplyClipDistances(); void ApplyClipDistances();
@ -142,7 +140,6 @@ public:
OpenGLState& ResetSampler(GLuint handle); OpenGLState& ResetSampler(GLuint handle);
OpenGLState& ResetProgram(GLuint handle); OpenGLState& ResetProgram(GLuint handle);
OpenGLState& ResetPipeline(GLuint handle); OpenGLState& ResetPipeline(GLuint handle);
OpenGLState& ResetVertexArray(GLuint handle);
OpenGLState& ResetFramebuffer(GLuint handle); OpenGLState& ResetFramebuffer(GLuint handle);
OpenGLState& ResetRenderbuffer(GLuint handle); OpenGLState& ResetRenderbuffer(GLuint handle);

View File

@ -441,22 +441,8 @@ void RendererOpenGL::InitOpenGLObjects() {
// Generate VBO handle for drawing // Generate VBO handle for drawing
vertex_buffer.Create(); vertex_buffer.Create();
// Generate VAO
vertex_array.Create();
state.draw.vertex_array = vertex_array.handle;
// Attach vertex data to VAO // Attach vertex data to VAO
glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
glVertexArrayAttribFormat(vertex_array.handle, PositionLocation, 2, GL_FLOAT, GL_FALSE,
offsetof(ScreenRectVertex, position));
glVertexArrayAttribFormat(vertex_array.handle, TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
offsetof(ScreenRectVertex, tex_coord));
glVertexArrayAttribBinding(vertex_array.handle, PositionLocation, 0);
glVertexArrayAttribBinding(vertex_array.handle, TexCoordLocation, 0);
glEnableVertexArrayAttrib(vertex_array.handle, PositionLocation);
glEnableVertexArrayAttrib(vertex_array.handle, TexCoordLocation);
glVertexArrayVertexBuffer(vertex_array.handle, 0, vertex_buffer.handle, 0,
sizeof(ScreenRectVertex));
// Allocate textures for the screen // Allocate textures for the screen
screen_info.texture.resource.Create(GL_TEXTURE_2D); screen_info.texture.resource.Create(GL_TEXTURE_2D);
@ -581,6 +567,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CW); glFrontFace(GL_CW);
glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
offsetof(ScreenRectVertex, position));
glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
offsetof(ScreenRectVertex, tex_coord));
glVertexAttribBinding(PositionLocation, 0);
glVertexAttribBinding(TexCoordLocation, 0);
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Restore default state // Restore default state

View File

@ -96,7 +96,6 @@ private:
OpenGLState state; OpenGLState state;
// OpenGL object IDs // OpenGL object IDs
OGLVertexArray vertex_array;
OGLBuffer vertex_buffer; OGLBuffer vertex_buffer;
OGLProgram shader; OGLProgram shader;
OGLFramebuffer screenshot_framebuffer; OGLFramebuffer screenshot_framebuffer;

View File

@ -24,8 +24,7 @@ VertexArrayPushBuffer::VertexArrayPushBuffer() = default;
VertexArrayPushBuffer::~VertexArrayPushBuffer() = default; VertexArrayPushBuffer::~VertexArrayPushBuffer() = default;
void VertexArrayPushBuffer::Setup(GLuint vao_) { void VertexArrayPushBuffer::Setup() {
vao = vao_;
index_buffer = nullptr; index_buffer = nullptr;
vertex_buffers.clear(); vertex_buffers.clear();
} }
@ -41,13 +40,12 @@ void VertexArrayPushBuffer::SetVertexBuffer(GLuint binding_index, const GLuint*
void VertexArrayPushBuffer::Bind() { void VertexArrayPushBuffer::Bind() {
if (index_buffer) { if (index_buffer) {
glVertexArrayElementBuffer(vao, *index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *index_buffer);
} }
// TODO(Rodrigo): Find a way to ARB_multi_bind this // TODO(Rodrigo): Find a way to ARB_multi_bind this
for (const auto& entry : vertex_buffers) { for (const auto& entry : vertex_buffers) {
glVertexArrayVertexBuffer(vao, entry.binding_index, *entry.buffer, entry.offset, glBindVertexBuffer(entry.binding_index, *entry.buffer, entry.offset, entry.stride);
entry.stride);
} }
} }

View File

@ -16,7 +16,7 @@ public:
explicit VertexArrayPushBuffer(); explicit VertexArrayPushBuffer();
~VertexArrayPushBuffer(); ~VertexArrayPushBuffer();
void Setup(GLuint vao_); void Setup();
void SetIndexBuffer(const GLuint* buffer); void SetIndexBuffer(const GLuint* buffer);
@ -28,7 +28,6 @@ public:
private: private:
struct Entry; struct Entry;
GLuint vao{};
const GLuint* index_buffer{}; const GLuint* index_buffer{};
std::vector<Entry> vertex_buffers; std::vector<Entry> vertex_buffers;
}; };