Compare commits

...

4 Commits

Author SHA1 Message Date
Rodolfo Bogado
02eacfd431 Multiple viewports are only valid while using geometry shaders so avoid uploading states that can be potentially invalid. 2018-11-22 16:04:02 -03:00
Rodolfo Bogado
3ae614c493 Add support for viewport_transform_enabled
fix Clear viewport area by calculating overlapping area when viewport and scissor are enabled at the same time.
add warning messages for extension that are not required but are needed for a correct emulation.
2018-11-22 12:17:37 -03:00
Rodolfo Bogado
0749600ca8 Implement depth clamp 2018-11-22 12:00:12 -03:00
Rodolfo Bogado
7aa12b2467 Add support for clear_flags register 2018-11-22 12:00:12 -03:00
5 changed files with 233 additions and 36 deletions

View File

@@ -624,7 +624,16 @@ public:
} }
} zeta; } zeta;
INSERT_PADDING_WORDS(0x5B); INSERT_PADDING_WORDS(0x41);
union {
BitField<0, 4, u32> stencil;
BitField<4, 4, u32> unknown;
BitField<8, 4, u32> scissor;
BitField<12, 4, u32> viewport;
} clear_flags;
INSERT_PADDING_WORDS(0x19);
std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
@@ -719,7 +728,20 @@ public:
u32 vb_element_base; u32 vb_element_base;
INSERT_PADDING_WORDS(0x38); INSERT_PADDING_WORDS(0x36);
union {
BitField<0, 1, u32> c0;
BitField<1, 1, u32> c1;
BitField<2, 1, u32> c2;
BitField<3, 1, u32> c3;
BitField<4, 1, u32> c4;
BitField<5, 1, u32> c5;
BitField<6, 1, u32> c6;
BitField<7, 1, u32> c7;
} clip_distance_enabled;
INSERT_PADDING_WORDS(0x1);
float point_size; float point_size;
@@ -863,7 +885,32 @@ public:
Cull cull; Cull cull;
INSERT_PADDING_WORDS(0x28); u32 pixel_center_integer;
INSERT_PADDING_WORDS(0x1);
u32 viewport_transform_enabled;
INSERT_PADDING_WORDS(0x3);
union {
BitField<0, 1, u32> depth_range_0_1;
BitField<3, 1, u32> depth_clamp_near;
BitField<4, 1, u32> depth_clamp_far;
} view_volume_clip_control;
union {
BitField<0, 4, u32> c0;
BitField<4, 4, u32> c1;
BitField<8, 4, u32> c2;
BitField<12, 4, u32> c3;
BitField<16, 4, u32> c4;
BitField<20, 4, u32> c5;
BitField<24, 4, u32> c6;
BitField<28, 4, u32> c7;
} clip_distance_mode;
INSERT_PADDING_WORDS(0x20);
struct { struct {
u32 enable; u32 enable;
@@ -1127,6 +1174,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
ASSERT_REG_POSITION(color_mask_common, 0x3E4); ASSERT_REG_POSITION(color_mask_common, 0x3E4);
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
ASSERT_REG_POSITION(zeta, 0x3F8); ASSERT_REG_POSITION(zeta, 0x3F8);
ASSERT_REG_POSITION(clear_flags, 0x43E);
ASSERT_REG_POSITION(vertex_attrib_format, 0x458); ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
ASSERT_REG_POSITION(rt_control, 0x487); ASSERT_REG_POSITION(rt_control, 0x487);
ASSERT_REG_POSITION(zeta_width, 0x48a); ASSERT_REG_POSITION(zeta_width, 0x48a);
@@ -1153,6 +1201,7 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); 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(clip_distance_enabled, 0x544);
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(multisample_control, 0x54F);
@@ -1171,6 +1220,9 @@ ASSERT_REG_POSITION(primitive_restart, 0x591);
ASSERT_REG_POSITION(index_array, 0x5F2); ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(instanced_arrays, 0x620); ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646); ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(pixel_center_integer, 0x649);
ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
ASSERT_REG_POSITION(clip_distance_mode, 0x650);
ASSERT_REG_POSITION(logic_op, 0x671); ASSERT_REG_POSITION(logic_op, 0x671);
ASSERT_REG_POSITION(clear_buffers, 0x674); ASSERT_REG_POSITION(clear_buffers, 0x674);
ASSERT_REG_POSITION(color_mask, 0x680); ASSERT_REG_POSITION(color_mask, 0x680);

View File

