diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 126 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 246 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 13 |
6 files changed, 307 insertions, 122 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 75e31c6de..a0527fe57 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -104,7 +104,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo } ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported"); - + OpenGLState::ApplyDefaultState(); // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 state.clip_distance[0] = true; @@ -115,8 +115,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo state.draw.shader_program = 0; state.Apply(); - glEnable(GL_BLEND); - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 752c4ee84..dcbf009c0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -58,16 +58,14 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, bool uncompressed) const { - const u32 compression_factor{GetCompressionFactor(pixel_format)}; + const u32 tile_x{GetDefaultBlockWidth(pixel_format)}; + const u32 tile_y{GetDefaultBlockHeight(pixel_format)}; const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; u32 m_depth = (layer_only ? 1U : depth); u32 m_width = MipWidth(mip_level); u32 m_height = MipHeight(mip_level); - m_width = uncompressed ? m_width - : std::max(1U, (m_width + compression_factor - 1) / compression_factor); - m_height = uncompressed - ? m_height - : std::max(1U, (m_height + compression_factor - 1) / compression_factor); + m_width = uncompressed ? m_width : std::max(1U, (m_width + tile_x - 1) / tile_x); + m_height = uncompressed ? m_height : std::max(1U, (m_height + tile_y - 1) / tile_y); m_depth = std::max(1U, m_depth >> mip_level); u32 m_block_height = MipBlockHeight(mip_level); u32 m_block_depth = MipBlockDepth(mip_level); @@ -312,6 +310,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5 + {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB // Depth formats {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F @@ -373,15 +373,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual // pixel values. - const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; + const u32 tile_size_x{GetDefaultBlockWidth(format)}; + const u32 tile_size_y{GetDefaultBlockHeight(format)}; if (morton_to_gl) { - const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( - addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth); + const std::vector<u8> data = + Tegra::Texture::UnswizzleTexture(addr, tile_size_x, tile_size_y, bytes_per_pixel, + stride, height, depth, block_height, block_depth); const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())}; memcpy(gl_buffer, data.data(), size_to_copy); } else { - Tegra::Texture::CopySwizzledData(stride / tile_size, height / tile_size, depth, + Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x, + (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr), gl_buffer, false, block_height, block_depth); } @@ -449,6 +452,8 @@ static constexpr GLConversionArray morton_to_gl_fns = { MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, + MortonCopy<true, PixelFormat::ASTC_2D_5X5>, + MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z24S8>, @@ -517,6 +522,8 @@ static constexpr GLConversionArray gl_to_morton_fns = { nullptr, nullptr, nullptr, + nullptr, + nullptr, MortonCopy<false, PixelFormat::Z32F>, MortonCopy<false, PixelFormat::Z16>, MortonCopy<false, PixelFormat::Z24S8>, @@ -908,21 +915,24 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { * typical desktop GPUs. */ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format, - u32 width, u32 height) { + u32 width, u32 height, u32 depth) { switch (pixel_format) { case PixelFormat::ASTC_2D_4X4: case PixelFormat::ASTC_2D_8X8: case PixelFormat::ASTC_2D_8X5: case PixelFormat::ASTC_2D_5X4: + case PixelFormat::ASTC_2D_5X5: case PixelFormat::ASTC_2D_4X4_SRGB: case PixelFormat::ASTC_2D_8X8_SRGB: case PixelFormat::ASTC_2D_8X5_SRGB: - case PixelFormat::ASTC_2D_5X4_SRGB: { + case PixelFormat::ASTC_2D_5X4_SRGB: + case PixelFormat::ASTC_2D_5X5_SRGB: { // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. u32 block_width{}; u32 block_height{}; std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format); - data = Tegra::Texture::ASTC::Decompress(data, width, height, block_width, block_height); + data = + Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height); break; } case PixelFormat::S8Z24: @@ -982,7 +992,7 @@ void CachedSurface::LoadGLBuffer() { } for (u32 i = 0; i < params.max_mip_level; i++) ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), - params.MipHeight(i)); + params.MipHeight(i), params.MipDepth(i)); } MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 5a5f2cec0..c0b6bc4e6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -141,7 +141,7 @@ struct SurfaceParams { } u32 MipDepth(u32 mip_level) const { - return std::max(1U, depth >> mip_level); + return is_layered ? depth : std::max(1U, depth >> mip_level); } // Auto block resizing algorithm from: diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d1f6ffe40..09b003c59 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -373,6 +373,7 @@ public: if (sets_cc) { const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); + LOG_WARNING(HW_GPU, "Control Codes Imcomplete."); } } @@ -1525,6 +1526,10 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::FADD_C: @@ -1535,6 +1540,10 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::MUFU: { @@ -1588,6 +1597,10 @@ private: '(' + condition + ") ? min(" + parameters + ") : max(" + parameters + ')', 1, 1, false, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::RRO_C: @@ -1618,6 +1631,10 @@ private: regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1, instr.fmul32.saturate, 0, true); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::FADD32I: { @@ -1641,6 +1658,10 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } } @@ -1661,6 +1682,10 @@ private: std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { @@ -1698,12 +1723,20 @@ private: // Cast to int is superfluous for arithmetic shift, it's only for a logical shift regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::SHL_C: case OpCode::Id::SHL_R: case OpCode::Id::SHL_IMM: regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code"); + UNREACHABLE(); + } break; default: { LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName()); @@ -1723,6 +1756,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, instr.iadd32i.saturate != 0); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; case OpCode::Id::LOP32I: { if (instr.alu.lop32i.invert_a) @@ -1734,6 +1771,10 @@ private: WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, Tegra::Shader::PredicateResultMode::None, Tegra::Shader::Pred::UnusedIndex); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { @@ -1770,6 +1811,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, instr.alu.saturate_d); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::IADD3_C: @@ -1831,6 +1876,11 @@ private: } regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::ISCADD_C: @@ -1846,6 +1896,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, true, 0, "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::POPC_C: @@ -1877,6 +1931,10 @@ private: WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::LOP3_C: @@ -1892,6 +1950,10 @@ private: } WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::IMNMX_C: @@ -1906,6 +1968,10 @@ private: '(' + condition + ") ? min(" + parameters + ") : max(" + parameters + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::LEA_R2: @@ -2107,6 +2173,10 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } @@ -2212,6 +2282,11 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::F2F_R: { @@ -2250,6 +2325,11 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::F2I_R: @@ -2299,6 +2379,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 1, false, 0, instr.conversion.dest_size); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { @@ -3107,6 +3191,11 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); } + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code"); + UNREACHABLE(); + } + break; } case OpCode::Type::PredicateSetPredicate: { @@ -3372,6 +3461,10 @@ private: } regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { @@ -3381,6 +3474,12 @@ private: EmitFragmentOutputsWrite(); } + const Tegra::Shader::ControlCode cc = instr.flow_control_code; + if (cc != Tegra::Shader::ControlCode::T) { + LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc)); + UNREACHABLE(); + } + switch (instr.flow.cond) { case Tegra::Shader::FlowCondition::Always: shader.AddLine("return true;"); @@ -3410,6 +3509,11 @@ private: // Enclose "discard" in a conditional, so that GLSL compilation does not complain // about unexecuted instructions that may follow this. + const Tegra::Shader::ControlCode cc = instr.flow_control_code; + if (cc != Tegra::Shader::ControlCode::T) { + LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc)); + UNREACHABLE(); + } shader.AddLine("if (true) {"); ++shader.scope; shader.AddLine("discard;"); @@ -3467,6 +3571,11 @@ private: case OpCode::Id::BRA: { ASSERT_MSG(instr.bra.constant_buffer == 0, "BRA with constant buffers are not implemented"); + const Tegra::Shader::ControlCode cc = instr.flow_control_code; + if (cc != Tegra::Shader::ControlCode::T) { + LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc)); + UNREACHABLE(); + } const u32 target = offset + instr.bra.GetBranchTarget(); shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); break; @@ -3507,13 +3616,21 @@ private: } case OpCode::Id::SYNC: { // The SYNC opcode jumps to the address previously set by the SSY opcode - ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); + const Tegra::Shader::ControlCode cc = instr.flow_control_code; + if (cc != Tegra::Shader::ControlCode::T) { + LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc)); + UNREACHABLE(); + } EmitPopFromFlowStack(); break; } case OpCode::Id::BRK: { // The BRK opcode jumps to the address previously set by the PBK opcode - ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); + const Tegra::Shader::ControlCode cc = instr.flow_control_code; + if (cc != Tegra::Shader::ControlCode::T) { + LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc)); + UNREACHABLE(); + } EmitPopFromFlowStack(); break; } @@ -3543,6 +3660,11 @@ private: regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, instr.vmad.saturate == 1, 0, Register::Size::Word, instr.vmad.cc); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code"); + UNREACHABLE(); + } + break; } case OpCode::Id::VSETP: { diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index d8a43cc94..b6b426f34 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -89,7 +89,18 @@ OpenGLState::OpenGLState() { point.size = 1; } -void OpenGLState::Apply() const { +void OpenGLState::ApplyDefaultState() { + glDisable(GL_FRAMEBUFFER_SRGB); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_PRIMITIVE_RESTART); + glDisable(GL_STENCIL_TEST); + glEnable(GL_BLEND); + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_SCISSOR_TEST); +} + +void OpenGLState::ApplySRgb() const { // sRGB if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { if (framebuffer_srgb.enabled) { @@ -100,96 +111,122 @@ void OpenGLState::Apply() const { glDisable(GL_FRAMEBUFFER_SRGB); } } +} + +void OpenGLState::ApplyCulling() const { // Culling - if (cull.enabled != cur_state.cull.enabled) { + const bool cull_changed = cull.enabled != cur_state.cull.enabled; + if (cull_changed) { if (cull.enabled) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } } + if (cull.enabled) { + if (cull_changed || cull.mode != cur_state.cull.mode) { + glCullFace(cull.mode); + } - if (cull.mode != cur_state.cull.mode) { - glCullFace(cull.mode); - } - - if (cull.front_face != cur_state.cull.front_face) { - glFrontFace(cull.front_face); + if (cull_changed || cull.front_face != cur_state.cull.front_face) { + glFrontFace(cull.front_face); + } } +} +void OpenGLState::ApplyDepth() const { // Depth test - if (depth.test_enabled != cur_state.depth.test_enabled) { + const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; + if (depth_test_changed) { if (depth.test_enabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } - - if (depth.test_func != cur_state.depth.test_func) { + if (depth.test_enabled && + (depth_test_changed || depth.test_func != cur_state.depth.test_func)) { glDepthFunc(depth.test_func); } - // Depth mask if (depth.write_mask != cur_state.depth.write_mask) { glDepthMask(depth.write_mask); } - // Depth range if (depth.depth_range_near != cur_state.depth.depth_range_near || depth.depth_range_far != cur_state.depth.depth_range_far) { glDepthRange(depth.depth_range_near, depth.depth_range_far); } +} - // Primitive restart - if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { +void OpenGLState::ApplyPrimitiveRestart() const { + const bool primitive_restart_changed = + primitive_restart.enabled != cur_state.primitive_restart.enabled; + if (primitive_restart_changed) { if (primitive_restart.enabled) { glEnable(GL_PRIMITIVE_RESTART); } else { glDisable(GL_PRIMITIVE_RESTART); } } - if (primitive_restart.index != cur_state.primitive_restart.index) { + if (primitive_restart_changed || + (primitive_restart.enabled && + primitive_restart.index != cur_state.primitive_restart.index)) { glPrimitiveRestartIndex(primitive_restart.index); } +} - // 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); - } - - // Stencil test - if (stencil.test_enabled != cur_state.stencil.test_enabled) { +void OpenGLState::ApplyStencilTest() const { + const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled; + if (stencil_test_changed) { if (stencil.test_enabled) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } } - auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) { - if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref || - config.test_mask != prev_config.test_mask) { - glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); - } - if (config.action_depth_fail != prev_config.action_depth_fail || - config.action_depth_pass != prev_config.action_depth_pass || - config.action_stencil_fail != prev_config.action_stencil_fail) { - glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, - config.action_depth_pass); - } - if (config.write_mask != prev_config.write_mask) { - glStencilMaskSeparate(face, config.write_mask); + if (stencil.test_enabled) { + auto config_stencil = [stencil_test_changed](GLenum face, const auto& config, + const auto& prev_config) { + if (stencil_test_changed || config.test_func != prev_config.test_func || + config.test_ref != prev_config.test_ref || + config.test_mask != prev_config.test_mask) { + glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); + } + if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail || + config.action_depth_pass != prev_config.action_depth_pass || + config.action_stencil_fail != prev_config.action_stencil_fail) { + glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, + config.action_depth_pass); + } + if (config.write_mask != prev_config.write_mask) { + glStencilMaskSeparate(face, config.write_mask); + } + }; + config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front); + config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); + } +} + +void OpenGLState::ApplyScissorTest() const { + const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; + if (scissor_changed) { + if (scissor.enabled) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); } - }; - config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front); - config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); + } + if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || + scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || + scissor.height != cur_state.scissor.height) { + glScissor(scissor.x, scissor.y, scissor.width, scissor.height); + } +} - // Blending - if (blend.enabled != cur_state.blend.enabled) { +void OpenGLState::ApplyBlending() const { + const bool blend_changed = blend.enabled != cur_state.blend.enabled; + if (blend_changed) { if (blend.enabled) { ASSERT(!logic_op.enabled); glEnable(GL_BLEND); @@ -197,29 +234,32 @@ void OpenGLState::Apply() const { glDisable(GL_BLEND); } } + if (blend.enabled) { + if (blend_changed || 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); + } - 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); - } - - 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); - } + if (blend_changed || 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); + } - if (blend.rgb_equation != cur_state.blend.rgb_equation || - blend.a_equation != cur_state.blend.a_equation) { - glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); + if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation || + blend.a_equation != cur_state.blend.a_equation) { + glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); + } } +} - // Logic Operation - if (logic_op.enabled != cur_state.logic_op.enabled) { +void OpenGLState::ApplyLogicOp() const { + const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; + if (logic_op_changed) { if (logic_op.enabled) { ASSERT(!blend.enabled); glEnable(GL_COLOR_LOGIC_OP); @@ -228,11 +268,13 @@ void OpenGLState::Apply() const { } } - if (logic_op.operation != cur_state.logic_op.operation) { + if (logic_op.enabled && + (logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) { glLogicOp(logic_op.operation); } +} - // Textures +void OpenGLState::ApplyTextures() const { for (std::size_t i = 0; i < std::size(texture_units); ++i) { const auto& texture_unit = texture_units[i]; const auto& cur_state_texture_unit = cur_state.texture_units[i]; @@ -251,28 +293,29 @@ void OpenGLState::Apply() const { glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); } } +} - // Samplers - { - bool has_delta{}; - std::size_t first{}, last{}; - std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; - for (std::size_t i = 0; i < std::size(samplers); ++i) { - samplers[i] = texture_units[i].sampler; - if (samplers[i] != cur_state.texture_units[i].sampler) { - if (!has_delta) { - first = i; - has_delta = true; - } - last = i; +void OpenGLState::ApplySamplers() const { + bool has_delta{}; + std::size_t first{}, last{}; + std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; + for (std::size_t i = 0; i < std::size(samplers); ++i) { + samplers[i] = texture_units[i].sampler; + if (samplers[i] != cur_state.texture_units[i].sampler) { + if (!has_delta) { + first = i; + has_delta = true; } - } - if (has_delta) { - glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), - samplers.data()); + last = i; } } + if (has_delta) { + glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), + samplers.data()); + } +} +void OpenGLState::Apply() const { // Framebuffer if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); @@ -305,27 +348,12 @@ void OpenGLState::Apply() const { if (draw.program_pipeline != cur_state.draw.program_pipeline) { glBindProgramPipeline(draw.program_pipeline); } - - // Scissor test - if (scissor.enabled != cur_state.scissor.enabled) { - if (scissor.enabled) { - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } - } - - if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y || - scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) { - glScissor(scissor.x, scissor.y, scissor.width, scissor.height); - } - + // Viewport if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y || viewport.width != cur_state.viewport.width || viewport.height != cur_state.viewport.height) { glViewport(viewport.x, viewport.y, viewport.width, viewport.height); } - // Clip distance for (std::size_t i = 0; i < clip_distance.size(); ++i) { if (clip_distance[i] != cur_state.clip_distance[i]) { @@ -336,12 +364,28 @@ void OpenGLState::Apply() const { } } } - + // 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); + } // Point if (point.size != cur_state.point.size) { glPointSize(point.size); } - + ApplyScissorTest(); + ApplyStencilTest(); + ApplySRgb(); + ApplyCulling(); + ApplyDepth(); + ApplyPrimitiveRestart(); + ApplyBlending(); + ApplyLogicOp(); + ApplyTextures(); + ApplySamplers(); cur_state = *this; } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 9e2c573b5..fe648aff6 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -173,7 +173,8 @@ public: } /// Apply this state as the current OpenGL state void Apply() const; - + /// Set the initial OpenGL state + static void ApplyDefaultState(); /// Resets any references to the given resource OpenGLState& UnbindTexture(GLuint handle); OpenGLState& ResetSampler(GLuint handle); @@ -188,6 +189,16 @@ private: // Workaround for sRGB problems caused by // QT not supporting srgb output static bool s_rgb_used; + void ApplySRgb() const; + void ApplyCulling() const; + void ApplyDepth() const; + void ApplyPrimitiveRestart() const; + void ApplyStencilTest() const; + void ApplyScissorTest() const; + void ApplyBlending() const; + void ApplyLogicOp() const; + void ApplyTextures() const; + void ApplySamplers() const; }; } // namespace OpenGL |
