renderer_opengl: Remove amd hacks and legacy paths

* AMDs new driver fixed many issues in the OpenGL driver. No reason to
  keep these hacks. In addition the upgrade to 4.3 guarantees the
  existance of required extensions, so no need to check for them
master
emufan4568 2022-08-21 01:52:49 +07:00
parent 025cd31420
commit 07a69b7c7b
8 changed files with 20 additions and 241 deletions

@ -2,11 +2,9 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/assert.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "video_core/renderer_opengl/gl_format_reinterpreter.h" #include "video_core/renderer_opengl/gl_format_reinterpreter.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_vars.h"
namespace OpenGL { namespace OpenGL {
@ -98,129 +96,6 @@ private:
OGLVertexArray vao; OGLVertexArray vao;
}; };
class PixelBufferD24S8toABGR final : public FormatReinterpreterBase {
public:
PixelBufferD24S8toABGR() {
attributeless_vao.Create();
d24s8_abgr_buffer.Create();
d24s8_abgr_buffer_size = 0;
constexpr std::string_view vs_source = R"(
const vec2 vertices[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0),
vec2(-1.0, 1.0), vec2(1.0, 1.0));
void main() {
gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0);
}
)";
std::string fs_source = GLES ? fragment_shader_precision_OES : "";
fs_source += R"(
uniform samplerBuffer tbo;
uniform vec2 tbo_size;
uniform vec4 viewport;
out vec4 color;
void main() {
vec2 tbo_coord = (gl_FragCoord.xy - viewport.xy) * tbo_size / viewport.zw;
int tbo_offset = int(tbo_coord.y) * int(tbo_size.x) + int(tbo_coord.x);
color = texelFetch(tbo, tbo_offset).rabg;
}
)";
d24s8_abgr_shader.Create(vs_source.data(), fs_source.c_str());
OpenGLState state = OpenGLState::GetCurState();
GLuint old_program = state.draw.shader_program;
state.draw.shader_program = d24s8_abgr_shader.handle;
state.Apply();
GLint tbo_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo");
ASSERT(tbo_u_id != -1);
glUniform1i(tbo_u_id, 0);
state.draw.shader_program = old_program;
state.Apply();
d24s8_abgr_tbo_size_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo_size");
ASSERT(d24s8_abgr_tbo_size_u_id != -1);
d24s8_abgr_viewport_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "viewport");
ASSERT(d24s8_abgr_viewport_u_id != -1);
}
~PixelBufferD24S8toABGR() {}
PixelFormat GetSourceFormat() const override {
return PixelFormat::D24S8;
}
void Reinterpret(const OGLTexture& src_tex, Common::Rectangle<u32> src_rect,
const OGLTexture& dst_tex, Common::Rectangle<u32> dst_rect) override {
OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state;
state.draw.read_framebuffer = read_fbo.handle;
state.draw.draw_framebuffer = draw_fbo.handle;
state.Apply();
glBindBuffer(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer.handle);
GLsizeiptr target_pbo_size =
static_cast<GLsizeiptr>(src_rect.GetWidth()) * src_rect.GetHeight() * 4;
if (target_pbo_size > d24s8_abgr_buffer_size) {
d24s8_abgr_buffer_size = target_pbo_size * 2;
glBufferData(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer_size, nullptr, GL_STREAM_COPY);
}
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
src_tex.handle, 0);
glReadPixels(static_cast<GLint>(src_rect.left), static_cast<GLint>(src_rect.bottom),
static_cast<GLsizei>(src_rect.GetWidth()),
static_cast<GLsizei>(src_rect.GetHeight()), GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
// PBO now contains src_tex in RABG format
state.draw.shader_program = d24s8_abgr_shader.handle;
state.draw.vertex_array = attributeless_vao.handle;
state.viewport.x = static_cast<GLint>(dst_rect.left);
state.viewport.y = static_cast<GLint>(dst_rect.bottom);
state.viewport.width = static_cast<GLsizei>(dst_rect.GetWidth());
state.viewport.height = static_cast<GLsizei>(dst_rect.GetHeight());
state.Apply();
OGLTexture tbo;
tbo.Create();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, tbo.handle);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, d24s8_abgr_buffer.handle);
glUniform2f(d24s8_abgr_tbo_size_u_id, static_cast<GLfloat>(src_rect.GetWidth()),
static_cast<GLfloat>(src_rect.GetHeight()));
glUniform4f(d24s8_abgr_viewport_u_id, static_cast<GLfloat>(state.viewport.x),
static_cast<GLfloat>(state.viewport.y),
static_cast<GLfloat>(state.viewport.width),
static_cast<GLfloat>(state.viewport.height));
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
dst_tex.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_BUFFER, 0);
}
private:
OGLVertexArray attributeless_vao;
OGLBuffer d24s8_abgr_buffer;
GLsizeiptr d24s8_abgr_buffer_size;
OGLProgram d24s8_abgr_shader;
GLint d24s8_abgr_tbo_size_u_id;
GLint d24s8_abgr_viewport_u_id;
};
class ShaderD24S8toRGBA8 final : public FormatReinterpreterBase { class ShaderD24S8toRGBA8 final : public FormatReinterpreterBase {
public: public:
@ -371,24 +246,13 @@ FormatReinterpreterOpenGL::FormatReinterpreterOpenGL() {
const std::string_view vendor{reinterpret_cast<const char*>(glGetString(GL_VENDOR))}; const std::string_view vendor{reinterpret_cast<const char*>(glGetString(GL_VENDOR))};
const std::string_view version{reinterpret_cast<const char*>(glGetString(GL_VERSION))}; const std::string_view version{reinterpret_cast<const char*>(glGetString(GL_VERSION))};
// Fallback to PBO path on obsolete intel drivers
// intel`s GL_VERSION string - `3.3.0 - Build 25.20.100.6373`
const bool intel_broken_drivers =
vendor.find("Intel") != vendor.npos && (std::atoi(version.substr(14, 2).data()) < 30);
auto Register = [this](PixelFormat dest, std::unique_ptr<FormatReinterpreterBase>&& obj) { auto Register = [this](PixelFormat dest, std::unique_ptr<FormatReinterpreterBase>&& obj) {
const u32 dst_index = static_cast<u32>(dest); const u32 dst_index = static_cast<u32>(dest);
return reinterpreters[dst_index].push_back(std::move(obj)); return reinterpreters[dst_index].push_back(std::move(obj));
}; };
if ((!intel_broken_drivers && GLAD_GL_ARB_stencil_texturing &&
GLAD_GL_ARB_texture_storage && GLAD_GL_ARB_copy_image) || GLES) {
Register(PixelFormat::RGBA8, std::make_unique<ShaderD24S8toRGBA8>()); Register(PixelFormat::RGBA8, std::make_unique<ShaderD24S8toRGBA8>());
LOG_INFO(Render_OpenGL, "Using shader for D24S8 to RGBA8 reinterpretation"); LOG_INFO(Render_OpenGL, "Using shader for D24S8 to RGBA8 reinterpretation");
} else {
Register(PixelFormat::RGBA8, std::make_unique<PixelBufferD24S8toABGR>());
LOG_INFO(Render_OpenGL, "Using PBO for D24S8 to RGBA8 reinterpretation");
}
Register(PixelFormat::RGB5A1, std::make_unique<RGBA4toRGB5A1>()); Register(PixelFormat::RGB5A1, std::make_unique<RGBA4toRGB5A1>());
} }

@ -13,7 +13,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/math_util.h" #include "common/math_util.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scope_exit.h"
#include "common/vector_math.h" #include "common/vector_math.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
@ -36,34 +35,13 @@ 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_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
static bool IsVendorAmd() {
const std::string_view gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
return gpu_vendor == "ATI Technologies Inc." || gpu_vendor == "Advanced Micro Devices, Inc.";
}
static bool IsVendorIntel() {
std::string gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
return gpu_vendor == "Intel Inc.";
}
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window) RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window)
: is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd), : vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE),
uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false), uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false),
index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false), index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false),
texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false), texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false),
texture_lf_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false) { texture_lf_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false) {
allow_shadow = GLES || (GLAD_GL_ARB_shader_image_load_store && GLAD_GL_ARB_shader_image_size &&
GLAD_GL_ARB_framebuffer_no_attachments);
if (!allow_shadow) {
LOG_WARNING(Render_OpenGL,
"Shadow might not be able to render because of unsupported OpenGL extensions.");
}
if (!GLAD_GL_ARB_copy_image && !GLES) {
LOG_WARNING(Render_OpenGL,
"ARB_copy_image not supported. Some games might produce artifacts.");
}
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
state.clip_distance[0] = true; state.clip_distance[0] = true;
@ -178,7 +156,7 @@ RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window)
} }
#else #else
shader_program_manager = std::make_unique<ShaderProgramManager>( shader_program_manager = std::make_unique<ShaderProgramManager>(
emu_window, GLAD_GL_ARB_separate_shader_objects, is_amd); emu_window, GLAD_GL_ARB_separate_shader_objects);
#endif #endif
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -574,9 +552,10 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
state.Apply(); state.Apply();
if (shadow_rendering) { if (shadow_rendering) {
if (!allow_shadow || color_surface == nullptr) { if (color_surface == nullptr) {
return true; return true;
} }
glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
color_surface->width * color_surface->res_scale); color_surface->width * color_surface->res_scale);
glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
@ -663,9 +642,6 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
using TextureType = Pica::TexturingRegs::TextureConfig::TextureType; using TextureType = Pica::TexturingRegs::TextureConfig::TextureType;
switch (texture.config.type.Value()) { switch (texture.config.type.Value()) {
case TextureType::Shadow2D: { case TextureType::Shadow2D: {
if (!allow_shadow)
continue;
Surface surface = res_cache.GetTextureSurface(texture); Surface surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) { if (surface != nullptr) {
CheckBarrier(state.image_shadow_texture_px = surface->texture.handle); CheckBarrier(state.image_shadow_texture_px = surface->texture.handle);
@ -675,8 +651,6 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
continue; continue;
} }
case TextureType::ShadowCube: { case TextureType::ShadowCube: {
if (!allow_shadow)
continue;
Pica::Texture::TextureInfo info = Pica::Texture::TextureInfo::FromPicaRegister( Pica::Texture::TextureInfo info = Pica::Texture::TextureInfo::FromPicaRegister(
texture.config, texture.format); texture.config, texture.format);
Surface surface; Surface surface;
@ -875,7 +849,6 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
state.texture_units[texture_index].texture_2d = 0; state.texture_units[texture_index].texture_2d = 0;
} }
state.texture_cube_unit.texture_cube = 0; state.texture_cube_unit.texture_cube = 0;
if (allow_shadow) {
state.image_shadow_texture_px = 0; state.image_shadow_texture_px = 0;
state.image_shadow_texture_nx = 0; state.image_shadow_texture_nx = 0;
state.image_shadow_texture_py = 0; state.image_shadow_texture_py = 0;
@ -883,7 +856,6 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
state.image_shadow_texture_pz = 0; state.image_shadow_texture_pz = 0;
state.image_shadow_texture_nz = 0; state.image_shadow_texture_nz = 0;
state.image_shadow_buffer = 0; state.image_shadow_buffer = 0;
}
state.Apply(); state.Apply();
if (shadow_rendering) { if (shadow_rendering) {

@ -263,8 +263,6 @@ private:
/// Setup geometry shader for AccelerateDrawBatch /// Setup geometry shader for AccelerateDrawBatch
bool SetupGeometryShader(); bool SetupGeometryShader();
bool is_amd;
OpenGLState state; OpenGLState state;
GLuint default_texture; GLuint default_texture;
@ -323,8 +321,6 @@ private:
std::array<GLvec2, 128> proctex_alpha_map_data{}; std::array<GLvec2, 128> proctex_alpha_map_data{};
std::array<GLvec4, 256> proctex_lut_data{}; std::array<GLvec4, 256> proctex_lut_data{};
std::array<GLvec4, 256> proctex_diff_lut_data{}; std::array<GLvec4, 256> proctex_diff_lut_data{};
bool allow_shadow;
}; };
} // namespace OpenGL } // namespace OpenGL

@ -1233,18 +1233,6 @@ ShaderDecompiler::ProgramResult GenerateFragmentShader(const PicaFSConfig& confi
const auto& state = config.state; const auto& state = config.state;
std::string out; std::string out;
if (GLES) {
out += R"(
#define ALLOW_SHADOW (defined(CITRA_GLES))
)";
} else {
out += R"(
#extension GL_ARB_shader_image_load_store : enable
#extension GL_ARB_shader_image_size : enable
#define ALLOW_SHADOW (defined(GL_ARB_shader_image_load_store) && defined(GL_ARB_shader_image_size))
)";
}
if (separable_shader && !GLES) { if (separable_shader && !GLES) {
out += "#extension GL_ARB_separate_shader_objects : enable\n"; out += "#extension GL_ARB_separate_shader_objects : enable\n";
} }
@ -1270,7 +1258,6 @@ uniform samplerBuffer texture_buffer_lut_lf;
uniform samplerBuffer texture_buffer_lut_rg; uniform samplerBuffer texture_buffer_lut_rg;
uniform samplerBuffer texture_buffer_lut_rgba; uniform samplerBuffer texture_buffer_lut_rgba;
#if ALLOW_SHADOW
layout(r32ui) uniform readonly uimage2D shadow_texture_px; layout(r32ui) uniform readonly uimage2D shadow_texture_px;
layout(r32ui) uniform readonly uimage2D shadow_texture_nx; layout(r32ui) uniform readonly uimage2D shadow_texture_nx;
layout(r32ui) uniform readonly uimage2D shadow_texture_py; layout(r32ui) uniform readonly uimage2D shadow_texture_py;
@ -1278,7 +1265,6 @@ layout(r32ui) uniform readonly uimage2D shadow_texture_ny;
layout(r32ui) uniform readonly uimage2D shadow_texture_pz; layout(r32ui) uniform readonly uimage2D shadow_texture_pz;
layout(r32ui) uniform readonly uimage2D shadow_texture_nz; layout(r32ui) uniform readonly uimage2D shadow_texture_nz;
layout(r32ui) uniform uimage2D shadow_buffer; layout(r32ui) uniform uimage2D shadow_buffer;
#endif
)"; )";
out += UniformBlockDef; out += UniformBlockDef;
@ -1332,8 +1318,6 @@ float getLod(vec2 coord) {
return log2(max(d.x, d.y)); return log2(max(d.x, d.y));
} }
#if ALLOW_SHADOW
uvec2 DecodeShadow(uint pixel) { uvec2 DecodeShadow(uint pixel) {
return uvec2(pixel >> 8, pixel & 0xFFu); return uvec2(pixel >> 8, pixel & 0xFFu);
} }
@ -1459,18 +1443,6 @@ vec4 shadowTextureCube(vec2 uv, float w) {
CompareShadow(pixels.w, z)); CompareShadow(pixels.w, z));
return vec4(mix2(s, f)); return vec4(mix2(s, f));
} }
#else
vec4 shadowTexture(vec2 uv, float w) {
return vec4(1.0);
}
vec4 shadowTextureCube(vec2 uv, float w) {
return vec4(1.0);
}
#endif
)"; )";
if (config.state.proctex.enable) if (config.state.proctex.enable)
@ -1559,7 +1531,6 @@ vec4 secondary_fragment_color = vec4(0.0);
if (state.shadow_rendering) { if (state.shadow_rendering) {
out += R"( out += R"(
#if ALLOW_SHADOW
uint d = uint(clamp(depth, 0.0, 1.0) * float(0xFFFFFF)); uint d = uint(clamp(depth, 0.0, 1.0) * float(0xFFFFFF));
uint s = uint(last_tex_env_out.g * float(0xFF)); uint s = uint(last_tex_env_out.g * float(0xFF));
ivec2 image_coord = ivec2(gl_FragCoord.xy); ivec2 image_coord = ivec2(gl_FragCoord.xy);
@ -1582,7 +1553,6 @@ do {
new = EncodeShadow(ref); new = EncodeShadow(ref);
} while ((old = imageAtomicCompSwap(shadow_buffer, image_coord, old, new)) != old2); } while ((old = imageAtomicCompSwap(shadow_buffer, image_coord, old, new)) != old2);
#endif // ALLOW_SHADOW
)"; )";
} else { } else {
out += "gl_FragDepth = depth;\n"; out += "gl_FragDepth = depth;\n";

@ -7,7 +7,6 @@
#include <unordered_map> #include <unordered_map>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include "core/core.h"
#include "core/frontend/scope_acquire_context.h" #include "core/frontend/scope_acquire_context.h"
#include "video_core/renderer_opengl/gl_shader_disk_cache.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h"
#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h"
@ -325,8 +324,8 @@ using FragmentShaders = ShaderCache<PicaFSConfig, &GenerateFragmentShader, GL_FR
class ShaderProgramManager::Impl { class ShaderProgramManager::Impl {
public: public:
explicit Impl(bool separable, bool is_amd) explicit Impl(bool separable)
: is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable), : separable(separable), programmable_vertex_shaders(separable),
trivial_vertex_shader(separable), fixed_geometry_shaders(separable), trivial_vertex_shader(separable), fixed_geometry_shaders(separable),
fragment_shaders(separable), disk_cache(separable) { fragment_shaders(separable), disk_cache(separable) {
if (separable) if (separable)
@ -359,7 +358,6 @@ public:
} }
}; };
bool is_amd;
bool separable; bool separable;
ShaderTuple current; ShaderTuple current;
@ -375,9 +373,8 @@ public:
ShaderDiskCache disk_cache; ShaderDiskCache disk_cache;
}; };
ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, bool separable, ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, bool separable)
bool is_amd) : impl(std::make_unique<Impl>(separable)), emu_window{emu_window_} {}
: impl(std::make_unique<Impl>(separable, is_amd)), emu_window{emu_window_} {}
ShaderProgramManager::~ShaderProgramManager() = default; ShaderProgramManager::~ShaderProgramManager() = default;
@ -439,15 +436,6 @@ void ShaderProgramManager::UseFragmentShader(const Pica::Regs& regs) {
void ShaderProgramManager::ApplyTo(OpenGLState& state) { void ShaderProgramManager::ApplyTo(OpenGLState& state) {
if (impl->separable) { if (impl->separable) {
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_VERTEX_SHADER_BIT, impl->current.vs);
glUseProgramStages(impl->pipeline.handle, GL_GEOMETRY_SHADER_BIT, impl->current.gs); glUseProgramStages(impl->pipeline.handle, GL_GEOMETRY_SHADER_BIT, impl->current.gs);
glUseProgramStages(impl->pipeline.handle, GL_FRAGMENT_SHADER_BIT, impl->current.fs); glUseProgramStages(impl->pipeline.handle, GL_FRAGMENT_SHADER_BIT, impl->current.fs);

@ -99,7 +99,7 @@ static_assert(sizeof(VSUniformData) < 16384,
/// A class that manage different shader stages and configures them with given config data. /// A class that manage different shader stages and configures them with given config data.
class ShaderProgramManager { class ShaderProgramManager {
public: public:
ShaderProgramManager(Frontend::EmuWindow& emu_window_, bool separable, bool is_amd); ShaderProgramManager(Frontend::EmuWindow& emu_window_, bool separable);
~ShaderProgramManager(); ~ShaderProgramManager();
void LoadDiskCache(const std::atomic_bool& stop_loading, void LoadDiskCache(const std::atomic_bool& stop_loading,

@ -7,7 +7,6 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h" #include "video_core/renderer_opengl/gl_stream_buffer.h"
MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning", MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
@ -15,21 +14,12 @@ MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
namespace OpenGL { namespace OpenGL {
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool array_buffer_for_amd, OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
bool prefer_coherent)
: gl_target(target), buffer_size(size) { : gl_target(target), buffer_size(size) {
gl_buffer.Create(); gl_buffer.Create();
glBindBuffer(gl_target, gl_buffer.handle); glBindBuffer(gl_target, gl_buffer.handle);
GLsizeiptr allocate_size = size; GLsizeiptr allocate_size = size;
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<byte> attributes in the
// vertex array. Doubling the allocation size for the vertex buffer seems to avoid the
// crash.
allocate_size *= 2;
}
if (GLAD_GL_ARB_buffer_storage) { if (GLAD_GL_ARB_buffer_storage) {
persistent = true; persistent = true;

@ -13,8 +13,7 @@ namespace OpenGL {
class OGLStreamBuffer : private NonCopyable { class OGLStreamBuffer : private NonCopyable {
public: public:
explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool array_buffer_for_amd, explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false);
bool prefer_coherent = false);
~OGLStreamBuffer(); ~OGLStreamBuffer();
GLuint GetHandle() const; GLuint GetHandle() const;