yuzu-emu
/
yuzu
Archived
1
0
Fork 0

Merge pull request #2002 from ReinUsesLisp/dsa-vao-buffer

gl_rasterizer: Use DSA for VAOs and buffers
This commit is contained in:
bunnei 2019-01-20 14:06:01 -05:00 committed by GitHub
commit cbf8bea9d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 73 additions and 103 deletions

View File

@ -14,7 +14,7 @@
namespace OpenGL { namespace OpenGL {
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size) OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size)
: RasterizerCache{rasterizer}, stream_buffer(GL_ARRAY_BUFFER, size) {} : RasterizerCache{rasterizer}, stream_buffer(size, true) {}
GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
std::size_t alignment, bool cache) { std::size_t alignment, bool cache) {

View File

@ -135,27 +135,31 @@ void RasterizerOpenGL::CheckExtensions() {
} }
} }
void RasterizerOpenGL::SetupVertexFormat() { GLuint 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;
if (!gpu.dirty_flags.vertex_attrib_format) if (!gpu.dirty_flags.vertex_attrib_format) {
return; return state.draw.vertex_array;
}
gpu.dirty_flags.vertex_attrib_format = false; gpu.dirty_flags.vertex_attrib_format = false;
MICROPROFILE_SCOPE(OpenGL_VAO); MICROPROFILE_SCOPE(OpenGL_VAO);
auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format);
auto& VAO = iter->second; auto& vao_entry = iter->second;
if (is_cache_miss) { if (is_cache_miss) {
VAO.Create(); vao_entry.Create();
state.draw.vertex_array = VAO.handle; const GLuint vao = vao_entry.handle;
state.ApplyVertexBufferState();
// The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work // Eventhough we are using DSA to create this vertex array, there is a bug on Intel's blob
// around. // that fails to properly create the vertex array if it's not bound even after creating it
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_cache.GetHandle()); // with glCreateVertexArrays
state.draw.vertex_array = vao;
state.ApplyVertexArrayState();
glVertexArrayElementBuffer(vao, buffer_cache.GetHandle());
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
// Enables the first 16 vertex attributes always, as we don't know which ones are actually // Enables the first 16 vertex attributes always, as we don't know which ones are actually
@ -163,7 +167,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
// for now to avoid OpenGL errors. // for now to avoid OpenGL errors.
// TODO(Subv): Analyze the shader to identify which attributes are actually used and don't // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
// assume every shader uses them all. // assume every shader uses them all.
for (unsigned index = 0; index < 16; ++index) { for (u32 index = 0; index < 16; ++index) {
const auto& attrib = regs.vertex_attrib_format[index]; const auto& attrib = regs.vertex_attrib_format[index];
// Ignore invalid attributes. // Ignore invalid attributes.
@ -178,28 +182,29 @@ void RasterizerOpenGL::SetupVertexFormat() {
ASSERT(buffer.IsEnabled()); ASSERT(buffer.IsEnabled());
glEnableVertexAttribArray(index); glEnableVertexArrayAttrib(vao, index);
if (attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SignedInt || if (attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SignedInt ||
attrib.type == attrib.type ==
Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnsignedInt) { Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnsignedInt) {
glVertexAttribIFormat(index, attrib.ComponentCount(), glVertexArrayAttribIFormat(vao, index, attrib.ComponentCount(),
MaxwellToGL::VertexType(attrib), attrib.offset); MaxwellToGL::VertexType(attrib), attrib.offset);
} else { } else {
glVertexAttribFormat(index, attrib.ComponentCount(), glVertexArrayAttribFormat(
MaxwellToGL::VertexType(attrib), vao, index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
} }
glVertexAttribBinding(index, attrib.buffer); glVertexArrayAttribBinding(vao, index, attrib.buffer);
} }
} }
state.draw.vertex_array = VAO.handle;
state.ApplyVertexBufferState();
// Rebinding the VAO invalidates the vertex buffer bindings. // Rebinding the VAO invalidates the vertex buffer bindings.
gpu.dirty_flags.vertex_array = 0xFFFFFFFF; gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
state.draw.vertex_array = vao_entry.handle;
return vao_entry.handle;
} }
void RasterizerOpenGL::SetupVertexBuffer() { void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) {
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs; const auto& regs = gpu.regs;
@ -217,7 +222,7 @@ void RasterizerOpenGL::SetupVertexBuffer() {
if (!vertex_array.IsEnabled()) if (!vertex_array.IsEnabled())
continue; continue;
Tegra::GPUVAddr start = vertex_array.StartAddress(); const Tegra::GPUVAddr start = vertex_array.StartAddress();
const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress();
ASSERT(end > start); ASSERT(end > start);
@ -225,21 +230,18 @@ void RasterizerOpenGL::SetupVertexBuffer() {
const GLintptr vertex_buffer_offset = buffer_cache.UploadMemory(start, size); const GLintptr vertex_buffer_offset = buffer_cache.UploadMemory(start, size);
// Bind the vertex array to the buffer at the current offset. // Bind the vertex array to the buffer at the current offset.
glBindVertexBuffer(index, buffer_cache.GetHandle(), vertex_buffer_offset, glVertexArrayVertexBuffer(vao, index, buffer_cache.GetHandle(), vertex_buffer_offset,
vertex_array.stride); vertex_array.stride);
if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) { if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) {
// Enable vertex buffer instancing with the specified divisor. // Enable vertex buffer instancing with the specified divisor.
glVertexBindingDivisor(index, vertex_array.divisor); glVertexArrayBindingDivisor(vao, index, vertex_array.divisor);
} else { } else {
// Disable the vertex buffer instancing. // Disable the vertex buffer instancing.
glVertexBindingDivisor(index, 0); glVertexArrayBindingDivisor(vao, index, 0);
} }
} }
// Implicit set by glBindVertexBuffer. Stupid glstate handling...
state.draw.vertex_buffer = buffer_cache.GetHandle();
gpu.dirty_flags.vertex_array = 0; gpu.dirty_flags.vertex_array = 0;
} }
@ -691,9 +693,6 @@ void RasterizerOpenGL::DrawArrays() {
// Draw the vertex batch // Draw the vertex batch
const bool is_indexed = accelerate_draw == AccelDraw::Indexed; const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
state.draw.vertex_buffer = buffer_cache.GetHandle();
state.ApplyVertexBufferState();
std::size_t buffer_size = CalculateVertexArraysSize(); std::size_t buffer_size = CalculateVertexArraysSize();
// Add space for index buffer (keeping in mind non-core primitives) // Add space for index buffer (keeping in mind non-core primitives)
@ -723,8 +722,9 @@ void RasterizerOpenGL::DrawArrays() {
gpu.dirty_flags.vertex_array = 0xFFFFFFFF; gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
} }
SetupVertexFormat(); const GLuint vao = SetupVertexFormat();
SetupVertexBuffer(); SetupVertexBuffer(vao);
DrawParameters params = SetupDraw(); DrawParameters params = SetupDraw();
SetupShaders(params.primitive_mode); SetupShaders(params.primitive_mode);

