fix viewport and scissor behavior

This commit is contained in:
Rodolfo Bogado 2018-11-13 20:13:16 -03:00
parent a819116154
commit 1881e86c43
6 changed files with 89 additions and 64 deletions

View file

@ -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

View file

@ -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);

View file

@ -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];
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() {

View file

@ -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:

View file

@ -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();

View file

@ -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,16 +154,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 +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