From 266f2b6242b93a65a8aee216a7e6534fc4429fd7 Mon Sep 17 00:00:00 2001 From: wwylele Date: Tue, 31 Jul 2018 13:51:42 +0300 Subject: [PATCH] gl_rasterizer: only apply AMD hack when the vendor is AMD --- .../renderer_opengl/gl_rasterizer.cpp | 16 +++++++++---- .../renderer_opengl/gl_rasterizer.h | 2 ++ .../renderer_opengl/gl_shader_manager.cpp | 24 ++++++++++++------- .../renderer_opengl/gl_shader_manager.h | 2 +- .../renderer_opengl/gl_stream_buffer.cpp | 5 ++-- .../renderer_opengl/gl_stream_buffer.h | 3 ++- 6 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 734eb4835..61cad2d92 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -34,11 +34,17 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); +static bool IsVendorAmd() { + std::string gpu_vendor{reinterpret_cast(glGetString(GL_VENDOR))}; + return gpu_vendor == "ATI Technologies Inc." || gpu_vendor == "Advanced Micro Devices, Inc."; +} + RasterizerOpenGL::RasterizerOpenGL() - : shader_dirty(true), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE), - uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE), - index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE), - texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE) { + : is_amd(IsVendorAmd()), shader_dirty(true), + vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd), + uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false), + index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false), + texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false) { allow_shadow = GLAD_GL_ARB_shader_image_load_store && GLAD_GL_ARB_shader_image_size && GLAD_GL_ARB_framebuffer_no_attachments; @@ -145,7 +151,7 @@ RasterizerOpenGL::RasterizerOpenGL() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer.GetHandle()); shader_program_manager = - std::make_unique(GLAD_GL_ARB_separate_shader_objects); + std::make_unique(GLAD_GL_ARB_separate_shader_objects, is_amd); glEnable(GL_BLEND); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 013a4a5e7..216a7b76c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -243,6 +243,8 @@ private: /// Setup geometry shader for AccelerateDrawBatch bool SetupGeometryShader(); + bool is_amd; + OpenGLState state; RasterizerCacheOpenGL res_cache; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 823ccde8b..519c15691 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -216,8 +216,8 @@ using FragmentShaders = class ShaderProgramManager::Impl { public: - explicit Impl(bool separable) - : separable(separable), programmable_vertex_shaders(separable), + explicit Impl(bool separable, bool is_amd) + : is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable), trivial_vertex_shader(separable), programmable_geometry_shaders(separable), fixed_geometry_shaders(separable), fragment_shaders(separable) { if (separable) @@ -248,6 +248,8 @@ public: }; }; + bool is_amd; + ShaderTuple current; ProgrammableVertexShaders programmable_vertex_shaders; @@ -263,8 +265,8 @@ public: OGLPipeline pipeline; }; -ShaderProgramManager::ShaderProgramManager(bool separable) - : impl(std::make_unique(separable)) {} +ShaderProgramManager::ShaderProgramManager(bool separable, bool is_amd) + : impl(std::make_unique(separable, is_amd)) {} ShaderProgramManager::~ShaderProgramManager() = default; @@ -304,11 +306,15 @@ void ShaderProgramManager::UseFragmentShader(const GLShader::PicaFSConfig& confi void ShaderProgramManager::ApplyTo(OpenGLState& state) { if (impl->separable) { - // Without this reseting, AMD sometimes freezes when one stage is changed but not for the - // others - glUseProgramStages(impl->pipeline.handle, - GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, - 0); + if (impl->is_amd) { + // Without this reseting, AMD sometimes freezes when one stage is changed but not for + // the others. + // On the other hand, including this reset seems to introduce memory leak in Intel + // Graphics. + glUseProgramStages( + impl->pipeline.handle, + GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, 0); + } glUseProgramStages(impl->pipeline.handle, GL_VERTEX_SHADER_BIT, impl->current.vs); glUseProgramStages(impl->pipeline.handle, GL_GEOMETRY_SHADER_BIT, impl->current.gs); diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 42f1fecf5..bbc6d5b10 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -99,7 +99,7 @@ static_assert(sizeof(GSUniformData) < 16384, /// A class that manage different shader stages and configures them with given config data. class ShaderProgramManager { public: - explicit ShaderProgramManager(bool separable); + ShaderProgramManager(bool separable, bool is_amd); ~ShaderProgramManager(); bool UseProgrammableVertexShader(const GLShader::PicaVSConfig& config, diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index 03a8ed8b7..d1aa324d4 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp @@ -9,13 +9,14 @@ #include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_stream_buffer.h" -OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) +OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool array_buffer_for_amd, + bool prefer_coherent) : gl_target(target), buffer_size(size) { gl_buffer.Create(); glBindBuffer(gl_target, gl_buffer.handle); GLsizeiptr allocate_size = size; - if (target == GL_ARRAY_BUFFER) { + if (array_buffer_for_amd) { // On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer // read position is near the end and is an out-of-bound access to the vertex buffer. This is // probably a bug in the driver and is related to the usage of vec3 attributes in the diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h index 45592daaf..71498f47d 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.h +++ b/src/video_core/renderer_opengl/gl_stream_buffer.h @@ -9,7 +9,8 @@ class OGLStreamBuffer : private NonCopyable { public: - explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false); + explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool array_buffer_for_amd, + bool prefer_coherent = false); ~OGLStreamBuffer(); GLuint GetHandle() const;