aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp49
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h31
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp171
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp37
-rw-r--r--src/video_core/renderer_opengl/gl_state.h9
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
10 files changed, 199 insertions, 121 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ae6aaee4c..630a58e49 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
has_ARB_direct_state_access = true;
} else if (extension == "GL_ARB_multi_bind") {
has_ARB_multi_bind = true;
- } else if (extension == "GL_ARB_separate_shader_objects") {
- has_ARB_separate_shader_objects = true;
- } else if (extension == "GL_ARB_vertex_attrib_binding") {
- has_ARB_vertex_attrib_binding = true;
}
}
- ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
OpenGLState::ApplyDefaultState();
// Create render framebuffer
@@ -542,6 +537,30 @@ void RasterizerOpenGL::Clear() {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
use_stencil = true;
clear_state.stencil.test_enabled = true;
+ if (regs.clear_flags.stencil) {
+ // Stencil affects the clear so fill it with the used masks
+ clear_state.stencil.front.test_func = GL_ALWAYS;
+ clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
+ clear_state.stencil.front.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.front.action_depth_fail = GL_KEEP;
+ clear_state.stencil.front.action_depth_pass = GL_KEEP;
+ clear_state.stencil.front.write_mask = regs.stencil_front_mask;
+ if (regs.stencil_two_side_enable) {
+ clear_state.stencil.back.test_func = GL_ALWAYS;
+ clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
+ clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_pass = GL_KEEP;
+ clear_state.stencil.back.write_mask = regs.stencil_back_mask;
+ } else {
+ clear_state.stencil.back.test_func = GL_ALWAYS;
+ clear_state.stencil.back.test_mask = 0xFFFFFFFF;
+ clear_state.stencil.back.write_mask = 0xFFFFFFFF;
+ clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_pass = GL_KEEP;
+ }
+ }
}
if (!use_color && !use_depth && !use_stencil) {
@@ -553,6 +572,14 @@ void RasterizerOpenGL::Clear() {
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
regs.clear_buffers.RT.Value());
+ if (regs.clear_flags.scissor) {
+ SyncScissorTest(clear_state);
+ }
+
+ if (regs.clear_flags.viewport) {
+ clear_state.EmulateViewportWithScissor();
+ }
+
clear_state.Apply();
if (use_color) {
@@ -588,7 +615,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncLogicOpState();
SyncCullMode();
SyncPrimitiveRestart();
- SyncScissorTest();
+ SyncScissorTest(state);
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
SyncPointState();
@@ -815,7 +842,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
}
const u32 bias = config.mip_lod_bias.Value();
// Sign extend the 13-bit value.
- const u32 mask = 1U << (13 - 1);
+ constexpr u32 mask = 1U << (13 - 1);
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
if (lod_bias != bias_lod) {
lod_bias = bias_lod;
@@ -947,8 +974,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
auto& viewport = current_state.viewports[i];
viewport.x = viewport_rect.left;
viewport.y = viewport_rect.bottom;
- viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
- viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
+ viewport.width = viewport_rect.GetWidth();
+ viewport.height = viewport_rect.GetHeight();
viewport.depth_range_far = regs.viewports[i].depth_range_far;
viewport.depth_range_near = regs.viewports[i].depth_range_near;
}
@@ -1120,11 +1147,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}
-void RasterizerOpenGL::SyncScissorTest() {
+void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
const auto& src = regs.scissor_test[i];
- auto& dst = state.viewports[i].scissor;
+ auto& dst = current_state.viewports[i].scissor;
dst.enabled = (src.enable != 0);
if (dst.enabled == 0) {
return;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6e78ab4cd..f4354289c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -91,19 +91,20 @@ private:
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
private:
- Tegra::Texture::TextureFilter mag_filter;
- Tegra::Texture::TextureFilter min_filter;
- Tegra::Texture::TextureMipmapFilter mip_filter;
- Tegra::Texture::WrapMode wrap_u;
- Tegra::Texture::WrapMode wrap_v;
- Tegra::Texture::WrapMode wrap_p;
- bool uses_depth_compare;
- Tegra::Texture::DepthCompareFunc depth_compare_func;
- GLvec4 border_color;
- float min_lod;
- float max_lod;
- float lod_bias;
- float max_anisotropic;
+ Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
+ Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
+ Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
+ Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
+ Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
+ Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
+ bool uses_depth_compare = false;
+ Tegra::Texture::DepthCompareFunc depth_compare_func =
+ Tegra::Texture::DepthCompareFunc::Always;
+ GLvec4 border_color = {};
+ float min_lod = 0.0f;
+ float max_lod = 16.0f;
+ float lod_bias = 0.0f;
+ float max_anisotropic = 1.0f;
};
/**
@@ -171,7 +172,7 @@ private:
void SyncMultiSampleState();
/// Syncs the scissor test state to match the guest state
- void SyncScissorTest();
+ void SyncScissorTest(OpenGLState& current_state);
/// Syncs the transform feedback state to match the guest state
void SyncTransformFeedback();
@@ -187,8 +188,6 @@ private:
bool has_ARB_direct_state_access = false;
bool has_ARB_multi_bind = false;
- bool has_ARB_separate_shader_objects = false;
- bool has_ARB_vertex_attrib_binding = false;
OpenGLState state;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b994e89dd..4f434fc31 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -265,11 +265,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
{GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXN2UNORM
{GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
- {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
+ {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
- {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
- ComponentType::Float, true}, // BC6H_UF16
- {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
+ {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
+ true}, // BC6H_UF16
+ {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
true}, // BC6H_SF16
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
@@ -306,8 +306,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
true}, // DXT23_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT45_SRGB
- {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
- ComponentType::UNorm, true}, // BC7U_SRGB
+ {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
+ true}, // BC7U_SRGB
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
{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
@@ -346,7 +346,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
case SurfaceTarget::TextureCubemap:
return GL_TEXTURE_CUBE_MAP;
case SurfaceTarget::TextureCubeArray:
- return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
+ return GL_TEXTURE_CUBE_MAP_ARRAY;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
UNREACHABLE();
@@ -726,7 +726,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
- glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
+ glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW);
if (source_format.compressed) {
glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a85a7c0c5..038b25c75 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
}
entries = program_result.second;
+ shader_length = entries.shader_length;
if (program_type != Maxwell::ShaderProgram::Geometry) {
OGLShader shader;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index ffbf21831..08f470de3 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -30,7 +30,7 @@ public:
}
std::size_t GetSizeInBytes() const override {
- return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
+ return shader_length;
}
// We do not have to flush this cache as things in it are never modified by us.
@@ -82,6 +82,7 @@ private:
u32 max_vertices, const std::string& debug_name);
VAddr addr;
+ std::size_t shader_length;
Maxwell::ShaderProgram program_type;
GLShader::ShaderSetup setup;
GLShader::ShaderEntries entries;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ba80e5832..97b9028c5 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -34,6 +34,17 @@ constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
+static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag",
+ "overflow_flag"};
+
+enum class InternalFlag : u64 {
+ ZeroFlag = 0,
+ SignFlag = 1,
+ CarryFlag = 2,
+ OverflowFlag = 3,
+ Amount
+};
+
class DecompileFail : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
@@ -84,7 +95,8 @@ struct Subroutine {
class ControlFlowAnalyzer {
public:
ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
- : program_code(program_code) {
+ : program_code(program_code), shader_coverage_begin(main_offset),
+ shader_coverage_end(main_offset + 1) {
// Recursively finds all subroutines.
const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
@@ -96,10 +108,16 @@ public:
return std::move(subroutines);
}
+ std::size_t GetShaderLength() const {
+ return shader_coverage_end * sizeof(u64);
+ }
+
private:
const ProgramCode& program_code;
std::set<Subroutine> subroutines;
std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
+ u32 shader_coverage_begin;
+ u32 shader_coverage_end;
/// Adds and analyzes a new subroutine if it is not added yet.
const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
@@ -141,6 +159,9 @@ private:
return exit_method;
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
+ shader_coverage_begin = std::min(shader_coverage_begin, offset);
+ shader_coverage_end = std::max(shader_coverage_end, offset + 1);
+
const Instruction instr = {program_code[offset]};
if (const auto opcode = OpCode::Decode(instr)) {
switch (opcode->get().GetId()) {
@@ -257,14 +278,6 @@ private:
const std::string& suffix;
};
-enum class InternalFlag : u64 {
- ZeroFlag = 0,
- CarryFlag = 1,
- OverflowFlag = 2,
- NaNFlag = 3,
- Amount
-};
-
/**
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
@@ -371,7 +384,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.");
+ LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
}
}
@@ -454,23 +467,25 @@ public:
shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");");
}
- std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
+ std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const {
switch (cc) {
- case Tegra::Shader::ControlCode::NEU:
+ case Tegra::Shader::ConditionCode::NEU:
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
default:
- UNIMPLEMENTED_MSG("Unimplemented Control Code: {}", static_cast<u32>(cc));
+ UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
return "false";
}
}
- std::string GetInternalFlag(const InternalFlag ii) const {
- const u32 code = static_cast<u32>(ii);
- return "internalFlag_" + std::to_string(code) + suffix;
+ std::string GetInternalFlag(const InternalFlag flag) const {
+ const auto index = static_cast<u32>(flag);
+ ASSERT(index < static_cast<u32>(InternalFlag::Amount));
+
+ return std::string(INTERNAL_FLAG_NAMES[index]) + '_' + suffix;
}
- void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
- shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
+ void SetInternalFlag(const InternalFlag flag, const std::string& value) const {
+ shader.AddLine(GetInternalFlag(flag) + " = " + value + ';');
}
/**
@@ -621,8 +636,8 @@ private:
/// Generates declarations for internal flags.
void GenerateInternalFlags() {
- for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
- const InternalFlag code = static_cast<InternalFlag>(ii);
+ for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
+ const InternalFlag code = static_cast<InternalFlag>(flag);
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
}
declarations.AddNewLine();
@@ -939,9 +954,10 @@ private:
class GLSLGenerator {
public:
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
- u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)
+ u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix,
+ std::size_t shader_length)
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
- stage(stage), suffix(suffix) {
+ stage(stage), suffix(suffix), shader_length(shader_length) {
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
local_memory_size = header.GetLocalMemorySize();
regs.SetLocalMemory(local_memory_size);
@@ -954,7 +970,7 @@ public:
/// Returns entries in the shader that are useful for external functions
ShaderEntries GetEntries() const {
- return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()};
+ return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
}
private:
@@ -1505,9 +1521,8 @@ private:
instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented",
instr.fmul.tab5c68_0
.Value()); // SMO typical sends 1 here which seems to be the default
- UNIMPLEMENTED_IF_MSG(instr.fmul.cc != 0, "FMUL cc is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "FMUL Generates an unhandled Control Code");
+ "Condition codes generation in FMUL is not implemented");
op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
@@ -1519,7 +1534,7 @@ private:
case OpCode::Id::FADD_R:
case OpCode::Id::FADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "FADD Generates an unhandled Control Code");
+ "Condition codes generation in FADD is not implemented");
op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
@@ -1569,7 +1584,7 @@ private:
case OpCode::Id::FMNMX_R:
case OpCode::Id::FMNMX_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "FMNMX Generates an unhandled Control Code");
+ "Condition codes generation in FMNMX is not implemented");
op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
@@ -1606,7 +1621,7 @@ private:
}
case OpCode::Id::FMUL32_IMM: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
- "FMUL32 Generates an unhandled Control Code");
+ "Condition codes generation in FMUL32 is not implemented");
regs.SetRegisterToFloat(instr.gpr0, 0,
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
@@ -1616,7 +1631,7 @@ private:
}
case OpCode::Id::FADD32I: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
- "FADD32 Generates an unhandled Control Code");
+ "Condition codes generation in FADD32I is not implemented");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b = GetImmediate32(instr);
@@ -1651,7 +1666,8 @@ private:
switch (opcode->get().GetId()) {
case OpCode::Id::BFE_IMM: {
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "BFE Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in BFE is not implemented");
std::string inner_shift =
'(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
@@ -1688,7 +1704,8 @@ private:
case OpCode::Id::SHR_C:
case OpCode::Id::SHR_R:
case OpCode::Id::SHR_IMM: {
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHR Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in SHR is not implemented");
if (!instr.shift.is_signed) {
// Logical shift right
@@ -1703,8 +1720,8 @@ private:
case OpCode::Id::SHL_C:
case OpCode::Id::SHL_R:
case OpCode::Id::SHL_IMM:
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHL Generates an unhandled Control Code");
-
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in SHL is not implemented");
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
break;
default: {
@@ -1720,7 +1737,7 @@ private:
switch (opcode->get().GetId()) {
case OpCode::Id::IADD32I:
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
- "IADD32 Generates an unhandled Control Code");
+ "Condition codes generation in IADD32I is not implemented");
if (instr.iadd32i.negate_a)
op_a = "-(" + op_a + ')';
@@ -1730,7 +1747,7 @@ private:
break;
case OpCode::Id::LOP32I: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
- "LOP32I Generates an unhandled Control Code");
+ "Condition codes generation in LOP32I is not implemented");
if (instr.alu.lop32i.invert_a)
op_a = "~(" + op_a + ')';
@@ -1769,7 +1786,7 @@ private:
case OpCode::Id::IADD_R:
case OpCode::Id::IADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "IADD Generates an unhandled Control Code");
+ "Condition codes generation in IADD is not implemented");
if (instr.alu_integer.negate_a)
op_a = "-(" + op_a + ')';
@@ -1785,7 +1802,7 @@ private:
case OpCode::Id::IADD3_R:
case OpCode::Id::IADD3_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "IADD3 Generates an unhandled Control Code");
+ "Condition codes generation in IADD3 is not implemented");
std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
@@ -1848,7 +1865,7 @@ private:
case OpCode::Id::ISCADD_R:
case OpCode::Id::ISCADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "ISCADD Generates an unhandled Control Code");
+ "Condition codes generation in ISCADD is not implemented");
if (instr.alu_integer.negate_a)
op_a = "-(" + op_a + ')';
@@ -1883,7 +1900,8 @@ private:
case OpCode::Id::LOP_C:
case OpCode::Id::LOP_R:
case OpCode::Id::LOP_IMM: {
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "LOP Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in LOP is not implemented");
if (instr.alu.lop.invert_a)
op_a = "~(" + op_a + ')';
@@ -1899,7 +1917,7 @@ private:
case OpCode::Id::LOP3_R:
case OpCode::Id::LOP3_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "LOP3 Generates an unhandled Control Code");
+ "Condition codes generation in LOP3 is not implemented");
const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
std::string lut;
@@ -1918,7 +1936,7 @@ private:
case OpCode::Id::IMNMX_IMM: {
UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
- "IMNMX Generates an unhandled Control Code");
+ "Condition codes generation in IMNMX is not implemented");
const std::string condition =
GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
@@ -2091,7 +2109,8 @@ private:
instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO
UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented",
instr.ffma.tab5980_1.Value());
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "FFMA Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in FFMA is not implemented");
switch (opcode->get().GetId()) {
case OpCode::Id::FFMA_CR: {
@@ -2201,7 +2220,8 @@ private:
case OpCode::Id::I2F_C: {
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.conversion.selector);
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "I2F Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in I2F is not implemented");
std::string op_a{};
@@ -2231,7 +2251,8 @@ private:
case OpCode::Id::F2F_R: {
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2F Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in F2F is not implemented");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
if (instr.conversion.abs_a) {
@@ -2269,7 +2290,8 @@ private:
case OpCode::Id::F2I_R:
case OpCode::Id::F2I_C: {
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2I Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in F2I is not implemented");
std::string op_a{};
if (instr.is_b_gpr) {
@@ -3118,7 +3140,8 @@ private:
break;
}
case OpCode::Type::PredicateSetRegister: {
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "PSET Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in PSET is not implemented");
const std::string op_a =
GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
@@ -3177,14 +3200,14 @@ private:
const std::string pred =
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
- const std::string control_code = regs.GetControlCode(instr.csetp.cc);
+ const std::string condition_code = regs.GetConditionCode(instr.csetp.cc);
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred3,
- '(' + control_code + ") " + combiner + " (" + pred + ')');
+ '(' + condition_code + ") " + combiner + " (" + pred + ')');
}
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred0,
- "!(" + control_code + ") " + combiner + " (" + pred + ')');
+ "!(" + condition_code + ") " + combiner + " (" + pred + ')');
}
break;
}
@@ -3315,7 +3338,8 @@ private:
case OpCode::Type::Xmad: {
UNIMPLEMENTED_IF(instr.xmad.sign_a);
UNIMPLEMENTED_IF(instr.xmad.sign_b);
- UNIMPLEMENTED_IF_MSG(instr.generates_cc, "XMAD Generates an unhandled Control Code");
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in XMAD is not implemented");
std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
std::string op_b;
@@ -3407,9 +3431,9 @@ private:
default: {
switch (opcode->get().GetId()) {
case OpCode::Id::EXIT: {
- const Tegra::Shader::ControlCode cc = instr.flow_control_code;
- UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
- "EXIT Control Code used: {}", static_cast<u32>(cc));
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
+ "EXIT condition code used: {}", static_cast<u32>(cc));
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
EmitFragmentOutputsWrite();
@@ -3441,9 +3465,9 @@ private:
case OpCode::Id::KIL: {
UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
- const Tegra::Shader::ControlCode cc = instr.flow_control_code;
- UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
- "KIL Control Code used: {}", static_cast<u32>(cc));
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
+ "KIL condition code used: {}", static_cast<u32>(cc));
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
// about unexecuted instructions that may follow this.
@@ -3505,9 +3529,9 @@ private:
UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
"BRA with constant buffers are not implemented");
- const Tegra::Shader::ControlCode cc = instr.flow_control_code;
- UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
- "BRA Control Code used: {}", static_cast<u32>(cc));
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
+ "BRA condition code used: {}", static_cast<u32>(cc));
const u32 target = offset + instr.bra.GetBranchTarget();
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
@@ -3550,9 +3574,9 @@ private:
break;
}
case OpCode::Id::SYNC: {
- const Tegra::Shader::ControlCode cc = instr.flow_control_code;
- UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
- "SYNC Control Code used: {}", static_cast<u32>(cc));
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
+ "SYNC condition code used: {}", static_cast<u32>(cc));
// The SYNC opcode jumps to the address previously set by the SSY opcode
EmitPopFromFlowStack();
@@ -3560,10 +3584,10 @@ private:
}
case OpCode::Id::BRK: {
// The BRK opcode jumps to the address previously set by the PBK opcode
- const Tegra::Shader::ControlCode cc = instr.flow_control_code;
- if (cc != Tegra::Shader::ControlCode::T) {
- UNIMPLEMENTED_MSG("BRK Control Code used: {}", static_cast<u32>(cc));
- }
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
+ "BRK condition code used: {}", static_cast<u32>(cc));
+
EmitPopFromFlowStack();
break;
}
@@ -3574,6 +3598,9 @@ private:
break;
}
case OpCode::Id::VMAD: {
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in VMAD is not implemented");
+
const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
const std::string op_a = GetVideoOperandA(instr);
const std::string op_b = GetVideoOperandB(instr);
@@ -3593,10 +3620,6 @@ 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) {
- UNIMPLEMENTED_MSG("VMAD Generates an unhandled Control Code");
- }
-
break;
}
case OpCode::Id::VSETP: {
@@ -3748,6 +3771,7 @@ private:
Maxwell3D::Regs::ShaderStage stage;
const std::string& suffix;
u64 local_memory_size;
+ std::size_t shader_length;
ShaderWriter shader;
ShaderWriter declarations;
@@ -3766,9 +3790,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
Maxwell3D::Regs::ShaderStage stage,
const std::string& suffix) {
try {
- const auto subroutines =
- ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
- GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
+ ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
+ const auto subroutines = analyzer.GetSubroutines();
+ GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
+ analyzer.GetShaderLength());
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
} catch (const DecompileFail& exception) {
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 520b9d4e3..b425d98ae 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -163,6 +163,7 @@ private:
struct ShaderEntries {
std::vector<ConstBufferEntry> const_buffer_entries;
std::vector<SamplerEntry> texture_samplers;
+ std::size_t shader_length;
};
using ProgramResult = std::pair<std::string, ShaderEntries>;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index d9910c6e8..934f4db78 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const {
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
}
}
+// Viewport does not affects glClearBuffer so emulate viewport using scissor test
+void OpenGLState::EmulateViewportWithScissor() {
+ auto& current = viewports[0];
+ if (current.scissor.enabled) {
+ const GLint left = std::max(current.x, current.scissor.x);
+ const GLint right =
+ std::max(current.x + current.width, current.scissor.x + current.scissor.width);
+ const GLint bottom = std::max(current.y, current.scissor.y);
+ const GLint top =
+ std::max(current.y + current.height, current.scissor.y + current.scissor.height);
+ current.scissor.x = std::max(left, 0);
+ current.scissor.y = std::max(bottom, 0);
+ current.scissor.width = std::max(right - left, 0);
+ current.scissor.height = std::max(top - bottom, 0);
+ } else {
+ current.scissor.enabled = true;
+ current.scissor.x = current.x;
+ current.scissor.y = current.y;
+ current.scissor.width = current.width;
+ current.scissor.height = current.height;
+ }
+}
void OpenGLState::ApplyViewport() const {
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
@@ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const {
const auto& updated = viewports[i];
if (updated.x != current.x || updated.y != current.y ||
updated.width != current.width || updated.height != current.height) {
- glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
+ glViewportIndexedf(
+ i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
+ static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
}
if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) {
@@ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const {
const auto& updated = viewports[0];
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
updated.height != current.height) {
- glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y),
- static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
+ glViewport(updated.x, updated.y, updated.width, updated.height);
}
if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) {
@@ -339,14 +362,14 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
updated.dst_a_func != current.dst_a_func) {
- glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
- updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
+ glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
+ updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
}
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
updated.a_equation != current.a_equation) {
- glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
- updated.a_equation);
+ glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
+ updated.a_equation);
}
}
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index bdc743b0f..032fc43f0 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -156,10 +156,10 @@ public:
} draw;
struct viewport {
- GLfloat x;
- GLfloat y;
- GLfloat width;
- GLfloat height;
+ GLint x;
+ GLint y;
+ GLint width;
+ GLint height;
GLfloat depth_range_near; // GL_DEPTH_RANGE
GLfloat depth_range_far; // GL_DEPTH_RANGE
struct {
@@ -206,6 +206,7 @@ public:
OpenGLState& ResetBuffer(GLuint handle);
OpenGLState& ResetVertexArray(GLuint handle);
OpenGLState& ResetFramebuffer(GLuint handle);
+ void EmulateViewportWithScissor();
private:
static OpenGLState cur_state;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 27b5b8960..1492e063a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -490,7 +490,7 @@ bool RendererOpenGL::Init() {
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
- if (!GLAD_GL_VERSION_3_3) {
+ if (!GLAD_GL_VERSION_4_3) {
return false;
}