HWRasterizer: Imm state tracker + track active tex

This commit is contained in:
tfarley 2016-04-27 13:43:08 -04:00
parent a6e76c0903
commit d9ef255f64
7 changed files with 447 additions and 294 deletions

View file

@ -37,10 +37,13 @@ static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
}
RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
state.MakeCurrent();
// Create sampler objects
for (size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
state.SetActiveTextureUnit(GL_TEXTURE0 + i);
state.SetSampler(texture_samplers[i].sampler.handle);
}
// Generate VBO, VAO and UBO
@ -48,10 +51,9 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
vertex_array.Create();
uniform_buffer.Create();
state.draw.vertex_array = vertex_array.handle;
state.draw.vertex_buffer = vertex_buffer.handle;
state.draw.uniform_buffer = uniform_buffer.handle;
state.Apply();
state.SetVertexArray(vertex_array.handle);
state.SetVertexBuffer(vertex_buffer.handle);
state.SetUniformBuffer(uniform_buffer.handle);
// Bind the UBO to binding point 0
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
@ -88,12 +90,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
// Allocate and bind lighting lut textures
for (size_t i = 0; i < lighting_luts.size(); ++i) {
lighting_luts[i].Create();
state.lighting_luts[i].texture_1d = lighting_luts[i].handle;
}
state.Apply();
for (size_t i = 0; i < lighting_luts.size(); ++i) {
glActiveTexture(GL_TEXTURE3 + i);
state.SetActiveTextureUnit(GL_TEXTURE3 + i);
state.SetLUTTexture1D(lighting_luts[i].handle);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -151,6 +149,8 @@ void RasterizerOpenGL::DrawTriangles() {
if (vertex_batch.empty())
return;
state.MakeCurrent();
const auto& regs = Pica::g_state.regs;
// Sync and bind the framebuffer surfaces
@ -159,8 +159,7 @@ void RasterizerOpenGL::DrawTriangles() {
MathUtil::Rectangle<int> rect;
std::tie(color_surface, depth_surface, rect) = res_cache.GetFramebufferSurfaces(regs.framebuffer);
state.draw.draw_framebuffer = framebuffer.handle;
state.Apply();
state.SetDrawFramebuffer(framebuffer.handle);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_surface != nullptr ? color_surface->texture.handle : 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
@ -188,14 +187,16 @@ void RasterizerOpenGL::DrawTriangles() {
if (texture.enabled) {
texture_samplers[texture_index].SyncWithConfig(texture.config);
CachedSurface* surface = res_cache.GetTextureSurface(texture);
state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index);
if (surface != nullptr) {
state.texture_units[texture_index].texture_2d = surface->texture.handle;
state.SetTexture2D(surface->texture.handle);
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
state.texture_units[texture_index].texture_2d = 0;
state.SetTexture2D(0);
}
} else {
state.texture_units[texture_index].texture_2d = 0;
state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index);
state.SetTexture2D(0);
}
}
@ -219,8 +220,6 @@ void RasterizerOpenGL::DrawTriangles() {
uniform_block_data.dirty = false;
}
state.Apply();
// Draw the vertex batch
glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
@ -240,14 +239,16 @@ void RasterizerOpenGL::DrawTriangles() {
// Unbind textures for potential future use as framebuffer attachments
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
state.texture_units[texture_index].texture_2d = 0;
state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index);
state.SetTexture2D(0);
}
state.Apply();
}
void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
const auto& regs = Pica::g_state.regs;
state.MakeCurrent();
switch(id) {
// Culling
case PICA_REG_INDEX(cull_mode):
@ -609,20 +610,20 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
return false;
}
OpenGLState cur_state = OpenGLState::GetCurState();
SurfaceType dst_type = CachedSurface::GetFormatType(dst_surface->pixel_format);
GLuint old_fb = cur_state.draw.draw_framebuffer;
cur_state.draw.draw_framebuffer = framebuffer.handle;
// TODO: When scissor test is implemented, need to disable scissor test in cur_state here so Clear call isn't affected
cur_state.Apply();
OpenGLState* old_state = OpenGLState::GetCurrentState();
utility_state.MakeCurrent();
utility_state.SetDrawFramebuffer(framebuffer.handle);
// TODO: When scissor test is implemented, need to disable scissor test in the state here so Clear call isn't affected
if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_surface->texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
old_state->MakeCurrent();
return false;
}
@ -640,6 +641,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
color_values[2] = config.value_24bit_b / 255.0f;
break;
default:
old_state->MakeCurrent();
return false;
}
} else if (config.fill_32bit) {
@ -653,6 +655,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
color_values[3] = (value & 0xFF) / 255.0f;
break;
default:
old_state->MakeCurrent();
return false;
}
} else {
@ -692,15 +695,12 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
color_values[1] = (value_16bit & 0xFF) / 255.0f;
break;
default:
old_state->MakeCurrent();
return false;
}
}
cur_state.color_mask.red_enabled = true;
cur_state.color_mask.green_enabled = true;
cur_state.color_mask.blue_enabled = true;
cur_state.color_mask.alpha_enabled = true;
cur_state.Apply();
utility_state.SetColorMask(true, true, true, true);
glClearBufferfv(GL_COLOR, 0, color_values);
} else if (dst_type == SurfaceType::Depth) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@ -708,6 +708,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
old_state->MakeCurrent();
return false;
}
@ -718,29 +719,26 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
value_float = config.value_32bit / 16777215.0f; // 2^24 - 1
}
cur_state.depth.write_mask = true;
cur_state.Apply();
utility_state.SetDepthWriteMask(true);
glClearBufferfv(GL_DEPTH, 0, &value_float);
} else if (dst_type == SurfaceType::DepthStencil) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0);
if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
old_state->MakeCurrent();
return false;
}
GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
GLint value_int = (config.value_32bit >> 24);
cur_state.depth.write_mask = true;
cur_state.stencil.write_mask = true;
cur_state.Apply();
utility_state.SetDepthWriteMask(true);
utility_state.SetStencilWriteMask(true);
glClearBufferfi(GL_DEPTH_STENCIL, 0, value_float, value_int);
}
cur_state.draw.draw_framebuffer = old_fb;
// TODO: Return scissor test to previous value when scissor test is implemented
cur_state.Apply();
old_state->MakeCurrent();
dst_surface->dirty = true;
res_cache.FlushRegion(dst_surface->addr, dst_surface->size, dst_surface, true);
@ -824,20 +822,20 @@ void RasterizerOpenGL::SetShader() {
PicaShaderConfig config = PicaShaderConfig::CurrentConfig();
std::unique_ptr<PicaShader> shader = std::make_unique<PicaShader>();
state.MakeCurrent();
// Find (or generate) the GLSL shader for the current TEV state
auto cached_shader = shader_cache.find(config);
if (cached_shader != shader_cache.end()) {
current_shader = cached_shader->second.get();
state.draw.shader_program = current_shader->shader.handle;
state.Apply();
state.SetShaderProgram(current_shader->shader.handle);
} else {
LOG_DEBUG(Render_OpenGL, "Creating new shader");
shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str());
state.draw.shader_program = shader->shader.handle;
state.Apply();
state.SetShaderProgram(shader->shader.handle);
// Set the texture samplers to correspond to different texture units
GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]");
@ -889,17 +887,17 @@ void RasterizerOpenGL::SyncCullMode() {
switch (regs.cull_mode) {
case Pica::Regs::CullMode::KeepAll:
state.cull.enabled = false;
state.SetCullEnabled(false);
break;
case Pica::Regs::CullMode::KeepClockWise:
state.cull.enabled = true;
state.cull.front_face = GL_CW;
state.SetCullEnabled(true);
state.SetCullFrontFace(GL_CW);
break;
case Pica::Regs::CullMode::KeepCounterClockWise:
state.cull.enabled = true;
state.cull.front_face = GL_CCW;
state.SetCullEnabled(true);
state.SetCullFrontFace(GL_CCW);
break;
default:
@ -919,23 +917,23 @@ void RasterizerOpenGL::SyncDepthModifiers() {
}
void RasterizerOpenGL::SyncBlendEnabled() {
state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1);
state.SetBlendEnabled(Pica::g_state.regs.output_merger.alphablend_enable == 1);
}
void RasterizerOpenGL::SyncBlendFuncs() {
const auto& regs = Pica::g_state.regs;
state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
state.SetBlendFunc(PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb),
PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb),
PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a),
PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a));
}
void RasterizerOpenGL::SyncBlendColor() {
auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw);
state.blend.color.red = blend_color[0];
state.blend.color.green = blend_color[1];
state.blend.color.blue = blend_color[2];
state.blend.color.alpha = blend_color[3];
state.SetBlendColor(blend_color[0],
blend_color[1],
blend_color[2],
blend_color[3]);
}
void RasterizerOpenGL::SyncAlphaTest() {
@ -947,7 +945,7 @@ void RasterizerOpenGL::SyncAlphaTest() {
}
void RasterizerOpenGL::SyncLogicOp() {
state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
state.SetLogicOp(PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op));
}
void RasterizerOpenGL::SyncColorWriteMask() {
@ -957,43 +955,43 @@ void RasterizerOpenGL::SyncColorWriteMask() {
return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE;
};
state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable);
state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable);
state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable);
state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable);
state.SetColorMask(IsColorWriteEnabled(regs.output_merger.red_enable),
IsColorWriteEnabled(regs.output_merger.green_enable),
IsColorWriteEnabled(regs.output_merger.blue_enable),
IsColorWriteEnabled(regs.output_merger.alpha_enable));
}
void RasterizerOpenGL::SyncStencilWriteMask() {
const auto& regs = Pica::g_state.regs;
state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0)
state.SetStencilWriteMask((regs.framebuffer.allow_depth_stencil_write != 0)
? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
: 0;
: 0);
}
void RasterizerOpenGL::SyncDepthWriteMask() {
const auto& regs = Pica::g_state.regs;
state.depth.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
state.SetDepthWriteMask((regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
? GL_TRUE
: GL_FALSE;
: GL_FALSE);
}
void RasterizerOpenGL::SyncStencilTest() {
const auto& regs = Pica::g_state.regs;
state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail);
state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail);
state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass);
state.SetStencilTestEnabled(regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8);
state.SetStencilFunc(PicaToGL::CompareFunc(regs.output_merger.stencil_test.func),
regs.output_merger.stencil_test.reference_value,
regs.output_merger.stencil_test.input_mask);
state.SetStencilOp(PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail),
PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail),
PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass));
}
void RasterizerOpenGL::SyncDepthTest() {
const auto& regs = Pica::g_state.regs;
state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 ||
regs.output_merger.depth_write_enable == 1;
state.depth.test_func = regs.output_merger.depth_test_enable == 1 ?
PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS;
state.SetDepthTestEnabled(regs.output_merger.depth_test_enable == 1 ||
regs.output_merger.depth_write_enable == 1);
state.SetDepthFunc(regs.output_merger.depth_test_enable == 1 ?
PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS);
}
void RasterizerOpenGL::SyncCombinerColor() {
@ -1032,7 +1030,7 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
if (new_data != lighting_lut_data[lut_index]) {
lighting_lut_data[lut_index] = new_data;
glActiveTexture(GL_TEXTURE3 + lut_index);
state.SetActiveTextureUnit(GL_TEXTURE3 + lut_index);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data());
}
}

