aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp7
-rw-r--r--src/video_core/engines/maxwell_3d.h142
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp161
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp152
-rw-r--r--src/video_core/renderer_opengl/gl_state.h32
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h6
-rw-r--r--src/video_core/textures/decoders.cpp85
-rw-r--r--src/video_core/textures/decoders.h7
-rw-r--r--src/video_core/textures/texture.h15
12 files changed, 368 insertions, 259 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 6de07ea56..a04e00ecb 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -34,8 +34,8 @@ void Maxwell3D::InitializeRegisterDefaults() {
// Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is
// needed for ARMS.
for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) {
- regs.viewport[viewport].depth_range_near = 0.0f;
- regs.viewport[viewport].depth_range_far = 1.0f;
+ regs.viewports[viewport].depth_range_near = 0.0f;
+ regs.viewports[viewport].depth_range_far = 1.0f;
}
// Doom and Bomberman seems to use the uninitialized registers and just enable blend
// so initialize blend registers with sane values
@@ -66,6 +66,9 @@ void Maxwell3D::InitializeRegisterDefaults() {
regs.stencil_back_func_func = Regs::ComparisonOp::Always;
regs.stencil_back_func_mask = 0xFFFFFFFF;
regs.stencil_back_mask = 0xFFFFFFFF;
+ // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
+ // register carrying a default value. Assume it's OpenGL's default (1).
+ regs.point_size = 1.0f;
}
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 91ca57883..9e480dc39 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -480,6 +480,67 @@ public:
};
};
+ struct ViewportTransform {
+ f32 scale_x;
+ f32 scale_y;
+ f32 scale_z;
+ f32 translate_x;
+ f32 translate_y;
+ f32 translate_z;
+ INSERT_PADDING_WORDS(2);
+
+ MathUtil::Rectangle<s32> GetRect() const {
+ return {
+ GetX(), // left
+ GetY() + GetHeight(), // top
+ GetX() + GetWidth(), // right
+ GetY() // bottom
+ };
+ };
+
+ s32 GetX() const {
+ return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x)));
+ }
+
+ s32 GetY() const {
+ return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y)));
+ }
+
+ s32 GetWidth() const {
+ return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX();
+ }
+
+ s32 GetHeight() const {
+ return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
+ }
+ };
+
+ struct ScissorTest {
+ u32 enable;
+ union {
+ BitField<0, 16, u32> min_x;
+ BitField<16, 16, u32> max_x;
+ };
+ union {
+ BitField<0, 16, u32> min_y;
+ BitField<16, 16, u32> max_y;
+ };
+ u32 fill;
+ };
+
+ struct ViewPort {
+ union {
+ BitField<0, 16, u32> x;
+ BitField<16, 16, u32> width;
+ };
+ union {
+ BitField<0, 16, u32> y;
+ BitField<16, 16, u32> height;
+ };
+ float depth_range_near;
+ float depth_range_far;
+ };
+
bool IsShaderConfigEnabled(std::size_t index) const {
// The VertexB is always enabled.
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
@@ -505,55 +566,11 @@ public:
INSERT_PADDING_WORDS(0x2E);
- RenderTargetConfig rt[NumRenderTargets];
-
- struct {
- f32 scale_x;
- f32 scale_y;
- f32 scale_z;
- f32 translate_x;
- f32 translate_y;
- f32 translate_z;
- INSERT_PADDING_WORDS(2);
-
- MathUtil::Rectangle<s32> GetRect() const {
- return {
- GetX(), // left
- GetY() + GetHeight(), // top
- GetX() + GetWidth(), // right
- GetY() // bottom
- };
- };
-
- s32 GetX() const {
- return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x)));
- }
+ std::array<RenderTargetConfig, NumRenderTargets> rt;
- s32 GetY() const {
- return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y)));
- }
+ std::array<ViewportTransform, NumViewports> viewport_transform;
- s32 GetWidth() const {
- return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX();
- }
-
- s32 GetHeight() const {
- return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
- }
- } viewport_transform[NumViewports];
-
- struct {
- union {
- BitField<0, 16, u32> x;
- BitField<16, 16, u32> width;
- };
- union {
- BitField<0, 16, u32> y;
- BitField<16, 16, u32> height;
- };
- float depth_range_near;
- float depth_range_far;
- } viewport[NumViewports];
+ std::array<ViewPort, NumViewports> viewports;
INSERT_PADDING_WORDS(0x1D);
@@ -571,19 +588,9 @@ public:
INSERT_PADDING_WORDS(0x17);
- struct {
- u32 enable;
- union {
- BitField<0, 16, u32> min_x;
- BitField<16, 16, u32> max_x;
- };
- union {
- BitField<0, 16, u32> min_y;
- BitField<16, 16, u32> max_y;
- };
- } scissor_test;
+ std::array<ScissorTest, NumViewports> scissor_test;
- INSERT_PADDING_WORDS(0x52);
+ INSERT_PADDING_WORDS(0x15);
s32 stencil_back_func_ref;
u32 stencil_back_mask;
@@ -700,7 +707,9 @@ public:
u32 stencil_front_func_mask;
u32 stencil_front_mask;
- INSERT_PADDING_WORDS(0x3);
+ INSERT_PADDING_WORDS(0x2);
+
+ u32 frag_color_clamp;
union {
BitField<4, 1, u32> triangle_rast_flip;
@@ -718,7 +727,12 @@ public:
u32 zeta_enable;
- INSERT_PADDING_WORDS(0x8);
+ union {
+ BitField<0, 1, u32> alpha_to_coverage;
+ BitField<4, 1, u32> alpha_to_one;
+ } multisample_control;
+
+ INSERT_PADDING_WORDS(0x7);
struct {
u32 tsc_address_high;
@@ -1100,8 +1114,8 @@ private:
ASSERT_REG_POSITION(macros, 0x45);
ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
ASSERT_REG_POSITION(rt, 0x200);
-ASSERT_REG_POSITION(viewport_transform[0], 0x280);
-ASSERT_REG_POSITION(viewport, 0x300);
+ASSERT_REG_POSITION(viewport_transform, 0x280);
+ASSERT_REG_POSITION(viewports, 0x300);
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(clear_color[0], 0x360);
ASSERT_REG_POSITION(clear_depth, 0x364);
@@ -1136,10 +1150,12 @@ ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4);
ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5);
ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
+ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
+ASSERT_REG_POSITION(multisample_control, 0x54F);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 54cc47a9b..ae6aaee4c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -107,8 +107,6 @@ 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;
// Create render framebuffer
framebuffer.Create();
@@ -582,6 +580,8 @@ void RasterizerOpenGL::DrawArrays() {
ConfigureFramebuffers(state);
SyncColorMask();
+ SyncFragmentColorClampState();
+ SyncMultiSampleState();
SyncDepthTestState();
SyncStencilTestState();
SyncBlendState();
@@ -642,7 +642,7 @@ void RasterizerOpenGL::DrawArrays() {
params.DispatchDraw();
// Disable scissor test
- state.scissor.enabled = false;
+ state.viewports[0].scissor.enabled = false;
accelerate_draw = AccelDraw::Disabled;
@@ -733,9 +733,8 @@ void RasterizerOpenGL::SamplerInfo::Create() {
glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
}
-void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) {
+void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
const GLuint s = sampler.handle;
- const Tegra::Texture::TSCEntry& config = info.tsc;
if (mag_filter != config.mag_filter) {
mag_filter = config.mag_filter;
glSamplerParameteri(
@@ -777,30 +776,50 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex
MaxwellToGL::DepthCompareFunc(depth_compare_func));
}
- if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border ||
- wrap_p == Tegra::Texture::WrapMode::Border) {
- const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
- config.border_color_b, config.border_color_a}};
- if (border_color != new_border_color) {
- border_color = new_border_color;
- glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
- }
+ GLvec4 new_border_color;
+ if (config.srgb_conversion) {
+ new_border_color[0] = config.srgb_border_color_r / 255.0f;
+ new_border_color[1] = config.srgb_border_color_g / 255.0f;
+ new_border_color[2] = config.srgb_border_color_g / 255.0f;
+ } else {
+ new_border_color[0] = config.border_color_r;
+ new_border_color[1] = config.border_color_g;
+ new_border_color[2] = config.border_color_b;
}
- if (info.tic.use_header_opt_control == 0) {
+ new_border_color[3] = config.border_color_a;
+
+ if (border_color != new_border_color) {
+ border_color = new_border_color;
+ glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
+ }
+
+ const float anisotropic_max = static_cast<float>(1 << config.max_anisotropy.Value());
+ if (anisotropic_max != max_anisotropic) {
+ max_anisotropic = anisotropic_max;
if (GLAD_GL_ARB_texture_filter_anisotropic) {
- glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY,
- static_cast<float>(1 << info.tic.max_anisotropy.Value()));
+ glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic);
} else if (GLAD_GL_EXT_texture_filter_anisotropic) {
- glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- static_cast<float>(1 << info.tic.max_anisotropy.Value()));
+ glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic);
}
- glSamplerParameterf(s, GL_TEXTURE_MIN_LOD,
- static_cast<float>(info.tic.res_min_mip_level.Value()));
- glSamplerParameterf(s, GL_TEXTURE_MAX_LOD,
- static_cast<float>(info.tic.res_max_mip_level.Value() == 0
- ? 16
- : info.tic.res_max_mip_level.Value()));
- glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f);
+ }
+ const float lod_min = static_cast<float>(config.min_lod_clamp.Value()) / 256.0f;
+ if (lod_min != min_lod) {
+ min_lod = lod_min;
+ glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, min_lod);
+ }
+
+ const float lod_max = static_cast<float>(config.max_lod_clamp.Value()) / 256.0f;
+ if (lod_max != max_lod) {
+ max_lod = lod_max;
+ glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, max_lod);
+ }
+ const u32 bias = config.mip_lod_bias.Value();
+ // Sign extend the 13-bit value.
+ const 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;
+ glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias);
}
}
@@ -899,7 +918,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
continue;
}
- texture_samplers[current_bindpoint].SyncWithConfig(texture);
+ texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
Surface surface = res_cache.GetTextureSurface(texture, entry);
if (surface != nullptr) {
state.texture_units[current_bindpoint].texture = surface->Texture().handle;
@@ -923,15 +942,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
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.depth_range_far = regs.viewport[i].depth_range_far;
- viewport.depth_range_near = regs.viewport[i].depth_range_near;
+ viewport.depth_range_far = regs.viewports[i].depth_range_far;
+ viewport.depth_range_near = regs.viewports[i].depth_range_near;
}
}
@@ -1022,7 +1041,9 @@ void RasterizerOpenGL::SyncStencilTestState() {
void RasterizerOpenGL::SyncColorMask() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ const std::size_t count =
+ regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1;
+ for (std::size_t i = 0; i < count; i++) {
const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
auto& dest = state.color_mask[i];
dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
@@ -1032,6 +1053,17 @@ void RasterizerOpenGL::SyncColorMask() {
}
}
+void RasterizerOpenGL::SyncMultiSampleState() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0;
+ state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0;
+}
+
+void RasterizerOpenGL::SyncFragmentColorClampState() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0;
+}
+
void RasterizerOpenGL::SyncBlendState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@@ -1043,43 +1075,40 @@ void RasterizerOpenGL::SyncBlendState() {
state.independant_blend.enabled = regs.independent_blend_enable;
if (!state.independant_blend.enabled) {
auto& blend = state.blend[0];
- blend.enabled = regs.blend.enable[0] != 0;
- blend.separate_alpha = regs.blend.separate_alpha;
- blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
- blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
- blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
- if (blend.separate_alpha) {
- blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
- blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
- blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
+ const auto& src = regs.blend;
+ blend.enabled = src.enable[0] != 0;
+ if (blend.enabled) {
+ blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
+ blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
+ blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
+ blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
+ blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
+ blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
}
- for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
state.blend[i].enabled = false;
}
return;
}
- for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
auto& blend = state.blend[i];
+ const auto& src = regs.independent_blend[i];
blend.enabled = regs.blend.enable[i] != 0;
if (!blend.enabled)
continue;
- blend.separate_alpha = regs.independent_blend[i].separate_alpha;
- blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
- blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
- blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
- if (blend.separate_alpha) {
- blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
- blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
- blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
- }
+ blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
+ blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
+ blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
+ blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
+ blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
+ blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
}
}
void RasterizerOpenGL::SyncLogicOpState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- // TODO(Subv): Support more than just render target 0.
state.logic_op.enabled = regs.logic_op.enable != 0;
if (!state.logic_op.enabled)
@@ -1092,19 +1121,21 @@ void RasterizerOpenGL::SyncLogicOpState() {
}
void RasterizerOpenGL::SyncScissorTest() {
- // TODO: what is the correct behavior here, a single scissor for all targets
- // or scissor disabled for the rest of the targets?
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- state.scissor.enabled = (regs.scissor_test.enable != 0);
- if (regs.scissor_test.enable == 0) {
- return;
+ 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;
+ dst.enabled = (src.enable != 0);
+ if (dst.enabled == 0) {
+ return;
+ }
+ const u32 width = src.max_x - src.min_x;
+ const u32 height = src.max_y - src.min_y;
+ dst.x = src.min_x;
+ dst.y = src.min_y;
+ dst.width = width;
+ dst.height = height;
}
- const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
- const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
- state.scissor.x = regs.scissor_test.min_x;
- state.scissor.y = regs.scissor_test.min_y;
- state.scissor.width = width;
- state.scissor.height = height;
}
void RasterizerOpenGL::SyncTransformFeedback() {
@@ -1118,11 +1149,7 @@ void RasterizerOpenGL::SyncTransformFeedback() {
void RasterizerOpenGL::SyncPointState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
-
- // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
- // register carrying a default value. For now, if the point size is zero, assume it's
- // OpenGL's default (1).
- state.point.size = regs.point_size == 0 ? 1 : regs.point_size;
+ state.point.size = regs.point_size;
}
void RasterizerOpenGL::CheckAlphaTests() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 8ef0f6c12..6e78ab4cd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -88,7 +88,7 @@ private:
/// SamplerInfo struct.
void Create();
/// Syncs the sampler object with the config, updating any necessary state.
- void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info);
+ void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
private:
Tegra::Texture::TextureFilter mag_filter;
@@ -100,6 +100,10 @@ private:
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;
};
/**
@@ -160,6 +164,12 @@ private:
/// Syncs the LogicOp state to match the guest state
void SyncLogicOpState();
+ /// Syncs the the color clamp state
+ void SyncFragmentColorClampState();
+
+ /// Syncs the alpha coverage and alpha to one
+ void SyncMultiSampleState();
+
/// Syncs the scissor test state to match the guest state
void SyncScissorTest();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b44ecfa1c..9ca82c06c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -381,11 +381,8 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
const u32 tile_size_y{GetDefaultBlockHeight(format)};
if (morton_to_gl) {
- 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);
+ 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,
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 2a069cdd8..9a5d7e289 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -67,6 +67,7 @@ public:
glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
state.draw.shader_program = 0;
state.draw.program_pipeline = pipeline.handle;
+ state.geometry_shaders.enabled = (gs != 0);
}
private:
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 98622a058..d9910c6e8 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -14,7 +14,10 @@ OpenGLState OpenGLState::cur_state;
bool OpenGLState::s_rgb_used;
OpenGLState::OpenGLState() {
// These all match default OpenGL values
+ geometry_shaders.enabled = false;
framebuffer_srgb.enabled = false;
+ multisample_control.alpha_to_coverage = false;
+ multisample_control.alpha_to_one = false;
cull.enabled = false;
cull.mode = GL_BACK;
cull.front_face = GL_CCW;
@@ -50,12 +53,12 @@ OpenGLState::OpenGLState() {
item.height = 0;
item.depth_range_near = 0.0f;
item.depth_range_far = 1.0f;
+ item.scissor.enabled = false;
+ item.scissor.x = 0;
+ item.scissor.y = 0;
+ item.scissor.width = 0;
+ item.scissor.height = 0;
}
- scissor.enabled = false;
- scissor.x = 0;
- scissor.y = 0;
- scissor.width = 0;
- scissor.height = 0;
for (auto& item : blend) {
item.enabled = true;
item.rgb_equation = GL_FUNC_ADD;
@@ -88,6 +91,7 @@ OpenGLState::OpenGLState() {
clip_distance = {};
point.size = 1;
+ fragment_color_clamp.enabled = false;
}
void OpenGLState::ApplyDefaultState() {
@@ -136,7 +140,7 @@ void OpenGLState::ApplyCulling() const {
}
void OpenGLState::ApplyColorMask() const {
- if (GLAD_GL_ARB_viewport_array) {
+ if (GLAD_GL_ARB_viewport_array && independant_blend.enabled) {
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
const auto& updated = color_mask[i];
const auto& current = cur_state.color_mask[i];
@@ -230,26 +234,10 @@ void OpenGLState::ApplyStencilTest() const {
}
}
-void OpenGLState::ApplyScissor() 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);
- }
- }
- if (scissor.enabled &&
- (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);
- }
-}
-
void OpenGLState::ApplyViewport() const {
- if (GLAD_GL_ARB_viewport_array) {
- for (GLuint i = 0;
- i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
+ if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
+ for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports);
+ i++) {
const auto& current = cur_state.viewports[i];
const auto& updated = viewports[i];
if (updated.x != current.x || updated.y != current.y ||
@@ -260,6 +248,22 @@ void OpenGLState::ApplyViewport() const {
updated.depth_range_far != current.depth_range_far) {
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
}
+ const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
+ if (scissor_changed) {
+ if (updated.scissor.enabled) {
+ glEnablei(GL_SCISSOR_TEST, i);
+ } else {
+ glDisablei(GL_SCISSOR_TEST, i);
+ }
+ }
+ if (updated.scissor.enabled &&
+ (scissor_changed || updated.scissor.x != current.scissor.x ||
+ updated.scissor.y != current.scissor.y ||
+ updated.scissor.width != current.scissor.width ||
+ updated.scissor.height != current.scissor.height)) {
+ glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
+ updated.scissor.height);
+ }
}
} else {
const auto& current = cur_state.viewports[0];
@@ -273,6 +277,21 @@ void OpenGLState::ApplyViewport() const {
updated.depth_range_far != current.depth_range_far) {
glDepthRange(updated.depth_range_near, updated.depth_range_far);
}
+ const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
+ if (scissor_changed) {
+ if (updated.scissor.enabled) {
+ glEnable(GL_SCISSOR_TEST);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ }
+ if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x ||
+ updated.scissor.y != current.scissor.y ||
+ updated.scissor.width != current.scissor.width ||
+ updated.scissor.height != current.scissor.height)) {
+ glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width,
+ updated.scissor.height);
+ }
}
}
@@ -290,27 +309,16 @@ void OpenGLState::ApplyGlobalBlending() const {
if (!updated.enabled) {
return;
}
- if (updated.separate_alpha) {
- 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) {
- glBlendFuncSeparate(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) {
- glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
- }
- } else {
- if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
- updated.dst_rgb_func != current.dst_rgb_func) {
- glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
- }
+ 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) {
+ glBlendFuncSeparate(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) {
- glBlendEquation(updated.rgb_equation);
- }
+ if (blend_changed || updated.rgb_equation != current.rgb_equation ||
+ updated.a_equation != current.a_equation) {
+ glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
}
}
@@ -328,29 +336,17 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
if (!updated.enabled) {
return;
}
- if (updated.separate_alpha) {
- 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);
- }
-
- 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);
- }
- } else {
- if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
- updated.dst_rgb_func != current.dst_rgb_func) {
- glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
- updated.dst_rgb_func);
- }
+ 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);
+ }
- if (blend_changed || updated.rgb_equation != current.rgb_equation) {
- glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
- }
+ 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);
}
}
@@ -481,9 +477,29 @@ void OpenGLState::Apply() const {
if (point.size != cur_state.point.size) {
glPointSize(point.size);
}
+ if (GLAD_GL_ARB_color_buffer_float) {
+ if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) {
+ glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
+ fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
+ }
+ }
+ if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) {
+ if (multisample_control.alpha_to_coverage) {
+ glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ } else {
+ glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ }
+ }
+ if (multisample_control.alpha_to_one != cur_state.multisample_control.alpha_to_one) {
+ if (multisample_control.alpha_to_one) {
+ glEnable(GL_SAMPLE_ALPHA_TO_ONE);
+ } else {
+ glDisable(GL_SAMPLE_ALPHA_TO_ONE);
+ }
+ }
+
ApplyColorMask();
ApplyViewport();
- ApplyScissor();
ApplyStencilTest();
ApplySRgb();
ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index e5d1baae6..bdc743b0f 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -40,6 +40,19 @@ public:
} framebuffer_srgb;
struct {
+ bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE
+ bool alpha_to_one; // GL_ALPHA_TO_ONE
+ } multisample_control;
+
+ struct {
+ bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
+ } fragment_color_clamp;
+
+ struct {
+ bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
+ } geometry_shaders;
+
+ struct {
bool enabled; // GL_CULL_FACE
GLenum mode; // GL_CULL_FACE_MODE
GLenum front_face; // GL_FRONT_FACE
@@ -79,7 +92,6 @@ public:
struct Blend {
bool enabled; // GL_BLEND
- bool separate_alpha; // Independent blend enabled
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
@@ -150,16 +162,15 @@ public:
GLfloat height;
GLfloat depth_range_near; // GL_DEPTH_RANGE
GLfloat depth_range_far; // GL_DEPTH_RANGE
+ struct {
+ bool enabled; // GL_SCISSOR_TEST
+ GLint x;
+ GLint y;
+ GLsizei width;
+ GLsizei height;
+ } scissor;
};
- std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
-
- struct {
- bool enabled; // GL_SCISSOR_TEST
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
- } scissor;
+ std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
struct {
float size; // GL_POINT_SIZE
@@ -214,7 +225,6 @@ private:
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
- void ApplyScissor() const;
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 3ce2cc6d2..065b3929c 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -180,6 +180,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
return GL_CLAMP_TO_BORDER;
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
return GL_MIRROR_CLAMP_TO_EDGE;
+ case Tegra::Texture::WrapMode::MirrorOnceBorder:
+ if (GL_EXT_texture_mirror_clamp) {
+ return GL_MIRROR_CLAMP_TO_BORDER_EXT;
+ } else {
+ return GL_MIRROR_CLAMP_TO_EDGE;
+ }
}
LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
return GL_REPEAT;
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 19f30b1b5..7eabd34f1 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -37,8 +37,14 @@ struct alignas(64) SwizzleTable {
std::array<std::array<u16, M>, N> values{};
};
-constexpr auto legacy_swizzle_table = SwizzleTable<8, 64, 1>();
-constexpr auto fast_swizzle_table = SwizzleTable<8, 4, 16>();
+constexpr u32 gob_size_x = 64;
+constexpr u32 gob_size_y = 8;
+constexpr u32 gob_size_z = 1;
+constexpr u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
+constexpr u32 fast_swizzle_align = 16;
+
+constexpr auto legacy_swizzle_table = SwizzleTable<gob_size_y, gob_size_x, gob_size_z>();
+constexpr auto fast_swizzle_table = SwizzleTable<gob_size_y, 4, fast_swizzle_align>();
/**
* This function manages ALL the GOBs(Group of Bytes) Inside a single block.
@@ -52,10 +58,7 @@ void PreciseProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, con
const u32 bytes_per_pixel, const u32 out_bytes_per_pixel) {
std::array<u8*, 2> data_ptrs;
u32 z_address = tile_offset;
- const u32 gob_size_x = 64;
- const u32 gob_size_y = 8;
- const u32 gob_size_z = 1;
- const u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
+
for (u32 z = z_start; z < z_end; z++) {
u32 y_address = z_address;
u32 pixel_base = layer_z * z + y_start * stride_x;
@@ -90,23 +93,19 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const
u32 z_address = tile_offset;
const u32 x_startb = x_start * bytes_per_pixel;
const u32 x_endb = x_end * bytes_per_pixel;
- constexpr u32 copy_size = 16;
- constexpr u32 gob_size_x = 64;
- constexpr u32 gob_size_y = 8;
- constexpr u32 gob_size_z = 1;
- const u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
+
for (u32 z = z_start; z < z_end; z++) {
u32 y_address = z_address;
u32 pixel_base = layer_z * z + y_start * stride_x;
for (u32 y = y_start; y < y_end; y++) {
const auto& table = fast_swizzle_table[y % gob_size_y];
- for (u32 xb = x_startb; xb < x_endb; xb += copy_size) {
- const u32 swizzle_offset{y_address + table[(xb / copy_size) % 4]};
+ for (u32 xb = x_startb; xb < x_endb; xb += fast_swizzle_align) {
+ const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]};
const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
const u32 pixel_index{out_x + pixel_base};
data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
- std::memcpy(data_ptrs[0], data_ptrs[1], copy_size);
+ std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align);
}
pixel_base += stride_x;
if ((y + 1) % gob_size_y == 0)
@@ -132,17 +131,15 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool
auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); };
const u32 stride_x = width * out_bytes_per_pixel;
const u32 layer_z = height * stride_x;
- constexpr u32 gob_x_bytes = 64;
- const u32 gob_elements_x = gob_x_bytes / bytes_per_pixel;
- constexpr u32 gob_elements_y = 8;
- constexpr u32 gob_elements_z = 1;
+ const u32 gob_elements_x = gob_size_x / bytes_per_pixel;
+ constexpr u32 gob_elements_y = gob_size_y;
+ constexpr u32 gob_elements_z = gob_size_z;
const u32 block_x_elements = gob_elements_x;
const u32 block_y_elements = gob_elements_y * block_height;
const u32 block_z_elements = gob_elements_z * block_depth;
const u32 blocks_on_x = div_ceil(width, block_x_elements);
const u32 blocks_on_y = div_ceil(height, block_y_elements);
const u32 blocks_on_z = div_ceil(depth, block_z_elements);
- constexpr u32 gob_size = gob_x_bytes * gob_elements_y * gob_elements_z;
const u32 xy_block_size = gob_size * block_height;
const u32 block_size = xy_block_size * block_depth;
u32 tile_offset = 0;
@@ -173,7 +170,7 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool
void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
u32 out_bytes_per_pixel, u8* const swizzled_data, u8* const unswizzled_data,
bool unswizzle, u32 block_height, u32 block_depth) {
- if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) {
+ if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) {
SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth,
bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth);
} else {
@@ -229,29 +226,38 @@ u32 BytesPerPixel(TextureFormat format) {
}
}
+void UnswizzleTexture(u8* const unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
+ u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height,
+ u32 block_depth) {
+ CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
+ (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
+ bytes_per_pixel, Memory::GetPointer(address), unswizzled_data, true,
+ block_height, block_depth);
+}
+
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
u32 block_height, u32 block_depth) {
std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel);
- CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
- (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
- bytes_per_pixel, Memory::GetPointer(address), unswizzled_data.data(), true,
- block_height, block_depth);
+ UnswizzleTexture(unswizzled_data.data(), address, tile_size_x, tile_size_y, bytes_per_pixel,
+ width, height, depth, block_height, block_depth);
return unswizzled_data;
}
void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
u32 block_height) {
- const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + 63) / 64};
+ const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) /
+ gob_size_x};
for (u32 line = 0; line < subrect_height; ++line) {
const u32 gob_address_y =
- (line / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
- (line % (8 * block_height) / 8) * 512;
- const auto& table = legacy_swizzle_table[line % 8];
+ (line / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs +
+ ((line % (gob_size_y * block_height)) / gob_size_y) * gob_size;
+ const auto& table = legacy_swizzle_table[line % gob_size_y];
for (u32 x = 0; x < subrect_width; ++x) {
- const u32 gob_address = gob_address_y + (x * bytes_per_pixel / 64) * 512 * block_height;
- const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % 64];
+ const u32 gob_address =
+ gob_address_y + (x * bytes_per_pixel / gob_size_x) * gob_size * block_height;
+ const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % gob_size_x];
const VAddr source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel;
const VAddr dest_addr = swizzled_data + swizzled_offset;
@@ -265,13 +271,13 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32
u32 block_height, u32 offset_x, u32 offset_y) {
for (u32 line = 0; line < subrect_height; ++line) {
const u32 y2 = line + offset_y;
- const u32 gob_address_y =
- (y2 / (8 * block_height)) * 512 * block_height + (y2 % (8 * block_height) / 8) * 512;
- const auto& table = legacy_swizzle_table[y2 % 8];
+ const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height +
+ ((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size;
+ const auto& table = legacy_swizzle_table[y2 % gob_size_y];
for (u32 x = 0; x < subrect_width; ++x) {
const u32 x2 = (x + offset_x) * bytes_per_pixel;
- const u32 gob_address = gob_address_y + (x2 / 64) * 512 * block_height;
- const u32 swizzled_offset = gob_address + table[x2 % 64];
+ const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height;
+ const u32 swizzled_offset = gob_address + table[x2 % gob_size_x];
const VAddr dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel;
const VAddr source_addr = swizzled_data + swizzled_offset;
@@ -325,12 +331,9 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
u32 block_height, u32 block_depth) {
if (tiled) {
- constexpr u32 gobs_in_x = 64;
- constexpr u32 gobs_in_y = 8;
- constexpr u32 gobs_in_z = 1;
- const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gobs_in_x);
- const u32 aligned_height = Common::AlignUp(height, gobs_in_y * block_height);
- const u32 aligned_depth = Common::AlignUp(depth, gobs_in_z * block_depth);
+ const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x);
+ const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height);
+ const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth);
return aligned_width * aligned_height * aligned_depth;
} else {
return width * height * depth * bytes_per_pixel;
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index ba065510b..f4ef7c73e 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -19,6 +19,13 @@ inline std::size_t GetGOBSize() {
/**
* Unswizzles a swizzled texture without changing its format.
*/
+void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
+ u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
+ u32 block_height = TICEntry::DefaultBlockHeight,
+ u32 block_depth = TICEntry::DefaultBlockHeight);
+/**
+ * Unswizzles a swizzled texture without changing its format.
+ */
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
u32 block_height = TICEntry::DefaultBlockHeight,
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index e199d019a..ffa08f5c1 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -190,6 +190,7 @@ struct TICEntry {
union {
BitField<0, 4, u32> res_min_mip_level;
BitField<4, 4, u32> res_max_mip_level;
+ BitField<12, 12, u32> min_lod_clamp;
};
GPUVAddr Address() const {
@@ -284,13 +285,25 @@ struct TSCEntry {
BitField<6, 3, WrapMode> wrap_p;
BitField<9, 1, u32> depth_compare_enabled;
BitField<10, 3, DepthCompareFunc> depth_compare_func;
+ BitField<13, 1, u32> srgb_conversion;
+ BitField<20, 3, u32> max_anisotropy;
};
union {
BitField<0, 2, TextureFilter> mag_filter;
BitField<4, 2, TextureFilter> min_filter;
BitField<6, 2, TextureMipmapFilter> mip_filter;
+ BitField<9, 1, u32> cubemap_interface_filtering;
+ BitField<12, 13, u32> mip_lod_bias;
+ };
+ union {
+ BitField<0, 12, u32> min_lod_clamp;
+ BitField<12, 12, u32> max_lod_clamp;
+ BitField<24, 8, u32> srgb_border_color_r;
+ };
+ union {
+ BitField<12, 8, u32> srgb_border_color_g;
+ BitField<20, 8, u32> srgb_border_color_b;
};
- INSERT_PADDING_BYTES(8);
float border_color_r;
float border_color_g;
float border_color_b;