summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp118
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp40
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp252
-rw-r--r--src/video_core/renderer_opengl/gl_state.h60
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp5
7 files changed, 341 insertions, 150 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 6ae2adfab..1bdd4c054 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -525,10 +525,10 @@ void RasterizerOpenGL::Clear() {
OpenGLState clear_state;
clear_state.draw.draw_framebuffer = framebuffer.handle;
- clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
- clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
- clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
- clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
+ clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
+ clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
+ clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
+ clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
regs.clear_buffers.A) {
@@ -587,14 +587,13 @@ void RasterizerOpenGL::DrawArrays() {
ScopeAcquireGLContext acquire_context{emu_window};
ConfigureFramebuffers();
-
+ SyncColorMask();
SyncDepthTestState();
SyncStencilTestState();
SyncBlendState();
SyncLogicOpState();
SyncCullMode();
SyncPrimitiveRestart();
- SyncDepthRange();
SyncScissorTest();
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
@@ -914,12 +913,16 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
void RasterizerOpenGL::SyncViewport() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
-
- state.viewport.x = viewport_rect.left;
- state.viewport.y = viewport_rect.bottom;
- state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
- state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
+ for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
+ auto& viewport = state.viewports[i];
+ viewport.x = viewport_rect.left;
+ viewport.y = viewport_rect.bottom;
+ 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() {
@@ -961,13 +964,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
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() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@@ -1008,26 +1004,60 @@ void RasterizerOpenGL::SyncStencilTestState() {
state.stencil.back.write_mask = regs.stencil_back_mask;
}
-void RasterizerOpenGL::SyncBlendState() {
+void RasterizerOpenGL::SyncColorMask() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
+ auto& dest = state.color_mask[i];
+ dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
+ dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE;
+ dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
+ dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
+ }
+}
- // TODO(Subv): Support more than just render target 0.
- state.blend.enabled = regs.blend.enable[0] != 0;
+void RasterizerOpenGL::SyncBlendState() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- if (!state.blend.enabled)
+ state.blend_color.red = regs.blend_color.r;
+ state.blend_color.green = regs.blend_color.g;
+ state.blend_color.blue = regs.blend_color.b;
+ state.blend_color.alpha = regs.blend_color.a;
+
+ state.independant_blend.enabled = regs.independent_blend_enable;
+ if (!state.independant_blend.enabled) {
+ auto& blend = state.blend[0];
+ blend.enabled = regs.blend.enable[0] != 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;
+ }
- ASSERT_MSG(regs.logic_op.enable == 0,
- "Blending and logic op can't be enabled at the same time.");
-
- ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented");
- ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented");
- state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb);
- state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb);
- state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb);
- state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a);
- state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a);
- state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a);
+ for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ auto& blend = state.blend[i];
+ blend.enabled = regs.blend.enable[i] != 0;
+ if (!blend.enabled)
+ continue;
+ blend.separate_alpha = regs.independent_blend[i].separate_alpha;
+ blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
+ blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
+ blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
+ if (blend.separate_alpha) {
+ 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() {
@@ -1046,19 +1076,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
}
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;
-
state.scissor.enabled = (regs.scissor_test.enable != 0);
- // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's
- // implemented.
- if (regs.scissor_test.enable != 0) {
- 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;
+ if (regs.scissor_test.enable == 0) {
+ return;
}
+ 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() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 0fab3eb28..5eee5f088 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -133,7 +133,7 @@ private:
u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
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();
/// Syncs the clip enabled status to match the guest state
@@ -148,9 +148,6 @@ private:
/// Syncs the primitve restart to match the guest state
void SyncPrimitiveRestart();
- /// Syncs the depth range to match the guest state
- void SyncDepthRange();
-
/// Syncs the depth test state to match the guest state
void SyncDepthTestState();
@@ -172,6 +169,9 @@ private:
/// Syncs the point state to match the guest state
void SyncPointState();
+ /// Syncs Color Mask
+ void SyncColorMask();
+
/// Check asserts for alpha testing.
void CheckAlphaTests();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 7d970efa0..49d63e6f3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -562,9 +562,11 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
}
}
+MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
+ MICROPROFILE_SCOPE(OpenGL_BlitSurface);
const auto& src_params{src_surface->GetSurfaceParams()};
const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -704,9 +706,11 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
0, 0, width, height, 1);
}
+MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
GLuint copy_pbo_handle, GLenum src_attachment = 0,
GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
+ MICROPROFILE_SCOPE(OpenGL_CopySurface);
ASSERT_MSG(dst_attachment == 0, "Unimplemented");
const auto& src_params{src_surface->GetSurfaceParams()};
@@ -975,7 +979,7 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
}
}
-MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
+MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
void CachedSurface::LoadGLBuffer() {
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
gl_buffer.resize(params.max_mip_level);
@@ -1157,7 +1161,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
-MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
+MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
if (params.type == SurfaceType::Fill)
return;
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index c10863337..c17d5ac00 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -5,21 +5,29 @@
#include <utility>
#include <glad/glad.h>
#include "common/common_types.h"
+#include "common/microprofile.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_state.h"
+MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192));
+MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192));
+
namespace OpenGL {
void OGLTexture::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenTextures(1, &handle);
}
void OGLTexture::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteTextures(1, &handle);
OpenGLState::GetCurState().UnbindTexture(handle).Apply();
handle = 0;
@@ -28,12 +36,16 @@ void OGLTexture::Release() {
void OGLSampler::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenSamplers(1, &handle);
}
void OGLSampler::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteSamplers(1, &handle);
OpenGLState::GetCurState().ResetSampler(handle).Apply();
handle = 0;
@@ -44,12 +56,16 @@ void OGLShader::Create(const char* source, GLenum type) {
return;
if (source == nullptr)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
handle = GLShader::LoadShader(source, type);
}
void OGLShader::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteShader(handle);
handle = 0;
}
@@ -63,12 +79,16 @@ void OGLProgram::CreateFromSource(const char* vert_shader, const char* geo_shade
geo.Create(geo_shader, GL_GEOMETRY_SHADER);
if (frag_shader)
frag.Create(frag_shader, GL_FRAGMENT_SHADER);
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
Create(separable_program, vert.handle, geo.handle, frag.handle);
}
void OGLProgram::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteProgram(handle);
OpenGLState::GetCurState().ResetProgram(handle).Apply();
handle = 0;
@@ -77,12 +97,16 @@ void OGLProgram::Release() {
void OGLPipeline::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenProgramPipelines(1, &handle);
}
void OGLPipeline::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteProgramPipelines(1, &handle);
OpenGLState::GetCurState().ResetPipeline(handle).Apply();
handle = 0;
@@ -91,12 +115,16 @@ void OGLPipeline::Release() {
void OGLBuffer::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenBuffers(1, &handle);
}
void OGLBuffer::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteBuffers(1, &handle);
OpenGLState::GetCurState().ResetBuffer(handle).Apply();
handle = 0;
@@ -105,12 +133,16 @@ void OGLBuffer::Release() {
void OGLSync::Create() {
if (handle != 0)
return;
+
+ // Don't profile here, this one is expected to happen ingame.
handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
void OGLSync::Release() {
if (handle == 0)
return;
+
+ // Don't profile here, this one is expected to happen ingame.
glDeleteSync(handle);
handle = 0;
}
@@ -118,12 +150,16 @@ void OGLSync::Release() {
void OGLVertexArray::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenVertexArrays(1, &handle);
}
void OGLVertexArray::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteVertexArrays(1, &handle);
OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
handle = 0;
@@ -132,12 +168,16 @@ void OGLVertexArray::Release() {
void OGLFramebuffer::Create() {
if (handle != 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenFramebuffers(1, &handle);
}
void OGLFramebuffer::Release() {
if (handle == 0)
return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteFramebuffers(1, &handle);
OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
handle = 0;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b6b426f34..9517285e5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -22,17 +22,15 @@ OpenGLState::OpenGLState() {
depth.test_enabled = false;
depth.test_func = GL_LESS;
depth.write_mask = GL_TRUE;
- depth.depth_range_near = 0.0f;
- depth.depth_range_far = 1.0f;
primitive_restart.enabled = false;
primitive_restart.index = 0;
-
- color_mask.red_enabled = GL_TRUE;
- color_mask.green_enabled = GL_TRUE;
- color_mask.blue_enabled = GL_TRUE;
- color_mask.alpha_enabled = GL_TRUE;
-
+ for (auto& item : color_mask) {
+ item.red_enabled = GL_TRUE;
+ item.green_enabled = GL_TRUE;
+ item.blue_enabled = GL_TRUE;
+ item.alpha_enabled = GL_TRUE;
+ }
stencil.test_enabled = false;
auto reset_stencil = [](auto& config) {
config.test_func = GL_ALWAYS;
@@ -45,19 +43,33 @@ OpenGLState::OpenGLState() {
};
reset_stencil(stencil.front);
reset_stencil(stencil.back);
-
- blend.enabled = true;
- blend.rgb_equation = GL_FUNC_ADD;
- blend.a_equation = GL_FUNC_ADD;
- blend.src_rgb_func = GL_ONE;
- blend.dst_rgb_func = GL_ZERO;
- blend.src_a_func = GL_ONE;
- blend.dst_a_func = GL_ZERO;
- blend.color.red = 0.0f;
- blend.color.green = 0.0f;
- blend.color.blue = 0.0f;
- blend.color.alpha = 0.0f;
-
+ for (auto& item : viewports) {
+ item.x = 0;
+ item.y = 0;
+ item.width = 0;
+ item.height = 0;
+ item.depth_range_near = 0.0f;
+ item.depth_range_far = 1.0f;
+ }
+ scissor.enabled = false;
+ scissor.x = 0;
+ scissor.y = 0;
+ 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.operation = GL_COPY;
@@ -73,17 +85,6 @@ OpenGLState::OpenGLState() {
draw.shader_program = 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 = {};
point.size = 1;
@@ -134,6 +135,32 @@ void OpenGLState::ApplyCulling() const {
}
}
+void OpenGLState::ApplyColorMask() const {
+ if (GLAD_GL_ARB_viewport_array) {
+ for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
+ const auto& updated = color_mask[i];
+ const auto& current = cur_state.color_mask[i];
+ if (updated.red_enabled != current.red_enabled ||
+ updated.green_enabled != current.green_enabled ||
+ updated.blue_enabled != current.blue_enabled ||
+ updated.alpha_enabled != current.alpha_enabled) {
+ glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
+ updated.blue_enabled, updated.alpha_enabled);
+ }
+ }
+ } else {
+ const auto& updated = color_mask[0];
+ const auto& current = cur_state.color_mask[0];
+ if (updated.red_enabled != current.red_enabled ||
+ updated.green_enabled != current.green_enabled ||
+ updated.blue_enabled != current.blue_enabled ||
+ updated.alpha_enabled != current.alpha_enabled) {
+ glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
+ updated.alpha_enabled);
+ }
+ }
+}
+
void OpenGLState::ApplyDepth() const {
// Depth test
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
@@ -152,11 +179,6 @@ void OpenGLState::ApplyDepth() const {
if (depth.write_mask != cur_state.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 {
@@ -208,7 +230,7 @@ void OpenGLState::ApplyStencilTest() const {
}
}
-void OpenGLState::ApplyScissorTest() const {
+void OpenGLState::ApplyScissor() const {
const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
if (scissor_changed) {
if (scissor.enabled) {
@@ -217,51 +239,141 @@ void OpenGLState::ApplyScissorTest() const {
glDisable(GL_SCISSOR_TEST);
}
}
- if (scissor_changed || 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) {
+ 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::ApplyBlending() const {
- const bool blend_changed = blend.enabled != cur_state.blend.enabled;
+void OpenGLState::ApplyViewport() const {
+ 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.enabled) {
- ASSERT(!logic_op.enabled);
+ if (updated.enabled) {
glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}
}
- if (blend.enabled) {
- if (blend_changed || 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);
+ 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) {
+ 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 ||
- blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
- blend.src_a_func != cur_state.blend.src_a_func ||
- blend.dst_a_func != cur_state.blend.dst_a_func) {
- glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
- blend.dst_a_func);
+ if (blend_changed || updated.rgb_equation != current.rgb_equation ||
+ updated.a_equation != current.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 || blend.rgb_equation != cur_state.blend.rgb_equation ||
- blend.a_equation != cur_state.blend.a_equation) {
- glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
+ if (blend_changed || updated.rgb_equation != current.rgb_equation) {
+ glBlendEquation(updated.rgb_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 {
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
if (logic_op_changed) {
if (logic_op.enabled) {
- ASSERT(!blend.enabled);
glEnable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_COLOR_LOGIC_OP);
@@ -348,12 +460,6 @@ void OpenGLState::Apply() const {
if (draw.program_pipeline != cur_state.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
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -364,19 +470,13 @@ void OpenGLState::Apply() const {
}
}
}
- // Color mask
- if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
- color_mask.green_enabled != cur_state.color_mask.green_enabled ||
- color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
- color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
- glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
- color_mask.alpha_enabled);
- }
// Point
if (point.size != cur_state.point.size) {
glPointSize(point.size);
}
- ApplyScissorTest();
+ ApplyColorMask();
+ ApplyViewport();
+ ApplyScissor();
ApplyStencilTest();
ApplySRgb();
ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fe648aff6..b8cf1f637 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -46,11 +46,9 @@ public:
} cull;
struct {
- bool test_enabled; // GL_DEPTH_TEST
- GLenum test_func; // GL_DEPTH_FUNC
- GLboolean write_mask; // GL_DEPTH_WRITEMASK
- GLfloat depth_range_near; // GL_DEPTH_RANGE
- GLfloat depth_range_far; // GL_DEPTH_RANGE
+ bool test_enabled; // GL_DEPTH_TEST
+ GLenum test_func; // GL_DEPTH_FUNC
+ GLboolean write_mask; // GL_DEPTH_WRITEMASK
} depth;
struct {
@@ -58,13 +56,14 @@ public:
GLuint index;
} primitive_restart; // GL_PRIMITIVE_RESTART
- struct {
+ struct ColorMask {
GLboolean red_enabled;
GLboolean green_enabled;
GLboolean blue_enabled;
GLboolean alpha_enabled;
- } color_mask; // GL_COLOR_WRITEMASK
-
+ };
+ std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
+ color_mask; // GL_COLOR_WRITEMASK
struct {
bool test_enabled; // GL_STENCIL_TEST
struct {
@@ -78,22 +77,28 @@ public:
} front, back;
} stencil;
- struct {
+ struct Blend {
bool enabled; // GL_BLEND
+ bool separate_alpha; // Independent blend enabled
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
GLenum dst_rgb_func; // GL_BLEND_DST_RGB
GLenum src_a_func; // GL_BLEND_SRC_ALPHA
GLenum dst_a_func; // GL_BLEND_DST_ALPHA
+ };
+ std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
- struct {
- GLclampf red;
- GLclampf green;
- GLclampf blue;
- GLclampf alpha;
- } color; // GL_BLEND_COLOR
- } blend;
+ struct {
+ bool enabled;
+ } independant_blend;
+
+ struct {
+ GLclampf red;
+ GLclampf green;
+ GLclampf blue;
+ GLclampf alpha;
+ } blend_color; // GL_BLEND_COLOR
struct {
bool enabled; // GL_LOGIC_OP_MODE
@@ -138,6 +143,16 @@ public:
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
} 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 {
bool enabled; // GL_SCISSOR_TEST
GLint x;
@@ -147,13 +162,6 @@ public:
} scissor;
struct {
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
- } viewport;
-
- struct {
float size; // GL_POINT_SIZE
} point;
@@ -191,14 +199,18 @@ private:
static bool s_rgb_used;
void ApplySRgb() const;
void ApplyCulling() const;
+ void ApplyColorMask() const;
void ApplyDepth() const;
void ApplyPrimitiveRestart() const;
void ApplyStencilTest() const;
- void ApplyScissorTest() const;
+ void ApplyViewport() const;
+ void ApplyTargetBlending(int target, bool force) const;
+ void ApplyGlobalBlending() const;
void ApplyBlending() const;
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
+ void ApplyScissor() const;
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index e409228cc..b97b895a4 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -6,9 +6,13 @@
#include <vector>
#include "common/alignment.h"
#include "common/assert.h"
+#include "common/microprofile.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
+MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
+ MP_RGB(128, 128, 192));
+
namespace OpenGL {
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
@@ -75,6 +79,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
}
if (invalidate || !persistent) {
+ MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);