From 392547a97c768f1241df853e34d3d7b52d220727 Mon Sep 17 00:00:00 2001 From: Markus Wick Date: Tue, 6 Nov 2018 10:40:49 +0100 Subject: [PATCH 1/4] gl_resource_manager: Split implementations in .cpp file Those implementations are quite costly, so there is no need to inline them to the caller. Ressource deletion is often a performance bug, so in this way, we support to add breakpoints to them. --- src/video_core/CMakeLists.txt | 1 + .../renderer_opengl/gl_resource_manager.cpp | 134 ++++++++++++++++++ .../renderer_opengl/gl_resource_manager.h | 123 +++------------- .../renderer_opengl/gl_shader_manager.h | 1 + 4 files changed, 155 insertions(+), 104 deletions(-) create mode 100644 src/video_core/renderer_opengl/gl_resource_manager.cpp diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 1e12f4ac2..2ad6d2d99 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(video_core STATIC renderer_opengl/gl_rasterizer.h renderer_opengl/gl_rasterizer_cache.cpp renderer_opengl/gl_rasterizer_cache.h + renderer_opengl/gl_resource_manager.cpp renderer_opengl/gl_resource_manager.h renderer_opengl/gl_shader_decompiler.cpp renderer_opengl/gl_shader_decompiler.h diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp new file mode 100644 index 000000000..32a7d52c6 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -0,0 +1,134 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.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" + +namespace OpenGL { + +void OGLTexture::Create() { + if (handle != 0) + return; + glGenTextures(1, &handle); +} + +void OGLTexture::Release() { + if (handle == 0) + return; + glDeleteTextures(1, &handle); + OpenGLState::GetCurState().ResetTexture(handle).Apply(); + handle = 0; +} + +void OGLSampler::Create() { + if (handle != 0) + return; + glGenSamplers(1, &handle); +} + +void OGLSampler::Release() { + if (handle == 0) + return; + glDeleteSamplers(1, &handle); + OpenGLState::GetCurState().ResetSampler(handle).Apply(); + handle = 0; +} + +void OGLShader::Create(const char* source, GLenum type) { + if (handle != 0) + return; + if (source == nullptr) + return; + handle = LoadShader(source, type); +} + +void OGLShader::Release() { + if (handle == 0) + return; + glDeleteShader(handle); + handle = 0; +} + +void OGLProgram::Create(bool separable_program, const std::vector& shaders) { + if (handle != 0) + return; + handle = LoadProgram(separable_program, shaders); +} + +void OGLProgram::Create(const char* vert_shader, const char* frag_shader) { + OGLShader vert, frag; + vert.Create(vert_shader, GL_VERTEX_SHADER); + frag.Create(frag_shader, GL_FRAGMENT_SHADER); + Create(false, {vert.handle, frag.handle}); +} + +void OGLProgram::Release() { + if (handle == 0) + return; + glDeleteProgram(handle); + OpenGLState::GetCurState().ResetProgram(handle).Apply(); + handle = 0; +} + +void OGLPipeline::Create() { + if (handle != 0) + return; + glGenProgramPipelines(1, &handle); +} + +void OGLPipeline::Release() { + if (handle == 0) + return; + glDeleteProgramPipelines(1, &handle); + OpenGLState::GetCurState().ResetPipeline(handle).Apply(); + handle = 0; +} + +void OGLBuffer::Create() { + if (handle != 0) + return; + glGenBuffers(1, &handle); +} + +void OGLBuffer::Release() { + if (handle == 0) + return; + glDeleteBuffers(1, &handle); + OpenGLState::GetCurState().ResetBuffer(handle).Apply(); + handle = 0; +} + +void OGLVertexArray::Create() { + if (handle != 0) + return; + glGenVertexArrays(1, &handle); +} + +void OGLVertexArray::Release() { + if (handle == 0) + return; + glDeleteVertexArrays(1, &handle); + OpenGLState::GetCurState().ResetVertexArray(handle).Apply(); + handle = 0; +} + +void OGLFramebuffer::Create() { + if (handle != 0) + return; + glGenFramebuffers(1, &handle); +} + +void OGLFramebuffer::Release() { + if (handle == 0) + return; + glDeleteFramebuffers(1, &handle); + OpenGLState::GetCurState().ResetFramebuffer(handle).Apply(); + handle = 0; +} + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 3fbf5eafb..ce7f7fbfb 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -9,7 +9,6 @@ #include #include "common/common_types.h" #include "video_core/renderer_opengl/gl_shader_util.h" -#include "video_core/renderer_opengl/gl_state.h" namespace OpenGL { @@ -30,20 +29,10 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create() { - if (handle != 0) - return; - glGenTextures(1, &handle); - } + void Create(); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteTextures(1, &handle); - OpenGLState::GetCurState().ResetTexture(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -65,20 +54,10 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create() { - if (handle != 0) - return; - glGenSamplers(1, &handle); - } + void Create(); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteSamplers(1, &handle); - OpenGLState::GetCurState().ResetSampler(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -99,20 +78,9 @@ public: return *this; } - void Create(const char* source, GLenum type) { - if (handle != 0) - return; - if (source == nullptr) - return; - handle = LoadShader(source, type); - } + void Create(const char* source, GLenum type); - void Release() { - if (handle == 0) - return; - glDeleteShader(handle); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -134,28 +102,13 @@ public: } /// Creates a new program from given shader objects - void Create(bool separable_program, const std::vector& shaders) { - if (handle != 0) - return; - handle = LoadProgram(separable_program, shaders); - } + void Create(bool separable_program, const std::vector& shaders); /// Creates a new program from given shader soruce code - void Create(const char* vert_shader, const char* frag_shader) { - OGLShader vert, frag; - vert.Create(vert_shader, GL_VERTEX_SHADER); - frag.Create(frag_shader, GL_FRAGMENT_SHADER); - Create(false, {vert.handle, frag.handle}); - } + void Create(const char* vert_shader, const char* frag_shader); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteProgram(handle); - OpenGLState::GetCurState().ResetProgram(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -175,19 +128,11 @@ public: return *this; } - void Create() { - if (handle != 0) - return; - glGenProgramPipelines(1, &handle); - } + /// Creates a new internal OpenGL resource and stores the handle + void Create(); - void Release() { - if (handle == 0) - return; - glDeleteProgramPipelines(1, &handle); - OpenGLState::GetCurState().ResetPipeline(handle).Apply(); - handle = 0; - } + /// Deletes the internal OpenGL resource + void Release(); GLuint handle = 0; }; @@ -209,20 +154,10 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create() { - if (handle != 0) - return; - glGenBuffers(1, &handle); - } + void Create(); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteBuffers(1, &handle); - OpenGLState::GetCurState().ResetBuffer(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -244,20 +179,10 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create() { - if (handle != 0) - return; - glGenVertexArrays(1, &handle); - } + void Create(); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteVertexArrays(1, &handle); - OpenGLState::GetCurState().ResetVertexArray(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; @@ -279,20 +204,10 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create() { - if (handle != 0) - return; - glGenFramebuffers(1, &handle); - } + void Create(); /// Deletes the internal OpenGL resource - void Release() { - if (handle == 0) - return; - glDeleteFramebuffers(1, &handle); - OpenGLState::GetCurState().ResetFramebuffer(handle).Apply(); - handle = 0; - } + void Release(); GLuint handle = 0; }; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 8c740f982..95c4a5f37 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -9,6 +9,7 @@ #include "video_core/regs_lighting.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_gen.h" +#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/pica_to_gl.h" namespace OpenGL { From 79696a1a43d036dd4c19bb04d63d0ab6b2bf546a Mon Sep 17 00:00:00 2001 From: Markus Wick Date: Tue, 6 Nov 2018 10:42:33 +0100 Subject: [PATCH 2/4] gl_stream_buffer: Profile orphaning of stream buffer. This serialize to the driver thread and so it may block for a while. So if it is in the benchmark, we get noticed if it happens too often. --- src/video_core/renderer_opengl/gl_stream_buffer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index 736cfa9c4..4b9da6285 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 #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 array_buffer_for_amd, @@ -76,6 +80,7 @@ std::tuple 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); From 2b793797e0a5f0e74d4330a0f9b9aa1bb605c951 Mon Sep 17 00:00:00 2001 From: Markus Wick Date: Tue, 6 Nov 2018 11:07:50 +0100 Subject: [PATCH 3/4] gl_resource_manager: Profile creation and deletion --- .../renderer_opengl/gl_resource_manager.cpp | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 32a7d52c6..1cffc8ea7 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 #include #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().ResetTexture(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 = LoadShader(source, type); } void OGLShader::Release() { if (handle == 0) return; + + MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); glDeleteShader(handle); handle = 0; } @@ -57,6 +73,8 @@ void OGLShader::Release() { void OGLProgram::Create(bool separable_program, const std::vector& shaders) { if (handle != 0) return; + + MICROPROFILE_SCOPE(OpenGL_ResourceCreation); handle = LoadProgram(separable_program, shaders); } @@ -64,12 +82,16 @@ void OGLProgram::Create(const char* vert_shader, const char* frag_shader) { OGLShader vert, frag; vert.Create(vert_shader, GL_VERTEX_SHADER); frag.Create(frag_shader, GL_FRAGMENT_SHADER); + + MICROPROFILE_SCOPE(OpenGL_ResourceCreation); Create(false, {vert.handle, frag.handle}); } void OGLProgram::Release() { if (handle == 0) return; + + MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); glDeleteProgram(handle); OpenGLState::GetCurState().ResetProgram(handle).Apply(); handle = 0; @@ -78,12 +100,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; @@ -92,12 +118,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; @@ -106,12 +136,16 @@ void OGLBuffer::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; @@ -120,12 +154,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; From 62036bdea8892d7ec0beb57dbec55b71adab3e69 Mon Sep 17 00:00:00 2001 From: Markus Wick Date: Tue, 6 Nov 2018 13:25:01 +0100 Subject: [PATCH 4/4] gl_rasterizer_cache: Add profiles for Copy and Blit They were missed, and Copy is very high in profile here. It doesn't block the GPU, but it stalls the driver thread. So with our bad GL instructions, this might block quite a while. --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 395a0e8fa..2a377e543 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -594,8 +594,11 @@ SurfaceInterval SurfaceParams::GetCopyableInterval(const Surface& src_surface) c return result; } +MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, SurfaceInterval copy_interval) { + MICROPROFILE_SCOPE(OpenGL_CopySurface); + SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); ASSERT(subrect_params.GetInterval() == copy_interval); @@ -625,7 +628,7 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac UNREACHABLE(); } -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(PAddr load_start, PAddr load_end) { ASSERT(type != SurfaceType::Fill); @@ -727,7 +730,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { } } -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(const MathUtil::Rectangle& rect, GLuint read_fb_handle, GLuint draw_fb_handle) { if (type == SurfaceType::Fill) @@ -1025,10 +1028,13 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { UnregisterSurface(*surface_cache.begin()->second.begin()); } +MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64)); bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle& src_rect, const Surface& dst_surface, const MathUtil::Rectangle& dst_rect) { + MICROPROFILE_SCOPE(OpenGL_BlitSurface); + if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) return false;