fix viewport and scissor behavior
This commit is contained in:
parent
a819116154
commit
1881e86c43
|
@ -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
|
||||||
|
|
|
@ -505,9 +505,9 @@ public:
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x2E);
|
INSERT_PADDING_WORDS(0x2E);
|
||||||
|
|
||||||
RenderTargetConfig rt[NumRenderTargets];
|
std::array<RenderTargetConfig, NumRenderTargets> rt;
|
||||||
|
|
||||||
struct {
|
struct ViewportTransform {
|
||||||
f32 scale_x;
|
f32 scale_x;
|
||||||
f32 scale_y;
|
f32 scale_y;
|
||||||
f32 scale_z;
|
f32 scale_z;
|
||||||
|
@ -540,9 +540,11 @@ public:
|
||||||
s32 GetHeight() const {
|
s32 GetHeight() const {
|
||||||
return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
|
return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
|
||||||
}
|
}
|
||||||
} viewport_transform[NumViewports];
|
};
|
||||||
|
|
||||||
struct {
|
std::array<ViewportTransform, NumViewports> viewport_transform;
|
||||||
|
|
||||||
|
struct ViewPort {
|
||||||
union {
|
union {
|
||||||
BitField<0, 16, u32> x;
|
BitField<0, 16, u32> x;
|
||||||
BitField<16, 16, u32> width;
|
BitField<16, 16, u32> width;
|
||||||
|
@ -553,7 +555,9 @@ public:
|
||||||
};
|
};
|
||||||
float depth_range_near;
|
float depth_range_near;
|
||||||
float depth_range_far;
|
float depth_range_far;
|
||||||
} viewport[NumViewports];
|
};
|
||||||
|
|
||||||
|
std::array<ViewPort, NumViewports> viewports;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x1D);
|
INSERT_PADDING_WORDS(0x1D);
|
||||||
|
|
||||||
|
@ -571,7 +575,7 @@ public:
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x17);
|
INSERT_PADDING_WORDS(0x17);
|
||||||
|
|
||||||
struct {
|
struct ScissorTest {
|
||||||
u32 enable;
|
u32 enable;
|
||||||
union {
|
union {
|
||||||
BitField<0, 16, u32> min_x;
|
BitField<0, 16, u32> min_x;
|
||||||
|
@ -581,9 +585,11 @@ public:
|
||||||
BitField<0, 16, u32> min_y;
|
BitField<0, 16, u32> min_y;
|
||||||
BitField<16, 16, u32> max_y;
|
BitField<16, 16, u32> max_y;
|
||||||
};
|
};
|
||||||
} scissor_test;
|
u32 fill;
|
||||||
|
};
|
||||||
|
std::array<ScissorTest, NumViewports> 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;
|
||||||
|
@ -1100,8 +1106,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);
|
||||||
|
|
|
@ -642,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;
|
||||||
|
|
||||||
|
@ -923,15 +923,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 (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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,7 +1079,6 @@ void RasterizerOpenGL::SyncBlendState() {
|
||||||
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)
|
||||||
|
@ -1092,19 +1091,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 (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
||||||
if (regs.scissor_test.enable == 0) {
|
const auto& src = regs.scissor_test[i];
|
||||||
|
auto& dst = state.viewports[i].scissor;
|
||||||
|
dst.enabled = (src.enable != 0);
|
||||||
|
if (dst.enabled == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
|
const u32 width = src.max_x - src.min_x;
|
||||||
const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
|
const u32 height = src.max_y - src.min_y;
|
||||||
state.scissor.x = regs.scissor_test.min_x;
|
dst.x = src.min_x;
|
||||||
state.scissor.y = regs.scissor_test.min_y;
|
dst.y = src.min_y;
|
||||||
state.scissor.width = width;
|
dst.width = width;
|
||||||
state.scissor.height = height;
|
dst.height = height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTransformFeedback() {
|
void RasterizerOpenGL::SyncTransformFeedback() {
|
||||||
|
|
|
@ -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,6 +14,7 @@ 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;
|
||||||
cull.enabled = false;
|
cull.enabled = false;
|
||||||
cull.mode = GL_BACK;
|
cull.mode = GL_BACK;
|
||||||
|
@ -50,12 +51,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;
|
||||||
|
@ -136,7 +137,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 +231,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 +245,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 +274,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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,7 +499,6 @@ void OpenGLState::Apply() const {
|
||||||
}
|
}
|
||||||
ApplyColorMask();
|
ApplyColorMask();
|
||||||
ApplyViewport();
|
ApplyViewport();
|
||||||
ApplyScissor();
|
|
||||||
ApplyStencilTest();
|
ApplyStencilTest();
|
||||||
ApplySRgb();
|
ApplySRgb();
|
||||||
ApplyCulling();
|
ApplyCulling();
|
||||||
|
|
|
@ -39,6 +39,10 @@ public:
|
||||||
bool enabled; // GL_FRAMEBUFFER_SRGB
|
bool enabled; // GL_FRAMEBUFFER_SRGB
|
||||||
} framebuffer_srgb;
|
} framebuffer_srgb;
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -150,9 +154,6 @@ 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
|
||||||
};
|
|
||||||
std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enabled; // GL_SCISSOR_TEST
|
bool enabled; // GL_SCISSOR_TEST
|
||||||
GLint x;
|
GLint x;
|
||||||
|
@ -160,6 +161,8 @@ public:
|
||||||
GLsizei width;
|
GLsizei width;
|
||||||
GLsizei height;
|
GLsizei height;
|
||||||
} scissor;
|
} scissor;
|
||||||
|
};
|
||||||
|
std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
float size; // GL_POINT_SIZE
|
float size; // GL_POINT_SIZE
|
||||||
|
@ -214,7 +217,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
|
||||||
|
|
Reference in New Issue