View File

@ -215,8 +215,10 @@ private:
std::size_t CalculateIndexBufferSize() const; std::size_t CalculateIndexBufferSize() const;
void SetupVertexFormat(); /// Updates and returns a vertex array object representing current vertex format
void SetupVertexBuffer(); GLuint SetupVertexFormat();
void SetupVertexBuffer(GLuint vao);
DrawParameters SetupDraw(); DrawParameters SetupDraw();

View File

@ -117,7 +117,7 @@ void OGLBuffer::Create() {
return; return;
MICROPROFILE_SCOPE(OpenGL_ResourceCreation); MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenBuffers(1, &handle); glCreateBuffers(1, &handle);
} }
void OGLBuffer::Release() { void OGLBuffer::Release() {
@ -126,7 +126,6 @@ void OGLBuffer::Release() {
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteBuffers(1, &handle); glDeleteBuffers(1, &handle);
OpenGLState::GetCurState().ResetBuffer(handle).Apply();
handle = 0; handle = 0;
} }
@ -152,7 +151,7 @@ void OGLVertexArray::Create() {
return; return;
MICROPROFILE_SCOPE(OpenGL_ResourceCreation); MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glGenVertexArrays(1, &handle); glCreateVertexArrays(1, &handle);
} }
void OGLVertexArray::Release() { void OGLVertexArray::Release() {

View File

@ -83,8 +83,6 @@ OpenGLState::OpenGLState() {
draw.read_framebuffer = 0; draw.read_framebuffer = 0;
draw.draw_framebuffer = 0; draw.draw_framebuffer = 0;
draw.vertex_array = 0; draw.vertex_array = 0;
draw.vertex_buffer = 0;
draw.uniform_buffer = 0;
draw.shader_program = 0; draw.shader_program = 0;
draw.program_pipeline = 0; draw.program_pipeline = 0;
@ -505,7 +503,6 @@ void OpenGLState::ApplySamplers() const {
} }
void OpenGLState::ApplyFramebufferState() const { void OpenGLState::ApplyFramebufferState() const {
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
} }
@ -514,16 +511,10 @@ void OpenGLState::ApplyFramebufferState() const {
} }
} }
void OpenGLState::ApplyVertexBufferState() const { void OpenGLState::ApplyVertexArrayState() const {
// Vertex array
if (draw.vertex_array != cur_state.draw.vertex_array) { if (draw.vertex_array != cur_state.draw.vertex_array) {
glBindVertexArray(draw.vertex_array); glBindVertexArray(draw.vertex_array);
} }
// Vertex buffer
if (draw.vertex_buffer != cur_state.draw.vertex_buffer) {
glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
}
} }
void OpenGLState::ApplyDepthClamp() const { void OpenGLState::ApplyDepthClamp() const {
@ -543,11 +534,7 @@ void OpenGLState::ApplyDepthClamp() const {
void OpenGLState::Apply() const { void OpenGLState::Apply() const {
ApplyFramebufferState(); ApplyFramebufferState();
ApplyVertexBufferState(); ApplyVertexArrayState();
// Uniform buffer
if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
}
// Shader program // Shader program
if (draw.shader_program != cur_state.draw.shader_program) { if (draw.shader_program != cur_state.draw.shader_program) {
@ -638,16 +625,6 @@ OpenGLState& OpenGLState::ResetPipeline(GLuint handle) {
return *this; return *this;
} }
OpenGLState& OpenGLState::ResetBuffer(GLuint handle) {
if (draw.vertex_buffer == handle) {
draw.vertex_buffer = 0;
}
if (draw.uniform_buffer == handle) {
draw.uniform_buffer = 0;
}
return *this;
}
OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) { OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) {
if (draw.vertex_array == handle) { if (draw.vertex_array == handle) {
draw.vertex_array = 0; draw.vertex_array = 0;

View File

@ -154,8 +154,6 @@ public:
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
GLuint shader_program; // GL_CURRENT_PROGRAM GLuint shader_program; // GL_CURRENT_PROGRAM
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
} draw; } draw;
@ -206,10 +204,10 @@ public:
} }
/// Apply this state as the current OpenGL state /// Apply this state as the current OpenGL state
void Apply() const; void Apply() const;
/// Apply only the state afecting the framebuffer /// Apply only the state affecting the framebuffer
void ApplyFramebufferState() const; void ApplyFramebufferState() const;
/// Apply only the state afecting the vertex buffer /// Apply only the state affecting the vertex array
void ApplyVertexBufferState() const; void ApplyVertexArrayState() const;
/// Set the initial OpenGL state /// Set the initial OpenGL state
static void ApplyDefaultState(); static void ApplyDefaultState();
/// Resets any references to the given resource /// Resets any references to the given resource
@ -217,7 +215,6 @@ public:
OpenGLState& ResetSampler(GLuint handle); OpenGLState& ResetSampler(GLuint handle);
OpenGLState& ResetProgram(GLuint handle); OpenGLState& ResetProgram(GLuint handle);
OpenGLState& ResetPipeline(GLuint handle); OpenGLState& ResetPipeline(GLuint handle);
OpenGLState& ResetBuffer(GLuint handle);
OpenGLState& ResetVertexArray(GLuint handle); OpenGLState& ResetVertexArray(GLuint handle);
OpenGLState& ResetFramebuffer(GLuint handle); OpenGLState& ResetFramebuffer(GLuint handle);
void EmulateViewportWithScissor(); void EmulateViewportWithScissor();

View File

@ -15,13 +15,12 @@ MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
namespace OpenGL { namespace OpenGL {
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) OGLStreamBuffer::OGLStreamBuffer(GLsizeiptr size, bool vertex_data_usage, bool prefer_coherent)
: gl_target(target), buffer_size(size) { : buffer_size(size) {
gl_buffer.Create(); gl_buffer.Create();
glBindBuffer(gl_target, gl_buffer.handle);
GLsizeiptr allocate_size = size; GLsizeiptr allocate_size = size;
if (target == GL_ARRAY_BUFFER) { if (vertex_data_usage) {
// On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer // 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 // 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 // probably a bug in the driver and is related to the usage of vec3<byte> attributes in the
@ -35,18 +34,17 @@ OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coh
coherent = prefer_coherent; coherent = prefer_coherent;
const GLbitfield flags = const GLbitfield flags =
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
glBufferStorage(gl_target, allocate_size, nullptr, flags); glNamedBufferStorage(gl_buffer.handle, allocate_size, nullptr, flags);
mapped_ptr = static_cast<u8*>(glMapBufferRange( mapped_ptr = static_cast<u8*>(glMapNamedBufferRange(
gl_target, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT))); gl_buffer.handle, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)));
} else { } else {
glBufferData(gl_target, allocate_size, nullptr, GL_STREAM_DRAW); glNamedBufferData(gl_buffer.handle, allocate_size, nullptr, GL_STREAM_DRAW);
} }
} }
OGLStreamBuffer::~OGLStreamBuffer() { OGLStreamBuffer::~OGLStreamBuffer() {
if (persistent) { if (persistent) {
glBindBuffer(gl_target, gl_buffer.handle); glUnmapNamedBuffer(gl_buffer.handle);
glUnmapBuffer(gl_target);
} }
gl_buffer.Release(); gl_buffer.Release();
} }
@ -74,7 +72,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
invalidate = true; invalidate = true;
if (persistent) { if (persistent) {
glUnmapBuffer(gl_target); glUnmapNamedBuffer(gl_buffer.handle);
} }
} }
@ -84,7 +82,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
mapped_ptr = static_cast<u8*>( mapped_ptr = static_cast<u8*>(
glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags)); glMapNamedBufferRange(gl_buffer.handle, buffer_pos, buffer_size - buffer_pos, flags));
mapped_offset = buffer_pos; mapped_offset = buffer_pos;
} }
@ -95,11 +93,11 @@ void OGLStreamBuffer::Unmap(GLsizeiptr size) {
ASSERT(size <= mapped_size); ASSERT(size <= mapped_size);
if (!coherent && size > 0) { if (!coherent && size > 0) {
glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size); glFlushMappedNamedBufferRange(gl_buffer.handle, buffer_pos - mapped_offset, size);
} }
if (!persistent) { if (!persistent) {
glUnmapBuffer(gl_target); glUnmapNamedBuffer(gl_buffer.handle);
} }
buffer_pos += size; buffer_pos += size;

