mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-27 01:02:48 +01:00
gl_state: Remove VAO cache and tracking
This commit is contained in:
parent
2a662fea36
commit
d5ab0358b6
10 changed files with 52 additions and 152 deletions
|
@ -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;
|
||||
// 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];
|
||||
|
||||
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.
|
||||
// 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())
|
||||
continue;
|
||||
|
||||
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);
|
||||
} else {
|
||||
glVertexArrayAttribFormat(
|
||||
vao, index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
|
||||
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
|
||||
}
|
||||
glVertexArrayAttribBinding(vao, index, attrib.buffer);
|
||||
// Ignore invalid attributes.
|
||||
if (!attrib.IsValid()) {
|
||||
glDisableVertexAttribArray(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
glEnableVertexAttribArray(index);
|
||||
|
||||
state.draw.vertex_array = vao_entry.handle;
|
||||
return vao_entry.handle;
|
||||
if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt ||
|
||||
attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) {
|
||||
glVertexAttribIFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
|
||||
attrib.offset);
|
||||
} else {
|
||||
glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
|
||||
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
|
||||
}
|
||||
glVertexAttribBinding(index, attrib.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -194,11 +194,11 @@ private:
|
|||
|
||||
std::size_t CalculateIndexBufferSize() const;
|
||||
|
||||
/// Updates and returns a vertex array object representing current vertex format
|
||||
GLuint SetupVertexFormat();
|
||||
/// Updates the current vertex format
|
||||
void SetupVertexFormat();
|
||||
|
||||
void SetupVertexBuffer(GLuint vao);
|
||||
void SetupVertexInstances(GLuint vao);
|
||||
void SetupVertexBuffer();
|
||||
void SetupVertexInstances();
|
||||
|
||||
GLintptr SetupIndexBuffer();
|
||||
|
||||
|
@ -217,10 +217,6 @@ private:
|
|||
ScreenInfo& screen_info;
|
||||
|
||||
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;
|
||||
OGLBufferCache buffer_cache;
|
||||
|
|
|
@ -189,24 +189,6 @@ void OGLSync::Release() {
|
|||
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() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
|
|
@ -241,31 +241,6 @@ public:
|
|||
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 {
|
||||
public:
|
||||
OGLFramebuffer() = default;
|
||||
|
|
|
@ -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() {
|
||||
if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) {
|
||||
glUseProgram(draw.shader_program);
|
||||
|
@ -338,7 +332,6 @@ void OpenGLState::ApplyImages() {
|
|||
void OpenGLState::Apply() {
|
||||
MICROPROFILE_SCOPE(OpenGL_State);
|
||||
ApplyFramebufferState();
|
||||
ApplyVertexArrayState();
|
||||
ApplyShaderProgram();
|
||||
ApplyProgramPipeline();
|
||||
ApplyClipDistances();
|
||||
|
@ -411,13 +404,6 @@ OpenGLState& OpenGLState::ResetPipeline(GLuint handle) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) {
|
||||
if (draw.vertex_array == handle) {
|
||||
draw.vertex_array = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) {
|
||||
if (draw.read_framebuffer == handle) {
|
||||
draw.read_framebuffer = 0;
|
||||
|
|
|
@ -74,7 +74,6 @@ public:
|
|||
struct {
|
||||
GLuint read_framebuffer = 0; // GL_READ_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 program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING
|
||||
} draw;
|
||||
|
@ -117,7 +116,6 @@ public:
|
|||
void Apply();
|
||||
|
||||
void ApplyFramebufferState();
|
||||
void ApplyVertexArrayState();
|
||||
void ApplyShaderProgram();
|
||||
void ApplyProgramPipeline();
|
||||
void ApplyClipDistances();
|
||||
|
@ -142,7 +140,6 @@ public:
|
|||
OpenGLState& ResetSampler(GLuint handle);
|
||||
OpenGLState& ResetProgram(GLuint handle);
|
||||
OpenGLState& ResetPipeline(GLuint handle);
|
||||
OpenGLState& ResetVertexArray(GLuint handle);
|
||||
OpenGLState& ResetFramebuffer(GLuint handle);
|
||||
OpenGLState& ResetRenderbuffer(GLuint handle);
|
||||
|
||||
|
|
|
@ -441,22 +441,8 @@ void RendererOpenGL::InitOpenGLObjects() {
|
|||
// Generate VBO handle for drawing
|
||||
vertex_buffer.Create();
|
||||
|
||||
// Generate VAO
|
||||
vertex_array.Create();
|
||||
state.draw.vertex_array = vertex_array.handle;
|
||||
|
||||
// Attach vertex data to VAO
|
||||
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
|
||||
screen_info.texture.resource.Create(GL_TEXTURE_2D);
|
||||
|
@ -581,6 +567,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
|
|||
glCullFace(GL_BACK);
|
||||
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));
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
// Restore default state
|
||||
|
|
|
@ -96,7 +96,6 @@ private:
|
|||
OpenGLState state;
|
||||
|
||||
// OpenGL object IDs
|
||||
OGLVertexArray vertex_array;
|
||||
OGLBuffer vertex_buffer;
|
||||
OGLProgram shader;
|
||||
OGLFramebuffer screenshot_framebuffer;
|
||||
|
|
|
@ -24,8 +24,7 @@ VertexArrayPushBuffer::VertexArrayPushBuffer() = default;
|
|||
|
||||
VertexArrayPushBuffer::~VertexArrayPushBuffer() = default;
|
||||
|
||||
void VertexArrayPushBuffer::Setup(GLuint vao_) {
|
||||
vao = vao_;
|
||||
void VertexArrayPushBuffer::Setup() {
|
||||
index_buffer = nullptr;
|
||||
vertex_buffers.clear();
|
||||
}
|
||||
|
@ -41,13 +40,12 @@ void VertexArrayPushBuffer::SetVertexBuffer(GLuint binding_index, const GLuint*
|
|||
|
||||
void VertexArrayPushBuffer::Bind() {
|
||||
if (index_buffer) {
|
||||
glVertexArrayElementBuffer(vao, *index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *index_buffer);
|
||||
}
|
||||
|
||||
// TODO(Rodrigo): Find a way to ARB_multi_bind this
|
||||
for (const auto& entry : vertex_buffers) {
|
||||
glVertexArrayVertexBuffer(vao, entry.binding_index, *entry.buffer, entry.offset,
|
||||
entry.stride);
|
||||
glBindVertexBuffer(entry.binding_index, *entry.buffer, entry.offset, entry.stride);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
explicit VertexArrayPushBuffer();
|
||||
~VertexArrayPushBuffer();
|
||||
|
||||
void Setup(GLuint vao_);
|
||||
void Setup();
|
||||
|
||||
void SetIndexBuffer(const GLuint* buffer);
|
||||
|
||||
|
@ -28,7 +28,6 @@ public:
|
|||
private:
|
||||
struct Entry;
|
||||
|
||||
GLuint vao{};
|
||||
const GLuint* index_buffer{};
|
||||
std::vector<Entry> vertex_buffers;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue