Line data Source code
1 : /* Copyright (C) 2023 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "Device.h"
21 :
22 : #include "lib/external_libraries/libsdl.h"
23 : #include "lib/hash.h"
24 : #include "lib/ogl.h"
25 : #include "ps/CLogger.h"
26 : #include "ps/ConfigDB.h"
27 : #include "ps/Profile.h"
28 : #include "renderer/backend/gl/DeviceCommandContext.h"
29 : #include "renderer/backend/gl/PipelineState.h"
30 : #include "renderer/backend/gl/Texture.h"
31 : #include "scriptinterface/JSON.h"
32 : #include "scriptinterface/Object.h"
33 : #include "scriptinterface/ScriptInterface.h"
34 : #include "scriptinterface/ScriptRequest.h"
35 :
36 : #if OS_WIN
37 : #include "lib/sysdep/os/win/wgfx.h"
38 :
39 : // We can't include wutil directly because GL headers conflict with Windows
40 : // until we use a proper GL loader.
41 : extern void* wutil_GetAppHDC();
42 : #endif
43 :
44 : #include <algorithm>
45 : #include <boost/algorithm/string/classification.hpp>
46 : #include <boost/algorithm/string/split.hpp>
47 :
48 : #if !CONFIG2_GLES && (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND))
49 :
50 : #if defined(SDL_VIDEO_DRIVER_X11)
51 : #include <glad/glx.h>
52 : #endif
53 : #if defined(SDL_VIDEO_DRIVER_WAYLAND)
54 : #include <glad/egl.h>
55 : #endif
56 : #include <SDL_syswm.h>
57 :
58 : #endif // !CONFIG2_GLES && (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND))
59 :
60 : namespace Renderer
61 : {
62 :
63 : namespace Backend
64 : {
65 :
66 : namespace GL
67 : {
68 :
69 : namespace
70 : {
71 :
72 0 : std::string GetNameImpl()
73 : {
74 : // GL_VENDOR+GL_RENDERER are good enough here, so we don't use WMI to detect the cards.
75 : // On top of that WMI can cause crashes with Nvidia Optimus and some netbooks
76 : // see http://trac.wildfiregames.com/ticket/1952
77 : // http://trac.wildfiregames.com/ticket/1575
78 : char cardName[128];
79 0 : const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
80 0 : const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
81 : // Happens if called before GL initialization.
82 0 : if (!vendor || !renderer)
83 0 : return {};
84 0 : sprintf_s(cardName, std::size(cardName), "%s %s", vendor, renderer);
85 :
86 : // Remove crap from vendor names. (don't dare touch the model name -
87 : // it's too risky, there are too many different strings).
88 : #define SHORTEN(what, charsToKeep) \
89 : if (!strncmp(cardName, what, std::size(what) - 1)) \
90 : memmove(cardName + charsToKeep, cardName + std::size(what) - 1, (strlen(cardName) - (std::size(what) - 1) + 1) * sizeof(char));
91 0 : SHORTEN("ATI Technologies Inc.", 3);
92 0 : SHORTEN("NVIDIA Corporation", 6);
93 0 : SHORTEN("S3 Graphics", 2); // returned by EnumDisplayDevices
94 0 : SHORTEN("S3 Graphics, Incorporated", 2); // returned by GL_VENDOR
95 : #undef SHORTEN
96 :
97 0 : return cardName;
98 : }
99 :
100 0 : std::string GetVersionImpl()
101 : {
102 0 : return reinterpret_cast<const char*>(glGetString(GL_VERSION));
103 : }
104 :
105 0 : std::string GetDriverInformationImpl()
106 : {
107 0 : const std::string version = GetVersionImpl();
108 :
109 0 : std::string driverInfo;
110 : #if OS_WIN
111 : driverInfo = CStrW(wgfx_DriverInfo()).ToUTF8();
112 : if (driverInfo.empty())
113 : #endif
114 : {
115 0 : if (!version.empty())
116 : {
117 : // Add "OpenGL" to differentiate this from the real driver version
118 : // (returned by platform-specific detect routines).
119 0 : driverInfo = std::string("OpenGL ") + version;
120 : }
121 : }
122 :
123 0 : if (driverInfo.empty())
124 0 : return version;
125 0 : return version + " " + driverInfo;
126 : }
127 :
128 0 : std::vector<std::string> GetExtensionsImpl()
129 : {
130 0 : std::vector<std::string> extensions;
131 0 : const std::string exts = ogl_ExtensionString();
132 0 : boost::split(extensions, exts, boost::algorithm::is_space(), boost::token_compress_on);
133 0 : std::sort(extensions.begin(), extensions.end());
134 0 : return extensions;
135 : }
136 :
137 0 : void GLAD_API_PTR OnDebugMessage(
138 : GLenum source, GLenum type, GLuint id, GLenum severity,
139 : GLsizei UNUSED(length), const GLchar* message, const void* UNUSED(user_param))
140 : {
141 0 : std::string debugSource = "unknown";
142 0 : std::string debugType = "unknown";
143 0 : std::string debugSeverity = "unknown";
144 :
145 0 : switch (source)
146 : {
147 0 : case GL_DEBUG_SOURCE_API:
148 0 : debugSource = "the API";
149 0 : break;
150 0 : case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
151 0 : debugSource = "the window system";
152 0 : break;
153 0 : case GL_DEBUG_SOURCE_SHADER_COMPILER:
154 0 : debugSource = "the shader compiler";
155 0 : break;
156 0 : case GL_DEBUG_SOURCE_THIRD_PARTY:
157 0 : debugSource = "a third party";
158 0 : break;
159 0 : case GL_DEBUG_SOURCE_APPLICATION:
160 0 : debugSource = "the application";
161 0 : break;
162 0 : case GL_DEBUG_SOURCE_OTHER:
163 0 : debugSource = "somewhere";
164 0 : break;
165 : }
166 :
167 0 : switch (type)
168 : {
169 0 : case GL_DEBUG_TYPE_ERROR:
170 0 : debugType = "error";
171 0 : break;
172 0 : case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
173 0 : debugType = "deprecated behaviour";
174 0 : break;
175 0 : case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
176 0 : debugType = "undefined behaviour";
177 0 : break;
178 0 : case GL_DEBUG_TYPE_PORTABILITY:
179 0 : debugType = "portability";
180 0 : break;
181 0 : case GL_DEBUG_TYPE_PERFORMANCE:
182 0 : debugType = "performance";
183 0 : break;
184 0 : case GL_DEBUG_TYPE_OTHER:
185 0 : debugType = "other";
186 0 : break;
187 0 : case GL_DEBUG_TYPE_MARKER:
188 0 : debugType = "marker";
189 0 : break;
190 0 : case GL_DEBUG_TYPE_PUSH_GROUP:
191 0 : debugType = "push group";
192 0 : break;
193 0 : case GL_DEBUG_TYPE_POP_GROUP:
194 0 : debugType = "pop group";
195 0 : break;
196 : }
197 :
198 0 : switch (severity)
199 : {
200 0 : case GL_DEBUG_SEVERITY_HIGH:
201 0 : debugSeverity = "high";
202 0 : break;
203 0 : case GL_DEBUG_SEVERITY_MEDIUM:
204 0 : debugSeverity = "medium";
205 0 : break;
206 0 : case GL_DEBUG_SEVERITY_LOW:
207 0 : debugSeverity = "low";
208 0 : break;
209 0 : case GL_DEBUG_SEVERITY_NOTIFICATION:
210 0 : debugSeverity = "notification";
211 0 : break;
212 : }
213 :
214 0 : if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
215 : {
216 0 : debug_printf(
217 : "OpenGL | %s: %s source: %s id %u: %s\n", debugSeverity.c_str(), debugType.c_str(), debugSource.c_str(), id, message);
218 : }
219 : else
220 : {
221 0 : LOGWARNING(
222 : "OpenGL | %s: %s source: %s id %u: %s\n", debugSeverity.c_str(), debugType.c_str(), debugSource.c_str(), id, message);
223 : }
224 0 : }
225 :
226 : } // anonymous namespace
227 :
228 : // static
229 0 : std::unique_ptr<IDevice> CDevice::Create(SDL_Window* window, const bool arb)
230 : {
231 0 : std::unique_ptr<CDevice> device(new CDevice());
232 :
233 0 : if (window)
234 : {
235 : // According to https://wiki.libsdl.org/SDL_CreateWindow we don't need to
236 : // call SDL_GL_LoadLibrary if we have a window with SDL_WINDOW_OPENGL,
237 : // because it'll be called internally for the first created window.
238 0 : device->m_Window = window;
239 0 : device->m_Context = SDL_GL_CreateContext(device->m_Window);
240 0 : if (!device->m_Context)
241 : {
242 0 : LOGERROR("SDL_GL_CreateContext failed: '%s'", SDL_GetError());
243 0 : return nullptr;
244 : }
245 0 : SDL_GL_GetDrawableSize(window, &device->m_SurfaceDrawableWidth, &device->m_SurfaceDrawableHeight);
246 :
247 : #if OS_WIN
248 : ogl_Init(SDL_GL_GetProcAddress, wutil_GetAppHDC());
249 : #elif (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) && !CONFIG2_GLES
250 : SDL_SysWMinfo wminfo;
251 : // The info structure must be initialized with the SDL version.
252 0 : SDL_VERSION(&wminfo.version);
253 0 : if (!SDL_GetWindowWMInfo(window, &wminfo))
254 : {
255 0 : LOGERROR("Failed to query SDL WM info: %s", SDL_GetError());
256 0 : return nullptr;
257 : }
258 0 : switch (wminfo.subsystem)
259 : {
260 : #if defined(SDL_VIDEO_DRIVER_WAYLAND)
261 0 : case SDL_SYSWM_WAYLAND:
262 : // TODO: maybe we need to load X11 functions
263 : // dynamically as well.
264 0 : ogl_Init(SDL_GL_GetProcAddress,
265 0 : GetWaylandDisplay(device->m_Window),
266 0 : static_cast<int>(wminfo.subsystem));
267 0 : break;
268 : #endif
269 : #if defined(SDL_VIDEO_DRIVER_X11)
270 0 : case SDL_SYSWM_X11:
271 0 : ogl_Init(SDL_GL_GetProcAddress,
272 0 : GetX11Display(device->m_Window),
273 0 : static_cast<int>(wminfo.subsystem));
274 0 : break;
275 : #endif
276 0 : default:
277 0 : ogl_Init(SDL_GL_GetProcAddress, nullptr,
278 0 : static_cast<int>(wminfo.subsystem));
279 0 : break;
280 : }
281 : #else
282 : ogl_Init(SDL_GL_GetProcAddress);
283 : #endif
284 : }
285 : else
286 : {
287 : #if OS_WIN
288 : ogl_Init(SDL_GL_GetProcAddress, wutil_GetAppHDC());
289 : #elif (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) && !CONFIG2_GLES
290 0 : bool initialized = false;
291 : // Currently we don't have access to the backend type without
292 : // the window. So we use hack to detect X11.
293 : #if defined(SDL_VIDEO_DRIVER_X11)
294 0 : Display* display = XOpenDisplay(NULL);
295 0 : if (display)
296 : {
297 0 : ogl_Init(SDL_GL_GetProcAddress, display, static_cast<int>(SDL_SYSWM_X11));
298 0 : initialized = true;
299 : }
300 : #endif
301 : #if defined(SDL_VIDEO_DRIVER_WAYLAND)
302 0 : if (!initialized)
303 : {
304 : // glad will find default EGLDisplay internally.
305 0 : ogl_Init(SDL_GL_GetProcAddress, nullptr, static_cast<int>(SDL_SYSWM_WAYLAND));
306 0 : initialized = true;
307 : }
308 : #endif
309 0 : if (!initialized)
310 : {
311 0 : LOGERROR("Can't initialize GL");
312 0 : return nullptr;
313 : }
314 : #else
315 : ogl_Init(SDL_GL_GetProcAddress);
316 : #endif
317 :
318 : #if OS_WIN || defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES
319 : // Hack to stop things looking very ugly when scrolling in Atlas.
320 0 : ogl_SetVsyncEnabled(true);
321 : #endif
322 : }
323 :
324 : // If we don't have GL2.0 then we don't have GLSL in core.
325 0 : if (!arb && !ogl_HaveVersion(2, 0))
326 0 : return nullptr;
327 :
328 0 : if ((ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr) // ARB
329 0 : && !ogl_HaveVersion(2, 0)) // GLSL
330 0 : || !ogl_HaveExtension("GL_ARB_vertex_buffer_object") // VBO
331 0 : || ogl_HaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", nullptr)
332 0 : || (!ogl_HaveExtension("GL_EXT_framebuffer_object") && !ogl_HaveExtension("GL_ARB_framebuffer_object")))
333 : {
334 : // It doesn't make sense to continue working here, because we're not
335 : // able to display anything.
336 0 : DEBUG_DISPLAY_FATAL_ERROR(
337 : L"Your graphics card doesn't appear to be fully compatible with OpenGL shaders."
338 : L" The game does not support pre-shader graphics cards."
339 : L" You are advised to try installing newer drivers and/or upgrade your graphics card."
340 : L" For more information, please see http://www.wildfiregames.com/forum/index.php?showtopic=16734"
341 : );
342 : }
343 :
344 0 : device->m_ARB = arb;
345 :
346 0 : device->m_Name = GetNameImpl();
347 0 : device->m_Version = GetVersionImpl();
348 0 : device->m_DriverInformation = GetDriverInformationImpl();
349 0 : device->m_Extensions = GetExtensionsImpl();
350 :
351 : // Set packing parameters for uploading and downloading data.
352 0 : glPixelStorei(GL_PACK_ALIGNMENT, 1);
353 0 : glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
354 :
355 0 : glEnable(GL_TEXTURE_2D);
356 :
357 0 : if (arb)
358 : {
359 : #if !CONFIG2_GLES
360 0 : glEnable(GL_VERTEX_PROGRAM_ARB);
361 0 : glEnable(GL_FRAGMENT_PROGRAM_ARB);
362 : #endif
363 : }
364 :
365 : #if CONFIG2_GLES
366 : device->m_UseFramebufferInvalidating = ogl_HaveExtension("GL_EXT_discard_framebuffer");
367 : #else
368 0 : device->m_UseFramebufferInvalidating = !arb && ogl_HaveExtension("GL_ARB_invalidate_subdata");
369 : #endif
370 :
371 0 : Capabilities& capabilities = device->m_Capabilities;
372 0 : capabilities.ARBShaders = !ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr);
373 0 : if (capabilities.ARBShaders)
374 0 : capabilities.ARBShadersShadow = ogl_HaveExtension("GL_ARB_fragment_program_shadow");
375 0 : capabilities.computeShaders = ogl_HaveVersion(4, 3) || ogl_HaveExtension("GL_ARB_compute_shader");
376 : #if CONFIG2_GLES
377 : // Some GLES implementations have GL_EXT_texture_compression_dxt1
378 : // but that only supports DXT1 so we can't use it.
379 : capabilities.S3TC = ogl_HaveExtensions(0, "GL_EXT_texture_compression_s3tc", nullptr) == 0;
380 : #else
381 : // Note: we don't bother checking for GL_S3_s3tc - it is incompatible
382 : // and irrelevant (was never widespread).
383 0 : capabilities.S3TC = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", nullptr) == 0;
384 : #endif
385 : #if CONFIG2_GLES
386 : capabilities.multisampling = false;
387 : capabilities.maxSampleCount = 1;
388 : #else
389 0 : capabilities.multisampling =
390 0 : ogl_HaveVersion(3, 3) &&
391 0 : ogl_HaveExtension("GL_ARB_multisample") &&
392 0 : ogl_HaveExtension("GL_ARB_texture_multisample");
393 0 : if (capabilities.multisampling)
394 : {
395 : // By default GL_MULTISAMPLE should be enabled, but enable it for buggy drivers.
396 0 : glEnable(GL_MULTISAMPLE);
397 0 : GLint maxSamples = 1;
398 0 : glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
399 0 : capabilities.maxSampleCount = maxSamples;
400 : }
401 : #endif
402 0 : capabilities.anisotropicFiltering = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic");
403 0 : if (capabilities.anisotropicFiltering)
404 : {
405 0 : GLfloat maxAnisotropy = 1.0f;
406 0 : glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
407 0 : capabilities.maxAnisotropy = maxAnisotropy;
408 : }
409 0 : GLint maxTextureSize = 1024;
410 0 : glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
411 0 : capabilities.maxTextureSize = maxTextureSize;
412 :
413 : #if CONFIG2_GLES
414 : const bool isDebugInCore = ogl_HaveVersion(3, 2);
415 : #else
416 0 : const bool isDebugInCore = ogl_HaveVersion(4, 3);
417 : #endif
418 0 : const bool hasDebug = isDebugInCore || ogl_HaveExtension("GL_KHR_debug");
419 0 : if (hasDebug)
420 : {
421 : #ifdef NDEBUG
422 : bool enableDebugMessages = false;
423 : CFG_GET_VAL("renderer.backend.debugmessages", enableDebugMessages);
424 : capabilities.debugLabels = false;
425 : CFG_GET_VAL("renderer.backend.debuglabels", capabilities.debugLabels);
426 : capabilities.debugScopedLabels = false;
427 : CFG_GET_VAL("renderer.backend.debugscopedlabels", capabilities.debugScopedLabels);
428 : #else
429 0 : const bool enableDebugMessages = true;
430 0 : capabilities.debugLabels = true;
431 0 : capabilities.debugScopedLabels = true;
432 : #endif
433 : if (enableDebugMessages)
434 : {
435 0 : glEnable(GL_DEBUG_OUTPUT);
436 : #if !CONFIG2_GLES
437 0 : glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
438 : #else
439 : #warning GLES without GL_DEBUG_OUTPUT_SYNCHRONOUS might call the callback from different threads which might be unsafe.
440 : #endif
441 0 : glDebugMessageCallback(OnDebugMessage, nullptr);
442 :
443 : // Filter out our own debug group messages
444 0 : const GLuint id = 0x0AD;
445 0 : glDebugMessageControl(
446 : GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE);
447 0 : glDebugMessageControl(
448 : GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE);
449 : }
450 : }
451 :
452 : #if CONFIG2_GLES
453 : capabilities.instancing = false;
454 : #else
455 0 : capabilities.instancing =
456 0 : !device->m_ARB &&
457 0 : (ogl_HaveVersion(3, 3) ||
458 0 : (ogl_HaveExtension("GL_ARB_draw_instanced") &&
459 0 : ogl_HaveExtension("GL_ARB_instanced_arrays")));
460 : #endif
461 :
462 0 : return device;
463 : }
464 :
465 : CDevice::CDevice() = default;
466 :
467 0 : CDevice::~CDevice()
468 : {
469 0 : if (m_Context)
470 0 : SDL_GL_DeleteContext(m_Context);
471 0 : }
472 :
473 0 : void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings)
474 : {
475 0 : const char* errstr = "(error)";
476 :
477 0 : Script::SetProperty(rq, settings, "name", m_ARB ? "glarb" : "gl");
478 :
479 : #define INTEGER(id) do { \
480 : GLint i = -1; \
481 : glGetIntegerv(GL_##id, &i); \
482 : if (ogl_SquelchError(GL_INVALID_ENUM)) \
483 : Script::SetProperty(rq, settings, "GL_" #id, errstr); \
484 : else \
485 : Script::SetProperty(rq, settings, "GL_" #id, i); \
486 : } while (false)
487 :
488 : #define INTEGER2(id) do { \
489 : GLint i[2] = { -1, -1 }; \
490 : glGetIntegerv(GL_##id, i); \
491 : if (ogl_SquelchError(GL_INVALID_ENUM)) { \
492 : Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \
493 : Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \
494 : } else { \
495 : Script::SetProperty(rq, settings, "GL_" #id "[0]", i[0]); \
496 : Script::SetProperty(rq, settings, "GL_" #id "[1]", i[1]); \
497 : } \
498 : } while (false)
499 :
500 : #define FLOAT(id) do { \
501 : GLfloat f = std::numeric_limits<GLfloat>::quiet_NaN(); \
502 : glGetFloatv(GL_##id, &f); \
503 : if (ogl_SquelchError(GL_INVALID_ENUM)) \
504 : Script::SetProperty(rq, settings, "GL_" #id, errstr); \
505 : else \
506 : Script::SetProperty(rq, settings, "GL_" #id, f); \
507 : } while (false)
508 :
509 : #define FLOAT2(id) do { \
510 : GLfloat f[2] = { std::numeric_limits<GLfloat>::quiet_NaN(), std::numeric_limits<GLfloat>::quiet_NaN() }; \
511 : glGetFloatv(GL_##id, f); \
512 : if (ogl_SquelchError(GL_INVALID_ENUM)) { \
513 : Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \
514 : Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \
515 : } else { \
516 : Script::SetProperty(rq, settings, "GL_" #id "[0]", f[0]); \
517 : Script::SetProperty(rq, settings, "GL_" #id "[1]", f[1]); \
518 : } \
519 : } while (false)
520 :
521 : #define STRING(id) do { \
522 : const char* c = (const char*)glGetString(GL_##id); \
523 : if (!c) c = ""; \
524 : if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \
525 : Script::SetProperty(rq, settings, "GL_" #id, std::string(c)); \
526 : } while (false)
527 :
528 : #define QUERY(target, pname) do { \
529 : GLint i = -1; \
530 : glGetQueryivARB(GL_##target, GL_##pname, &i); \
531 : if (ogl_SquelchError(GL_INVALID_ENUM)) \
532 : Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, errstr); \
533 : else \
534 : Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, i); \
535 : } while (false)
536 :
537 : #define VERTEXPROGRAM(id) do { \
538 : GLint i = -1; \
539 : glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \
540 : if (ogl_SquelchError(GL_INVALID_ENUM)) \
541 : Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \
542 : else \
543 : Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \
544 : } while (false)
545 :
546 : #define FRAGMENTPROGRAM(id) do { \
547 : GLint i = -1; \
548 : glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \
549 : if (ogl_SquelchError(GL_INVALID_ENUM)) \
550 : Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \
551 : else \
552 : Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \
553 : } while (false)
554 :
555 : #define BOOL(id) INTEGER(id)
556 :
557 0 : ogl_WarnIfError();
558 :
559 : // Core OpenGL 1.3:
560 : // (We don't bother checking extension strings for anything older than 1.3;
561 : // it'll just produce harmless warnings)
562 0 : STRING(VERSION);
563 0 : STRING(VENDOR);
564 0 : STRING(RENDERER);
565 0 : STRING(EXTENSIONS);
566 :
567 : #if !CONFIG2_GLES
568 0 : INTEGER(MAX_CLIP_PLANES);
569 : #endif
570 0 : INTEGER(SUBPIXEL_BITS);
571 : #if !CONFIG2_GLES
572 0 : INTEGER(MAX_3D_TEXTURE_SIZE);
573 : #endif
574 0 : INTEGER(MAX_TEXTURE_SIZE);
575 0 : INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE);
576 0 : INTEGER2(MAX_VIEWPORT_DIMS);
577 :
578 : #if !CONFIG2_GLES
579 0 : BOOL(RGBA_MODE);
580 0 : BOOL(INDEX_MODE);
581 0 : BOOL(DOUBLEBUFFER);
582 0 : BOOL(STEREO);
583 : #endif
584 :
585 0 : FLOAT2(ALIASED_POINT_SIZE_RANGE);
586 0 : FLOAT2(ALIASED_LINE_WIDTH_RANGE);
587 : #if !CONFIG2_GLES
588 0 : INTEGER(MAX_ELEMENTS_INDICES);
589 0 : INTEGER(MAX_ELEMENTS_VERTICES);
590 0 : INTEGER(MAX_TEXTURE_UNITS);
591 : #endif
592 0 : INTEGER(SAMPLE_BUFFERS);
593 0 : INTEGER(SAMPLES);
594 : // TODO: compressed texture formats
595 0 : INTEGER(RED_BITS);
596 0 : INTEGER(GREEN_BITS);
597 0 : INTEGER(BLUE_BITS);
598 0 : INTEGER(ALPHA_BITS);
599 : #if !CONFIG2_GLES
600 0 : INTEGER(INDEX_BITS);
601 : #endif
602 0 : INTEGER(DEPTH_BITS);
603 0 : INTEGER(STENCIL_BITS);
604 :
605 : #if !CONFIG2_GLES
606 :
607 : // Core OpenGL 2.0 (treated as extensions):
608 :
609 0 : if (ogl_HaveExtension("GL_EXT_texture_lod_bias"))
610 : {
611 0 : FLOAT(MAX_TEXTURE_LOD_BIAS_EXT);
612 : }
613 :
614 0 : if (ogl_HaveExtension("GL_ARB_occlusion_query"))
615 : {
616 0 : QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS);
617 : }
618 :
619 0 : if (ogl_HaveExtension("GL_ARB_shading_language_100"))
620 : {
621 0 : STRING(SHADING_LANGUAGE_VERSION_ARB);
622 : }
623 :
624 0 : if (ogl_HaveExtension("GL_ARB_vertex_shader"))
625 : {
626 0 : INTEGER(MAX_VERTEX_ATTRIBS_ARB);
627 0 : INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB);
628 0 : INTEGER(MAX_VARYING_FLOATS_ARB);
629 0 : INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB);
630 0 : INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB);
631 : }
632 :
633 0 : if (ogl_HaveExtension("GL_ARB_fragment_shader"))
634 : {
635 0 : INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB);
636 : }
637 :
638 0 : if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") ||
639 0 : ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
640 : {
641 0 : INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB);
642 0 : INTEGER(MAX_TEXTURE_COORDS_ARB);
643 : }
644 :
645 0 : if (ogl_HaveExtension("GL_ARB_draw_buffers"))
646 : {
647 0 : INTEGER(MAX_DRAW_BUFFERS_ARB);
648 : }
649 :
650 : // Core OpenGL 3.0:
651 :
652 0 : if (ogl_HaveExtension("GL_EXT_gpu_shader4"))
653 : {
654 0 : INTEGER(MIN_PROGRAM_TEXEL_OFFSET_EXT); // no _EXT version of these in glext.h
655 0 : INTEGER(MAX_PROGRAM_TEXEL_OFFSET_EXT);
656 : }
657 :
658 0 : if (ogl_HaveExtension("GL_EXT_framebuffer_object"))
659 : {
660 0 : INTEGER(MAX_COLOR_ATTACHMENTS_EXT);
661 0 : INTEGER(MAX_RENDERBUFFER_SIZE_EXT);
662 : }
663 :
664 0 : if (ogl_HaveExtension("GL_EXT_framebuffer_multisample"))
665 : {
666 0 : INTEGER(MAX_SAMPLES_EXT);
667 : }
668 :
669 0 : if (ogl_HaveExtension("GL_EXT_texture_array"))
670 : {
671 0 : INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT);
672 : }
673 :
674 0 : if (ogl_HaveExtension("GL_EXT_transform_feedback"))
675 : {
676 0 : INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT);
677 0 : INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT);
678 0 : INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT);
679 : }
680 :
681 :
682 : // Other interesting extensions:
683 :
684 0 : if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query"))
685 : {
686 0 : QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS);
687 : }
688 :
689 0 : if (ogl_HaveExtension("GL_ARB_timer_query"))
690 : {
691 0 : QUERY(TIMESTAMP, QUERY_COUNTER_BITS);
692 : }
693 :
694 0 : if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"))
695 : {
696 0 : FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT);
697 : }
698 :
699 0 : if (ogl_HaveExtension("GL_ARB_texture_rectangle"))
700 : {
701 0 : INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB);
702 : }
703 :
704 0 : if (m_ARB)
705 : {
706 0 : if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
707 : {
708 0 : INTEGER(MAX_PROGRAM_MATRICES_ARB);
709 0 : INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB);
710 : }
711 :
712 0 : if (ogl_HaveExtension("GL_ARB_vertex_program"))
713 : {
714 0 : VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
715 0 : VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
716 0 : VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
717 0 : VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
718 0 : VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
719 0 : VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
720 0 : VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
721 0 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
722 0 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
723 0 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
724 0 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);
725 0 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);
726 :
727 0 : if (ogl_HaveExtension("GL_ARB_fragment_program"))
728 : {
729 : // The spec seems to say these should be supported, but
730 : // Mesa complains about them so let's not bother
731 : /*
732 : VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
733 : VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
734 : VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
735 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
736 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
737 : VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
738 : */
739 : }
740 : }
741 :
742 0 : if (ogl_HaveExtension("GL_ARB_fragment_program"))
743 : {
744 0 : FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
745 0 : FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
746 0 : FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
747 0 : FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
748 0 : FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
749 0 : FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
750 0 : FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
751 0 : FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
752 0 : FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
753 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
754 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
755 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
756 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
757 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
758 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
759 0 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);
760 :
761 0 : if (ogl_HaveExtension("GL_ARB_vertex_program"))
762 : {
763 : // The spec seems to say these should be supported, but
764 : // Intel drivers on Windows complain about them so let's not bother
765 : /*
766 : FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
767 : FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);
768 : */
769 : }
770 : }
771 : }
772 :
773 0 : if (ogl_HaveExtension("GL_ARB_geometry_shader4"))
774 : {
775 0 : INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB);
776 0 : INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB);
777 0 : INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB);
778 0 : INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB);
779 0 : INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB);
780 0 : INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB);
781 : }
782 :
783 : #else // CONFIG2_GLES
784 :
785 : // Core OpenGL ES 2.0:
786 :
787 : STRING(SHADING_LANGUAGE_VERSION);
788 : INTEGER(MAX_VERTEX_ATTRIBS);
789 : INTEGER(MAX_VERTEX_UNIFORM_VECTORS);
790 : INTEGER(MAX_VARYING_VECTORS);
791 : INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
792 : INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS);
793 : INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS);
794 : INTEGER(MAX_TEXTURE_IMAGE_UNITS);
795 : INTEGER(MAX_RENDERBUFFER_SIZE);
796 :
797 : #endif // CONFIG2_GLES
798 :
799 :
800 : // TODO: Support OpenGL platforms which don't use GLX as well.
801 : #if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES
802 :
803 : #define GLXQCR_INTEGER(id) do { \
804 : unsigned int i = UINT_MAX; \
805 : if (glXQueryCurrentRendererIntegerMESA(id, &i)) \
806 : Script::SetProperty(rq, settings, #id, i); \
807 : } while (false)
808 :
809 : #define GLXQCR_INTEGER2(id) do { \
810 : unsigned int i[2] = { UINT_MAX, UINT_MAX }; \
811 : if (glXQueryCurrentRendererIntegerMESA(id, i)) { \
812 : Script::SetProperty(rq, settings, #id "[0]", i[0]); \
813 : Script::SetProperty(rq, settings, #id "[1]", i[1]); \
814 : } \
815 : } while (false)
816 :
817 : #define GLXQCR_INTEGER3(id) do { \
818 : unsigned int i[3] = { UINT_MAX, UINT_MAX, UINT_MAX }; \
819 : if (glXQueryCurrentRendererIntegerMESA(id, i)) { \
820 : Script::SetProperty(rq, settings, #id "[0]", i[0]); \
821 : Script::SetProperty(rq, settings, #id "[1]", i[1]); \
822 : Script::SetProperty(rq, settings, #id "[2]", i[2]); \
823 : } \
824 : } while (false)
825 :
826 : #define GLXQCR_STRING(id) do { \
827 : const char* str = glXQueryCurrentRendererStringMESA(id); \
828 : if (str) \
829 : Script::SetProperty(rq, settings, #id ".string", str); \
830 : } while (false)
831 :
832 :
833 : SDL_SysWMinfo wminfo;
834 0 : SDL_VERSION(&wminfo.version);
835 0 : const int ret = SDL_GetWindowWMInfo(m_Window, &wminfo);
836 0 : if (ret && wminfo.subsystem == SDL_SYSWM_X11)
837 : {
838 0 : Display* dpy = wminfo.info.x11.display;
839 0 : int scrnum = DefaultScreen(dpy);
840 :
841 0 : const char* glxexts = glXQueryExtensionsString(dpy, scrnum);
842 :
843 0 : Script::SetProperty(rq, settings, "glx_extensions", glxexts);
844 :
845 0 : if (strstr(glxexts, "GLX_MESA_query_renderer") && glXQueryCurrentRendererIntegerMESA && glXQueryCurrentRendererStringMESA)
846 : {
847 0 : GLXQCR_INTEGER(GLX_RENDERER_VENDOR_ID_MESA);
848 0 : GLXQCR_INTEGER(GLX_RENDERER_DEVICE_ID_MESA);
849 0 : GLXQCR_INTEGER3(GLX_RENDERER_VERSION_MESA);
850 0 : GLXQCR_INTEGER(GLX_RENDERER_ACCELERATED_MESA);
851 0 : GLXQCR_INTEGER(GLX_RENDERER_VIDEO_MEMORY_MESA);
852 0 : GLXQCR_INTEGER(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA);
853 0 : GLXQCR_INTEGER(GLX_RENDERER_PREFERRED_PROFILE_MESA);
854 0 : GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA);
855 0 : GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA);
856 0 : GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA);
857 0 : GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA);
858 0 : GLXQCR_STRING(GLX_RENDERER_VENDOR_ID_MESA);
859 0 : GLXQCR_STRING(GLX_RENDERER_DEVICE_ID_MESA);
860 : }
861 : }
862 : #endif // SDL_VIDEO_DRIVER_X11
863 0 : }
864 :
865 0 : std::unique_ptr<IDeviceCommandContext> CDevice::CreateCommandContext()
866 : {
867 0 : std::unique_ptr<CDeviceCommandContext> commandContet = CDeviceCommandContext::Create(this);
868 0 : m_ActiveCommandContext = commandContet.get();
869 0 : return commandContet;
870 : }
871 :
872 0 : std::unique_ptr<IGraphicsPipelineState> CDevice::CreateGraphicsPipelineState(
873 : const SGraphicsPipelineStateDesc& pipelineStateDesc)
874 : {
875 0 : return CGraphicsPipelineState::Create(this, pipelineStateDesc);
876 : }
877 :
878 0 : std::unique_ptr<IVertexInputLayout> CDevice::CreateVertexInputLayout(
879 : const PS::span<const SVertexAttributeFormat> attributes)
880 : {
881 0 : return std::make_unique<CVertexInputLayout>(this, attributes);
882 : }
883 :
884 0 : std::unique_ptr<ITexture> CDevice::CreateTexture(
885 : const char* name, const ITexture::Type type, const uint32_t usage,
886 : const Format format, const uint32_t width, const uint32_t height,
887 : const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
888 : {
889 0 : return CTexture::Create(this, name, type, usage,
890 0 : format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
891 : }
892 :
893 0 : std::unique_ptr<ITexture> CDevice::CreateTexture2D(
894 : const char* name, const uint32_t usage,
895 : const Format format, const uint32_t width, const uint32_t height,
896 : const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
897 : {
898 : return CreateTexture(name, CTexture::Type::TEXTURE_2D, usage,
899 0 : format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
900 : }
901 :
902 0 : std::unique_ptr<IFramebuffer> CDevice::CreateFramebuffer(
903 : const char* name, SColorAttachment* colorAttachment,
904 : SDepthStencilAttachment* depthStencilAttachment)
905 : {
906 0 : return CFramebuffer::Create(
907 0 : this, name, colorAttachment, depthStencilAttachment);
908 : }
909 :
910 0 : std::unique_ptr<IBuffer> CDevice::CreateBuffer(
911 : const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic)
912 : {
913 0 : return CBuffer::Create(this, name, type, size, dynamic);
914 : }
915 :
916 0 : std::unique_ptr<IShaderProgram> CDevice::CreateShaderProgram(
917 : const CStr& name, const CShaderDefines& defines)
918 : {
919 0 : return CShaderProgram::Create(this, name, defines);
920 : }
921 :
922 0 : bool CDevice::AcquireNextBackbuffer()
923 : {
924 0 : ENSURE(!m_BackbufferAcquired);
925 0 : m_BackbufferAcquired = true;
926 0 : return true;
927 : }
928 :
929 0 : size_t CDevice::BackbufferKeyHash::operator()(const BackbufferKey& key) const
930 : {
931 0 : size_t seed = 0;
932 0 : hash_combine(seed, std::get<0>(key));
933 0 : hash_combine(seed, std::get<1>(key));
934 0 : hash_combine(seed, std::get<2>(key));
935 0 : hash_combine(seed, std::get<3>(key));
936 0 : return seed;
937 : }
938 :
939 0 : IFramebuffer* CDevice::GetCurrentBackbuffer(
940 : const AttachmentLoadOp colorAttachmentLoadOp,
941 : const AttachmentStoreOp colorAttachmentStoreOp,
942 : const AttachmentLoadOp depthStencilAttachmentLoadOp,
943 : const AttachmentStoreOp depthStencilAttachmentStoreOp)
944 : {
945 : const BackbufferKey key{
946 : colorAttachmentLoadOp, colorAttachmentStoreOp,
947 0 : depthStencilAttachmentLoadOp, depthStencilAttachmentStoreOp};
948 0 : auto it = m_Backbuffers.find(key);
949 0 : if (it == m_Backbuffers.end())
950 : {
951 0 : it = m_Backbuffers.emplace(key, CFramebuffer::CreateBackbuffer(
952 : this, m_SurfaceDrawableWidth, m_SurfaceDrawableHeight,
953 : colorAttachmentLoadOp, colorAttachmentStoreOp,
954 0 : depthStencilAttachmentLoadOp, depthStencilAttachmentStoreOp)).first;
955 : }
956 0 : return it->second.get();
957 : }
958 :
959 0 : void CDevice::Present()
960 : {
961 0 : ENSURE(m_BackbufferAcquired);
962 0 : m_BackbufferAcquired = false;
963 :
964 0 : if (m_Window)
965 : {
966 0 : PROFILE3("swap buffers");
967 0 : SDL_GL_SwapWindow(m_Window);
968 0 : ogl_WarnIfError();
969 : }
970 :
971 0 : bool checkGLErrorAfterSwap = false;
972 0 : CFG_GET_VAL("gl.checkerrorafterswap", checkGLErrorAfterSwap);
973 : #if defined(NDEBUG)
974 : if (!checkGLErrorAfterSwap)
975 : return;
976 : #endif
977 0 : PROFILE3("error check");
978 : // We have to check GL errors after SwapBuffer to avoid possible
979 : // synchronizations during rendering.
980 0 : if (GLenum err = glGetError())
981 0 : ONCE(LOGERROR("GL error %s (0x%04x) occurred", ogl_GetErrorName(err), err));
982 0 : }
983 :
984 0 : void CDevice::OnWindowResize(const uint32_t width, const uint32_t height)
985 : {
986 0 : ENSURE(!m_BackbufferAcquired);
987 0 : m_Backbuffers.clear();
988 0 : m_SurfaceDrawableWidth = width;
989 0 : m_SurfaceDrawableHeight = height;
990 0 : }
991 :
992 0 : bool CDevice::IsTextureFormatSupported(const Format format) const
993 : {
994 0 : bool supported = false;
995 0 : switch (format)
996 : {
997 0 : case Format::UNDEFINED:
998 0 : break;
999 :
1000 0 : case Format::R8G8B8_UNORM: FALLTHROUGH;
1001 : case Format::R8G8B8A8_UNORM: FALLTHROUGH;
1002 : case Format::A8_UNORM: FALLTHROUGH;
1003 : case Format::L8_UNORM:
1004 0 : supported = true;
1005 0 : break;
1006 :
1007 0 : case Format::R32_SFLOAT: FALLTHROUGH;
1008 : case Format::R32G32_SFLOAT: FALLTHROUGH;
1009 : case Format::R32G32B32_SFLOAT: FALLTHROUGH;
1010 : case Format::R32G32B32A32_SFLOAT:
1011 0 : break;
1012 :
1013 0 : case Format::D16_UNORM: FALLTHROUGH;
1014 : case Format::D24_UNORM: FALLTHROUGH;
1015 : case Format::D32_SFLOAT:
1016 0 : supported = true;
1017 0 : break;
1018 0 : case Format::D24_UNORM_S8_UINT:
1019 : #if !CONFIG2_GLES
1020 0 : supported = true;
1021 : #endif
1022 0 : break;
1023 :
1024 0 : case Format::D32_SFLOAT_S8_UINT:
1025 0 : break;
1026 :
1027 0 : case Format::BC1_RGB_UNORM: FALLTHROUGH;
1028 : case Format::BC1_RGBA_UNORM: FALLTHROUGH;
1029 : case Format::BC2_UNORM: FALLTHROUGH;
1030 : case Format::BC3_UNORM:
1031 0 : supported = m_Capabilities.S3TC;
1032 0 : break;
1033 :
1034 0 : default:
1035 0 : break;
1036 : }
1037 0 : return supported;
1038 : }
1039 :
1040 0 : bool CDevice::IsFramebufferFormatSupported(const Format format) const
1041 : {
1042 0 : bool supported = false;
1043 0 : switch (format)
1044 : {
1045 0 : case Format::UNDEFINED:
1046 0 : break;
1047 : #if !CONFIG2_GLES
1048 0 : case Format::R8_UNORM:
1049 0 : supported = ogl_HaveVersion(3, 0);
1050 0 : break;
1051 : #endif
1052 0 : case Format::R8G8B8A8_UNORM:
1053 0 : supported = true;
1054 0 : break;
1055 0 : default:
1056 0 : break;
1057 : }
1058 0 : return supported;
1059 : }
1060 :
1061 0 : Format CDevice::GetPreferredDepthStencilFormat(
1062 : const uint32_t UNUSED(usage), const bool depth, const bool stencil) const
1063 : {
1064 0 : ENSURE(depth || stencil);
1065 0 : if (stencil)
1066 : #if CONFIG2_GLES
1067 : return Format::UNDEFINED;
1068 : #else
1069 0 : return Format::D24_UNORM_S8_UINT;
1070 : #endif
1071 : else
1072 0 : return Format::D24_UNORM;
1073 : }
1074 :
1075 0 : std::unique_ptr<IDevice> CreateDevice(SDL_Window* window, const bool arb)
1076 : {
1077 0 : return GL::CDevice::Create(window, arb);
1078 : }
1079 :
1080 : } // namespace GL
1081 :
1082 : } // namespace Backend
1083 :
1084 3 : } // namespace Renderer
|