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.cpp209
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp210
-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.cpp4
7 files changed, 236 insertions, 313 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..d458f77e4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -15,6 +15,7 @@
#include "core/memory.h"
#include "core/settings.h"
#include "video_core/engines/maxwell_3d.h"
+#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_state.h"
@@ -22,10 +23,11 @@
#include "video_core/surface.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
-#include "video_core/utils.h"
namespace OpenGL {
+using VideoCore::MortonSwizzle;
+using VideoCore::MortonSwizzleMode;
using VideoCore::Surface::ComponentTypeFromDepthFormat;
using VideoCore::Surface::ComponentTypeFromRenderTarget;
using VideoCore::Surface::ComponentTypeFromTexture;
@@ -265,11 +267,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 +308,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 +348,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();
@@ -370,174 +372,7 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
return {0, actual_height, MipWidth(mip_level), 0};
}
-template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
- std::size_t gl_buffer_size, VAddr addr) {
- constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
-
- // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
- // pixel values.
- const u32 tile_size_x{GetDefaultBlockWidth(format)};
- const u32 tile_size_y{GetDefaultBlockHeight(format)};
-
- if (morton_to_gl) {
- Tegra::Texture::UnswizzleTexture(gl_buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel,
- stride, height, depth, block_height, block_depth);
- } else {
- 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);
- }
-}
-
-using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
- VideoCore::Surface::MaxPixelFormat>;
-
-static constexpr GLConversionArray morton_to_gl_fns = {
- // clang-format off
- MortonCopy<true, PixelFormat::ABGR8U>,
- MortonCopy<true, PixelFormat::ABGR8S>,
- MortonCopy<true, PixelFormat::ABGR8UI>,
- MortonCopy<true, PixelFormat::B5G6R5U>,
- MortonCopy<true, PixelFormat::A2B10G10R10U>,
- MortonCopy<true, PixelFormat::A1B5G5R5U>,
- MortonCopy<true, PixelFormat::R8U>,
- MortonCopy<true, PixelFormat::R8UI>,
- MortonCopy<true, PixelFormat::RGBA16F>,
- MortonCopy<true, PixelFormat::RGBA16U>,
- MortonCopy<true, PixelFormat::RGBA16UI>,
- MortonCopy<true, PixelFormat::R11FG11FB10F>,
- MortonCopy<true, PixelFormat::RGBA32UI>,
- MortonCopy<true, PixelFormat::DXT1>,
- MortonCopy<true, PixelFormat::DXT23>,
- MortonCopy<true, PixelFormat::DXT45>,
- MortonCopy<true, PixelFormat::DXN1>,
- MortonCopy<true, PixelFormat::DXN2UNORM>,
- MortonCopy<true, PixelFormat::DXN2SNORM>,
- MortonCopy<true, PixelFormat::BC7U>,
- MortonCopy<true, PixelFormat::BC6H_UF16>,
- MortonCopy<true, PixelFormat::BC6H_SF16>,
- MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
- MortonCopy<true, PixelFormat::G8R8U>,
- MortonCopy<true, PixelFormat::G8R8S>,
- MortonCopy<true, PixelFormat::BGRA8>,
- MortonCopy<true, PixelFormat::RGBA32F>,
- MortonCopy<true, PixelFormat::RG32F>,
- MortonCopy<true, PixelFormat::R32F>,
- MortonCopy<true, PixelFormat::R16F>,
- MortonCopy<true, PixelFormat::R16U>,
- MortonCopy<true, PixelFormat::R16S>,
- MortonCopy<true, PixelFormat::R16UI>,
- MortonCopy<true, PixelFormat::R16I>,
- MortonCopy<true, PixelFormat::RG16>,
- MortonCopy<true, PixelFormat::RG16F>,
- MortonCopy<true, PixelFormat::RG16UI>,
- MortonCopy<true, PixelFormat::RG16I>,
- MortonCopy<true, PixelFormat::RG16S>,
- MortonCopy<true, PixelFormat::RGB32F>,
- MortonCopy<true, PixelFormat::RGBA8_SRGB>,
- MortonCopy<true, PixelFormat::RG8U>,
- MortonCopy<true, PixelFormat::RG8S>,
- MortonCopy<true, PixelFormat::RG32UI>,
- MortonCopy<true, PixelFormat::R32UI>,
- MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
- MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
- MortonCopy<true, PixelFormat::ASTC_2D_5X4>,
- MortonCopy<true, PixelFormat::BGRA8_SRGB>,
- MortonCopy<true, PixelFormat::DXT1_SRGB>,
- MortonCopy<true, PixelFormat::DXT23_SRGB>,
- MortonCopy<true, PixelFormat::DXT45_SRGB>,
- MortonCopy<true, PixelFormat::BC7U_SRGB>,
- MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
- 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::ASTC_2D_10X8>,
- MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
- MortonCopy<true, PixelFormat::Z32F>,
- MortonCopy<true, PixelFormat::Z16>,
- MortonCopy<true, PixelFormat::Z24S8>,
- MortonCopy<true, PixelFormat::S8Z24>,
- MortonCopy<true, PixelFormat::Z32FS8>,
- // clang-format on
-};
-
-static constexpr GLConversionArray gl_to_morton_fns = {
- // clang-format off
- MortonCopy<false, PixelFormat::ABGR8U>,
- MortonCopy<false, PixelFormat::ABGR8S>,
- MortonCopy<false, PixelFormat::ABGR8UI>,
- MortonCopy<false, PixelFormat::B5G6R5U>,
- MortonCopy<false, PixelFormat::A2B10G10R10U>,
- MortonCopy<false, PixelFormat::A1B5G5R5U>,
- MortonCopy<false, PixelFormat::R8U>,
- MortonCopy<false, PixelFormat::R8UI>,
- MortonCopy<false, PixelFormat::RGBA16F>,
- MortonCopy<false, PixelFormat::RGBA16U>,
- MortonCopy<false, PixelFormat::RGBA16UI>,
- MortonCopy<false, PixelFormat::R11FG11FB10F>,
- MortonCopy<false, PixelFormat::RGBA32UI>,
- MortonCopy<false, PixelFormat::DXT1>,
- MortonCopy<false, PixelFormat::DXT23>,
- MortonCopy<false, PixelFormat::DXT45>,
- MortonCopy<false, PixelFormat::DXN1>,
- MortonCopy<false, PixelFormat::DXN2UNORM>,
- MortonCopy<false, PixelFormat::DXN2SNORM>,
- MortonCopy<false, PixelFormat::BC7U>,
- MortonCopy<false, PixelFormat::BC6H_UF16>,
- MortonCopy<false, PixelFormat::BC6H_SF16>,
- // TODO(Subv): Swizzling ASTC formats are not supported
- nullptr,
- MortonCopy<false, PixelFormat::G8R8U>,
- MortonCopy<false, PixelFormat::G8R8S>,
- MortonCopy<false, PixelFormat::BGRA8>,
- MortonCopy<false, PixelFormat::RGBA32F>,
- MortonCopy<false, PixelFormat::RG32F>,
- MortonCopy<false, PixelFormat::R32F>,
- MortonCopy<false, PixelFormat::R16F>,
- MortonCopy<false, PixelFormat::R16U>,
- MortonCopy<false, PixelFormat::R16S>,
- MortonCopy<false, PixelFormat::R16UI>,
- MortonCopy<false, PixelFormat::R16I>,
- MortonCopy<false, PixelFormat::RG16>,
- MortonCopy<false, PixelFormat::RG16F>,
- MortonCopy<false, PixelFormat::RG16UI>,
- MortonCopy<false, PixelFormat::RG16I>,
- MortonCopy<false, PixelFormat::RG16S>,
- MortonCopy<false, PixelFormat::RGB32F>,
- MortonCopy<false, PixelFormat::RGBA8_SRGB>,
- MortonCopy<false, PixelFormat::RG8U>,
- MortonCopy<false, PixelFormat::RG8S>,
- MortonCopy<false, PixelFormat::RG32UI>,
- MortonCopy<false, PixelFormat::R32UI>,
- nullptr,
- nullptr,
- nullptr,
- MortonCopy<false, PixelFormat::BGRA8_SRGB>,
- MortonCopy<false, PixelFormat::DXT1_SRGB>,
- MortonCopy<false, PixelFormat::DXT23_SRGB>,
- MortonCopy<false, PixelFormat::DXT45_SRGB>,
- MortonCopy<false, PixelFormat::BC7U_SRGB>,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- MortonCopy<false, PixelFormat::Z32F>,
- MortonCopy<false, PixelFormat::Z16>,
- MortonCopy<false, PixelFormat::Z24S8>,
- MortonCopy<false, PixelFormat::S8Z24>,
- MortonCopy<false, PixelFormat::Z32FS8>,
- // clang-format on
-};
-
-void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
+void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
std::vector<u8>& gl_buffer, u32 mip_level) {
u32 depth = params.MipDepth(mip_level);
if (params.target == SurfaceTarget::Texture2D) {
@@ -550,19 +385,19 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
const u64 layer_size = params.LayerMemorySize();
const u64 gl_size = params.LayerSizeGL(mip_level);
for (u32 i = 0; i < params.depth; i++) {
- functions[static_cast<std::size_t>(params.pixel_format)](
- params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
- params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,
- gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
+ MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
+ params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
+ params.MipBlockDepth(mip_level), 1, gl_buffer.data() + offset_gl, gl_size,
+ params.addr + offset);
offset += layer_size;
offset_gl += gl_size;
}
} else {
const u64 offset = params.GetMipmapLevelOffset(mip_level);
- functions[static_cast<std::size_t>(params.pixel_format)](
- params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
- params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(),
- gl_buffer.size(), params.addr + offset);
+ MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
+ params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
+ params.MipBlockDepth(mip_level), depth, gl_buffer.data(), gl_buffer.size(),
+ params.addr + offset);
}
}
@@ -726,7 +561,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);
@@ -996,7 +831,7 @@ void CachedSurface::LoadGLBuffer() {
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
for (u32 i = 0; i < params.max_mip_level; i++)
- SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);
+ SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i);
} else {
const auto texture_src_data{Memory::GetPointer(params.addr)};
const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
@@ -1035,7 +870,7 @@ void CachedSurface::FlushGLBuffer() {
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
- SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);
+ SwizzleFunc(MortonSwizzleMode::LinearToMorton, params, gl_buffer[0], 0);
} else {
std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8c43f0ead..9dbaf26d4 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;
@@ -267,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
@@ -381,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.");
}
}
@@ -464,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 + ';');
}
/**
@@ -495,27 +500,42 @@ public:
const Register& buf_reg) {
const std::string dest = GetOutputAttribute(attribute);
const std::string src = GetRegisterAsFloat(val_reg);
+ if (dest.empty())
+ return;
- if (!dest.empty()) {
- // Can happen with unknown/unimplemented output attributes, in which case we ignore the
- // instruction for now.
- if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
- // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
- // shader. These instructions use a dirty register as buffer index, to avoid some
- // drivers from complaining about out of boundary writes, guard them.
- const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
- std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
- shader.AddLine("amem[" + buf_index + "][" +
- std::to_string(static_cast<u32>(attribute)) + ']' +
- GetSwizzle(elem) + " = " + src + ';');
- } else {
- if (attribute == Attribute::Index::PointSize) {
- fixed_pipeline_output_attributes_used.insert(attribute);
- shader.AddLine(dest + " = " + src + ';');
- } else {
- shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
- }
- }
+ // Can happen with unknown/unimplemented output attributes, in which case we ignore the
+ // instruction for now.
+ if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
+ // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
+ // shader. These instructions use a dirty register as buffer index, to avoid some
+ // drivers from complaining about out of boundary writes, guard them.
+ const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
+ std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
+ shader.AddLine("amem[" + buf_index + "][" +
+ std::to_string(static_cast<u32>(attribute)) + ']' + GetSwizzle(elem) +
+ " = " + src + ';');
+ return;
+ }
+
+ switch (attribute) {
+ case Attribute::Index::ClipDistances0123:
+ case Attribute::Index::ClipDistances4567: {
+ const u64 index = attribute == Attribute::Index::ClipDistances4567 ? 4 : 0 + elem;
+ UNIMPLEMENTED_IF_MSG(
+ ((header.vtg.clip_distances >> index) & 1) == 0,
+ "Shader is setting gl_ClipDistance{} without enabling it in the header", index);
+
+ fixed_pipeline_output_attributes_used.insert(attribute);
+ shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
+ break;
+ }
+ case Attribute::Index::PointSize:
+ fixed_pipeline_output_attributes_used.insert(attribute);
+ shader.AddLine(dest + " = " + src + ';');
+ break;
+ default:
+ shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
+ break;
}
}
@@ -631,8 +651,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();
@@ -735,12 +755,19 @@ private:
void GenerateVertex() {
if (stage != Maxwell3D::Regs::ShaderStage::Vertex)
return;
+ bool clip_distances_declared = false;
+
declarations.AddLine("out gl_PerVertex {");
++declarations.scope;
declarations.AddLine("vec4 gl_Position;");
for (auto& o : fixed_pipeline_output_attributes_used) {
if (o == Attribute::Index::PointSize)
declarations.AddLine("float gl_PointSize;");
+ if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 ||
+ o == Attribute::Index::ClipDistances4567)) {
+ declarations.AddLine("float gl_ClipDistance[];");
+ clip_distances_declared = true;
+ }
}
--declarations.scope;
declarations.AddLine("};");
@@ -911,6 +938,10 @@ private:
return "gl_PointSize";
case Attribute::Index::Position:
return "position";
+ case Attribute::Index::ClipDistances0123:
+ case Attribute::Index::ClipDistances4567: {
+ return "gl_ClipDistance";
+ }
default:
const u32 index{static_cast<u32>(attribute) -
static_cast<u32>(Attribute::Index::Attribute_0)};
@@ -1526,9 +1557,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);
@@ -1540,7 +1570,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);
@@ -1590,7 +1620,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);
@@ -1627,7 +1657,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) + " * " +
@@ -1637,7 +1667,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);
@@ -1672,7 +1702,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()) + ')';
@@ -1709,7 +1740,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
@@ -1724,8 +1756,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: {
@@ -1741,7 +1773,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 + ')';
@@ -1751,7 +1783,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 + ')';
@@ -1790,7 +1822,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 + ')';
@@ -1806,7 +1838,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);
@@ -1869,7 +1901,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 + ')';
@@ -1904,7 +1936,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 + ')';
@@ -1920,7 +1953,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;
@@ -1939,7 +1972,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);
@@ -2112,7 +2145,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: {
@@ -2222,7 +2256,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{};
@@ -2252,7 +2287,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) {
@@ -2290,7 +2326,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) {
@@ -3201,7 +3238,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);
@@ -3260,14 +3298,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;
}
@@ -3398,7 +3436,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;
@@ -3490,9 +3529,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();
@@ -3524,9 +3563,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.
@@ -3588,9 +3627,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; }");
@@ -3633,9 +3672,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();
@@ -3643,10 +3682,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;
}
@@ -3657,6 +3696,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);
@@ -3676,10 +3718,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: {
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..4fd0d66c5 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -19,9 +19,9 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tracer/recorder.h"
+#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
-#include "video_core/utils.h"
namespace OpenGL {
@@ -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;
}