View file

@ -351,6 +351,7 @@ private:
void SyncLightPosition(int light_index);
OpenGLState state;
OpenGLState utility_state;
RasterizerCacheOpenGL res_cache;

View file

@ -105,17 +105,15 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) {
using SurfaceType = CachedSurface::SurfaceType;
OpenGLState cur_state = OpenGLState::GetCurState();
OpenGLState* old_state = OpenGLState::GetCurrentState();
utility_state.MakeCurrent();
// Make sure textures aren't bound to texture units, since going to bind them to framebuffer components
OpenGLState::ResetTexture(src_tex);
OpenGLState::ResetTexture(dst_tex);
// Keep track of previous framebuffer bindings
GLuint old_fbs[2] = { cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer };
cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle;
cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle;
cur_state.Apply();
utility_state.SetReadFramebuffer(transfer_framebuffers[0].handle);
utility_state.SetDrawFramebuffer(transfer_framebuffers[1].handle);
u32 buffers = 0;
@ -148,10 +146,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
}
if (OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
old_state->MakeCurrent();
return false;
}
if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
old_state->MakeCurrent();
return false;
}
@ -159,10 +159,7 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom,
buffers, buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
// Restore previous framebuffer bindings
cur_state.draw.read_framebuffer = old_fbs[0];
cur_state.draw.draw_framebuffer = old_fbs[1];
cur_state.Apply();
old_state->MakeCurrent();
return true;
}
@ -177,17 +174,15 @@ bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, const Ma
return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect);
}
static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) {
void RasterizerCacheOpenGL::AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) {
// Allocate an uninitialized texture of appropriate size and format for the surface
using SurfaceType = CachedSurface::SurfaceType;
OpenGLState cur_state = OpenGLState::GetCurState();
OpenGLState* old_state = OpenGLState::GetCurrentState();
utility_state.MakeCurrent();
// Keep track of previous texture bindings
GLuint old_tex = cur_state.texture_units[0].texture_2d;
cur_state.texture_units[0].texture_2d = texture;
cur_state.Apply();
glActiveTexture(GL_TEXTURE0);
utility_state.SetActiveTextureUnit(GL_TEXTURE0);
utility_state.SetTexture2D(texture);
SurfaceType type = CachedSurface::GetFormatType(pixel_format);
@ -211,9 +206,7 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Restore previous texture bindings
cur_state.texture_units[0].texture_2d = old_tex;
cur_state.Apply();
old_state->MakeCurrent();
}
MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192));
@ -295,12 +288,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
Memory::RasterizerFlushRegion(params.addr, params_size);
// Load data from memory to the new surface
OpenGLState cur_state = OpenGLState::GetCurState();
OpenGLState* old_state = OpenGLState::GetCurrentState();
utility_state.MakeCurrent();
GLuint old_tex = cur_state.texture_units[0].texture_2d;
cur_state.texture_units[0].texture_2d = new_surface->texture.handle;
cur_state.Apply();
glActiveTexture(GL_TEXTURE0);
utility_state.SetActiveTextureUnit(GL_TEXTURE0);
utility_state.SetTexture2D(new_surface->texture.handle);
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride);
if (!new_surface->is_tiled) {
@ -375,8 +367,6 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
new_surface->texture.Release();
new_surface->texture.handle = scaled_texture.handle;
scaled_texture.handle = 0;
cur_state.texture_units[0].texture_2d = new_surface->texture.handle;
cur_state.Apply();
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
@ -384,8 +374,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
cur_state.texture_units[0].texture_2d = old_tex;
cur_state.Apply();
old_state->MakeCurrent();
}
Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1);
@ -607,8 +596,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
return;
}
OpenGLState cur_state = OpenGLState::GetCurState();
GLuint old_tex = cur_state.texture_units[0].texture_2d;
OpenGLState* old_state = OpenGLState::GetCurrentState();
utility_state.MakeCurrent();
OGLTexture unscaled_tex;
GLuint texture_to_flush = surface->texture.handle;
@ -625,9 +614,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
texture_to_flush = unscaled_tex.handle;
}
cur_state.texture_units[0].texture_2d = texture_to_flush;
cur_state.Apply();
glActiveTexture(GL_TEXTURE0);
utility_state.SetActiveTextureUnit(GL_TEXTURE0);
utility_state.SetTexture2D(texture_to_flush);
glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride);
if (!surface->is_tiled) {
@ -676,8 +664,7 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
surface->dirty = false;
cur_state.texture_units[0].texture_2d = old_tex;
cur_state.Apply();
old_state->MakeCurrent();
}
void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate) {

View file

@ -217,6 +217,10 @@ public:
void FlushAll();
private:
void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height);
OpenGLState utility_state;
SurfaceCache surface_cache;
OGLFramebuffer transfer_framebuffers[2];
};

