GL: Eliminiate most redundant state setting calls at draw time

This commit is contained in:
Connor McLaughlin
2019-10-04 22:10:43 +10:00
parent 8987fa93c2
commit 4fa79f1503
7 changed files with 118 additions and 52 deletions

View File

@ -26,6 +26,7 @@ bool GPU_HW_OpenGL::Initialize(System* system, DMA* dma, InterruptController* in
return false;
m_system->GetHostInterface()->SetDisplayTexture(m_display_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT, 1.0f);
RestoreGraphicsAPIState();
return true;
}
@ -36,6 +37,37 @@ void GPU_HW_OpenGL::Reset()
ClearFramebuffer();
}
void GPU_HW_OpenGL::ResetGraphicsAPIState()
{
GPU_HW::ResetGraphicsAPIState();
glEnable(GL_CULL_FACE);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glLineWidth(1.0f);
glBindVertexArray(0);
}
void GPU_HW_OpenGL::RestoreGraphicsAPIState()
{
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
glLineWidth(static_cast<float>(m_resolution_scale));
UpdateDrawingArea();
m_last_transparency_enable = false;
glDisable(GL_BLEND);
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
glBindVertexArray(m_vao_id);
}
void GPU_HW_OpenGL::RenderStatistics()
{
GPU_HW::RenderStatistics();
@ -156,6 +188,7 @@ void GPU_HW_OpenGL::CreateFramebuffer()
linear_filter ? GL_LINEAR : GL_NEAREST);
glDeleteFramebuffers(1, &old_vram_fbo);
glEnable(GL_SCISSOR_TEST);
old_vram_texture.reset();
}
@ -187,15 +220,16 @@ void GPU_HW_OpenGL::CreateFramebuffer()
glBindFramebuffer(GL_FRAMEBUFFER, m_display_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_display_texture->GetGLId(), 0);
Assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
}
void GPU_HW_OpenGL::ClearFramebuffer()
{
// TODO: get rid of the FBO switches
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_SCISSOR_TEST);
m_vram_read_texture_dirty = true;
}
@ -305,7 +339,7 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blendi
return true;
}
void GPU_HW_OpenGL::SetProgram()
void GPU_HW_OpenGL::SetDrawState()
{
const GL::Program& prog =
m_render_programs[BoolToUInt32(m_batch.texture_enable)][BoolToUInt32(m_batch.texture_blending_enable)]
@ -326,14 +360,30 @@ void GPU_HW_OpenGL::SetProgram()
if (m_batch.texture_enable)
m_vram_read_texture->Bind();
if (m_last_transparency_enable != m_batch.transparency_enable ||
(!m_last_transparency_enable && m_last_transparency_mode != m_batch.transparency_mode))
{
m_last_transparency_enable = m_batch.texture_enable;
m_last_transparency_mode = m_batch.transparency_mode;
if (!m_batch.transparency_enable)
{
glDisable(GL_BLEND);
}
else
{
glEnable(GL_BLEND);
glBlendEquationSeparate(m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground ?
GL_FUNC_REVERSE_SUBTRACT :
GL_FUNC_ADD,
GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
}
}
}
void GPU_HW_OpenGL::SetViewport()
{
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
}
void GPU_HW_OpenGL::SetScissor()
void GPU_HW_OpenGL::UpdateDrawingArea()
{
int left, top, right, bottom;
CalcScissorRect(&left, &top, &right, &bottom);
@ -347,22 +397,6 @@ void GPU_HW_OpenGL::SetScissor()
glScissor(x, y, width, height);
}
void GPU_HW_OpenGL::SetBlendState()
{
if (!m_batch.transparency_enable)
{
glDisable(GL_BLEND);
return;
}
glEnable(GL_BLEND);
glBlendEquationSeparate(m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground ?
GL_FUNC_REVERSE_SUBTRACT :
GL_FUNC_ADD,
GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
}
void GPU_HW_OpenGL::UpdateDisplay()
{
GPU_HW::UpdateDisplay();
@ -415,7 +449,9 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer)
glBlitFramebuffer(scaled_x, texture_height - scaled_y - height, scaled_x + scaled_width, scaled_y + scaled_height,
0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_vram_downsample_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_vram_fbo);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_buffer.data());
glEnable(GL_SCISSOR_TEST);
}
else
{
@ -457,8 +493,6 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u16 color)
width *= m_resolution_scale;
height *= m_resolution_scale;
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
glEnable(GL_SCISSOR_TEST);
glScissor(x, m_vram_texture->GetHeight() - y - height, width, height);
@ -466,6 +500,7 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u16 color)
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT);
UpdateDrawingArea();
InvalidateVRAMReadCache();
}
@ -517,9 +552,9 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
const u32 scaled_flipped_y = m_vram_texture->GetHeight() - scaled_y - scaled_height;
glDisable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_vram_downsample_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_vram_fbo);
glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, scaled_x + scaled_width,
scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST);
}
}
@ -540,6 +575,7 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST);
InvalidateVRAMReadCache();
}
@ -565,21 +601,9 @@ void GPU_HW_OpenGL::FlushRender()
m_stats.num_batches++;
m_stats.num_vertices += static_cast<u32>(m_batch.vertices.size());
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
glLineWidth(static_cast<float>(m_resolution_scale));
SetProgram();
SetViewport();
SetScissor();
SetBlendState();
glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo);
glBindVertexArray(m_vao_id);
SetDrawState();
Assert((m_batch.vertices.size() * sizeof(HWVertex)) <= VERTEX_BUFFER_SIZE);
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast<GLsizei>(sizeof(HWVertex) * m_batch.vertices.size()),
m_batch.vertices.data());