mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 07:30:15 +00:00
HWRasterizer: Imm state tracker + track active tex
This commit is contained in:
parent
a6e76c0903
commit
d9ef255f64
@ -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)
|
||||
? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
|
||||
: 0;
|
||||
state.SetStencilWriteMask((regs.framebuffer.allow_depth_stencil_write != 0)
|
||||
? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
|
||||
: 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)
|
||||
? GL_TRUE
|
||||
: GL_FALSE;
|
||||
state.SetDepthWriteMask((regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
|
||||
? GL_TRUE
|
||||
: 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());
|
||||
}
|
||||
}
|
||||
|
@ -351,6 +351,7 @@ private:
|
||||
void SyncLightPosition(int light_index);
|
||||
|
||||
OpenGLState state;
|
||||
OpenGLState utility_state;
|
||||
|
||||
RasterizerCacheOpenGL res_cache;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
cull.enabled = n_enabled;
|
||||
}
|
||||
|
||||
if (cull.mode != cur_state.cull.mode) {
|
||||
glCullFace(cull.mode);
|
||||
void OpenGLState::SetCullMode(GLenum n_mode) {
|
||||
if (n_mode != cur_state->cull.mode) {
|
||||
glCullFace(n_mode);
|
||||
}
|
||||
cull.mode = n_mode;
|
||||
}
|
||||
|
||||
if (cull.front_face != cur_state.cull.front_face) {
|
||||
glFrontFace(cull.front_face);
|
||||
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;
|
||||
}
|
||||
|
||||
// Depth test
|
||||
if (depth.test_enabled != cur_state.depth.test_enabled) {
|
||||
if (depth.test_enabled) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
depth.test_enabled = n_test_enabled;
|
||||
}
|
||||
|
||||
if (depth.test_func != cur_state.depth.test_func) {
|
||||
glDepthFunc(depth.test_func);
|
||||
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;
|
||||
}
|
||||
|
||||
// Depth mask
|
||||
if (depth.write_mask != cur_state.depth.write_mask) {
|
||||
glDepthMask(depth.write_mask);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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::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;
|
||||
}
|
||||
|
||||
// Stencil test
|
||||
if (stencil.test_enabled != cur_state.stencil.test_enabled) {
|
||||
if (stencil.test_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);
|
||||
}
|
||||
}
|
||||
stencil.test_enabled = n_test_enabled;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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::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;
|
||||
}
|
||||
|
||||
// Stencil mask
|
||||
if (stencil.write_mask != cur_state.stencil.write_mask) {
|
||||
glStencilMask(stencil.write_mask);
|
||||
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;
|
||||
}
|
||||
|
||||
// Blending
|
||||
if (blend.enabled != cur_state.blend.enabled) {
|
||||
if (blend.enabled) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
blend.enabled = n_enabled;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
SetCullEnabled(cull.enabled);
|
||||
SetCullMode(cull.mode);
|
||||
SetCullFrontFace(cull.front_face);
|
||||
|
||||
if (logic_op != cur_state.logic_op) {
|
||||
glLogicOp(logic_op);
|
||||
}
|
||||
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);
|
||||
|
||||
// Textures
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user