@@ -118,10 +118,43 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
CheckExtensions();
} }
RasterizerOpenGL::~RasterizerOpenGL() {} RasterizerOpenGL::~RasterizerOpenGL() {}
void RasterizerOpenGL::CheckExtensions() {
if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) {
LOG_WARNING(
Render_OpenGL,
"Anisotropic filter is not supported! this can cause graphical issues in some games.");
}
if (!GLAD_GL_ARB_viewport_array) {
LOG_WARNING(Render_OpenGL, "Viewport arrays are not supported! this can potyentially cause "
"issues in games that use geometry shaders.");
}
if (!GLAD_GL_ARB_color_buffer_float) {
LOG_WARNING(
Render_OpenGL,
"Color clamp control is not supported! this can cause graphical issues in some games.");
}
if (!GLAD_GL_ARB_buffer_storage) {
LOG_WARNING(
Render_OpenGL,
"Buffer storage control is not supported! this can cause performance degradation.");
}
if (!GLAD_GL_AMD_depth_clamp_separate) {
if (!GLAD_GL_ARB_depth_clamp) {
LOG_WARNING(
Render_OpenGL,
"Depth Clamp is not supported! this can cause graphical issues in some games.");
} else {
LOG_WARNING(Render_OpenGL, "Separate Depth Clamp is not supported! this can cause "
"graphical issues in some games.");
}
}
}
void RasterizerOpenGL::SetupVertexFormat() { void RasterizerOpenGL::SetupVertexFormat() {
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
@@ -266,6 +299,11 @@ DrawParameters RasterizerOpenGL::SetupDraw() {
return params; return params;
} }
bool RasterizerOpenGL::GeometryShaderActive() {
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
return gpu.regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
}
void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
MICROPROFILE_SCOPE(OpenGL_Shader); MICROPROFILE_SCOPE(OpenGL_Shader);
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
@@ -542,6 +580,30 @@ void RasterizerOpenGL::Clear() {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
use_stencil = true; use_stencil = true;
clear_state.stencil.test_enabled = true; clear_state.stencil.test_enabled = true;
if (regs.clear_flags.stencil) {
// Stencil affects the clear so fill it with the used masks
clear_state.stencil.front.test_func = GL_ALWAYS;
clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
clear_state.stencil.front.action_stencil_fail = GL_KEEP;
clear_state.stencil.front.action_depth_fail = GL_KEEP;
clear_state.stencil.front.action_depth_pass = GL_KEEP;
clear_state.stencil.front.write_mask = regs.stencil_front_mask;
if (regs.stencil_two_side_enable) {
clear_state.stencil.back.test_func = GL_ALWAYS;
clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
clear_state.stencil.back.action_depth_fail = GL_KEEP;
clear_state.stencil.back.action_depth_pass = GL_KEEP;
clear_state.stencil.back.write_mask = regs.stencil_back_mask;
} else {
clear_state.stencil.back.test_func = GL_ALWAYS;
clear_state.stencil.back.test_mask = 0xFFFFFFFF;
clear_state.stencil.back.write_mask = 0xFFFFFFFF;
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
clear_state.stencil.back.action_depth_fail = GL_KEEP;
clear_state.stencil.back.action_depth_pass = GL_KEEP;
}
}
} }
if (!use_color && !use_depth && !use_stencil) { if (!use_color && !use_depth && !use_stencil) {
@@ -553,6 +615,15 @@ void RasterizerOpenGL::Clear() {
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
regs.clear_buffers.RT.Value()); regs.clear_buffers.RT.Value());
if (regs.clear_flags.scissor) {
SyncScissorTest(clear_state);
}
if (regs.clear_flags.viewport) {
// Viewport does not affects glClearBuffer so emulate viewport using Scissor
clear_state.TranslateViewportToScissor();
}
clear_state.Apply(); clear_state.Apply();
if (use_color) { if (use_color) {
@@ -577,7 +648,7 @@ void RasterizerOpenGL::DrawArrays() {
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
ScopeAcquireGLContext acquire_context{emu_window}; ScopeAcquireGLContext acquire_context{emu_window};
state.geometry_shaders.enabled = GeometryShaderActive();
ConfigureFramebuffers(state); ConfigureFramebuffers(state);
SyncColorMask(); SyncColorMask();
SyncFragmentColorClampState(); SyncFragmentColorClampState();
@@ -588,7 +659,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncLogicOpState(); SyncLogicOpState();
SyncCullMode(); SyncCullMode();
SyncPrimitiveRestart(); SyncPrimitiveRestart();
SyncScissorTest(); SyncScissorTest(state);
// Alpha Testing is synced on shaders. // Alpha Testing is synced on shaders.
SyncTransformFeedback(); SyncTransformFeedback();
SyncPointState(); SyncPointState();
@@ -815,7 +886,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
} }
const u32 bias = config.mip_lod_bias.Value(); const u32 bias = config.mip_lod_bias.Value();
// Sign extend the 13-bit value. // Sign extend the 13-bit value.
const u32 mask = 1U << (13 - 1); constexpr u32 mask = 1U << (13 - 1);
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
if (lod_bias != bias_lod) { if (lod_bias != bias_lod) {
lod_bias = bias_lod; lod_bias = bias_lod;
@@ -942,16 +1013,28 @@ 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 (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { const std::size_t viewport_count =
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; current_state.geometry_shaders.enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
for (std::size_t i = 0; i < viewport_count; i++) {
auto& viewport = current_state.viewports[i]; auto& viewport = current_state.viewports[i];
viewport.x = viewport_rect.left; const auto& src = regs.viewports[i];
viewport.y = viewport_rect.bottom; if (regs.viewport_transform_enabled) {
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); viewport.x = viewport_rect.left;
viewport.y = viewport_rect.bottom;
viewport.width = viewport_rect.GetWidth();
viewport.height = viewport_rect.GetHeight();
} else {
viewport.x = src.x;
viewport.y = src.y;
viewport.width = src.width;
viewport.height = src.height;
}
viewport.depth_range_far = regs.viewports[i].depth_range_far; viewport.depth_range_far = regs.viewports[i].depth_range_far;
viewport.depth_range_near = regs.viewports[i].depth_range_near; viewport.depth_range_near = regs.viewports[i].depth_range_near;
} }
current_state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
current_state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
} }
void RasterizerOpenGL::SyncClipEnabled() { void RasterizerOpenGL::SyncClipEnabled() {
@@ -1120,11 +1203,13 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
} }
void RasterizerOpenGL::SyncScissorTest() { void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { const std::size_t viewport_count =
current_state.geometry_shaders.enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
for (std::size_t i = 0; i < viewport_count; i++) {
const auto& src = regs.scissor_test[i]; const auto& src = regs.scissor_test[i];
auto& dst = state.viewports[i].scissor; auto& dst = current_state.viewports[i].scissor;
dst.enabled = (src.enable != 0); dst.enabled = (src.enable != 0);
if (dst.enabled == 0) { if (dst.enabled == 0) {
return; return;

View File

@@ -91,19 +91,20 @@ private:
void SyncWithConfig(const Tegra::Texture::TSCEntry& info); void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
private: private:
Tegra::Texture::TextureFilter mag_filter; Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
Tegra::Texture::TextureFilter min_filter; Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
Tegra::Texture::TextureMipmapFilter mip_filter; Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
Tegra::Texture::WrapMode wrap_v; Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
Tegra::Texture::WrapMode wrap_p; Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
bool uses_depth_compare; bool uses_depth_compare = false;
Tegra::Texture::DepthCompareFunc depth_compare_func; Tegra::Texture::DepthCompareFunc depth_compare_func =
GLvec4 border_color; Tegra::Texture::DepthCompareFunc::Always;
float min_lod; GLvec4 border_color = {};
float max_lod; float min_lod = 0.f;
float lod_bias; float max_lod = 16.0f;
float max_anisotropic; float lod_bias = 0.0f;
float max_anisotropic = 1.0f;
}; };
/** /**
@@ -171,7 +172,7 @@ private:
void SyncMultiSampleState(); 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(OpenGLState& current_state);
/// Syncs the transform feedback state to match the guest state /// Syncs the transform feedback state to match the guest state
void SyncTransformFeedback(); void SyncTransformFeedback();
@@ -185,6 +186,10 @@ private:
/// Check asserts for alpha testing. /// Check asserts for alpha testing.
void CheckAlphaTests(); void CheckAlphaTests();
/// check for extension that are not strictly required
/// but are needed for correct emulation
void CheckExtensions();
bool has_ARB_direct_state_access = false; bool has_ARB_direct_state_access = false;
bool has_ARB_multi_bind = false; bool has_ARB_multi_bind = false;
bool has_ARB_separate_shader_objects = false; bool has_ARB_separate_shader_objects = false;
@@ -223,6 +228,7 @@ private:
DrawParameters SetupDraw(); DrawParameters SetupDraw();
void SetupShaders(GLenum primitive_mode); void SetupShaders(GLenum primitive_mode);
bool GeometryShaderActive();
enum class AccelDraw { Disabled, Arrays, Indexed }; enum class AccelDraw { Disabled, Arrays, Indexed };
AccelDraw accelerate_draw = AccelDraw::Disabled; AccelDraw accelerate_draw = AccelDraw::Disabled;

View File

@@ -92,6 +92,8 @@ OpenGLState::OpenGLState() {
point.size = 1; point.size = 1;
fragment_color_clamp.enabled = false; fragment_color_clamp.enabled = false;
depth_clamp.far_plane = false;
depth_clamp.near_plane = false;
} }
void OpenGLState::ApplyDefaultState() { void OpenGLState::ApplyDefaultState() {
@@ -234,6 +236,28 @@ void OpenGLState::ApplyStencilTest() const {
} }
} }
void OpenGLState::TranslateViewportToScissor() {
auto& current = this->viewports[0];
if (current.scissor.enabled) {
GLint left = std::max(current.x, current.scissor.x);
GLint right =
std::max(current.x + current.width, current.scissor.x + current.scissor.width);
GLint bottom = std::max(current.y, current.scissor.y);
GLint top =
std::max(current.y + current.height, current.scissor.y + current.scissor.height);
current.scissor.x = std::max(left, 0);
current.scissor.y = std::max(bottom, 0);
current.scissor.width = std::max(right - left, 0);
current.scissor.height = std::max(top - bottom, 0);
} else {
current.scissor.enabled = true;
current.scissor.x = current.x;
current.scissor.y = current.y;
current.scissor.width = current.width;
current.scissor.height = current.height;
}
}
void OpenGLState::ApplyViewport() const { void OpenGLState::ApplyViewport() const {
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports);
@@ -242,7 +266,9 @@ void OpenGLState::ApplyViewport() const {
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 ||
updated.width != current.width || updated.height != current.height) { updated.width != current.width || updated.height != current.height) {
glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height); glViewportIndexedf(
i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
} }
if (updated.depth_range_near != current.depth_range_near || if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) { updated.depth_range_far != current.depth_range_far) {
@@ -270,8 +296,7 @@ void OpenGLState::ApplyViewport() const {
const auto& updated = viewports[0]; const auto& updated = viewports[0];
if (updated.x != current.x || updated.y != current.y || updated.width != current.width || if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
updated.height != current.height) { updated.height != current.height) {
glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y), glViewport(updated.x, updated.y, updated.width, updated.height);
static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
} }
if (updated.depth_range_near != current.depth_range_near || if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) { updated.depth_range_far != current.depth_range_far) {
@@ -483,6 +508,29 @@ void OpenGLState::Apply() const {
fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
} }
} }
if (depth_clamp.far_plane != cur_state.depth_clamp.far_plane ||
depth_clamp.near_plane != cur_state.depth_clamp.near_plane) {
if (GLAD_GL_AMD_depth_clamp_separate) {
if (depth_clamp.far_plane) {
glEnable(GL_DEPTH_CLAMP_FAR_AMD);
} else {
glDisable(GL_DEPTH_CLAMP_FAR_AMD);
}
if (depth_clamp.near_plane) {
glEnable(GL_DEPTH_CLAMP_NEAR_AMD);
} else {
glDisable(GL_DEPTH_CLAMP_NEAR_AMD);
}
} else {
if (depth_clamp.far_plane || depth_clamp.near_plane) {
glEnable(GL_DEPTH_CLAMP);
} else {
glDisable(GL_DEPTH_CLAMP);
}
UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
"Unimplemented Depth Clamp Separation!");
}
}
if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) { if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) {
if (multisample_control.alpha_to_coverage) { if (multisample_control.alpha_to_coverage) {
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);

View File

@@ -48,6 +48,11 @@ public:
bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
} fragment_color_clamp; } fragment_color_clamp;
struct {
bool far_plane;
bool near_plane;
} depth_clamp; // GL_DEPTH_CLAMP
struct { struct {
bool enabled; // viewports arrays are only supported when geometry shaders are enabled. bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
} geometry_shaders; } geometry_shaders;
@@ -156,10 +161,10 @@ public:
} draw; } draw;
struct viewport { struct viewport {
GLfloat x; GLint x;
GLfloat y; GLint y;
GLfloat width; GLint width;
GLfloat height; GLint 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 { struct {
@@ -206,6 +211,7 @@ public:
OpenGLState& ResetBuffer(GLuint handle); OpenGLState& ResetBuffer(GLuint handle);
OpenGLState& ResetVertexArray(GLuint handle); OpenGLState& ResetVertexArray(GLuint handle);
OpenGLState& ResetFramebuffer(GLuint handle); OpenGLState& ResetFramebuffer(GLuint handle);
void TranslateViewportToScissor();
private: private:
static OpenGLState cur_state; static OpenGLState cur_state;