View file

@ -9,7 +9,8 @@
#include "video_core/renderer_opengl/gl_state.h"
OpenGLState OpenGLState::cur_state;
static OpenGLState default_state;
OpenGLState* OpenGLState::cur_state = &default_state;
OpenGLState::OpenGLState() {
// These all match default OpenGL values
@ -56,6 +57,8 @@ OpenGLState::OpenGLState() {
lut.texture_1d = 0;
}
active_texture_unit = GL_TEXTURE0;
draw.read_framebuffer = 0;
draw.draw_framebuffer = 0;
draw.vertex_array = 0;
@ -64,159 +67,290 @@ OpenGLState::OpenGLState() {
draw.shader_program = 0;
}
void OpenGLState::Apply() const {
// Culling
if (cull.enabled != cur_state.cull.enabled) {
if (cull.enabled) {
OpenGLState* OpenGLState::GetCurrentState() {
return cur_state;
}
void OpenGLState::SetCullEnabled(bool n_enabled) {
if (n_enabled != cur_state->cull.enabled) {
if (n_enabled) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
}
if (cull.mode != cur_state.cull.mode) {
glCullFace(cull.mode);
cull.enabled = n_enabled;
}
if (cull.front_face != cur_state.cull.front_face) {
glFrontFace(cull.front_face);
void OpenGLState::SetCullMode(GLenum n_mode) {
if (n_mode != cur_state->cull.mode) {
glCullFace(n_mode);
}
cull.mode = n_mode;
}
// Depth test
if (depth.test_enabled != cur_state.depth.test_enabled) {
if (depth.test_enabled) {
void OpenGLState::SetCullFrontFace(GLenum n_front_face) {
if (n_front_face != cur_state->cull.front_face) {
glFrontFace(n_front_face);
}
cull.front_face = n_front_face;
}
void OpenGLState::SetDepthTestEnabled(bool n_test_enabled) {
if (n_test_enabled != cur_state->depth.test_enabled) {
if (n_test_enabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
if (depth.test_func != cur_state.depth.test_func) {
glDepthFunc(depth.test_func);
depth.test_enabled = n_test_enabled;
}
// Depth mask
if (depth.write_mask != cur_state.depth.write_mask) {
glDepthMask(depth.write_mask);
void OpenGLState::SetDepthFunc(GLenum n_test_func) {
if (n_test_func != cur_state->depth.test_func) {
glDepthFunc(n_test_func);
}
depth.test_func = n_test_func;
}
// Color mask
if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
color_mask.green_enabled != cur_state.color_mask.green_enabled ||
color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
glColorMask(color_mask.red_enabled, color_mask.green_enabled,
color_mask.blue_enabled, color_mask.alpha_enabled);
void OpenGLState::SetDepthWriteMask(GLboolean n_write_mask) {
if (n_write_mask != cur_state->depth.write_mask) {
glDepthMask(n_write_mask);
}
depth.write_mask = n_write_mask;
}
// Stencil test
if (stencil.test_enabled != cur_state.stencil.test_enabled) {
if (stencil.test_enabled) {
void OpenGLState::SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_enabled) {
if (n_red_enabled != cur_state->color_mask.red_enabled ||
n_green_enabled != cur_state->color_mask.green_enabled ||
n_blue_enabled != cur_state->color_mask.blue_enabled ||
n_alpha_enabled != cur_state->color_mask.alpha_enabled) {
glColorMask(n_red_enabled, n_green_enabled,
n_blue_enabled, n_alpha_enabled);
}
color_mask.red_enabled = n_red_enabled;
color_mask.green_enabled = n_green_enabled;
color_mask.blue_enabled = n_blue_enabled;
color_mask.alpha_enabled = n_alpha_enabled;
}
void OpenGLState::SetStencilTestEnabled(bool n_test_enabled) {
if (n_test_enabled != cur_state->stencil.test_enabled) {
if (n_test_enabled) {
glEnable(GL_STENCIL_TEST);
} else {
glDisable(GL_STENCIL_TEST);
}
}
if (stencil.test_func != cur_state.stencil.test_func ||
stencil.test_ref != cur_state.stencil.test_ref ||
stencil.test_mask != cur_state.stencil.test_mask) {
glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
stencil.test_enabled = n_test_enabled;
}
if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail ||
stencil.action_depth_pass != cur_state.stencil.action_depth_pass ||
stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) {
glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass);
void OpenGLState::SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_test_mask) {
if (n_test_func != cur_state->stencil.test_func ||
n_test_ref != cur_state->stencil.test_ref ||
n_test_mask != cur_state->stencil.test_mask) {
glStencilFunc(n_test_func, n_test_ref, n_test_mask);
}
stencil.test_func = n_test_func;
stencil.test_ref = n_test_ref;
stencil.test_mask = n_test_mask;
}
// Stencil mask
if (stencil.write_mask != cur_state.stencil.write_mask) {
glStencilMask(stencil.write_mask);
void OpenGLState::SetStencilOp(GLenum n_action_stencil_fail, GLenum n_action_depth_fail, GLenum n_action_depth_pass) {
if (n_action_stencil_fail != cur_state->stencil.action_depth_fail ||
n_action_depth_fail != cur_state->stencil.action_depth_pass ||
n_action_depth_pass != cur_state->stencil.action_stencil_fail) {
glStencilOp(n_action_stencil_fail, n_action_depth_fail, n_action_depth_pass);
}
stencil.action_depth_fail = n_action_stencil_fail;
stencil.action_depth_pass = n_action_depth_fail;
stencil.action_stencil_fail = n_action_depth_pass;
}
// Blending
if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) {
void OpenGLState::SetStencilWriteMask(GLuint n_write_mask) {
if (n_write_mask != cur_state->stencil.write_mask) {
glStencilMask(n_write_mask);
}
stencil.write_mask = n_write_mask;
}
void OpenGLState::SetBlendEnabled(bool n_enabled) {
if (n_enabled != cur_state->blend.enabled) {
if (n_enabled) {
glEnable(GL_BLEND);
cur_state.logic_op = GL_COPY;
glLogicOp(cur_state.logic_op);
SetLogicOp(GL_COPY);
glDisable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_BLEND);
glEnable(GL_COLOR_LOGIC_OP);
}
}
if (blend.color.red != cur_state.blend.color.red ||
blend.color.green != cur_state.blend.color.green ||
blend.color.blue != cur_state.blend.color.blue ||
blend.color.alpha != cur_state.blend.color.alpha) {
glBlendColor(blend.color.red, blend.color.green,
blend.color.blue, blend.color.alpha);
blend.enabled = n_enabled;
}
if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
blend.src_a_func != cur_state.blend.src_a_func ||
blend.dst_a_func != cur_state.blend.dst_a_func) {
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func,
blend.src_a_func, blend.dst_a_func);
void OpenGLState::SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLenum n_src_a_func, GLenum n_dst_a_func) {
if (n_src_rgb_func != cur_state->blend.src_rgb_func ||
n_dst_rgb_func != cur_state->blend.dst_rgb_func ||
n_src_a_func != cur_state->blend.src_a_func ||
n_dst_a_func != cur_state->blend.dst_a_func) {
glBlendFuncSeparate(n_src_rgb_func, n_dst_rgb_func,
n_src_a_func, n_dst_a_func);
}
blend.src_rgb_func = n_src_rgb_func;
blend.dst_rgb_func = n_dst_rgb_func;
blend.src_a_func = n_src_a_func;
blend.dst_a_func = n_dst_a_func;
}
if (logic_op != cur_state.logic_op) {
glLogicOp(logic_op);
void OpenGLState::SetBlendColor(GLclampf n_red, GLclampf n_green, GLclampf n_blue, GLclampf n_alpha) {
if (n_red != cur_state->blend.color.red ||
n_green != cur_state->blend.color.green ||
n_blue != cur_state->blend.color.blue ||
n_alpha != cur_state->blend.color.alpha) {
glBlendColor(n_red, n_green,
n_blue, n_alpha);
}
blend.color.red = n_red;
blend.color.green = n_green;
blend.color.blue = n_blue;
blend.color.alpha = n_alpha;
}
// Textures
void OpenGLState::SetLogicOp(GLenum n_logic_op) {
if (n_logic_op != cur_state->logic_op) {
glLogicOp(n_logic_op);
}
logic_op = n_logic_op;
}
void OpenGLState::SetTexture2D(GLuint n_texture_2d) {
unsigned unit_index = active_texture_unit - GL_TEXTURE0;
ASSERT(unit_index < ARRAY_SIZE(texture_units));
if (n_texture_2d != cur_state->texture_units[unit_index].texture_2d) {
glBindTexture(GL_TEXTURE_2D, n_texture_2d);
}
texture_units[unit_index].texture_2d = n_texture_2d;
}
void OpenGLState::SetSampler(GLuint n_sampler) {
unsigned unit_index = active_texture_unit - GL_TEXTURE0;
ASSERT(unit_index < ARRAY_SIZE(texture_units));
if (n_sampler != cur_state->texture_units[unit_index].sampler) {
glBindSampler(unit_index, n_sampler);
}
texture_units[unit_index].sampler = n_sampler;
}
void OpenGLState::SetLUTTexture1D(GLuint n_texture_1d) {
unsigned unit_index = active_texture_unit - GL_TEXTURE3;
ASSERT(unit_index < ARRAY_SIZE(lighting_luts));
if (n_texture_1d != cur_state->lighting_luts[unit_index].texture_1d) {
glBindTexture(GL_TEXTURE_1D, n_texture_1d);
}
lighting_luts[unit_index].texture_1d = n_texture_1d;
}
void OpenGLState::SetActiveTextureUnit(GLenum n_active_texture_unit) {
if (n_active_texture_unit != cur_state->active_texture_unit) {
glActiveTexture(n_active_texture_unit);
}
active_texture_unit = n_active_texture_unit;
}
void OpenGLState::SetReadFramebuffer(GLuint n_read_framebuffer) {
if (n_read_framebuffer != cur_state->draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, n_read_framebuffer);
}
draw.read_framebuffer = n_read_framebuffer;
}
void OpenGLState::SetDrawFramebuffer(GLuint n_draw_framebuffer) {
if (n_draw_framebuffer != cur_state->draw.draw_framebuffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, n_draw_framebuffer);
}
draw.draw_framebuffer = n_draw_framebuffer;
}
void OpenGLState::SetVertexArray(GLuint n_vertex_array) {
if (n_vertex_array != cur_state->draw.vertex_array) {
glBindVertexArray(n_vertex_array);
}
draw.vertex_array = n_vertex_array;
}
void OpenGLState::SetVertexBuffer(GLuint n_vertex_buffer) {
if (n_vertex_buffer != cur_state->draw.vertex_buffer) {
glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer);
}
draw.vertex_buffer = n_vertex_buffer;
}
void OpenGLState::SetUniformBuffer(GLuint n_uniform_buffer) {
if (n_uniform_buffer != cur_state->draw.uniform_buffer) {
glBindBuffer(GL_UNIFORM_BUFFER, n_uniform_buffer);
}
draw.uniform_buffer = n_uniform_buffer;
}
void OpenGLState::SetShaderProgram(GLuint n_shader_program) {
if (n_shader_program != cur_state->draw.shader_program) {
glUseProgram(n_shader_program);
}
draw.shader_program = n_shader_program;
}
void OpenGLState::MakeCurrent() {
if (cur_state == this) {
return;
}
SetCullEnabled(cull.enabled);
SetCullMode(cull.mode);
SetCullFrontFace(cull.front_face);
SetDepthTestEnabled(depth.test_enabled);
SetDepthFunc(depth.test_func);
SetDepthWriteMask(depth.write_mask);
SetColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, color_mask.alpha_enabled);
SetStencilTestEnabled(stencil.test_enabled);
SetStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
SetStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass);
SetStencilWriteMask(stencil.write_mask);
SetBlendEnabled(blend.enabled);
SetBlendFunc(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func);
SetBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
SetLogicOp(logic_op);
for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
}
if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
glBindSampler(i, texture_units[i].sampler);
}
SetActiveTextureUnit(GL_TEXTURE0 + i);
SetTexture2D(texture_units[i].texture_2d);
SetSampler(texture_units[i].sampler);
}
// Lighting LUTs
for (unsigned i = 0; i < ARRAY_SIZE(lighting_luts); ++i) {
if (lighting_luts[i].texture_1d != cur_state.lighting_luts[i].texture_1d) {
glActiveTexture(GL_TEXTURE3 + i);
glBindTexture(GL_TEXTURE_1D, lighting_luts[i].texture_1d);
}
SetActiveTextureUnit(GL_TEXTURE3 + i);
SetLUTTexture1D(lighting_luts[i].texture_1d);
}
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
}
if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
}
SetActiveTextureUnit(active_texture_unit);
// Vertex array
if (draw.vertex_array != cur_state.draw.vertex_array) {
glBindVertexArray(draw.vertex_array);
}
SetReadFramebuffer(draw.read_framebuffer);
SetDrawFramebuffer(draw.draw_framebuffer);
SetVertexArray(draw.vertex_array);
SetVertexBuffer(draw.vertex_buffer);
SetUniformBuffer(draw.uniform_buffer);
SetShaderProgram(draw.shader_program);
// Vertex buffer
if (draw.vertex_buffer != cur_state.draw.vertex_buffer) {
glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
}
// Uniform buffer
if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
}
// Shader program
if (draw.shader_program != cur_state.draw.shader_program) {
glUseProgram(draw.shader_program);
}
cur_state = *this;
cur_state = this;
}
GLenum OpenGLState::CheckFBStatus(GLenum target) {
@ -230,47 +364,55 @@ GLenum OpenGLState::CheckFBStatus(GLenum target) {
}
void OpenGLState::ResetTexture(GLuint handle) {
for (auto& unit : cur_state.texture_units) {
if (unit.texture_2d == handle) {
unit.texture_2d = 0;
for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
if (cur_state->texture_units[i].texture_2d == handle) {
cur_state->SetActiveTextureUnit(GL_TEXTURE0 + i);
cur_state->SetTexture2D(0);
}
}
for (unsigned i = 0; i < ARRAY_SIZE(lighting_luts); ++i) {
if (cur_state->lighting_luts[i].texture_1d == handle) {
cur_state->SetActiveTextureUnit(GL_TEXTURE3 + i);
cur_state->SetLUTTexture1D(0);
}
}
}
void OpenGLState::ResetSampler(GLuint handle) {
for (auto& unit : cur_state.texture_units) {
if (unit.sampler == handle) {
unit.sampler = 0;
for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
if (cur_state->texture_units[i].texture_2d == handle) {
cur_state->SetActiveTextureUnit(GL_TEXTURE0 + i);
cur_state->SetSampler(0);
}
}
}
void OpenGLState::ResetProgram(GLuint handle) {
if (cur_state.draw.shader_program == handle) {
cur_state.draw.shader_program = 0;
if (cur_state->draw.shader_program == handle) {
cur_state->SetShaderProgram(0);
}
}
void OpenGLState::ResetBuffer(GLuint handle) {
if (cur_state.draw.vertex_buffer == handle) {
cur_state.draw.vertex_buffer = 0;
if (cur_state->draw.vertex_buffer == handle) {
cur_state->SetVertexBuffer(0);
}
if (cur_state.draw.uniform_buffer == handle) {
cur_state.draw.uniform_buffer = 0;
if (cur_state->draw.uniform_buffer == handle) {
cur_state->SetUniformBuffer(0);
}
}
void OpenGLState::ResetVertexArray(GLuint handle) {
if (cur_state.draw.vertex_array == handle) {
cur_state.draw.vertex_array = 0;
if (cur_state->draw.vertex_array == handle) {
cur_state->SetVertexArray(0);
}
}
void OpenGLState::ResetFramebuffer(GLuint handle) {
if (cur_state.draw.read_framebuffer == handle) {
cur_state.draw.read_framebuffer = 0;
if (cur_state->draw.read_framebuffer == handle) {
cur_state->SetReadFramebuffer(0);
}
if (cur_state.draw.draw_framebuffer == handle) {
cur_state.draw.draw_framebuffer = 0;
if (cur_state->draw.draw_framebuffer == handle) {
cur_state->SetDrawFramebuffer(0);
}
}

View file

@ -8,6 +8,60 @@
class OpenGLState {
public:
OpenGLState();
static OpenGLState* GetCurrentState();
/// Apply this state as the current OpenGL state
void MakeCurrent();
/// Check the status of the current OpenGL read or draw framebuffer configuration
static GLenum CheckFBStatus(GLenum target);
/// Resets and unbinds any references to the given resource in the current OpenGL state
static void ResetTexture(GLuint handle);
static void ResetSampler(GLuint handle);
static void ResetProgram(GLuint handle);
static void ResetBuffer(GLuint handle);
static void ResetVertexArray(GLuint handle);
static void ResetFramebuffer(GLuint handle);
void SetCullEnabled(bool n_enabled);
void SetCullMode(GLenum n_mode);
void SetCullFrontFace(GLenum n_front_face);
void SetDepthTestEnabled(bool n_test_enabled);
void SetDepthFunc(GLenum n_test_func);
void SetDepthWriteMask(GLboolean n_write_mask);
void SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_enabled);
void SetStencilTestEnabled(bool n_test_enabled);
void SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_test_mask);
void SetStencilOp(GLenum n_action_stencil_fail, GLenum n_action_depth_fail, GLenum n_action_depth_pass);
void SetStencilWriteMask(GLuint n_write_mask);
void SetBlendEnabled(bool n_enabled);
void SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLenum n_src_a_func, GLenum n_dst_a_func);
void SetBlendColor(GLclampf n_red, GLclampf n_green, GLclampf n_blue, GLclampf n_alpha);
void SetLogicOp(GLenum n_logic_op);
void SetTexture2D(GLuint n_texture_2d);
void SetSampler(GLuint n_sampler);
void SetLUTTexture1D(GLuint n_texture_1d);
void SetActiveTextureUnit(GLenum n_active_texture_unit);
void SetReadFramebuffer(GLuint n_read_framebuffer);
void SetDrawFramebuffer(GLuint n_draw_framebuffer);
void SetVertexArray(GLuint n_vertex_array);
void SetVertexBuffer(GLuint n_vertex_buffer);
void SetUniformBuffer(GLuint n_uniform_buffer);
void SetShaderProgram(GLuint n_shader_program);
private:
struct {
bool enabled; // GL_CULL_FACE
GLenum mode; // GL_CULL_FACE_MODE
@ -32,10 +86,10 @@ public:
GLenum test_func; // GL_STENCIL_FUNC
GLint test_ref; // GL_STENCIL_REF
GLuint test_mask; // GL_STENCIL_VALUE_MASK
GLuint write_mask; // GL_STENCIL_WRITEMASK
GLenum action_stencil_fail; // GL_STENCIL_FAIL
GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL
GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS
GLuint write_mask; // GL_STENCIL_WRITEMASK
} stencil;
struct {
@ -65,6 +119,8 @@ public:
GLuint texture_1d; // GL_TEXTURE_BINDING_1D
} lighting_luts[6];
GLenum active_texture_unit; // GL_ACTIVE_TEXTURE
struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
@ -74,27 +130,5 @@ public:
GLuint shader_program; // GL_CURRENT_PROGRAM
} draw;
OpenGLState();
/// Get the currently active OpenGL state
static const OpenGLState& GetCurState() {
return cur_state;
}
/// Apply this state as the current OpenGL state
void Apply() const;
/// Check the status of the current OpenGL read or draw framebuffer configuration
static GLenum CheckFBStatus(GLenum target);
/// Resets and unbinds any references to the given resource in the current OpenGL state
static void ResetTexture(GLuint handle);
static void ResetSampler(GLuint handle);
static void ResetProgram(GLuint handle);
static void ResetBuffer(GLuint handle);
static void ResetVertexArray(GLuint handle);
static void ResetFramebuffer(GLuint handle);
private:
static OpenGLState cur_state;
static OpenGLState* cur_state;
};

View file

@ -108,9 +108,7 @@ RendererOpenGL::~RendererOpenGL() {
/// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers() {
// Maintain the rasterizer's state as a priority
OpenGLState prev_state = OpenGLState::GetCurState();
state.Apply();
state.MakeCurrent();
for (int i : {0, 1}) {
const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
@ -157,8 +155,6 @@ void RendererOpenGL::SwapBuffers() {
render_window->PollEvents();
render_window->SwapBuffers();
prev_state.Apply();
profiler.BeginFrame();
RefreshRasterizerSetting();
@ -201,10 +197,9 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr);
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
state.Apply();
state.SetActiveTextureUnit(GL_TEXTURE0);
state.SetTexture2D(screen_info.texture.resource.handle);
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
// Update existing texture
@ -217,8 +212,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
state.texture_units[0].texture_2d = 0;
state.Apply();
state.SetTexture2D(0);
}
}
@ -229,29 +223,28 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
*/
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b,
const TextureInfo& texture) {
state.texture_units[0].texture_2d = texture.resource.handle;
state.Apply();
state.SetActiveTextureUnit(GL_TEXTURE0);
state.SetTexture2D(texture.resource.handle);
glActiveTexture(GL_TEXTURE0);
u8 framebuffer_data[3] = { color_r, color_g, color_b };
// Update existing texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data);
state.texture_units[0].texture_2d = 0;
state.Apply();
state.SetTexture2D(0);
}
/**
* Initializes the OpenGL state and creates persistent objects.
*/
void RendererOpenGL::InitOpenGLObjects() {
state.MakeCurrent();
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);
// Link shaders and get variable locations
shader.Create(vertex_shader, fragment_shader);
state.draw.shader_program = shader.handle;
state.Apply();
state.SetShaderProgram(shader.handle);
uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture");
attrib_position = glGetAttribLocation(shader.handle, "vert_position");
@ -263,10 +256,9 @@ void RendererOpenGL::InitOpenGLObjects() {
// Generate VAO
vertex_array.Create();
state.draw.vertex_array = vertex_array.handle;
state.draw.vertex_buffer = vertex_buffer.handle;
state.draw.uniform_buffer = 0;
state.Apply();
state.SetVertexArray(vertex_array.handle);
state.SetVertexBuffer(vertex_buffer.handle);
state.SetUniformBuffer(0);
// Attach vertex data to VAO
glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
@ -282,21 +274,19 @@ void RendererOpenGL::InitOpenGLObjects() {
// Allocation of storage is deferred until the first frame, when we
// know the framebuffer size.
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
state.Apply();
state.SetActiveTextureUnit(GL_TEXTURE0);
state.SetTexture2D(screen_info.texture.resource.handle);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
state.SetTexture2D(0);
screen_info.display_texture = screen_info.texture.resource.handle;
}
state.texture_units[0].texture_2d = 0;
state.Apply();
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
@ -347,15 +337,13 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
UNIMPLEMENTED();
}
state.texture_units[0].texture_2d = texture.resource.handle;
state.Apply();
state.SetActiveTextureUnit(GL_TEXTURE0);
state.SetTexture2D(texture.resource.handle);
glActiveTexture(GL_TEXTURE0);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
texture.gl_format, texture.gl_type, nullptr);
state.texture_units[0].texture_2d = 0;
state.Apply();
state.SetTexture2D(0);
}
/**
@ -371,14 +359,13 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
ScreenRectVertex(x+w, y+h, texcoords.top, texcoords.right),
}};
state.texture_units[0].texture_2d = screen_info.display_texture;
state.Apply();
state.SetActiveTextureUnit(GL_TEXTURE0);
state.SetTexture2D(screen_info.display_texture);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
state.texture_units[0].texture_2d = 0;
state.Apply();
state.SetTexture2D(0);
}
/**
@ -396,7 +383,7 @@ void RendererOpenGL::DrawScreens() {
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
// Bind texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
state.SetActiveTextureUnit(GL_TEXTURE0);
glUniform1i(uniform_color_texture, 0);
DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, (float)layout.top_screen.top,