View File

@ -13,7 +13,7 @@ namespace OpenGL {
class OGLStreamBuffer : private NonCopyable { class OGLStreamBuffer : private NonCopyable {
public: public:
explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false); explicit OGLStreamBuffer(GLsizeiptr size, bool vertex_data_usage, bool prefer_coherent = false);
~OGLStreamBuffer(); ~OGLStreamBuffer();
GLuint GetHandle() const; GLuint GetHandle() const;
@ -33,7 +33,6 @@ public:
private: private:
OGLBuffer gl_buffer; OGLBuffer gl_buffer;
GLenum gl_target;
bool coherent = false; bool coherent = false;
bool persistent = false; bool persistent = false;

View File

@ -245,20 +245,20 @@ void RendererOpenGL::InitOpenGLObjects() {
// Generate VAO // Generate VAO
vertex_array.Create(); vertex_array.Create();
state.draw.vertex_array = vertex_array.handle; state.draw.vertex_array = vertex_array.handle;
state.draw.vertex_buffer = vertex_buffer.handle;
state.draw.uniform_buffer = 0;
state.Apply();
// Attach vertex data to VAO // Attach vertex data to VAO
glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), glVertexArrayAttribFormat(vertex_array.handle, attrib_position, 2, GL_FLOAT, GL_FALSE,
(GLvoid*)offsetof(ScreenRectVertex, position)); offsetof(ScreenRectVertex, position));
glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), glVertexArrayAttribFormat(vertex_array.handle, attrib_tex_coord, 2, GL_FLOAT, GL_FALSE,
(GLvoid*)offsetof(ScreenRectVertex, tex_coord)); offsetof(ScreenRectVertex, tex_coord));
glEnableVertexAttribArray(attrib_position); glVertexArrayAttribBinding(vertex_array.handle, attrib_position, 0);
glEnableVertexAttribArray(attrib_tex_coord); glVertexArrayAttribBinding(vertex_array.handle, attrib_tex_coord, 0);
glEnableVertexArrayAttrib(vertex_array.handle, attrib_position);
glEnableVertexArrayAttrib(vertex_array.handle, attrib_tex_coord);
glVertexArrayVertexBuffer(vertex_array.handle, 0, vertex_buffer.handle, 0,
sizeof(ScreenRectVertex));
// Allocate textures for the screen // Allocate textures for the screen
screen_info.texture.resource.Create(); screen_info.texture.resource.Create();
@ -370,14 +370,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
state.texture_units[0].texture = screen_info.display_texture; state.texture_units[0].texture = screen_info.display_texture;
state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
// Workaround brigthness problems in SMO by enabling sRGB in the final output // Workaround brigthness problems in SMO by enabling sRGB in the final output
// if it has been used in the frame // if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
// Needed because of this bug in QT
// QTBUG-50987
state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed(); state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
state.Apply(); state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// restore default state // Restore default state
state.framebuffer_srgb.enabled = false; state.framebuffer_srgb.enabled = false;
state.texture_units[0].texture = 0; state.texture_units[0].texture = 0;
state.Apply(); state.Apply();