Implement multi-target viewports and blending

This commit is contained in:
Rodolfo Bogado 2018-11-02 00:21:25 -03:00
parent 38c1c500ab
commit 145ae36963
6 changed files with 258 additions and 127 deletions

View file

@ -37,6 +37,22 @@ void Maxwell3D::InitializeRegisterDefaults() {
regs.viewport[viewport].depth_range_near = 0.0f; regs.viewport[viewport].depth_range_near = 0.0f;
regs.viewport[viewport].depth_range_far = 1.0f; regs.viewport[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
regs.blend.equation_rgb = Regs::Blend::Equation::Add;
regs.blend.factor_source_rgb = Regs::Blend::Factor::One;
regs.blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
regs.blend.equation_a = Regs::Blend::Equation::Add;
regs.blend.factor_source_a = Regs::Blend::Factor::One;
regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
}
} }
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {

View file

@ -646,8 +646,14 @@ public:
ComparisonOp depth_test_func; ComparisonOp depth_test_func;
float alpha_test_ref; float alpha_test_ref;
ComparisonOp alpha_test_func; ComparisonOp alpha_test_func;
u32 draw_tfb_stride;
INSERT_PADDING_WORDS(0x9); struct {
float r;
float g;
float b;
float a;
} blend_color;
INSERT_PADDING_WORDS(0x4);
struct { struct {
u32 separate_alpha; u32 separate_alpha;
@ -1087,6 +1093,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
ASSERT_REG_POSITION(depth_test_func, 0x4C3); ASSERT_REG_POSITION(depth_test_func, 0x4C3);
ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
ASSERT_REG_POSITION(blend_color, 0x4C7);
ASSERT_REG_POSITION(blend, 0x4CF); ASSERT_REG_POSITION(blend, 0x4CF);
ASSERT_REG_POSITION(stencil_enable, 0x4E0); ASSERT_REG_POSITION(stencil_enable, 0x4E0);
ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);

View file

@ -580,7 +580,6 @@ void RasterizerOpenGL::DrawArrays() {
SyncLogicOpState(); SyncLogicOpState();
SyncCullMode(); SyncCullMode();
SyncPrimitiveRestart(); SyncPrimitiveRestart();
SyncDepthRange();
SyncScissorTest(); SyncScissorTest();
// Alpha Testing is synced on shaders. // Alpha Testing is synced on shaders.
SyncTransformFeedback(); SyncTransformFeedback();
@ -899,12 +898,16 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
void RasterizerOpenGL::SyncViewport() { void RasterizerOpenGL::SyncViewport() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
state.viewport.x = viewport_rect.left; auto& viewport = state.viewports[i];
state.viewport.y = viewport_rect.bottom; viewport.x = viewport_rect.left;
state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); viewport.y = viewport_rect.bottom;
state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
viewport.depth_range_far = regs.viewport[i].depth_range_far;
viewport.depth_range_near = regs.viewport[i].depth_range_near;
}
} }
void RasterizerOpenGL::SyncClipEnabled() { void RasterizerOpenGL::SyncClipEnabled() {
@ -946,13 +949,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
state.primitive_restart.index = regs.primitive_restart.index; state.primitive_restart.index = regs.primitive_restart.index;
} }
void RasterizerOpenGL::SyncDepthRange() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
state.depth.depth_range_near = regs.viewport->depth_range_near;
state.depth.depth_range_far = regs.viewport->depth_range_far;
}
void RasterizerOpenGL::SyncDepthTestState() { void RasterizerOpenGL::SyncDepthTestState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@ -996,23 +992,44 @@ void RasterizerOpenGL::SyncStencilTestState() {
void RasterizerOpenGL::SyncBlendState() { void RasterizerOpenGL::SyncBlendState() {
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.blend_color.red = regs.blend_color.r;
state.blend.enabled = regs.blend.enable[0] != 0; state.blend_color.green = regs.blend_color.g;
state.blend_color.blue = regs.blend_color.b;
state.blend_color.alpha = regs.blend_color.a;
if (!state.blend.enabled) state.independant_blend.enabled = regs.independent_blend_enable;
if (!state.independant_blend.enabled) {
auto& blend = state.blend[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);
}
for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
state.blend[i].enabled = false;
}
return; return;
}
ASSERT_MSG(regs.logic_op.enable == 0, for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
"Blending and logic op can't be enabled at the same time."); auto& blend = state.blend[i];
blend.enabled = regs.blend.enable[i] != 0;
ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); if (!blend.enabled)
ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); continue;
state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); blend.separate_alpha = regs.independent_blend[i].separate_alpha;
state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb); blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a); blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); if (blend.separate_alpha) {
state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); 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);
}
}
} }
void RasterizerOpenGL::SyncLogicOpState() { void RasterizerOpenGL::SyncLogicOpState() {
@ -1031,19 +1048,19 @@ 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); state.scissor.enabled = (regs.scissor_test.enable != 0);
// TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's if (regs.scissor_test.enable == 0) {
// implemented. return;
if (regs.scissor_test.enable != 0) { }
const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x; 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; const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
state.scissor.x = regs.scissor_test.min_x; state.scissor.x = regs.scissor_test.min_x;
state.scissor.y = regs.scissor_test.min_y; state.scissor.y = regs.scissor_test.min_y;
state.scissor.width = width; state.scissor.width = width;
state.scissor.height = height; state.scissor.height = height;
}
} }
void RasterizerOpenGL::SyncTransformFeedback() { void RasterizerOpenGL::SyncTransformFeedback() {

View file

@ -133,7 +133,7 @@ private:
u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
GLenum primitive_mode, u32 current_unit); GLenum primitive_mode, u32 current_unit);
/// Syncs the viewport to match the guest state /// Syncs the viewport and depth range to match the guest state
void SyncViewport(); void SyncViewport();
/// Syncs the clip enabled status to match the guest state /// Syncs the clip enabled status to match the guest state
@ -148,9 +148,6 @@ private:
/// Syncs the primitve restart to match the guest state /// Syncs the primitve restart to match the guest state
void SyncPrimitiveRestart(); void SyncPrimitiveRestart();
/// Syncs the depth range to match the guest state
void SyncDepthRange();
/// Syncs the depth test state to match the guest state /// Syncs the depth test state to match the guest state
void SyncDepthTestState(); void SyncDepthTestState();

