mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-26 08:42:45 +01:00
commit
6dc33fb812
9 changed files with 317 additions and 213 deletions
|
@ -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
|
// Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is
|
||||||
// needed for ARMS.
|
// needed for ARMS.
|
||||||
for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) {
|
for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) {
|
||||||
regs.viewport[viewport].depth_range_near = 0.0f;
|
regs.viewports[viewport].depth_range_near = 0.0f;
|
||||||
regs.viewport[viewport].depth_range_far = 1.0f;
|
regs.viewports[viewport].depth_range_far = 1.0f;
|
||||||
}
|
}
|
||||||
// Doom and Bomberman seems to use the uninitialized registers and just enable blend
|
// Doom and Bomberman seems to use the uninitialized registers and just enable blend
|
||||||
// so initialize blend registers with sane values
|
// 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_func = Regs::ComparisonOp::Always;
|
||||||
regs.stencil_back_func_mask = 0xFFFFFFFF;
|
regs.stencil_back_func_mask = 0xFFFFFFFF;
|
||||||
regs.stencil_back_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) {
|
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
|
||||||
|
|
|
@ -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 {
|
bool IsShaderConfigEnabled(std::size_t index) const {
|
||||||
// The VertexB is always enabled.
|
// The VertexB is always enabled.
|
||||||
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
|
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
|
||||||
|
@ -505,55 +566,11 @@ public:
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x2E);
|
INSERT_PADDING_WORDS(0x2E);
|
||||||
|
|
||||||
RenderTargetConfig rt[NumRenderTargets];
|
std::array<RenderTargetConfig, NumRenderTargets> rt;
|
||||||
|
|
||||||
struct {
|
std::array<ViewportTransform, NumViewports> viewport_transform;
|
||||||
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 {
|
std::array<ViewPort, NumViewports> viewports;
|
||||||
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();
|
|
||||||
}
|
|
||||||
} 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];
|
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x1D);
|
INSERT_PADDING_WORDS(0x1D);
|
||||||
|
|
||||||
|
@ -571,19 +588,9 @@ public:
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x17);
|
INSERT_PADDING_WORDS(0x17);
|
||||||
|
|
||||||
struct {
|
std::array<ScissorTest, NumViewports> scissor_test;
|
||||||
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;
|
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x52);
|
INSERT_PADDING_WORDS(0x15);
|
||||||
|
|
||||||
s32 stencil_back_func_ref;
|
s32 stencil_back_func_ref;
|
||||||
u32 stencil_back_mask;
|
u32 stencil_back_mask;
|
||||||
|
@ -700,7 +707,9 @@ public:
|
||||||
u32 stencil_front_func_mask;
|
u32 stencil_front_func_mask;
|
||||||
u32 stencil_front_mask;
|
u32 stencil_front_mask;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x3);
|
INSERT_PADDING_WORDS(0x2);
|
||||||
|
|
||||||
|
u32 frag_color_clamp;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<4, 1, u32> triangle_rast_flip;
|
BitField<4, 1, u32> triangle_rast_flip;
|
||||||
|
@ -718,7 +727,12 @@ public:
|
||||||
|
|
||||||
u32 zeta_enable;
|
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 {
|
struct {
|
||||||
u32 tsc_address_high;
|
u32 tsc_address_high;
|
||||||
|
@ -1100,8 +1114,8 @@ private:
|
||||||
ASSERT_REG_POSITION(macros, 0x45);
|
ASSERT_REG_POSITION(macros, 0x45);
|
||||||
ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
|
ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
|
||||||
ASSERT_REG_POSITION(rt, 0x200);
|
ASSERT_REG_POSITION(rt, 0x200);
|
||||||
ASSERT_REG_POSITION(viewport_transform[0], 0x280);
|
ASSERT_REG_POSITION(viewport_transform, 0x280);
|
||||||
ASSERT_REG_POSITION(viewport, 0x300);
|
ASSERT_REG_POSITION(viewports, 0x300);
|
||||||
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
|
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
|
||||||
ASSERT_REG_POSITION(clear_color[0], 0x360);
|
ASSERT_REG_POSITION(clear_color[0], 0x360);
|
||||||
ASSERT_REG_POSITION(clear_depth, 0x364);
|
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_ref, 0x4E5);
|
||||||
ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
|
ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
|
||||||
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
|
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
|
||||||
|
ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
|
||||||
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
|
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
|
||||||
ASSERT_REG_POSITION(vb_element_base, 0x50D);
|
ASSERT_REG_POSITION(vb_element_base, 0x50D);
|
||||||
ASSERT_REG_POSITION(point_size, 0x546);
|
ASSERT_REG_POSITION(point_size, 0x546);
|
||||||
ASSERT_REG_POSITION(zeta_enable, 0x54E);
|
ASSERT_REG_POSITION(zeta_enable, 0x54E);
|
||||||
|
ASSERT_REG_POSITION(multisample_control, 0x54F);
|
||||||
ASSERT_REG_POSITION(tsc, 0x557);
|
ASSERT_REG_POSITION(tsc, 0x557);
|
||||||
ASSERT_REG_POSITION(tic, 0x55D);
|
ASSERT_REG_POSITION(tic, 0x55D);
|
||||||
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
|
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
|
||||||
|
|
|
@ -580,6 +580,8 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
|
|
||||||
ConfigureFramebuffers(state);
|
ConfigureFramebuffers(state);
|
||||||
SyncColorMask();
|
SyncColorMask();
|
||||||
|
SyncFragmentColorClampState();
|
||||||
|
SyncMultiSampleState();
|
||||||
SyncDepthTestState();
|
SyncDepthTestState();
|
||||||
SyncStencilTestState();
|
SyncStencilTestState();
|
||||||
SyncBlendState();
|
SyncBlendState();
|
||||||
|
@ -640,7 +642,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
params.DispatchDraw();
|
params.DispatchDraw();
|
||||||
|
|
||||||
// Disable scissor test
|
// Disable scissor test
|
||||||
state.scissor.enabled = false;
|
state.viewports[0].scissor.enabled = false;
|
||||||
|
|
||||||
accelerate_draw = AccelDraw::Disabled;
|
accelerate_draw = AccelDraw::Disabled;
|
||||||
|
|
||||||
|
@ -731,9 +733,8 @@ void RasterizerOpenGL::SamplerInfo::Create() {
|
||||||
glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
|
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 GLuint s = sampler.handle;
|
||||||
const Tegra::Texture::TSCEntry& config = info.tsc;
|
|
||||||
if (mag_filter != config.mag_filter) {
|
if (mag_filter != config.mag_filter) {
|
||||||
mag_filter = config.mag_filter;
|
mag_filter = config.mag_filter;
|
||||||
glSamplerParameteri(
|
glSamplerParameteri(
|
||||||
|
@ -775,30 +776,50 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex
|
||||||
MaxwellToGL::DepthCompareFunc(depth_compare_func));
|
MaxwellToGL::DepthCompareFunc(depth_compare_func));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border ||
|
GLvec4 new_border_color;
|
||||||
wrap_p == Tegra::Texture::WrapMode::Border) {
|
if (config.srgb_conversion) {
|
||||||
const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
|
new_border_color[0] = config.srgb_border_color_r / 255.0f;
|
||||||
config.border_color_b, config.border_color_a}};
|
new_border_color[1] = config.srgb_border_color_g / 255.0f;
|
||||||
if (border_color != new_border_color) {
|
new_border_color[2] = config.srgb_border_color_g / 255.0f;
|
||||||
border_color = new_border_color;
|
} else {
|
||||||
glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
|
new_border_color[0] = config.border_color_r;
|
||||||
|
new_border_color[1] = config.border_color_g;
|
||||||
|
new_border_color[2] = config.border_color_b;
|
||||||
|
}
|
||||||
|
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, max_anisotropic);
|
||||||
|
} else if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
||||||
|
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.tic.use_header_opt_control == 0) {
|
const float lod_min = static_cast<float>(config.min_lod_clamp.Value()) / 256.0f;
|
||||||
if (GLAD_GL_ARB_texture_filter_anisotropic) {
|
if (lod_min != min_lod) {
|
||||||
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY,
|
min_lod = lod_min;
|
||||||
static_cast<float>(1 << info.tic.max_anisotropy.Value()));
|
glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, min_lod);
|
||||||
} else if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
}
|
||||||
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
|
||||||
static_cast<float>(1 << info.tic.max_anisotropy.Value()));
|
const float lod_max = static_cast<float>(config.max_lod_clamp.Value()) / 256.0f;
|
||||||
}
|
if (lod_max != max_lod) {
|
||||||
glSamplerParameterf(s, GL_TEXTURE_MIN_LOD,
|
max_lod = lod_max;
|
||||||
static_cast<float>(info.tic.res_min_mip_level.Value()));
|
glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, max_lod);
|
||||||
glSamplerParameterf(s, GL_TEXTURE_MAX_LOD,
|
}
|
||||||
static_cast<float>(info.tic.res_max_mip_level.Value() == 0
|
const u32 bias = config.mip_lod_bias.Value();
|
||||||
? 16
|
// Sign extend the 13-bit value.
|
||||||
: info.tic.res_max_mip_level.Value()));
|
const u32 mask = 1U << (13 - 1);
|
||||||
glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,7 +918,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_samplers[current_bindpoint].SyncWithConfig(texture);
|
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
||||||
Surface surface = res_cache.GetTextureSurface(texture, entry);
|
Surface surface = res_cache.GetTextureSurface(texture, entry);
|
||||||
if (surface != nullptr) {
|
if (surface != nullptr) {
|
||||||
state.texture_units[current_bindpoint].texture = surface->Texture().handle;
|
state.texture_units[current_bindpoint].texture = surface->Texture().handle;
|
||||||
|
@ -921,15 +942,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
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()};
|
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
|
||||||
auto& viewport = current_state.viewports[i];
|
auto& viewport = current_state.viewports[i];
|
||||||
viewport.x = viewport_rect.left;
|
viewport.x = viewport_rect.left;
|
||||||
viewport.y = viewport_rect.bottom;
|
viewport.y = viewport_rect.bottom;
|
||||||
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
|
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
|
||||||
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
||||||
viewport.depth_range_far = regs.viewport[i].depth_range_far;
|
viewport.depth_range_far = regs.viewports[i].depth_range_far;
|
||||||
viewport.depth_range_near = regs.viewport[i].depth_range_near;
|
viewport.depth_range_near = regs.viewports[i].depth_range_near;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1020,7 +1041,9 @@ void RasterizerOpenGL::SyncStencilTestState() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncColorMask() {
|
void RasterizerOpenGL::SyncColorMask() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
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];
|
const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
|
||||||
auto& dest = state.color_mask[i];
|
auto& dest = state.color_mask[i];
|
||||||
dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
|
dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
|
||||||
|
@ -1030,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() {
|
void RasterizerOpenGL::SyncBlendState() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
|
||||||
|
@ -1041,43 +1075,40 @@ void RasterizerOpenGL::SyncBlendState() {
|
||||||
state.independant_blend.enabled = regs.independent_blend_enable;
|
state.independant_blend.enabled = regs.independent_blend_enable;
|
||||||
if (!state.independant_blend.enabled) {
|
if (!state.independant_blend.enabled) {
|
||||||
auto& blend = state.blend[0];
|
auto& blend = state.blend[0];
|
||||||
blend.enabled = regs.blend.enable[0] != 0;
|
const auto& src = regs.blend;
|
||||||
blend.separate_alpha = regs.blend.separate_alpha;
|
blend.enabled = src.enable[0] != 0;
|
||||||
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
|
if (blend.enabled) {
|
||||||
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
|
blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
|
||||||
blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
|
blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
|
||||||
if (blend.separate_alpha) {
|
blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
|
||||||
blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
|
blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
|
||||||
blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
|
blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
|
||||||
blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_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;
|
state.blend[i].enabled = false;
|
||||||
}
|
}
|
||||||
return;
|
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];
|
auto& blend = state.blend[i];
|
||||||
|
const auto& src = regs.independent_blend[i];
|
||||||
blend.enabled = regs.blend.enable[i] != 0;
|
blend.enabled = regs.blend.enable[i] != 0;
|
||||||
if (!blend.enabled)
|
if (!blend.enabled)
|
||||||
continue;
|
continue;
|
||||||
blend.separate_alpha = regs.independent_blend[i].separate_alpha;
|
blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
|
||||||
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
|
blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
|
||||||
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
|
blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
|
||||||
blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
|
blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
|
||||||
if (blend.separate_alpha) {
|
blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
|
||||||
blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
|
blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncLogicOpState() {
|
void RasterizerOpenGL::SyncLogicOpState() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
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;
|
state.logic_op.enabled = regs.logic_op.enable != 0;
|
||||||
|
|
||||||
if (!state.logic_op.enabled)
|
if (!state.logic_op.enabled)
|
||||||
|
@ -1090,19 +1121,21 @@ void RasterizerOpenGL::SyncLogicOpState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncScissorTest() {
|
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;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
state.scissor.enabled = (regs.scissor_test.enable != 0);
|
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
||||||
if (regs.scissor_test.enable == 0) {
|
const auto& src = regs.scissor_test[i];
|
||||||
return;
|
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() {
|
void RasterizerOpenGL::SyncTransformFeedback() {
|
||||||
|
@ -1116,11 +1149,7 @@ void RasterizerOpenGL::SyncTransformFeedback() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncPointState() {
|
void RasterizerOpenGL::SyncPointState() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
state.point.size = regs.point_size;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::CheckAlphaTests() {
|
void RasterizerOpenGL::CheckAlphaTests() {
|
||||||
|
|
|
@ -88,7 +88,7 @@ private:
|
||||||
/// SamplerInfo struct.
|
/// SamplerInfo struct.
|
||||||
void Create();
|
void Create();
|
||||||
/// Syncs the sampler object with the config, updating any necessary state.
|
/// 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:
|
private:
|
||||||
Tegra::Texture::TextureFilter mag_filter;
|
Tegra::Texture::TextureFilter mag_filter;
|
||||||
|
@ -100,6 +100,10 @@ private:
|
||||||
bool uses_depth_compare;
|
bool uses_depth_compare;
|
||||||
Tegra::Texture::DepthCompareFunc depth_compare_func;
|
Tegra::Texture::DepthCompareFunc depth_compare_func;
|
||||||
GLvec4 border_color;
|
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
|
/// Syncs the LogicOp state to match the guest state
|
||||||
void SyncLogicOpState();
|
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
|
/// Syncs the scissor test state to match the guest state
|
||||||
void SyncScissorTest();
|
void SyncScissorTest();
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
|
glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
|
||||||
state.draw.shader_program = 0;
|
state.draw.shader_program = 0;
|
||||||
state.draw.program_pipeline = pipeline.handle;
|
state.draw.program_pipeline = pipeline.handle;
|
||||||
|
state.geometry_shaders.enabled = (gs != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -14,7 +14,10 @@ OpenGLState OpenGLState::cur_state;
|
||||||
bool OpenGLState::s_rgb_used;
|
bool OpenGLState::s_rgb_used;
|
||||||
OpenGLState::OpenGLState() {
|
OpenGLState::OpenGLState() {
|
||||||
// These all match default OpenGL values
|
// These all match default OpenGL values
|
||||||
|
geometry_shaders.enabled = false;
|
||||||
framebuffer_srgb.enabled = false;
|
framebuffer_srgb.enabled = false;
|
||||||
|
multisample_control.alpha_to_coverage = false;
|
||||||
|
multisample_control.alpha_to_one = false;
|
||||||
cull.enabled = false;
|
cull.enabled = false;
|
||||||
cull.mode = GL_BACK;
|
cull.mode = GL_BACK;
|
||||||
cull.front_face = GL_CCW;
|
cull.front_face = GL_CCW;
|
||||||
|
@ -50,12 +53,12 @@ OpenGLState::OpenGLState() {
|
||||||
item.height = 0;
|
item.height = 0;
|
||||||
item.depth_range_near = 0.0f;
|
item.depth_range_near = 0.0f;
|
||||||
item.depth_range_far = 1.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) {
|
for (auto& item : blend) {
|
||||||
item.enabled = true;
|
item.enabled = true;
|
||||||
item.rgb_equation = GL_FUNC_ADD;
|
item.rgb_equation = GL_FUNC_ADD;
|
||||||
|
@ -88,6 +91,7 @@ OpenGLState::OpenGLState() {
|
||||||
clip_distance = {};
|
clip_distance = {};
|
||||||
|
|
||||||
point.size = 1;
|
point.size = 1;
|
||||||
|
fragment_color_clamp.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyDefaultState() {
|
void OpenGLState::ApplyDefaultState() {
|
||||||
|
@ -136,7 +140,7 @@ void OpenGLState::ApplyCulling() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyColorMask() 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++) {
|
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||||
const auto& updated = color_mask[i];
|
const auto& updated = color_mask[i];
|
||||||
const auto& current = cur_state.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 {
|
void OpenGLState::ApplyViewport() const {
|
||||||
if (GLAD_GL_ARB_viewport_array) {
|
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
|
||||||
for (GLuint i = 0;
|
for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports);
|
||||||
i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
|
i++) {
|
||||||
const auto& current = cur_state.viewports[i];
|
const auto& current = cur_state.viewports[i];
|
||||||
const auto& updated = viewports[i];
|
const auto& updated = viewports[i];
|
||||||
if (updated.x != current.x || updated.y != current.y ||
|
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) {
|
updated.depth_range_far != current.depth_range_far) {
|
||||||
glDepthRangeIndexed(i, updated.depth_range_near, updated.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 {
|
} else {
|
||||||
const auto& current = cur_state.viewports[0];
|
const auto& current = cur_state.viewports[0];
|
||||||
|
@ -273,6 +277,21 @@ void OpenGLState::ApplyViewport() const {
|
||||||
updated.depth_range_far != current.depth_range_far) {
|
updated.depth_range_far != current.depth_range_far) {
|
||||||
glDepthRange(updated.depth_range_near, updated.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) {
|
if (!updated.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (updated.separate_alpha) {
|
if (blend_changed || updated.src_rgb_func != current.src_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_rgb_func != current.dst_rgb_func ||
|
updated.dst_a_func != current.dst_a_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,
|
||||||
glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
|
updated.dst_a_func);
|
||||||
updated.dst_a_func);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
||||||
updated.a_equation != current.a_equation) {
|
updated.a_equation != current.a_equation) {
|
||||||
glBlendEquationSeparate(updated.rgb_equation, updated.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.rgb_equation != current.rgb_equation) {
|
|
||||||
glBlendEquation(updated.rgb_equation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,29 +336,17 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
|
||||||
if (!updated.enabled) {
|
if (!updated.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (updated.separate_alpha) {
|
if (blend_changed || updated.src_rgb_func != current.src_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_rgb_func != current.dst_rgb_func ||
|
updated.dst_a_func != current.dst_a_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,
|
||||||
glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
|
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
|
||||||
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
||||||
updated.a_equation != current.a_equation) {
|
updated.a_equation != current.a_equation) {
|
||||||
glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
|
glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
|
||||||
updated.a_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.rgb_equation != current.rgb_equation) {
|
|
||||||
glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,9 +477,29 @@ void OpenGLState::Apply() const {
|
||||||
if (point.size != cur_state.point.size) {
|
if (point.size != cur_state.point.size) {
|
||||||
glPointSize(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();
|
ApplyColorMask();
|
||||||
ApplyViewport();
|
ApplyViewport();
|
||||||
ApplyScissor();
|
|
||||||
ApplyStencilTest();
|
ApplyStencilTest();
|
||||||
ApplySRgb();
|
ApplySRgb();
|
||||||
ApplyCulling();
|
ApplyCulling();
|
||||||
|
|
|
@ -39,6 +39,19 @@ public:
|
||||||
bool enabled; // GL_FRAMEBUFFER_SRGB
|
bool enabled; // GL_FRAMEBUFFER_SRGB
|
||||||
} framebuffer_srgb;
|
} 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 {
|
struct {
|
||||||
bool enabled; // GL_CULL_FACE
|
bool enabled; // GL_CULL_FACE
|
||||||
GLenum mode; // GL_CULL_FACE_MODE
|
GLenum mode; // GL_CULL_FACE_MODE
|
||||||
|
@ -79,7 +92,6 @@ public:
|
||||||
|
|
||||||
struct Blend {
|
struct Blend {
|
||||||
bool enabled; // GL_BLEND
|
bool enabled; // GL_BLEND
|
||||||
bool separate_alpha; // Independent blend enabled
|
|
||||||
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
|
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
|
||||||
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
|
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
|
||||||
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
|
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
|
||||||
|
@ -150,16 +162,15 @@ public:
|
||||||
GLfloat height;
|
GLfloat height;
|
||||||
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
||||||
GLfloat depth_range_far; // 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;
|
std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
|
||||||
|
|
||||||
struct {
|
|
||||||
bool enabled; // GL_SCISSOR_TEST
|
|
||||||
GLint x;
|
|
||||||
GLint y;
|
|
||||||
GLsizei width;
|
|
||||||
GLsizei height;
|
|
||||||
} scissor;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
float size; // GL_POINT_SIZE
|
float size; // GL_POINT_SIZE
|
||||||
|
@ -214,7 +225,6 @@ private:
|
||||||
void ApplyLogicOp() const;
|
void ApplyLogicOp() const;
|
||||||
void ApplyTextures() const;
|
void ApplyTextures() const;
|
||||||
void ApplySamplers() const;
|
void ApplySamplers() const;
|
||||||
void ApplyScissor() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -180,6 +180,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
||||||
return GL_CLAMP_TO_BORDER;
|
return GL_CLAMP_TO_BORDER;
|
||||||
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
||||||
return GL_MIRROR_CLAMP_TO_EDGE;
|
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));
|
LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
|
||||||
return GL_REPEAT;
|
return GL_REPEAT;
|
||||||
|
|
|
@ -190,6 +190,7 @@ struct TICEntry {
|
||||||
union {
|
union {
|
||||||
BitField<0, 4, u32> res_min_mip_level;
|
BitField<0, 4, u32> res_min_mip_level;
|
||||||
BitField<4, 4, u32> res_max_mip_level;
|
BitField<4, 4, u32> res_max_mip_level;
|
||||||
|
BitField<12, 12, u32> min_lod_clamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
GPUVAddr Address() const {
|
GPUVAddr Address() const {
|
||||||
|
@ -284,13 +285,25 @@ struct TSCEntry {
|
||||||
BitField<6, 3, WrapMode> wrap_p;
|
BitField<6, 3, WrapMode> wrap_p;
|
||||||
BitField<9, 1, u32> depth_compare_enabled;
|
BitField<9, 1, u32> depth_compare_enabled;
|
||||||
BitField<10, 3, DepthCompareFunc> depth_compare_func;
|
BitField<10, 3, DepthCompareFunc> depth_compare_func;
|
||||||
|
BitField<13, 1, u32> srgb_conversion;
|
||||||
|
BitField<20, 3, u32> max_anisotropy;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
BitField<0, 2, TextureFilter> mag_filter;
|
BitField<0, 2, TextureFilter> mag_filter;
|
||||||
BitField<4, 2, TextureFilter> min_filter;
|
BitField<4, 2, TextureFilter> min_filter;
|
||||||
BitField<6, 2, TextureMipmapFilter> mip_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_r;
|
||||||
float border_color_g;
|
float border_color_g;
|
||||||
float border_color_b;
|
float border_color_b;
|
||||||
|
|
Loading…
Reference in a new issue