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, ¤t_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 }