View file

@ -22,8 +22,6 @@ OpenGLState::OpenGLState() {
depth.test_enabled = false; depth.test_enabled = false;
depth.test_func = GL_LESS; depth.test_func = GL_LESS;
depth.write_mask = GL_TRUE; depth.write_mask = GL_TRUE;
depth.depth_range_near = 0.0f;
depth.depth_range_far = 1.0f;
primitive_restart.enabled = false; primitive_restart.enabled = false;
primitive_restart.index = 0; primitive_restart.index = 0;
@ -45,19 +43,33 @@ OpenGLState::OpenGLState() {
}; };
reset_stencil(stencil.front); reset_stencil(stencil.front);
reset_stencil(stencil.back); reset_stencil(stencil.back);
for (auto& item : viewports) {
blend.enabled = true; item.x = 0;
blend.rgb_equation = GL_FUNC_ADD; item.y = 0;
blend.a_equation = GL_FUNC_ADD; item.width = 0;
blend.src_rgb_func = GL_ONE; item.height = 0;
blend.dst_rgb_func = GL_ZERO; item.depth_range_near = 0.0f;
blend.src_a_func = GL_ONE; item.depth_range_far = 1.0f;
blend.dst_a_func = GL_ZERO; }
blend.color.red = 0.0f; scissor.enabled = false;
blend.color.green = 0.0f; scissor.x = 0;
blend.color.blue = 0.0f; scissor.y = 0;
blend.color.alpha = 0.0f; scissor.width = 0;
scissor.height = 0;
for (auto& item : blend) {
item.enabled = true;
item.rgb_equation = GL_FUNC_ADD;
item.a_equation = GL_FUNC_ADD;
item.src_rgb_func = GL_ONE;
item.dst_rgb_func = GL_ZERO;
item.src_a_func = GL_ONE;
item.dst_a_func = GL_ZERO;
}
independant_blend.enabled = false;
blend_color.red = 0.0f;
blend_color.green = 0.0f;
blend_color.blue = 0.0f;
blend_color.alpha = 0.0f;
logic_op.enabled = false; logic_op.enabled = false;
logic_op.operation = GL_COPY; logic_op.operation = GL_COPY;
@ -73,17 +85,6 @@ OpenGLState::OpenGLState() {
draw.shader_program = 0; draw.shader_program = 0;
draw.program_pipeline = 0; draw.program_pipeline = 0;
scissor.enabled = false;
scissor.x = 0;
scissor.y = 0;
scissor.width = 0;
scissor.height = 0;
viewport.x = 0;
viewport.y = 0;
viewport.width = 0;
viewport.height = 0;
clip_distance = {}; clip_distance = {};
point.size = 1; point.size = 1;
@ -152,11 +153,6 @@ void OpenGLState::ApplyDepth() const {
if (depth.write_mask != cur_state.depth.write_mask) { if (depth.write_mask != cur_state.depth.write_mask) {
glDepthMask(depth.write_mask); glDepthMask(depth.write_mask);
} }
// Depth range
if (depth.depth_range_near != cur_state.depth.depth_range_near ||
depth.depth_range_far != cur_state.depth.depth_range_far) {
glDepthRange(depth.depth_range_near, depth.depth_range_far);
}
} }
void OpenGLState::ApplyPrimitiveRestart() const { void OpenGLState::ApplyPrimitiveRestart() const {
@ -208,7 +204,7 @@ void OpenGLState::ApplyStencilTest() const {
} }
} }
void OpenGLState::ApplyScissorTest() const { void OpenGLState::ApplyScissor() const {
const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
if (scissor_changed) { if (scissor_changed) {
if (scissor.enabled) { if (scissor.enabled) {
@ -217,51 +213,141 @@ void OpenGLState::ApplyScissorTest() const {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
} }
if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || if (scissor.enabled &&
scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
scissor.height != cur_state.scissor.height) { scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
glScissor(scissor.x, scissor.y, scissor.width, scissor.height); glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
} }
} }
void OpenGLState::ApplyBlending() const { void OpenGLState::ApplyViewport() const {
const bool blend_changed = blend.enabled != cur_state.blend.enabled; if (GLAD_GL_ARB_viewport_array) {
for (GLuint i = 0;
i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
const auto& current = cur_state.viewports[i];
const auto& updated = viewports[i];
if (updated.x != current.x || updated.y != current.y ||
updated.width != current.width || updated.height != current.height) {
glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
}
if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) {
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
}
}
} else {
const auto& current = cur_state.viewports[0];
const auto& updated = viewports[0];
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
updated.height != current.height) {
glViewport(updated.x, updated.y, updated.width, updated.height);
}
if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) {
glDepthRange(updated.depth_range_near, updated.depth_range_far);
}
}
}
void OpenGLState::ApplyGlobalBlending() const {
const Blend& current = cur_state.blend[0];
const Blend& updated = blend[0];
const bool blend_changed = updated.enabled != current.enabled;
if (blend_changed) { if (blend_changed) {
if (blend.enabled) { if (updated.enabled) {
ASSERT(!logic_op.enabled);
glEnable(GL_BLEND); glEnable(GL_BLEND);
} else { } else {
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
} }
if (blend.enabled) { if (!updated.enabled) {
if (blend_changed || blend.color.red != cur_state.blend.color.red || return;
blend.color.green != cur_state.blend.color.green || }
blend.color.blue != cur_state.blend.color.blue || if (updated.separate_alpha) {
blend.color.alpha != cur_state.blend.color.alpha) { if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 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 || blend.src_rgb_func != cur_state.blend.src_rgb_func || if (blend_changed || updated.rgb_equation != current.rgb_equation ||
blend.dst_rgb_func != cur_state.blend.dst_rgb_func || updated.a_equation != current.a_equation) {
blend.src_a_func != cur_state.blend.src_a_func || glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
blend.dst_a_func != cur_state.blend.dst_a_func) { }
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, } else {
blend.dst_a_func); 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 || blend.rgb_equation != cur_state.blend.rgb_equation || if (blend_changed || updated.rgb_equation != current.rgb_equation) {
blend.a_equation != cur_state.blend.a_equation) { glBlendEquation(updated.rgb_equation);
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
} }
} }
} }
void OpenGLState::ApplyTargetBlending(int target, bool force) const {
const Blend& updated = blend[target];
const Blend& current = cur_state.blend[target];
const bool blend_changed = updated.enabled != current.enabled || force;
if (blend_changed) {
if (updated.enabled) {
glEnablei(GL_BLEND, static_cast<GLuint>(target));
} else {
glDisablei(GL_BLEND, static_cast<GLuint>(target));
}
}
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.rgb_equation != current.rgb_equation) {
glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
}
}
}
void OpenGLState::ApplyBlending() const {
if (independant_blend.enabled) {
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
ApplyTargetBlending(i,
independant_blend.enabled != cur_state.independant_blend.enabled);
}
} else {
ApplyGlobalBlending();
}
if (blend_color.red != cur_state.blend_color.red ||
blend_color.green != cur_state.blend_color.green ||
blend_color.blue != cur_state.blend_color.blue ||
blend_color.alpha != cur_state.blend_color.alpha) {
glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
}
}
void OpenGLState::ApplyLogicOp() const { void OpenGLState::ApplyLogicOp() const {
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
if (logic_op_changed) { if (logic_op_changed) {
if (logic_op.enabled) { if (logic_op.enabled) {
ASSERT(!blend.enabled);
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
} else { } else {
glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_COLOR_LOGIC_OP);
@ -348,12 +434,6 @@ void OpenGLState::Apply() const {
if (draw.program_pipeline != cur_state.draw.program_pipeline) { if (draw.program_pipeline != cur_state.draw.program_pipeline) {
glBindProgramPipeline(draw.program_pipeline); glBindProgramPipeline(draw.program_pipeline);
} }
// Viewport
if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
viewport.width != cur_state.viewport.width ||
viewport.height != cur_state.viewport.height) {
glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
}
// Clip distance // Clip distance
for (std::size_t i = 0; i < clip_distance.size(); ++i) { for (std::size_t i = 0; i < clip_distance.size(); ++i) {
if (clip_distance[i] != cur_state.clip_distance[i]) { if (clip_distance[i] != cur_state.clip_distance[i]) {
@ -376,7 +456,8 @@ void OpenGLState::Apply() const {
if (point.size != cur_state.point.size) { if (point.size != cur_state.point.size) {
glPointSize(point.size); glPointSize(point.size);
} }
ApplyScissorTest(); ApplyViewport();
ApplyScissor();
ApplyStencilTest(); ApplyStencilTest();
ApplySRgb(); ApplySRgb();
ApplyCulling(); ApplyCulling();

View file

@ -49,8 +49,6 @@ public:
bool test_enabled; // GL_DEPTH_TEST bool test_enabled; // GL_DEPTH_TEST
GLenum test_func; // GL_DEPTH_FUNC GLenum test_func; // GL_DEPTH_FUNC
GLboolean write_mask; // GL_DEPTH_WRITEMASK GLboolean write_mask; // GL_DEPTH_WRITEMASK
GLfloat depth_range_near; // GL_DEPTH_RANGE
GLfloat depth_range_far; // GL_DEPTH_RANGE
} depth; } depth;
struct { struct {
@ -78,22 +76,28 @@ public:
} front, back; } front, back;
} stencil; } stencil;
struct { 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
GLenum dst_rgb_func; // GL_BLEND_DST_RGB GLenum dst_rgb_func; // GL_BLEND_DST_RGB
GLenum src_a_func; // GL_BLEND_SRC_ALPHA GLenum src_a_func; // GL_BLEND_SRC_ALPHA
GLenum dst_a_func; // GL_BLEND_DST_ALPHA GLenum dst_a_func; // GL_BLEND_DST_ALPHA
};
std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
struct {
bool enabled;
} independant_blend;
struct { struct {
GLclampf red; GLclampf red;
GLclampf green; GLclampf green;
GLclampf blue; GLclampf blue;
GLclampf alpha; GLclampf alpha;
} color; // GL_BLEND_COLOR } blend_color; // GL_BLEND_COLOR
} blend;
struct { struct {
bool enabled; // GL_LOGIC_OP_MODE bool enabled; // GL_LOGIC_OP_MODE
@ -138,6 +142,16 @@ public:
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
} draw; } draw;
struct viewport {
GLfloat x;
GLfloat y;
GLfloat width;
GLfloat height;
GLfloat depth_range_near; // 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;
@ -146,13 +160,6 @@ public:
GLsizei height; GLsizei height;
} scissor; } scissor;
struct {
GLint x;
GLint y;
GLsizei width;
GLsizei height;
} viewport;
struct { struct {
float size; // GL_POINT_SIZE float size; // GL_POINT_SIZE
} point; } point;
@ -194,11 +201,14 @@ private:
void ApplyDepth() const; void ApplyDepth() const;
void ApplyPrimitiveRestart() const; void ApplyPrimitiveRestart() const;
void ApplyStencilTest() const; void ApplyStencilTest() const;
void ApplyScissorTest() const; void ApplyViewport() const;
void ApplyTargetBlending(int target, bool force) const;
void ApplyGlobalBlending() const;
void ApplyBlending() const; void ApplyBlending() const;
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