duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

opengl_device.cpp (37997B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #include "opengl_device.h"
      5 #include "opengl_pipeline.h"
      6 #include "opengl_stream_buffer.h"
      7 #include "opengl_texture.h"
      8 
      9 #include "core/host.h"
     10 
     11 #include "common/align.h"
     12 #include "common/assert.h"
     13 #include "common/error.h"
     14 #include "common/log.h"
     15 #include "common/string_util.h"
     16 
     17 #include "fmt/format.h"
     18 
     19 #include <array>
     20 #include <tuple>
     21 
     22 Log_SetChannel(OpenGLDevice);
     23 
     24 static constexpr const std::array<GLenum, GPUDevice::MAX_RENDER_TARGETS> s_draw_buffers = {
     25   {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}};
     26 
     27 OpenGLDevice::OpenGLDevice()
     28 {
     29   // Something which won't be matched..
     30   std::memset(&m_last_rasterization_state, 0xFF, sizeof(m_last_rasterization_state));
     31   std::memset(&m_last_depth_state, 0xFF, sizeof(m_last_depth_state));
     32   std::memset(&m_last_blend_state, 0xFF, sizeof(m_last_blend_state));
     33   m_last_blend_state.enable = false;
     34   m_last_blend_state.constant = 0;
     35 }
     36 
     37 OpenGLDevice::~OpenGLDevice()
     38 {
     39   Assert(!m_gl_context);
     40   Assert(!m_pipeline_disk_cache_file);
     41 }
     42 
     43 void OpenGLDevice::BindUpdateTextureUnit()
     44 {
     45   GetInstance().SetActiveTexture(UPDATE_TEXTURE_UNIT - GL_TEXTURE0);
     46 }
     47 
     48 bool OpenGLDevice::ShouldUsePBOsForDownloads()
     49 {
     50   return !GetInstance().m_disable_pbo && !GetInstance().m_disable_async_download;
     51 }
     52 
     53 void OpenGLDevice::SetErrorObject(Error* errptr, std::string_view prefix, GLenum glerr)
     54 {
     55   Error::SetStringFmt(errptr, "{}GL Error 0x{:04X}", prefix, static_cast<unsigned>(glerr));
     56 }
     57 
     58 RenderAPI OpenGLDevice::GetRenderAPI() const
     59 {
     60   return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
     61 }
     62 
     63 std::unique_ptr<GPUTexture> OpenGLDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
     64                                                         GPUTexture::Type type, GPUTexture::Format format,
     65                                                         const void* data, u32 data_stride)
     66 {
     67   return OpenGLTexture::Create(width, height, layers, levels, samples, type, format, data, data_stride);
     68 }
     69 
     70 bool OpenGLDevice::SupportsTextureFormat(GPUTexture::Format format) const
     71 {
     72   const auto [gl_internal_format, gl_format, gl_type] =
     73     OpenGLTexture::GetPixelFormatMapping(format, m_gl_context->IsGLES());
     74   return (gl_internal_format != static_cast<GLenum>(0));
     75 }
     76 
     77 void OpenGLDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
     78                                      GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width,
     79                                      u32 height)
     80 {
     81   OpenGLTexture* D = static_cast<OpenGLTexture*>(dst);
     82   OpenGLTexture* S = static_cast<OpenGLTexture*>(src);
     83   CommitClear(D);
     84   CommitClear(S);
     85 
     86   s_stats.num_copies++;
     87 
     88   const GLuint sid = S->GetGLId();
     89   const GLuint did = D->GetGLId();
     90   if (GLAD_GL_VERSION_4_3 || GLAD_GL_ARB_copy_image)
     91   {
     92     glCopyImageSubData(sid, GL_TEXTURE_2D, src_level, src_x, src_y, src_layer, did, GL_TEXTURE_2D, dst_level, dst_x,
     93                        dst_y, dst_layer, width, height, 1);
     94   }
     95   else if (GLAD_GL_EXT_copy_image)
     96   {
     97     glCopyImageSubDataEXT(sid, GL_TEXTURE_2D, src_level, src_x, src_y, src_layer, did, GL_TEXTURE_2D, dst_level, dst_x,
     98                           dst_y, dst_layer, width, height, 1);
     99   }
    100   else if (GLAD_GL_OES_copy_image)
    101   {
    102     glCopyImageSubDataOES(sid, GL_TEXTURE_2D, src_level, src_x, src_y, src_layer, did, GL_TEXTURE_2D, dst_level, dst_x,
    103                           dst_y, dst_layer, width, height, 1);
    104   }
    105   else
    106   {
    107     glBindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo);
    108     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_write_fbo);
    109     if (D->IsTextureArray())
    110       glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, did, dst_level, dst_layer);
    111     else
    112       glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, D->GetGLTarget(), did, dst_level);
    113     if (S->IsTextureArray())
    114       glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sid, src_level, src_layer);
    115     else
    116       glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, S->GetGLTarget(), sid, src_level);
    117 
    118     glDisable(GL_SCISSOR_TEST);
    119     glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height,
    120                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
    121     glEnable(GL_SCISSOR_TEST);
    122 
    123     if (m_current_fbo)
    124     {
    125       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
    126       glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    127     }
    128     else
    129     {
    130       glBindFramebuffer(GL_FRAMEBUFFER, 0);
    131     }
    132   }
    133 }
    134 
    135 void OpenGLDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
    136                                         GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height)
    137 {
    138   OpenGLTexture* D = static_cast<OpenGLTexture*>(dst);
    139   OpenGLTexture* S = static_cast<OpenGLTexture*>(src);
    140 
    141   glBindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo);
    142   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_write_fbo);
    143   if (D->IsTextureArray())
    144     glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, D->GetGLId(), dst_level, dst_layer);
    145   else
    146     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, D->GetGLTarget(), D->GetGLId(), dst_level);
    147   glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, S->GetGLTarget(), S->GetGLId(), 0);
    148 
    149   CommitClear(S);
    150   if (width == D->GetMipWidth(dst_level) && height == D->GetMipHeight(dst_level))
    151   {
    152     D->SetState(GPUTexture::State::Dirty);
    153     if (glInvalidateFramebuffer)
    154     {
    155       const GLenum attachment = GL_COLOR_ATTACHMENT0;
    156       glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &attachment);
    157     }
    158   }
    159   else
    160   {
    161     CommitClear(D);
    162   }
    163 
    164   s_stats.num_copies++;
    165 
    166   glDisable(GL_SCISSOR_TEST);
    167   glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height,
    168                     GL_COLOR_BUFFER_BIT, GL_LINEAR);
    169   glEnable(GL_SCISSOR_TEST);
    170 
    171   if (m_current_fbo)
    172   {
    173     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
    174     glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    175   }
    176   else
    177   {
    178     glBindFramebuffer(GL_FRAMEBUFFER, 0);
    179   }
    180 }
    181 
    182 void OpenGLDevice::ClearRenderTarget(GPUTexture* t, u32 c)
    183 {
    184   GPUDevice::ClearRenderTarget(t, c);
    185   if (const s32 idx = IsRenderTargetBound(t); idx >= 0)
    186     CommitRTClearInFB(static_cast<OpenGLTexture*>(t), static_cast<u32>(idx));
    187 }
    188 
    189 void OpenGLDevice::ClearDepth(GPUTexture* t, float d)
    190 {
    191   GPUDevice::ClearDepth(t, d);
    192   if (m_current_depth_target == t)
    193     CommitDSClearInFB(static_cast<OpenGLTexture*>(t));
    194 }
    195 
    196 void OpenGLDevice::InvalidateRenderTarget(GPUTexture* t)
    197 {
    198   GPUDevice::InvalidateRenderTarget(t);
    199   if (t->IsRenderTarget())
    200   {
    201     if (const s32 idx = IsRenderTargetBound(t); idx >= 0)
    202       CommitRTClearInFB(static_cast<OpenGLTexture*>(t), static_cast<u32>(idx));
    203   }
    204   else
    205   {
    206     DebugAssert(t->IsDepthStencil());
    207     if (m_current_depth_target == t)
    208       CommitDSClearInFB(static_cast<OpenGLTexture*>(t));
    209   }
    210 }
    211 
    212 void OpenGLDevice::PushDebugGroup(const char* name)
    213 {
    214 #ifdef _DEBUG
    215   if (!glPushDebugGroup)
    216     return;
    217 
    218   glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, static_cast<GLsizei>(std::strlen(name)), name);
    219 #endif
    220 }
    221 
    222 void OpenGLDevice::PopDebugGroup()
    223 {
    224 #ifdef _DEBUG
    225   if (!glPopDebugGroup)
    226     return;
    227 
    228   glPopDebugGroup();
    229 #endif
    230 }
    231 
    232 void OpenGLDevice::InsertDebugMessage(const char* msg)
    233 {
    234 #ifdef _DEBUG
    235   if (!glDebugMessageInsert)
    236     return;
    237 
    238   if (msg[0] != '\0')
    239   {
    240     glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION,
    241                          static_cast<GLsizei>(std::strlen(msg)), msg);
    242   }
    243 #endif
    244 }
    245 
    246 void OpenGLDevice::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
    247 {
    248   // OpenGL does not support Mailbox.
    249   mode = (mode == GPUVSyncMode::Mailbox) ? GPUVSyncMode::FIFO : mode;
    250   m_allow_present_throttle = allow_present_throttle;
    251 
    252   if (m_vsync_mode == mode)
    253     return;
    254 
    255   m_vsync_mode = mode;
    256   SetSwapInterval();
    257 }
    258 
    259 static void GLAD_API_PTR GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
    260                                          const GLchar* message, const void* userParam)
    261 {
    262   switch (severity)
    263   {
    264     case GL_DEBUG_SEVERITY_HIGH_KHR:
    265       ERROR_LOG(message);
    266       break;
    267     case GL_DEBUG_SEVERITY_MEDIUM_KHR:
    268       WARNING_LOG(message);
    269       break;
    270     case GL_DEBUG_SEVERITY_LOW_KHR:
    271       INFO_LOG(message);
    272       break;
    273     case GL_DEBUG_SEVERITY_NOTIFICATION:
    274       // Log_DebugPrint(message);
    275       break;
    276   }
    277 }
    278 
    279 bool OpenGLDevice::HasSurface() const
    280 {
    281   return m_window_info.type != WindowInfo::Type::Surfaceless;
    282 }
    283 
    284 bool OpenGLDevice::CreateDevice(std::string_view adapter, bool threaded_presentation,
    285                                 std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
    286                                 Error* error)
    287 {
    288   m_gl_context = OpenGLContext::Create(m_window_info, error);
    289   if (!m_gl_context)
    290   {
    291     ERROR_LOG("Failed to create any GL context");
    292     m_gl_context.reset();
    293     return false;
    294   }
    295 
    296   // Is this needed?
    297   m_window_info = m_gl_context->GetWindowInfo();
    298   m_vsync_mode = (m_vsync_mode == GPUVSyncMode::Mailbox) ? GPUVSyncMode::FIFO : m_vsync_mode;
    299 
    300   const bool opengl_is_available =
    301     ((!m_gl_context->IsGLES() && (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_uniform_buffer_object)) ||
    302      (m_gl_context->IsGLES() && GLAD_GL_ES_VERSION_3_1));
    303   if (!opengl_is_available)
    304   {
    305     Host::ReportErrorAsync(TRANSLATE_SV("GPUDevice", "Error"),
    306                            TRANSLATE_SV("GPUDevice", "OpenGL renderer unavailable, your driver or hardware is not "
    307                                                      "recent enough. OpenGL 3.1 or OpenGL ES 3.1 is required."));
    308     m_gl_context.reset();
    309     return false;
    310   }
    311 
    312   SetSwapInterval();
    313   if (HasSurface())
    314     RenderBlankFrame();
    315 
    316   if (m_debug_device && GLAD_GL_KHR_debug)
    317   {
    318     if (m_gl_context->IsGLES())
    319       glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
    320     else
    321       glDebugMessageCallback(GLDebugCallback, nullptr);
    322 
    323     glEnable(GL_DEBUG_OUTPUT);
    324     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
    325   }
    326   else
    327   {
    328     // Nail the function pointers so that we don't waste time calling them.
    329     glPushDebugGroup = nullptr;
    330     glPopDebugGroup = nullptr;
    331     glDebugMessageInsert = nullptr;
    332     glObjectLabel = nullptr;
    333   }
    334 
    335   if (!CheckFeatures(disabled_features))
    336     return false;
    337 
    338   if (!CreateBuffers())
    339     return false;
    340 
    341   // Scissor test should always be enabled.
    342   glEnable(GL_SCISSOR_TEST);
    343 
    344   return true;
    345 }
    346 
    347 bool OpenGLDevice::CheckFeatures(FeatureMask disabled_features)
    348 {
    349   const bool is_gles = m_gl_context->IsGLES();
    350 
    351   bool vendor_id_amd = false;
    352   // bool vendor_id_nvidia = false;
    353   bool vendor_id_intel = false;
    354   bool vendor_id_arm = false;
    355   bool vendor_id_qualcomm = false;
    356   bool vendor_id_powervr = false;
    357 
    358   const char* vendor = (const char*)glGetString(GL_VENDOR);
    359   const char* renderer = (const char*)glGetString(GL_RENDERER);
    360   if (std::strstr(vendor, "Advanced Micro Devices") || std::strstr(vendor, "ATI Technologies Inc.") ||
    361       std::strstr(vendor, "ATI"))
    362   {
    363     INFO_LOG("AMD GPU detected.");
    364     vendor_id_amd = true;
    365   }
    366   else if (std::strstr(vendor, "NVIDIA Corporation"))
    367   {
    368     INFO_LOG("NVIDIA GPU detected.");
    369     // vendor_id_nvidia = true;
    370   }
    371   else if (std::strstr(vendor, "Intel"))
    372   {
    373     INFO_LOG("Intel GPU detected.");
    374     vendor_id_intel = true;
    375   }
    376   else if (std::strstr(vendor, "ARM"))
    377   {
    378     INFO_LOG("ARM GPU detected.");
    379     vendor_id_arm = true;
    380   }
    381   else if (std::strstr(vendor, "Qualcomm"))
    382   {
    383     INFO_LOG("Qualcomm GPU detected.");
    384     vendor_id_qualcomm = true;
    385   }
    386   else if (std::strstr(vendor, "Imagination Technologies") || std::strstr(renderer, "PowerVR"))
    387   {
    388     INFO_LOG("PowerVR GPU detected.");
    389     vendor_id_powervr = true;
    390   }
    391 
    392   // Don't use PBOs when we don't have ARB_buffer_storage, orphaning buffers probably ends up worse than just
    393   // using the normal texture update routines and letting the driver take care of it. PBOs are also completely
    394   // broken on mobile drivers.
    395   const bool is_shitty_mobile_driver = (vendor_id_powervr || vendor_id_qualcomm || vendor_id_arm);
    396   m_disable_pbo =
    397     (!GLAD_GL_VERSION_4_4 && !GLAD_GL_ARB_buffer_storage && !GLAD_GL_EXT_buffer_storage) || is_shitty_mobile_driver;
    398   if (m_disable_pbo && !is_shitty_mobile_driver)
    399     WARNING_LOG("Not using PBOs for texture uploads because buffer_storage is unavailable.");
    400 
    401   GLint max_texture_size = 1024;
    402   GLint max_samples = 1;
    403   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
    404   DEV_LOG("GL_MAX_TEXTURE_SIZE: {}", max_texture_size);
    405   glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
    406   DEV_LOG("GL_MAX_SAMPLES: {}", max_samples);
    407   m_max_texture_size = std::max(1024u, static_cast<u32>(max_texture_size));
    408   m_max_multisamples = std::max(1u, static_cast<u32>(max_samples));
    409 
    410   GLint max_dual_source_draw_buffers = 0;
    411   glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers);
    412   m_features.dual_source_blend =
    413     !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && (max_dual_source_draw_buffers > 0) &&
    414     (GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended);
    415 
    416   m_features.framebuffer_fetch =
    417     !(disabled_features & (FEATURE_MASK_FEEDBACK_LOOPS | FEATURE_MASK_FRAMEBUFFER_FETCH)) &&
    418     (GLAD_GL_EXT_shader_framebuffer_fetch || GLAD_GL_ARM_shader_framebuffer_fetch);
    419 
    420 #ifdef __APPLE__
    421   // Partial texture buffer uploads appear to be broken in macOS's OpenGL driver.
    422   m_features.supports_texture_buffers = false;
    423 #else
    424   m_features.supports_texture_buffers =
    425     !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS) && (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2);
    426 
    427   // And Samsung's ANGLE/GLES driver?
    428   if (std::strstr(reinterpret_cast<const char*>(glGetString(GL_RENDERER)), "ANGLE"))
    429     m_features.supports_texture_buffers = false;
    430 
    431   if (m_features.supports_texture_buffers)
    432   {
    433     GLint max_texel_buffer_size = 0;
    434     glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, reinterpret_cast<GLint*>(&max_texel_buffer_size));
    435     DEV_LOG("GL_MAX_TEXTURE_BUFFER_SIZE: {}", max_texel_buffer_size);
    436     if (max_texel_buffer_size < static_cast<GLint>(MIN_TEXEL_BUFFER_ELEMENTS))
    437     {
    438       WARNING_LOG("GL_MAX_TEXTURE_BUFFER_SIZE ({}) is below required minimum ({}), not using texture buffers.",
    439                   max_texel_buffer_size, MIN_TEXEL_BUFFER_ELEMENTS);
    440       m_features.supports_texture_buffers = false;
    441     }
    442   }
    443 #endif
    444 
    445   if (!m_features.supports_texture_buffers && !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS))
    446   {
    447     // Try SSBOs.
    448     GLint max_fragment_storage_blocks = 0;
    449     GLint64 max_ssbo_size = 0;
    450     if (GLAD_GL_VERSION_4_3 || GLAD_GL_ES_VERSION_3_1 || GLAD_GL_ARB_shader_storage_buffer_object)
    451     {
    452       glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &max_fragment_storage_blocks);
    453       glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_ssbo_size);
    454     }
    455 
    456     DEV_LOG("GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: {}", max_fragment_storage_blocks);
    457     DEV_LOG("GL_MAX_SHADER_STORAGE_BLOCK_SIZE: {}", max_ssbo_size);
    458     m_features.texture_buffers_emulated_with_ssbo =
    459       (max_fragment_storage_blocks > 0 && max_ssbo_size >= static_cast<GLint64>(1024 * 512 * sizeof(u16)));
    460     if (m_features.texture_buffers_emulated_with_ssbo)
    461     {
    462       INFO_LOG("Using shader storage buffers for VRAM writes.");
    463       m_features.supports_texture_buffers = true;
    464     }
    465     else
    466     {
    467       WARNING_LOG("Both texture buffers and SSBOs are not supported. Performance will suffer.");
    468     }
    469   }
    470 
    471   // Sample rate shading is broken on AMD and Intel.
    472   // If AMD and Intel can't get it right, I very much doubt broken mobile drivers can.
    473   m_features.per_sample_shading = (GLAD_GL_VERSION_4_0 || GLAD_GL_ES_VERSION_3_2 || GLAD_GL_ARB_sample_shading) &&
    474                                   (!vendor_id_amd && !vendor_id_intel && !is_shitty_mobile_driver);
    475 
    476   // noperspective is not supported in GLSL ES.
    477   m_features.noperspective_interpolation = !is_gles;
    478 
    479   // glBlitFramebufer with same source/destination should be legal, but on Mali (at least Bifrost) it breaks.
    480   // So, blit from the shadow texture, like in the other renderers.
    481   m_features.texture_copy_to_self = !vendor_id_arm && !(disabled_features & FEATURE_MASK_TEXTURE_COPY_TO_SELF);
    482 
    483   m_features.feedback_loops = false;
    484 
    485   m_features.geometry_shaders =
    486     !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && (GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2);
    487 
    488   m_features.gpu_timing = !(m_gl_context->IsGLES() &&
    489                             (!GLAD_GL_EXT_disjoint_timer_query || !glGetQueryObjectivEXT || !glGetQueryObjectui64vEXT));
    490   m_features.partial_msaa_resolve = true;
    491   m_features.memory_import = true;
    492   m_features.explicit_present = false;
    493 
    494   m_features.shader_cache = false;
    495 
    496   m_features.pipeline_cache = m_gl_context->IsGLES() || GLAD_GL_ARB_get_program_binary;
    497   if (m_features.pipeline_cache)
    498   {
    499     // check that there's at least one format and the extension isn't being "faked"
    500     GLint num_formats = 0;
    501     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
    502     DEV_LOG("{} program binary formats supported by driver", num_formats);
    503     m_features.pipeline_cache = (num_formats > 0);
    504   }
    505 
    506   if (!m_features.pipeline_cache)
    507   {
    508     WARNING_LOG("Your GL driver does not support program binaries. Hopefully it has a built-in cache, otherwise "
    509                 "startup will be slow due to compiling shaders.");
    510   }
    511 
    512   // Mobile drivers prefer textures to not be updated mid-frame.
    513   m_features.prefer_unused_textures = is_gles || vendor_id_arm || vendor_id_powervr || vendor_id_qualcomm;
    514 
    515   if (vendor_id_intel)
    516   {
    517     // Intel drivers corrupt image on readback when syncs are used for downloads.
    518     WARNING_LOG("Disabling async downloads with PBOs due to it being broken on Intel drivers.");
    519     m_disable_async_download = true;
    520   }
    521 
    522   return true;
    523 }
    524 
    525 void OpenGLDevice::DestroyDevice()
    526 {
    527   if (!m_gl_context)
    528     return;
    529 
    530   ClosePipelineCache();
    531   DestroyBuffers();
    532 
    533   m_gl_context->DoneCurrent();
    534   m_gl_context.reset();
    535 }
    536 
    537 bool OpenGLDevice::UpdateWindow()
    538 {
    539   Assert(m_gl_context);
    540 
    541   DestroySurface();
    542 
    543   if (!AcquireWindow(false))
    544     return false;
    545 
    546   if (!m_gl_context->ChangeSurface(m_window_info))
    547   {
    548     ERROR_LOG("Failed to change surface");
    549     return false;
    550   }
    551 
    552   m_window_info = m_gl_context->GetWindowInfo();
    553 
    554   if (m_window_info.type != WindowInfo::Type::Surfaceless)
    555   {
    556     // reset vsync rate, since it (usually) gets lost
    557     SetSwapInterval();
    558     RenderBlankFrame();
    559   }
    560 
    561   return true;
    562 }
    563 
    564 void OpenGLDevice::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
    565 {
    566   if (m_window_info.IsSurfaceless())
    567     return;
    568 
    569   m_window_info.surface_scale = new_window_scale;
    570   if (m_window_info.surface_width == static_cast<u32>(new_window_width) &&
    571       m_window_info.surface_height == static_cast<u32>(new_window_height))
    572   {
    573     return;
    574   }
    575 
    576   m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
    577   m_window_info = m_gl_context->GetWindowInfo();
    578 }
    579 
    580 std::string OpenGLDevice::GetDriverInfo() const
    581 {
    582   const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
    583   const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
    584   const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
    585   const char* gl_shading_language_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    586   return fmt::format("OpenGL Context:\n{}\n{} {}\nGLSL: {}", gl_version, gl_vendor, gl_renderer,
    587                      gl_shading_language_version);
    588 }
    589 
    590 void OpenGLDevice::ExecuteAndWaitForGPUIdle()
    591 {
    592   // Could be glFinish(), but I'm afraid for mobile drivers...
    593   glFlush();
    594 }
    595 
    596 void OpenGLDevice::SetSwapInterval()
    597 {
    598   if (m_window_info.type == WindowInfo::Type::Surfaceless)
    599     return;
    600 
    601   // Window framebuffer has to be bound to call SetSwapInterval.
    602   const s32 interval = static_cast<s32>(m_vsync_mode == GPUVSyncMode::FIFO);
    603   GLint current_fbo = 0;
    604   glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
    605   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    606 
    607   if (!m_gl_context->SetSwapInterval(interval))
    608     WARNING_LOG("Failed to set swap interval to {}", interval);
    609 
    610   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
    611 }
    612 
    613 void OpenGLDevice::RenderBlankFrame()
    614 {
    615   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    616   glDisable(GL_SCISSOR_TEST);
    617   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    618   glClearBufferfv(GL_COLOR, 0, GSVector4::cxpr(0.0f, 0.0f, 0.0f, 1.0f).F32);
    619   glColorMask(m_last_blend_state.write_r, m_last_blend_state.write_g, m_last_blend_state.write_b,
    620               m_last_blend_state.write_a);
    621   glEnable(GL_SCISSOR_TEST);
    622   m_gl_context->SwapBuffers();
    623   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
    624 }
    625 
    626 s32 OpenGLDevice::IsRenderTargetBound(const GPUTexture* tex) const
    627 {
    628   for (u32 i = 0; i < m_num_current_render_targets; i++)
    629   {
    630     if (m_current_render_targets[i] == tex)
    631       return static_cast<s32>(i);
    632   }
    633 
    634   return -1;
    635 }
    636 
    637 GLuint OpenGLDevice::CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags)
    638 {
    639   glGetError();
    640 
    641   GLuint fbo_id;
    642   glGenFramebuffers(1, &fbo_id);
    643   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
    644 
    645   for (u32 i = 0; i < num_rts; i++)
    646   {
    647     OpenGLTexture* const RT = static_cast<OpenGLTexture*>(rts[i]);
    648     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, RT->GetGLTarget(), RT->GetGLId(), 0);
    649   }
    650 
    651   if (ds)
    652   {
    653     OpenGLTexture* const DS = static_cast<OpenGLTexture*>(ds);
    654     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, DS->GetGLTarget(), DS->GetGLId(), 0);
    655   }
    656 
    657   glDrawBuffers(num_rts, s_draw_buffers.data());
    658 
    659   if (glGetError() != GL_NO_ERROR || glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    660   {
    661     ERROR_LOG("Failed to create GL framebuffer: {}", static_cast<s32>(glGetError()));
    662     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLDevice::GetInstance().m_current_fbo);
    663     glDeleteFramebuffers(1, &fbo_id);
    664     return {};
    665   }
    666 
    667   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLDevice::GetInstance().m_current_fbo);
    668   return fbo_id;
    669 }
    670 
    671 void OpenGLDevice::DestroyFramebuffer(GLuint fbo)
    672 {
    673   if (fbo != 0)
    674     glDeleteFramebuffers(1, &fbo);
    675 }
    676 
    677 void OpenGLDevice::DestroySurface()
    678 {
    679   if (!m_gl_context)
    680     return;
    681 
    682   m_window_info.SetSurfaceless();
    683   if (!m_gl_context->ChangeSurface(m_window_info))
    684     ERROR_LOG("Failed to switch to surfaceless");
    685 }
    686 
    687 bool OpenGLDevice::CreateBuffers()
    688 {
    689   if (!(m_vertex_buffer = OpenGLStreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE)) ||
    690       !(m_index_buffer = OpenGLStreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE)) ||
    691       !(m_uniform_buffer = OpenGLStreamBuffer::Create(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE))) [[unlikely]]
    692   {
    693     ERROR_LOG("Failed to create one or more device buffers.");
    694     return false;
    695   }
    696 
    697   GL_OBJECT_NAME(m_vertex_buffer, "Device Vertex Buffer");
    698   GL_OBJECT_NAME(m_index_buffer, "Device Index Buffer");
    699   GL_OBJECT_NAME(m_uniform_buffer, "Device Uniform Buffer");
    700 
    701   glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<GLint*>(&m_uniform_buffer_alignment));
    702 
    703   if (!m_disable_pbo)
    704   {
    705     if (!(m_texture_stream_buffer = OpenGLStreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_STREAM_BUFFER_SIZE)))
    706       [[unlikely]]
    707     {
    708       ERROR_LOG("Failed to create texture stream buffer");
    709       return false;
    710     }
    711 
    712     // Need to unbind otherwise normal uploads will fail.
    713     m_texture_stream_buffer->Unbind();
    714 
    715     GL_OBJECT_NAME(m_texture_stream_buffer, "Device Texture Stream Buffer");
    716   }
    717 
    718   GLuint fbos[2];
    719   glGetError();
    720   glGenFramebuffers(static_cast<GLsizei>(std::size(fbos)), fbos);
    721   if (const GLenum err = glGetError(); err != GL_NO_ERROR) [[unlikely]]
    722   {
    723     ERROR_LOG("Failed to create framebuffers: {}", err);
    724     return false;
    725   }
    726   m_read_fbo = fbos[0];
    727   m_write_fbo = fbos[1];
    728 
    729   return true;
    730 }
    731 
    732 void OpenGLDevice::DestroyBuffers()
    733 {
    734   if (m_write_fbo != 0)
    735     glDeleteFramebuffers(1, &m_write_fbo);
    736   if (m_read_fbo != 0)
    737     glDeleteFramebuffers(1, &m_read_fbo);
    738   m_texture_stream_buffer.reset();
    739   m_uniform_buffer.reset();
    740   m_index_buffer.reset();
    741   m_vertex_buffer.reset();
    742 }
    743 
    744 bool OpenGLDevice::BeginPresent(bool skip_present, u32 clear_color)
    745 {
    746   if (skip_present || m_window_info.type == WindowInfo::Type::Surfaceless)
    747   {
    748     if (!skip_present)
    749     {
    750       glFlush();
    751       TrimTexturePool();
    752     }
    753 
    754     return false;
    755   }
    756 
    757   glBindFramebuffer(GL_FRAMEBUFFER, 0);
    758   glDisable(GL_SCISSOR_TEST);
    759   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    760   glClearBufferfv(GL_COLOR, 0, GSVector4::rgba32(clear_color).F32);
    761   glColorMask(m_last_blend_state.write_r, m_last_blend_state.write_g, m_last_blend_state.write_b,
    762               m_last_blend_state.write_a);
    763   glEnable(GL_SCISSOR_TEST);
    764 
    765   m_current_fbo = 0;
    766   m_num_current_render_targets = 0;
    767   std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
    768   m_current_depth_target = nullptr;
    769 
    770   const GSVector4i window_rc = GSVector4i(0, 0, m_window_info.surface_width, m_window_info.surface_height);
    771   m_last_viewport = window_rc;
    772   m_last_scissor = window_rc;
    773   UpdateViewport();
    774   UpdateScissor();
    775   return true;
    776 }
    777 
    778 void OpenGLDevice::EndPresent(bool explicit_present)
    779 {
    780   DebugAssert(!explicit_present);
    781   DebugAssert(m_current_fbo == 0);
    782 
    783   if (m_gpu_timing_enabled)
    784     PopTimestampQuery();
    785 
    786   m_gl_context->SwapBuffers();
    787 
    788   if (m_gpu_timing_enabled)
    789     KickTimestampQuery();
    790 
    791   TrimTexturePool();
    792 }
    793 
    794 void OpenGLDevice::SubmitPresent()
    795 {
    796   Panic("Not supported by this API.");
    797 }
    798 
    799 void OpenGLDevice::CreateTimestampQueries()
    800 {
    801   const bool gles = m_gl_context->IsGLES();
    802   const auto GenQueries = gles ? glGenQueriesEXT : glGenQueries;
    803 
    804   GenQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
    805   KickTimestampQuery();
    806 }
    807 
    808 void OpenGLDevice::DestroyTimestampQueries()
    809 {
    810   if (m_timestamp_queries[0] == 0)
    811     return;
    812 
    813   const bool gles = m_gl_context->IsGLES();
    814   const auto DeleteQueries = gles ? glDeleteQueriesEXT : glDeleteQueries;
    815 
    816   if (m_timestamp_query_started)
    817   {
    818     const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
    819     EndQuery(GL_TIME_ELAPSED);
    820   }
    821 
    822   DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
    823   m_timestamp_queries.fill(0);
    824   m_read_timestamp_query = 0;
    825   m_write_timestamp_query = 0;
    826   m_waiting_timestamp_queries = 0;
    827   m_timestamp_query_started = false;
    828 }
    829 
    830 void OpenGLDevice::PopTimestampQuery()
    831 {
    832   const bool gles = m_gl_context->IsGLES();
    833 
    834   if (gles)
    835   {
    836     GLint disjoint = 0;
    837     glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint);
    838     if (disjoint)
    839     {
    840       VERBOSE_LOG("GPU timing disjoint, resetting.");
    841       if (m_timestamp_query_started)
    842         glEndQueryEXT(GL_TIME_ELAPSED);
    843 
    844       m_read_timestamp_query = 0;
    845       m_write_timestamp_query = 0;
    846       m_waiting_timestamp_queries = 0;
    847       m_timestamp_query_started = false;
    848     }
    849   }
    850 
    851   while (m_waiting_timestamp_queries > 0)
    852   {
    853     const auto GetQueryObjectiv = gles ? glGetQueryObjectivEXT : glGetQueryObjectiv;
    854     const auto GetQueryObjectui64v = gles ? glGetQueryObjectui64vEXT : glGetQueryObjectui64v;
    855 
    856     GLint available = 0;
    857     GetQueryObjectiv(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT_AVAILABLE, &available);
    858     if (!available)
    859       break;
    860 
    861     u64 result = 0;
    862     GetQueryObjectui64v(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT, &result);
    863     m_accumulated_gpu_time += static_cast<float>(static_cast<double>(result) / 1000000.0);
    864     m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
    865     m_waiting_timestamp_queries--;
    866   }
    867 
    868   if (m_timestamp_query_started)
    869   {
    870     const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
    871     EndQuery(GL_TIME_ELAPSED);
    872 
    873     m_write_timestamp_query = (m_write_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
    874     m_timestamp_query_started = false;
    875     m_waiting_timestamp_queries++;
    876   }
    877 }
    878 
    879 void OpenGLDevice::KickTimestampQuery()
    880 {
    881   if (m_timestamp_query_started || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
    882     return;
    883 
    884   const bool gles = m_gl_context->IsGLES();
    885   const auto BeginQuery = gles ? glBeginQueryEXT : glBeginQuery;
    886 
    887   BeginQuery(GL_TIME_ELAPSED, m_timestamp_queries[m_write_timestamp_query]);
    888   m_timestamp_query_started = true;
    889 }
    890 
    891 bool OpenGLDevice::SetGPUTimingEnabled(bool enabled)
    892 {
    893   if (m_gpu_timing_enabled == enabled)
    894     return true;
    895   else if (!m_features.gpu_timing)
    896     return false;
    897 
    898   m_gpu_timing_enabled = enabled;
    899   if (m_gpu_timing_enabled)
    900     CreateTimestampQueries();
    901   else
    902     DestroyTimestampQueries();
    903 
    904   return true;
    905 }
    906 
    907 float OpenGLDevice::GetAndResetAccumulatedGPUTime()
    908 {
    909   const float value = m_accumulated_gpu_time;
    910   m_accumulated_gpu_time = 0.0f;
    911   return value;
    912 }
    913 
    914 void OpenGLDevice::SetActiveTexture(u32 slot)
    915 {
    916   if (m_last_texture_unit != slot)
    917   {
    918     m_last_texture_unit = slot;
    919     glActiveTexture(GL_TEXTURE0 + slot);
    920   }
    921 }
    922 
    923 void OpenGLDevice::UnbindTexture(GLuint id)
    924 {
    925   for (u32 slot = 0; slot < MAX_TEXTURE_SAMPLERS; slot++)
    926   {
    927     auto& ss = m_last_samplers[slot];
    928     if (ss.first == id)
    929     {
    930       ss.first = 0;
    931 
    932       const GLenum unit = GL_TEXTURE0 + slot;
    933       if (m_last_texture_unit != unit)
    934       {
    935         m_last_texture_unit = unit;
    936         glActiveTexture(unit);
    937       }
    938 
    939       glBindTexture(GL_TEXTURE_2D, 0);
    940     }
    941   }
    942 }
    943 
    944 void OpenGLDevice::UnbindTexture(OpenGLTexture* tex)
    945 {
    946   UnbindTexture(tex->GetGLId());
    947 
    948   if (tex->IsRenderTarget())
    949   {
    950     for (u32 i = 0; i < m_num_current_render_targets; i++)
    951     {
    952       if (m_current_render_targets[i] == tex)
    953       {
    954         WARNING_LOG("Unbinding current RT");
    955         SetRenderTargets(nullptr, 0, m_current_depth_target);
    956         break;
    957       }
    958     }
    959 
    960     m_framebuffer_manager.RemoveRTReferences(tex);
    961   }
    962   else if (tex->IsDepthStencil())
    963   {
    964     if (m_current_depth_target == tex)
    965     {
    966       WARNING_LOG("Unbinding current DS");
    967       SetRenderTargets(nullptr, 0, nullptr);
    968     }
    969 
    970     m_framebuffer_manager.RemoveDSReferences(tex);
    971   }
    972 }
    973 
    974 void OpenGLDevice::UnbindSSBO(GLuint id)
    975 {
    976   if (m_last_ssbo != id)
    977     return;
    978 
    979   m_last_ssbo = 0;
    980   glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
    981 }
    982 
    983 void OpenGLDevice::UnbindSampler(GLuint id)
    984 {
    985   for (u32 slot = 0; slot < MAX_TEXTURE_SAMPLERS; slot++)
    986   {
    987     auto& ss = m_last_samplers[slot];
    988     if (ss.second == id)
    989     {
    990       ss.second = 0;
    991       glBindSampler(slot, 0);
    992     }
    993   }
    994 }
    995 
    996 void OpenGLDevice::UnbindPipeline(const OpenGLPipeline* pl)
    997 {
    998   if (m_current_pipeline == pl)
    999   {
   1000     m_current_pipeline = nullptr;
   1001     glUseProgram(0);
   1002   }
   1003 }
   1004 
   1005 ALWAYS_INLINE_RELEASE void OpenGLDevice::SetVertexBufferOffsets(u32 base_vertex)
   1006 {
   1007   const OpenGLPipeline::VertexArrayCacheKey& va = m_last_vao->first;
   1008   const size_t stride = va.vertex_attribute_stride;
   1009   for (u32 i = 0; i < va.num_vertex_attributes; i++)
   1010   {
   1011     glBindVertexBuffer(i, m_vertex_buffer->GetGLBufferId(), base_vertex * stride + va.vertex_attributes[i].offset,
   1012                        static_cast<GLsizei>(stride));
   1013   }
   1014 }
   1015 
   1016 void OpenGLDevice::Draw(u32 vertex_count, u32 base_vertex)
   1017 {
   1018   s_stats.num_draws++;
   1019 
   1020   if (glDrawElementsBaseVertex) [[likely]]
   1021   {
   1022     glDrawArrays(m_current_pipeline->GetTopology(), base_vertex, vertex_count);
   1023     return;
   1024   }
   1025 
   1026   SetVertexBufferOffsets(base_vertex);
   1027   glDrawArrays(m_current_pipeline->GetTopology(), 0, vertex_count);
   1028 }
   1029 
   1030 void OpenGLDevice::DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex)
   1031 {
   1032   s_stats.num_draws++;
   1033 
   1034   if (glDrawElementsBaseVertex) [[likely]]
   1035   {
   1036     const void* indices = reinterpret_cast<const void*>(static_cast<uintptr_t>(base_index) * sizeof(u16));
   1037     glDrawElementsBaseVertex(m_current_pipeline->GetTopology(), index_count, GL_UNSIGNED_SHORT, indices, base_vertex);
   1038     return;
   1039   }
   1040 
   1041   SetVertexBufferOffsets(base_vertex);
   1042 
   1043   const void* indices = reinterpret_cast<const void*>(static_cast<uintptr_t>(base_index) * sizeof(u16));
   1044   glDrawElements(m_current_pipeline->GetTopology(), index_count, GL_UNSIGNED_SHORT, indices);
   1045 }
   1046 
   1047 void OpenGLDevice::DrawIndexedWithBarrier(u32 index_count, u32 base_index, u32 base_vertex, DrawBarrier type)
   1048 {
   1049   Panic("Barriers are not supported");
   1050 }
   1051 
   1052 void OpenGLDevice::MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space,
   1053                                    u32* map_base_vertex)
   1054 {
   1055   const auto res = m_vertex_buffer->Map(vertex_size, vertex_size * vertex_count);
   1056   *map_ptr = res.pointer;
   1057   *map_space = res.space_aligned;
   1058   *map_base_vertex = res.index_aligned;
   1059 }
   1060 
   1061 void OpenGLDevice::UnmapVertexBuffer(u32 vertex_size, u32 vertex_count)
   1062 {
   1063   const u32 size = vertex_size * vertex_count;
   1064   s_stats.buffer_streamed += size;
   1065   m_vertex_buffer->Unmap(size);
   1066 }
   1067 
   1068 void OpenGLDevice::MapIndexBuffer(u32 index_count, DrawIndex** map_ptr, u32* map_space, u32* map_base_index)
   1069 {
   1070   const auto res = m_index_buffer->Map(sizeof(DrawIndex), sizeof(DrawIndex) * index_count);
   1071   *map_ptr = static_cast<DrawIndex*>(res.pointer);
   1072   *map_space = res.space_aligned;
   1073   *map_base_index = res.index_aligned;
   1074 }
   1075 
   1076 void OpenGLDevice::UnmapIndexBuffer(u32 used_index_count)
   1077 {
   1078   const u32 size = sizeof(DrawIndex) * used_index_count;
   1079   s_stats.buffer_streamed += size;
   1080   m_index_buffer->Unmap(size);
   1081 }
   1082 
   1083 void OpenGLDevice::PushUniformBuffer(const void* data, u32 data_size)
   1084 {
   1085   const auto res = m_uniform_buffer->Map(m_uniform_buffer_alignment, data_size);
   1086   std::memcpy(res.pointer, data, data_size);
   1087   m_uniform_buffer->Unmap(data_size);
   1088   s_stats.buffer_streamed += data_size;
   1089   glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_buffer->GetGLBufferId(), res.buffer_offset, data_size);
   1090 }
   1091 
   1092 void* OpenGLDevice::MapUniformBuffer(u32 size)
   1093 {
   1094   const auto res = m_uniform_buffer->Map(m_uniform_buffer_alignment, size);
   1095   return res.pointer;
   1096 }
   1097 
   1098 void OpenGLDevice::UnmapUniformBuffer(u32 size)
   1099 {
   1100   const u32 pos = m_uniform_buffer->Unmap(size);
   1101   s_stats.buffer_streamed += size;
   1102   glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_buffer->GetGLBufferId(), pos, size);
   1103 }
   1104 
   1105 void OpenGLDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
   1106                                     GPUPipeline::RenderPassFlag feedback_loop)
   1107 {
   1108   // DebugAssert(!feedback_loop); TODO
   1109   bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
   1110   bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
   1111   bool needs_rt_clear = false;
   1112 
   1113   m_current_depth_target = static_cast<OpenGLTexture*>(ds);
   1114   for (u32 i = 0; i < num_rts; i++)
   1115   {
   1116     OpenGLTexture* const dt = static_cast<OpenGLTexture*>(rts[i]);
   1117     changed |= m_current_render_targets[i] != dt;
   1118     m_current_render_targets[i] = dt;
   1119     needs_rt_clear |= dt->IsClearedOrInvalidated();
   1120   }
   1121   for (u32 i = num_rts; i < m_num_current_render_targets; i++)
   1122     m_current_render_targets[i] = nullptr;
   1123   m_num_current_render_targets = num_rts;
   1124   if (changed)
   1125   {
   1126     GLuint fbo = 0;
   1127     if (m_num_current_render_targets > 0 || m_current_depth_target)
   1128     {
   1129       if ((fbo = m_framebuffer_manager.Lookup(rts, num_rts, ds, 0)) == 0)
   1130       {
   1131         ERROR_LOG("Failed to get FBO for {} render targets", num_rts);
   1132         m_current_fbo = 0;
   1133         std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
   1134         m_num_current_render_targets = 0;
   1135         m_current_depth_target = nullptr;
   1136         return;
   1137       }
   1138     }
   1139 
   1140     s_stats.num_render_passes++;
   1141     m_current_fbo = fbo;
   1142     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
   1143   }
   1144 
   1145   if (needs_rt_clear)
   1146   {
   1147     for (u32 i = 0; i < num_rts; i++)
   1148     {
   1149       OpenGLTexture* const dt = static_cast<OpenGLTexture*>(rts[i]);
   1150       if (dt->IsClearedOrInvalidated())
   1151         CommitRTClearInFB(dt, i);
   1152     }
   1153   }
   1154 
   1155   if (needs_ds_clear)
   1156     CommitDSClearInFB(static_cast<OpenGLTexture*>(ds));
   1157 }
   1158 
   1159 void OpenGLDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
   1160 {
   1161   DebugAssert(slot < MAX_TEXTURE_SAMPLERS);
   1162   auto& sslot = m_last_samplers[slot];
   1163 
   1164   OpenGLTexture* T = static_cast<OpenGLTexture*>(texture);
   1165   GLuint Tid;
   1166   if (T)
   1167   {
   1168     Tid = T->GetGLId();
   1169     CommitClear(T);
   1170   }
   1171   else
   1172   {
   1173     Tid = 0;
   1174   }
   1175 
   1176   if (sslot.first != Tid)
   1177   {
   1178     sslot.first = Tid;
   1179 
   1180     SetActiveTexture(slot);
   1181     glBindTexture(T ? T->GetGLTarget() : GL_TEXTURE_2D, T ? T->GetGLId() : 0);
   1182   }
   1183 
   1184   const GLuint Sid = sampler ? static_cast<const OpenGLSampler*>(sampler)->GetID() : 0;
   1185   if (sslot.second != Sid)
   1186   {
   1187     sslot.second = Sid;
   1188     glBindSampler(slot, Sid);
   1189   }
   1190 }
   1191 
   1192 void OpenGLDevice::SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer)
   1193 {
   1194   const OpenGLTextureBuffer* B = static_cast<const OpenGLTextureBuffer*>(buffer);
   1195   if (!m_features.texture_buffers_emulated_with_ssbo)
   1196   {
   1197     const GLuint Tid = B ? B->GetTextureId() : 0;
   1198     if (m_last_samplers[slot].first != Tid)
   1199     {
   1200       m_last_samplers[slot].first = Tid;
   1201       SetActiveTexture(slot);
   1202       glBindTexture(GL_TEXTURE_BUFFER, Tid);
   1203     }
   1204   }
   1205   else
   1206   {
   1207     DebugAssert(slot == 0);
   1208     const GLuint bid = B ? B->GetBuffer()->GetGLBufferId() : 0;
   1209     if (m_last_ssbo == bid)
   1210       return;
   1211 
   1212     m_last_ssbo = bid;
   1213     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, bid);
   1214   }
   1215 }
   1216 
   1217 void OpenGLDevice::SetViewport(const GSVector4i rc)
   1218 {
   1219   if (m_last_viewport.eq(rc))
   1220     return;
   1221 
   1222   m_last_viewport = rc;
   1223   UpdateViewport();
   1224 }
   1225 
   1226 void OpenGLDevice::SetScissor(const GSVector4i rc)
   1227 {
   1228   if (m_last_scissor.eq(rc))
   1229     return;
   1230 
   1231   m_last_scissor = rc;
   1232   UpdateScissor();
   1233 }
   1234 
   1235 void OpenGLDevice::UpdateViewport()
   1236 {
   1237   glViewport(m_last_viewport.left, m_last_viewport.top, m_last_viewport.width(), m_last_viewport.height());
   1238 }
   1239 
   1240 void OpenGLDevice::UpdateScissor()
   1241 {
   1242   glScissor(m_last_scissor.left, m_last_scissor.top, m_last_scissor.width(), m_last_scissor.height());
   1243 }