OpenTTD Source 20260911-master-gee2b2ac12a
opengl.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11
12/* Define to disable buffer syncing. Will increase max fast forward FPS but produces artifacts. Mainly useful for performance testing. */
13// #define NO_GL_BUFFER_SYNC
14/* Define to allow software rendering backends. */
15// #define GL_ALLOW_SOFTWARE_RENDERER
16
17#if defined(_WIN32)
18# include <windows.h>
19#endif
20
21#define GL_GLEXT_PROTOTYPES
22#if defined(__APPLE__)
23# define GL_SILENCE_DEPRECATION
24# include <OpenGL/gl3.h>
25#else
26# include <GL/gl.h>
27#endif
28#include "../3rdparty/opengl/glext.h"
29
30#include "opengl.h"
32#include "../core/math_func.hpp"
33#include "../gfx_func.h"
34#include "../debug.h"
36#include "../zoom_func.h"
38
40#include "../table/sprites.h"
41
42
43#include "../safeguards.h"
44
45
46/* Define function pointers of all OpenGL functions that we load dynamically. */
47
48#define GL(function) static decltype(&function) _ ## function
49
50GL(glGetString);
51GL(glGetIntegerv);
52GL(glGetError);
53GL(glDebugMessageControl);
54GL(glDebugMessageCallback);
55
56GL(glDisable);
57GL(glEnable);
58GL(glViewport);
59GL(glClear);
60GL(glClearColor);
61GL(glBlendFunc);
62GL(glDrawArrays);
63
64GL(glTexImage1D);
65GL(glTexImage2D);
66GL(glTexParameteri);
67GL(glTexSubImage1D);
68GL(glTexSubImage2D);
69GL(glBindTexture);
70GL(glDeleteTextures);
71GL(glGenTextures);
72GL(glPixelStorei);
73
74GL(glActiveTexture);
75
76GL(glGenBuffers);
77GL(glDeleteBuffers);
78GL(glBindBuffer);
79GL(glBufferData);
80GL(glBufferSubData);
81GL(glMapBuffer);
82GL(glUnmapBuffer);
83GL(glClearBufferSubData);
84
85GL(glBufferStorage);
86GL(glMapBufferRange);
87GL(glClientWaitSync);
88GL(glFenceSync);
89GL(glDeleteSync);
90
91GL(glGenVertexArrays);
92GL(glDeleteVertexArrays);
93GL(glBindVertexArray);
94
95GL(glCreateProgram);
96GL(glDeleteProgram);
97GL(glLinkProgram);
98GL(glUseProgram);
99GL(glGetProgramiv);
100GL(glGetProgramInfoLog);
101GL(glCreateShader);
102GL(glDeleteShader);
103GL(glShaderSource);
104GL(glCompileShader);
105GL(glAttachShader);
106GL(glGetShaderiv);
107GL(glGetShaderInfoLog);
108GL(glGetUniformLocation);
109GL(glUniform1i);
110GL(glUniform1f);
111GL(glUniform2f);
112GL(glUniform4f);
113
114GL(glGetAttribLocation);
115GL(glEnableVertexAttribArray);
116GL(glDisableVertexAttribArray);
117GL(glVertexAttribPointer);
118GL(glBindFragDataLocation);
119
120#undef GL
121
122
125 float x, y;
126 float u, v;
127};
128
130static const int MAX_CACHED_CURSORS = 48;
131
132/* static */ OpenGLBackend *OpenGLBackend::instance = nullptr;
133
134GetOGLProcAddressProc GetOGLProcAddress;
135
136static std::optional<std::string_view> GlGetString(GLenum name)
137{
138 auto str = reinterpret_cast<const char *>(_glGetString(name));
139 if (str == nullptr) return {};
140 return str;
141}
142
150bool HasStringInExtensionList(std::string_view string, std::string_view substring)
151{
152 StringConsumer consumer{string};
153 while (consumer.AnyBytesLeft()) {
154 if (substring == consumer.ReadUntil(" ", StringConsumer::SKIP_ALL_SEPARATORS)) return true;
155 }
156
157 return false;
158}
159
165static bool IsOpenGLExtensionSupported(std::string_view extension)
166{
167 static PFNGLGETSTRINGIPROC glGetStringi = nullptr;
168 static bool glGetStringi_loaded = false;
169
170 /* Starting with OpenGL 3.0 the preferred API to get the extensions
171 * has changed. Try to load the required function once. */
172 if (!glGetStringi_loaded) {
173 if (IsOpenGLVersionAtLeast(3, 0)) glGetStringi = (PFNGLGETSTRINGIPROC)GetOGLProcAddress("glGetStringi");
174 glGetStringi_loaded = true;
175 }
176
177 if (glGetStringi != nullptr) {
178 /* New style: Each supported extension can be queried and compared independently. */
179 GLint num_exts;
180 _glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);
181
182 for (GLint i = 0; i < num_exts; i++) {
183 const char *entry = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
184 if (entry != nullptr && entry == extension) return true;
185 }
186 } else if (auto str = GlGetString(GL_EXTENSIONS); str.has_value()) {
187 /* Old style: A single, space-delimited string for all extensions. */
188 return HasStringInExtensionList(*str, extension);
189 }
190
191 return false;
192}
193
194static uint8_t _gl_major_ver = 0;
195static uint8_t _gl_minor_ver = 0;
196
204bool IsOpenGLVersionAtLeast(uint8_t major, uint8_t minor)
205{
206 return (_gl_major_ver > major) || (_gl_major_ver == major && _gl_minor_ver >= minor);
207}
208
216template <typename F>
217static bool BindGLProc(F &f, const char *name)
218{
219 f = reinterpret_cast<F>(GetOGLProcAddress(name));
220 return f != nullptr;
221}
222
228{
229 if (!BindGLProc(_glGetString, "glGetString")) return false;
230 if (!BindGLProc(_glGetIntegerv, "glGetIntegerv")) return false;
231 if (!BindGLProc(_glGetError, "glGetError")) return false;
232
233 return true;
234}
235
241{
242 if (!BindGLProc(_glDisable, "glDisable")) return false;
243 if (!BindGLProc(_glEnable, "glEnable")) return false;
244 if (!BindGLProc(_glViewport, "glViewport")) return false;
245 if (!BindGLProc(_glTexImage1D, "glTexImage1D")) return false;
246 if (!BindGLProc(_glTexImage2D, "glTexImage2D")) return false;
247 if (!BindGLProc(_glTexParameteri, "glTexParameteri")) return false;
248 if (!BindGLProc(_glTexSubImage1D, "glTexSubImage1D")) return false;
249 if (!BindGLProc(_glTexSubImage2D, "glTexSubImage2D")) return false;
250 if (!BindGLProc(_glBindTexture, "glBindTexture")) return false;
251 if (!BindGLProc(_glDeleteTextures, "glDeleteTextures")) return false;
252 if (!BindGLProc(_glGenTextures, "glGenTextures")) return false;
253 if (!BindGLProc(_glPixelStorei, "glPixelStorei")) return false;
254 if (!BindGLProc(_glClear, "glClear")) return false;
255 if (!BindGLProc(_glClearColor, "glClearColor")) return false;
256 if (!BindGLProc(_glBlendFunc, "glBlendFunc")) return false;
257 if (!BindGLProc(_glDrawArrays, "glDrawArrays")) return false;
258
259 return true;
260}
261
267{
268 if (IsOpenGLVersionAtLeast(1, 3)) {
269 if (!BindGLProc(_glActiveTexture, "glActiveTexture")) return false;
270 } else {
271 if (!BindGLProc(_glActiveTexture, "glActiveTextureARB")) return false;
272 }
273
274 return true;
275}
276
281static bool BindVBOExtension()
282{
283 if (IsOpenGLVersionAtLeast(1, 5)) {
284 if (!BindGLProc(_glGenBuffers, "glGenBuffers")) return false;
285 if (!BindGLProc(_glDeleteBuffers, "glDeleteBuffers")) return false;
286 if (!BindGLProc(_glBindBuffer, "glBindBuffer")) return false;
287 if (!BindGLProc(_glBufferData, "glBufferData")) return false;
288 if (!BindGLProc(_glBufferSubData, "glBufferSubData")) return false;
289 if (!BindGLProc(_glMapBuffer, "glMapBuffer")) return false;
290 if (!BindGLProc(_glUnmapBuffer, "glUnmapBuffer")) return false;
291 } else {
292 if (!BindGLProc(_glGenBuffers, "glGenBuffersARB")) return false;
293 if (!BindGLProc(_glDeleteBuffers, "glDeleteBuffersARB")) return false;
294 if (!BindGLProc(_glBindBuffer, "glBindBufferARB")) return false;
295 if (!BindGLProc(_glBufferData, "glBufferDataARB")) return false;
296 if (!BindGLProc(_glBufferSubData, "glBufferSubDataARB")) return false;
297 if (!BindGLProc(_glMapBuffer, "glMapBufferARB")) return false;
298 if (!BindGLProc(_glUnmapBuffer, "glUnmapBufferARB")) return false;
299 }
300
301 if (IsOpenGLVersionAtLeast(4, 3) || IsOpenGLExtensionSupported("GL_ARB_clear_buffer_object")) {
302 BindGLProc(_glClearBufferSubData, "glClearBufferSubData");
303 } else {
304 _glClearBufferSubData = nullptr;
305 }
306
307 return true;
308}
309
314static bool BindVBAExtension()
315{
316 /* The APPLE and ARB variants have different semantics (that don't matter for us).
317 * Successfully getting pointers to one variant doesn't mean it is supported for
318 * the current context. Always check the extension strings as well. */
319 if (IsOpenGLVersionAtLeast(3, 0) || IsOpenGLExtensionSupported("GL_ARB_vertex_array_object")) {
320 if (!BindGLProc(_glGenVertexArrays, "glGenVertexArrays")) return false;
321 if (!BindGLProc(_glDeleteVertexArrays, "glDeleteVertexArrays")) return false;
322 if (!BindGLProc(_glBindVertexArray, "glBindVertexArray")) return false;
323 } else if (IsOpenGLExtensionSupported("GL_APPLE_vertex_array_object")) {
324 if (!BindGLProc(_glGenVertexArrays, "glGenVertexArraysAPPLE")) return false;
325 if (!BindGLProc(_glDeleteVertexArrays, "glDeleteVertexArraysAPPLE")) return false;
326 if (!BindGLProc(_glBindVertexArray, "glBindVertexArrayAPPLE")) return false;
327 }
328
329 return true;
330}
331
337{
338 if (IsOpenGLVersionAtLeast(2, 0)) {
339 if (!BindGLProc(_glCreateProgram, "glCreateProgram")) return false;
340 if (!BindGLProc(_glDeleteProgram, "glDeleteProgram")) return false;
341 if (!BindGLProc(_glLinkProgram, "glLinkProgram")) return false;
342 if (!BindGLProc(_glUseProgram, "glUseProgram")) return false;
343 if (!BindGLProc(_glGetProgramiv, "glGetProgramiv")) return false;
344 if (!BindGLProc(_glGetProgramInfoLog, "glGetProgramInfoLog")) return false;
345 if (!BindGLProc(_glCreateShader, "glCreateShader")) return false;
346 if (!BindGLProc(_glDeleteShader, "glDeleteShader")) return false;
347 if (!BindGLProc(_glShaderSource, "glShaderSource")) return false;
348 if (!BindGLProc(_glCompileShader, "glCompileShader")) return false;
349 if (!BindGLProc(_glAttachShader, "glAttachShader")) return false;
350 if (!BindGLProc(_glGetShaderiv, "glGetShaderiv")) return false;
351 if (!BindGLProc(_glGetShaderInfoLog, "glGetShaderInfoLog")) return false;
352 if (!BindGLProc(_glGetUniformLocation, "glGetUniformLocation")) return false;
353 if (!BindGLProc(_glUniform1i, "glUniform1i")) return false;
354 if (!BindGLProc(_glUniform1f, "glUniform1f")) return false;
355 if (!BindGLProc(_glUniform2f, "glUniform2f")) return false;
356 if (!BindGLProc(_glUniform4f, "glUniform4f")) return false;
357
358 if (!BindGLProc(_glGetAttribLocation, "glGetAttribLocation")) return false;
359 if (!BindGLProc(_glEnableVertexAttribArray, "glEnableVertexAttribArray")) return false;
360 if (!BindGLProc(_glDisableVertexAttribArray, "glDisableVertexAttribArray")) return false;
361 if (!BindGLProc(_glVertexAttribPointer, "glVertexAttribPointer")) return false;
362 } else {
363 /* In the ARB extension programs and shaders are in the same object space. */
364 if (!BindGLProc(_glCreateProgram, "glCreateProgramObjectARB")) return false;
365 if (!BindGLProc(_glDeleteProgram, "glDeleteObjectARB")) return false;
366 if (!BindGLProc(_glLinkProgram, "glLinkProgramARB")) return false;
367 if (!BindGLProc(_glUseProgram, "glUseProgramObjectARB")) return false;
368 if (!BindGLProc(_glGetProgramiv, "glGetObjectParameterivARB")) return false;
369 if (!BindGLProc(_glGetProgramInfoLog, "glGetInfoLogARB")) return false;
370 if (!BindGLProc(_glCreateShader, "glCreateShaderObjectARB")) return false;
371 if (!BindGLProc(_glDeleteShader, "glDeleteObjectARB")) return false;
372 if (!BindGLProc(_glShaderSource, "glShaderSourceARB")) return false;
373 if (!BindGLProc(_glCompileShader, "glCompileShaderARB")) return false;
374 if (!BindGLProc(_glAttachShader, "glAttachObjectARB")) return false;
375 if (!BindGLProc(_glGetShaderiv, "glGetObjectParameterivARB")) return false;
376 if (!BindGLProc(_glGetShaderInfoLog, "glGetInfoLogARB")) return false;
377 if (!BindGLProc(_glGetUniformLocation, "glGetUniformLocationARB")) return false;
378 if (!BindGLProc(_glUniform1i, "glUniform1iARB")) return false;
379 if (!BindGLProc(_glUniform1f, "glUniform1fARB")) return false;
380 if (!BindGLProc(_glUniform2f, "glUniform2fARB")) return false;
381 if (!BindGLProc(_glUniform4f, "glUniform4fARB")) return false;
382
383 if (!BindGLProc(_glGetAttribLocation, "glGetAttribLocationARB")) return false;
384 if (!BindGLProc(_glEnableVertexAttribArray, "glEnableVertexAttribArrayARB")) return false;
385 if (!BindGLProc(_glDisableVertexAttribArray, "glDisableVertexAttribArrayARB")) return false;
386 if (!BindGLProc(_glVertexAttribPointer, "glVertexAttribPointerARB")) return false;
387 }
388
389 /* Bind functions only needed when using GLSL 1.50 shaders. */
390 if (IsOpenGLVersionAtLeast(3, 0)) {
391 BindGLProc(_glBindFragDataLocation, "glBindFragDataLocation");
392 } else if (IsOpenGLExtensionSupported("GL_EXT_gpu_shader4")) {
393 BindGLProc(_glBindFragDataLocation, "glBindFragDataLocationEXT");
394 } else {
395 _glBindFragDataLocation = nullptr;
396 }
397
398 return true;
399}
400
406{
407 /* Optional functions for persistent buffer mapping. */
408 if (IsOpenGLVersionAtLeast(3, 0)) {
409 if (!BindGLProc(_glMapBufferRange, "glMapBufferRange")) return false;
410 }
411 if (IsOpenGLVersionAtLeast(4, 4) || IsOpenGLExtensionSupported("GL_ARB_buffer_storage")) {
412 if (!BindGLProc(_glBufferStorage, "glBufferStorage")) return false;
413 }
414#ifndef NO_GL_BUFFER_SYNC
415 if (IsOpenGLVersionAtLeast(3, 2) || IsOpenGLExtensionSupported("GL_ARB_sync")) {
416 if (!BindGLProc(_glClientWaitSync, "glClientWaitSync")) return false;
417 if (!BindGLProc(_glFenceSync, "glFenceSync")) return false;
418 if (!BindGLProc(_glDeleteSync, "glDeleteSync")) return false;
419 }
420#endif
421
422 return true;
423}
424
431void APIENTRY DebugOutputCallback(GLenum, GLenum type, GLuint, GLenum severity, GLsizei, const GLchar *message, const void *)
432{
433 /* Make severity human readable. */
434 std::string_view severity_str;
435 switch (severity) {
436 case GL_DEBUG_SEVERITY_HIGH: severity_str = "high"; break;
437 case GL_DEBUG_SEVERITY_MEDIUM: severity_str = "medium"; break;
438 case GL_DEBUG_SEVERITY_LOW: severity_str = "low"; break;
439 }
440
441 /* Make type human readable.*/
442 std::string_view type_str = "Other";
443 switch (type) {
444 case GL_DEBUG_TYPE_ERROR: type_str = "Error"; break;
445 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: type_str = "Deprecated"; break;
446 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: type_str = "Undefined behaviour"; break;
447 case GL_DEBUG_TYPE_PERFORMANCE: type_str = "Performance"; break;
448 case GL_DEBUG_TYPE_PORTABILITY: type_str = "Portability"; break;
449 }
450
451 Debug(Facility::Driver, Severity::Debug2, "OpenGL: {} ({}) - {}", type_str, severity_str, message);
452}
453
456{
457#ifndef NO_DEBUG_MESSAGES
459
460 if (IsOpenGLVersionAtLeast(4, 3)) {
461 BindGLProc(_glDebugMessageControl, "glDebugMessageControl");
462 BindGLProc(_glDebugMessageCallback, "glDebugMessageCallback");
463 } else if (IsOpenGLExtensionSupported("GL_ARB_debug_output")) {
464 BindGLProc(_glDebugMessageControl, "glDebugMessageControlARB");
465 BindGLProc(_glDebugMessageCallback, "glDebugMessageCallbackARB");
466 }
467
468 if (_glDebugMessageControl != nullptr && _glDebugMessageCallback != nullptr) {
469 /* Enable debug output. As synchronous debug output costs performance, we only enable it with a high debug level. */
470 _glEnable(GL_DEBUG_OUTPUT);
471 if (IsVisibleSeverity(Facility::Driver, Severity::Trace2)) _glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
472
473 _glDebugMessageCallback(&DebugOutputCallback, nullptr);
474 /* Enable all messages on highest debug level.*/
475 _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, IsVisibleSeverity(Facility::Driver, Severity::Trace3) ? GL_TRUE : GL_FALSE);
476 /* Get debug messages for errors and undefined/deprecated behaviour. */
477 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, nullptr, GL_TRUE);
478 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0, nullptr, GL_TRUE);
479 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, nullptr, GL_TRUE);
480 }
481#endif
482}
483
490/* static */ std::optional<std::string_view> OpenGLBackend::Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
491{
493
494 GetOGLProcAddress = get_proc;
495
497 return OpenGLBackend::instance->Init(screen_res);
498}
499
503/* static */ void OpenGLBackend::Destroy()
504{
506 OpenGLBackend::instance = nullptr;
507}
508
515
520{
521 if (_glDeleteProgram != nullptr) {
522 _glDeleteProgram(this->remap_program);
523 _glDeleteProgram(this->vid_program);
524 _glDeleteProgram(this->pal_program);
525 _glDeleteProgram(this->sprite_program);
526 }
527 if (_glDeleteVertexArrays != nullptr) _glDeleteVertexArrays(1, &this->vao_quad);
528 if (_glDeleteBuffers != nullptr) {
529 _glDeleteBuffers(1, &this->vbo_quad);
530 _glDeleteBuffers(1, &this->vid_pbo);
531 _glDeleteBuffers(1, &this->anim_pbo);
532 }
533 if (_glDeleteTextures != nullptr) {
536
537 _glDeleteTextures(1, &this->vid_texture);
538 _glDeleteTextures(1, &this->anim_texture);
539 _glDeleteTextures(1, &this->pal_texture);
540 }
541}
542
543static std::tuple<uint8_t, uint8_t> DecodeVersion(std::string_view ver)
544{
545 StringConsumer consumer{ver};
546 int major = consumer.ReadIntegerBase<uint8_t>(10);
547 if (consumer.ReadIf(".")) return {major, consumer.ReadIntegerBase<uint8_t>(10)};
548 return {major, 0};
549}
550
556std::optional<std::string_view> OpenGLBackend::Init(const Dimension &screen_res)
557{
558 if (!BindBasicInfoProcs()) return "OpenGL not supported";
559
560 /* Always query the supported OpenGL version as the current context might have changed. */
561 auto ver = GlGetString(GL_VERSION);
562 auto vend = GlGetString(GL_VENDOR);
563 auto renderer = GlGetString(GL_RENDERER);
564
565 if (!ver.has_value() || !vend.has_value() || !renderer.has_value()) return "OpenGL not supported";
566
567 Debug(Facility::Driver, Severity::Error, "OpenGL driver: {} - {} ({})", *vend, *renderer, *ver);
568
569#ifndef GL_ALLOW_SOFTWARE_RENDERER
570 /* Don't use MESA software rendering backends as they are slower than
571 * just using a non-OpenGL video driver. */
572 if (renderer->starts_with("llvmpipe") || renderer->starts_with("softpipe")) return "Software renderer detected, not using OpenGL";
573#endif
574
575 std::tie(_gl_major_ver, _gl_minor_ver) = DecodeVersion(*ver);
576
577#ifdef _WIN32
578 /* Old drivers on Windows (especially if made by Intel) seem to be
579 * unstable, so cull the oldest stuff here. */
580 if (!IsOpenGLVersionAtLeast(3, 2)) return "Need at least OpenGL version 3.2 on Windows";
581#endif
582
583 if (!BindBasicOpenGLProcs()) return "Failed to bind basic OpenGL functions.";
584
586
587 /* OpenGL 1.3 is the absolute minimum. */
588 if (!IsOpenGLVersionAtLeast(1, 3)) return "OpenGL version >= 1.3 required";
589 /* Check for non-power-of-two texture support. */
590 if (!IsOpenGLVersionAtLeast(2, 0) && !IsOpenGLExtensionSupported("GL_ARB_texture_non_power_of_two")) return "Non-power-of-two textures not supported";
591 /* Check for single element texture formats. */
592 if (!IsOpenGLVersionAtLeast(3, 0) && !IsOpenGLExtensionSupported("GL_ARB_texture_rg")) return "Single element texture formats not supported";
593 if (!BindTextureExtensions()) return "Failed to bind texture extension functions";
594 /* Check for vertex buffer objects. */
595 if (!IsOpenGLVersionAtLeast(1, 5) && !IsOpenGLExtensionSupported("ARB_vertex_buffer_object")) return "Vertex buffer objects not supported";
596 if (!BindVBOExtension()) return "Failed to bind VBO extension functions";
597 /* Check for pixel buffer objects. */
598 if (!IsOpenGLVersionAtLeast(2, 1) && !IsOpenGLExtensionSupported("GL_ARB_pixel_buffer_object")) return "Pixel buffer objects not supported";
599 /* Check for vertex array objects. */
600 if (!IsOpenGLVersionAtLeast(3, 0) && (!IsOpenGLExtensionSupported("GL_ARB_vertex_array_object") || !IsOpenGLExtensionSupported("GL_APPLE_vertex_array_object"))) return "Vertex array objects not supported";
601 if (!BindVBAExtension()) return "Failed to bind VBA extension functions";
602 /* Check for shader objects. */
603 if (!IsOpenGLVersionAtLeast(2, 0) && (!IsOpenGLExtensionSupported("GL_ARB_shader_objects") || !IsOpenGLExtensionSupported("GL_ARB_fragment_shader") || !IsOpenGLExtensionSupported("GL_ARB_vertex_shader"))) return "No shader support";
604 if (!BindShaderExtensions()) return "Failed to bind shader extension functions";
605 if (IsOpenGLVersionAtLeast(3, 2) && _glBindFragDataLocation == nullptr) return "OpenGL claims to support version 3.2 but doesn't have glBindFragDataLocation";
606
608#ifndef NO_GL_BUFFER_SYNC
610#endif
611
613 Debug(Facility::Driver, Severity::Error, "OpenGL claims to support persistent buffer mapping but doesn't export all functions, not using persistent mapping.");
614 this->persistent_mapping_supported = false;
615 }
616 if (this->persistent_mapping_supported) Debug(Facility::Driver, Severity::Notice, "OpenGL: Using persistent buffer mapping");
617
618 /* Check maximum texture size against screen resolution. */
619 GLint max_tex_size = 0;
620 _glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
621 if (std::max(screen_res.width, screen_res.height) > (uint)max_tex_size) return "Max supported texture size is too small";
622
623 /* Check available texture units. */
624 GLint max_tex_units = 0;
625 _glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tex_units);
626 if (max_tex_units < 4) return "Not enough simultaneous textures supported";
627
628 Debug(Facility::Driver, Severity::Warning, "OpenGL shading language version: {}, texture units = {}", GlGetString(GL_SHADING_LANGUAGE_VERSION).value_or("Unknown version"), max_tex_units);
629
630 if (!this->InitShaders()) return "Failed to initialize shaders";
631
632 /* Setup video buffer texture. */
633 _glGenTextures(1, &this->vid_texture);
634 _glBindTexture(GL_TEXTURE_2D, this->vid_texture);
635 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
636 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
637 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
638 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
639 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
640 _glBindTexture(GL_TEXTURE_2D, 0);
641 if (_glGetError() != GL_NO_ERROR) return "Can't generate video buffer texture";
642
643 /* Setup video buffer texture. */
644 _glGenTextures(1, &this->anim_texture);
645 _glBindTexture(GL_TEXTURE_2D, this->anim_texture);
646 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
647 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
648 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
649 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
650 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
651 _glBindTexture(GL_TEXTURE_2D, 0);
652 if (_glGetError() != GL_NO_ERROR) return "Can't generate animation buffer texture";
653
654 /* Setup palette texture. */
655 _glGenTextures(1, &this->pal_texture);
656 _glBindTexture(GL_TEXTURE_1D, this->pal_texture);
657 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
658 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
659 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
660 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
661 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
662 _glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, 256, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
663 _glBindTexture(GL_TEXTURE_1D, 0);
664 if (_glGetError() != GL_NO_ERROR) return "Can't generate palette lookup texture";
665
666 /* Bind uniforms in rendering shader program. */
667 GLint tex_location = _glGetUniformLocation(this->vid_program, "colour_tex");
668 GLint palette_location = _glGetUniformLocation(this->vid_program, "palette");
669 GLint sprite_location = _glGetUniformLocation(this->vid_program, "sprite");
670 GLint screen_location = _glGetUniformLocation(this->vid_program, "screen");
671 _glUseProgram(this->vid_program);
672 _glUniform1i(tex_location, 0); // Texture unit 0.
673 _glUniform1i(palette_location, 1); // Texture unit 1.
674 /* Values that result in no transform. */
675 _glUniform4f(sprite_location, 0.0f, 0.0f, 1.0f, 1.0f);
676 _glUniform2f(screen_location, 1.0f, 1.0f);
677
678 /* Bind uniforms in palette rendering shader program. */
679 tex_location = _glGetUniformLocation(this->pal_program, "colour_tex");
680 palette_location = _glGetUniformLocation(this->pal_program, "palette");
681 sprite_location = _glGetUniformLocation(this->pal_program, "sprite");
682 screen_location = _glGetUniformLocation(this->pal_program, "screen");
683 _glUseProgram(this->pal_program);
684 _glUniform1i(tex_location, 0); // Texture unit 0.
685 _glUniform1i(palette_location, 1); // Texture unit 1.
686 _glUniform4f(sprite_location, 0.0f, 0.0f, 1.0f, 1.0f);
687 _glUniform2f(screen_location, 1.0f, 1.0f);
688
689 /* Bind uniforms in remap shader program. */
690 tex_location = _glGetUniformLocation(this->remap_program, "colour_tex");
691 palette_location = _glGetUniformLocation(this->remap_program, "palette");
692 GLint remap_location = _glGetUniformLocation(this->remap_program, "remap_tex");
693 this->remap_sprite_loc = _glGetUniformLocation(this->remap_program, "sprite");
694 this->remap_screen_loc = _glGetUniformLocation(this->remap_program, "screen");
695 this->remap_zoom_loc = _glGetUniformLocation(this->remap_program, "zoom");
696 this->remap_rgb_loc = _glGetUniformLocation(this->remap_program, "rgb");
697 _glUseProgram(this->remap_program);
698 _glUniform1i(tex_location, 0); // Texture unit 0.
699 _glUniform1i(palette_location, 1); // Texture unit 1.
700 _glUniform1i(remap_location, 2); // Texture unit 2.
701
702 /* Bind uniforms in sprite shader program. */
703 tex_location = _glGetUniformLocation(this->sprite_program, "colour_tex");
704 palette_location = _glGetUniformLocation(this->sprite_program, "palette");
705 remap_location = _glGetUniformLocation(this->sprite_program, "remap_tex");
706 GLint pal_location = _glGetUniformLocation(this->sprite_program, "pal");
707 this->sprite_sprite_loc = _glGetUniformLocation(this->sprite_program, "sprite");
708 this->sprite_screen_loc = _glGetUniformLocation(this->sprite_program, "screen");
709 this->sprite_zoom_loc = _glGetUniformLocation(this->sprite_program, "zoom");
710 this->sprite_rgb_loc = _glGetUniformLocation(this->sprite_program, "rgb");
711 this->sprite_crash_loc = _glGetUniformLocation(this->sprite_program, "crash");
712 _glUseProgram(this->sprite_program);
713 _glUniform1i(tex_location, 0); // Texture unit 0.
714 _glUniform1i(palette_location, 1); // Texture unit 1.
715 _glUniform1i(remap_location, 2); // Texture unit 2.
716 _glUniform1i(pal_location, 3); // Texture unit 3.
717 (void)_glGetError(); // Clear errors.
718
719 /* Create pixel buffer object as video buffer storage. */
720 _glGenBuffers(1, &this->vid_pbo);
721 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
722 _glGenBuffers(1, &this->anim_pbo);
723 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
724 if (_glGetError() != GL_NO_ERROR) return "Can't allocate pixel buffer for video buffer";
725
726 /* Prime vertex buffer with a full-screen quad and store
727 * the corresponding state in a vertex array object. */
728 static const Simple2DVertex vert_array[] = {
729 /* x y u v */
730 { 1.f, -1.f, 1.f, 1.f },
731 { 1.f, 1.f, 1.f, 0.f },
732 { -1.f, -1.f, 0.f, 1.f },
733 { -1.f, 1.f, 0.f, 0.f },
734 };
735
736 /* Create VAO. */
737 _glGenVertexArrays(1, &this->vao_quad);
738 _glBindVertexArray(this->vao_quad);
739
740 /* Create and fill VBO. */
741 _glGenBuffers(1, &this->vbo_quad);
742 _glBindBuffer(GL_ARRAY_BUFFER, this->vbo_quad);
743 _glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
744 if (_glGetError() != GL_NO_ERROR) return "Can't generate VBO for fullscreen quad";
745
746 /* Set vertex state. */
747 GLint loc_position = _glGetAttribLocation(this->vid_program, "position");
748 GLint colour_position = _glGetAttribLocation(this->vid_program, "colour_uv");
749 _glEnableVertexAttribArray(loc_position);
750 _glEnableVertexAttribArray(colour_position);
751 _glVertexAttribPointer(loc_position, 2, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, x));
752 _glVertexAttribPointer(colour_position, 2, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, u));
753 _glBindVertexArray(0);
754
755 /* Create resources for sprite rendering. */
756 if (!OpenGLSprite::Create()) return "Failed to create sprite rendering resources";
757
758 this->PrepareContext();
759 (void)_glGetError(); // Clear errors.
760
761 return std::nullopt;
762}
763
764void OpenGLBackend::PrepareContext()
765{
766 _glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
767 _glDisable(GL_DEPTH_TEST);
768 /* Enable alpha blending using the src alpha factor. */
769 _glEnable(GL_BLEND);
770 _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
771}
772
773std::string OpenGLBackend::GetDriverName()
774{
775 auto renderer = GlGetString(GL_RENDERER);
776 auto version = GlGetString(GL_VERSION);
777 /* Skipping GL_VENDOR as it tends to be "obvious" from the renderer and version data, and just makes the string pointlessly longer */
778 return fmt::format("{}, {}", renderer.value_or("Unknown renderer"), version.value_or("Unknown version"));
779}
780
786static bool VerifyShader(GLuint shader)
787{
788 static ReusableBuffer<char> log_buf;
789
790 GLint result = GL_FALSE;
791 _glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
792
793 /* Output log if there is one. */
794 GLint log_len = 0;
795 _glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
796 if (log_len > 0) {
797 _glGetShaderInfoLog(shader, log_len, nullptr, log_buf.Allocate(log_len));
798 Debug(Facility::Driver, result != GL_TRUE ? Severity::Critical : Severity::Warning, "{}", log_buf.GetBuffer()); // Always print on failure.
799 }
800
801 return result == GL_TRUE;
802}
803
809static bool VerifyProgram(GLuint program)
810{
811 static ReusableBuffer<char> log_buf;
812
813 GLint result = GL_FALSE;
814 _glGetProgramiv(program, GL_LINK_STATUS, &result);
815
816 /* Output log if there is one. */
817 GLint log_len = 0;
818 _glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
819 if (log_len > 0) {
820 _glGetProgramInfoLog(program, log_len, nullptr, log_buf.Allocate(log_len));
821 Debug(Facility::Driver, result != GL_TRUE ? Severity::Critical : Severity::Warning, "{}", log_buf.GetBuffer()); // Always print on failure.
822 }
823
824 return result == GL_TRUE;
825}
826
832{
833 auto ver = GlGetString(GL_SHADING_LANGUAGE_VERSION);
834 if (!ver.has_value()) return false;
835
836 auto [glsl_major, glsl_minor] = DecodeVersion(*ver);
837
838 bool glsl_150 = (IsOpenGLVersionAtLeast(3, 2) || glsl_major > 1 || (glsl_major == 1 && glsl_minor >= 5)) && _glBindFragDataLocation != nullptr;
839
840 /* Create vertex shader. */
841 GLuint vert_shader = _glCreateShader(GL_VERTEX_SHADER);
842 _glShaderSource(vert_shader, glsl_150 ? lengthof(_vertex_shader_sprite_150) : lengthof(_vertex_shader_sprite), glsl_150 ? _vertex_shader_sprite_150 : _vertex_shader_sprite, nullptr);
843 _glCompileShader(vert_shader);
844 if (!VerifyShader(vert_shader)) return false;
845
846 /* Create fragment shader for plain RGBA. */
847 GLuint frag_shader_rgb = _glCreateShader(GL_FRAGMENT_SHADER);
848 _glShaderSource(frag_shader_rgb, glsl_150 ? lengthof(_frag_shader_direct_150) : lengthof(_frag_shader_direct), glsl_150 ? _frag_shader_direct_150 : _frag_shader_direct, nullptr);
849 _glCompileShader(frag_shader_rgb);
850 if (!VerifyShader(frag_shader_rgb)) return false;
851
852 /* Create fragment shader for paletted only. */
853 GLuint frag_shader_pal = _glCreateShader(GL_FRAGMENT_SHADER);
854 _glShaderSource(frag_shader_pal, glsl_150 ? lengthof(_frag_shader_palette_150) : lengthof(_frag_shader_palette), glsl_150 ? _frag_shader_palette_150 : _frag_shader_palette, nullptr);
855 _glCompileShader(frag_shader_pal);
856 if (!VerifyShader(frag_shader_pal)) return false;
857
858 /* Sprite remap fragment shader. */
859 GLuint remap_shader = _glCreateShader(GL_FRAGMENT_SHADER);
861 _glCompileShader(remap_shader);
862 if (!VerifyShader(remap_shader)) return false;
863
864 /* Sprite fragment shader. */
865 GLuint sprite_shader = _glCreateShader(GL_FRAGMENT_SHADER);
867 _glCompileShader(sprite_shader);
868 if (!VerifyShader(sprite_shader)) return false;
869
870 /* Link shaders to program. */
871 this->vid_program = _glCreateProgram();
872 _glAttachShader(this->vid_program, vert_shader);
873 _glAttachShader(this->vid_program, frag_shader_rgb);
874
875 this->pal_program = _glCreateProgram();
876 _glAttachShader(this->pal_program, vert_shader);
877 _glAttachShader(this->pal_program, frag_shader_pal);
878
879 this->remap_program = _glCreateProgram();
880 _glAttachShader(this->remap_program, vert_shader);
881 _glAttachShader(this->remap_program, remap_shader);
882
883 this->sprite_program = _glCreateProgram();
884 _glAttachShader(this->sprite_program, vert_shader);
885 _glAttachShader(this->sprite_program, sprite_shader);
886
887 if (glsl_150) {
888 /* Bind fragment shader outputs. */
889 _glBindFragDataLocation(this->vid_program, 0, "colour");
890 _glBindFragDataLocation(this->pal_program, 0, "colour");
891 _glBindFragDataLocation(this->remap_program, 0, "colour");
892 _glBindFragDataLocation(this->sprite_program, 0, "colour");
893 }
894
895 _glLinkProgram(this->vid_program);
896 if (!VerifyProgram(this->vid_program)) return false;
897
898 _glLinkProgram(this->pal_program);
899 if (!VerifyProgram(this->pal_program)) return false;
900
901 _glLinkProgram(this->remap_program);
902 if (!VerifyProgram(this->remap_program)) return false;
903
904 _glLinkProgram(this->sprite_program);
905 if (!VerifyProgram(this->sprite_program)) return false;
906
907 _glDeleteShader(vert_shader);
908 _glDeleteShader(frag_shader_rgb);
909 _glDeleteShader(frag_shader_pal);
910 _glDeleteShader(remap_shader);
911 _glDeleteShader(sprite_shader);
912
913 return true;
914}
915
922template <class T>
923static void ClearPixelBuffer(size_t len, T data)
924{
925 T *buf = reinterpret_cast<T *>(_glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE));
926 for (size_t i = 0; i < len; i++) {
927 *buf++ = data;
928 }
929 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
930}
931
939bool OpenGLBackend::Resize(int w, int h, bool force)
940{
941 if (!force && _screen.width == w && _screen.height == h) return false;
942
944 int pitch = Align(w, 4);
945 size_t line_pixel_count = static_cast<size_t>(pitch) * h;
946
947 _glViewport(0, 0, w, h);
948
949 _glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
950
951 this->vid_buffer = nullptr;
953 _glDeleteBuffers(1, &this->vid_pbo);
954 _glGenBuffers(1, &this->vid_pbo);
955 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
956 _glBufferStorage(GL_PIXEL_UNPACK_BUFFER, line_pixel_count * bpp / 8, nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_CLIENT_STORAGE_BIT);
957 } else {
958 /* Re-allocate video buffer texture and backing store. */
959 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
960 _glBufferData(GL_PIXEL_UNPACK_BUFFER, line_pixel_count * bpp / 8, nullptr, GL_DYNAMIC_DRAW);
961 }
962
963 if (bpp == 32) {
964 /* Initialize backing store alpha to opaque for 32bpp modes. */
965 Colour black(0, 0, 0);
966 if (_glClearBufferSubData != nullptr) {
967 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_RGBA8, 0, line_pixel_count * bpp / 8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &black.data);
968 } else {
969 ClearPixelBuffer<uint32_t>(line_pixel_count, black.data);
970 }
971 } else if (bpp == 8) {
972 if (_glClearBufferSubData != nullptr) {
973 uint8_t b = 0;
974 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_R8, 0, line_pixel_count, GL_RED, GL_UNSIGNED_BYTE, &b);
975 } else {
976 ClearPixelBuffer<uint8_t>(line_pixel_count, 0);
977 }
978 }
979
980 _glActiveTexture(GL_TEXTURE0);
981 _glBindTexture(GL_TEXTURE_2D, this->vid_texture);
982 if (bpp == 8) {
983 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
984 } else {
985 _glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
986 }
987 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
988
989 /* Does this blitter need a separate animation buffer? */
990 if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
991 this->anim_buffer = nullptr;
993 _glDeleteBuffers(1, &this->anim_pbo);
994 _glGenBuffers(1, &this->anim_pbo);
995 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
996 _glBufferStorage(GL_PIXEL_UNPACK_BUFFER, line_pixel_count, nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_CLIENT_STORAGE_BIT);
997 } else {
998 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
999 _glBufferData(GL_PIXEL_UNPACK_BUFFER, line_pixel_count, nullptr, GL_DYNAMIC_DRAW);
1000 }
1001
1002 /* Initialize buffer as 0 == no remap. */
1003 if (_glClearBufferSubData != nullptr) {
1004 uint8_t b = 0;
1005 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_R8, 0, line_pixel_count, GL_RED, GL_UNSIGNED_BYTE, &b);
1006 } else {
1007 ClearPixelBuffer<uint8_t>(line_pixel_count, 0);
1008 }
1009
1010 _glBindTexture(GL_TEXTURE_2D, this->anim_texture);
1011 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
1012 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1013 } else {
1014 if (this->anim_buffer != nullptr) {
1015 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
1016 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1017 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1018 this->anim_buffer = nullptr;
1019 }
1020
1021 /* Allocate dummy texture that always reads as 0 == no remap. */
1022 uint dummy = 0;
1023 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1024 _glBindTexture(GL_TEXTURE_2D, this->anim_texture);
1025 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &dummy);
1026 }
1027
1028 _glBindTexture(GL_TEXTURE_2D, 0);
1029
1030 /* Set new viewport. */
1031 _screen.height = h;
1032 _screen.width = w;
1033 _screen.pitch = pitch;
1034 _screen.dst_ptr = nullptr;
1035
1036 /* Update screen size in remap shader program. */
1037 _glUseProgram(this->remap_program);
1038 _glUniform2f(this->remap_screen_loc, (float)_screen.width, (float)_screen.height);
1039
1040 _glClear(GL_COLOR_BUFFER_BIT);
1041
1042 return true;
1043}
1044
1051void OpenGLBackend::UpdatePalette(const Colour *pal, uint first, uint length)
1052{
1053 assert(first + length <= 256);
1054
1055 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1056 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1057 _glActiveTexture(GL_TEXTURE1);
1058 _glBindTexture(GL_TEXTURE_1D, this->pal_texture);
1059 _glTexSubImage1D(GL_TEXTURE_1D, 0, first, length, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pal + first);
1060}
1061
1066{
1067 _glClear(GL_COLOR_BUFFER_BIT);
1068
1069 _glDisable(GL_BLEND);
1070
1071 /* Blit video buffer to screen. */
1072 _glActiveTexture(GL_TEXTURE0);
1073 _glBindTexture(GL_TEXTURE_2D, this->vid_texture);
1074 _glActiveTexture(GL_TEXTURE1);
1075 _glBindTexture(GL_TEXTURE_1D, this->pal_texture);
1076 /* Is the blitter relying on a separate animation buffer? */
1077 if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
1078 _glActiveTexture(GL_TEXTURE2);
1079 _glBindTexture(GL_TEXTURE_2D, this->anim_texture);
1080 _glUseProgram(this->remap_program);
1081 _glUniform4f(this->remap_sprite_loc, 0.0f, 0.0f, 1.0f, 1.0f);
1082 _glUniform2f(this->remap_screen_loc, 1.0f, 1.0f);
1083 _glUniform1f(this->remap_zoom_loc, 0);
1084 _glUniform1i(this->remap_rgb_loc, 1);
1085 } else {
1086 _glUseProgram(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 8 ? this->pal_program : this->vid_program);
1087 }
1088 _glBindVertexArray(this->vao_quad);
1089 _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1090
1091 _glEnable(GL_BLEND);
1092}
1093
1098{
1099 if (!this->cursor_in_window) return;
1100
1101 /* Draw cursor on screen */
1102 _cur_dpi = &_screen;
1103 for (const auto &cs : this->cursor_sprites) {
1104 /* Sprites are cached by PopulateCursorCache(). */
1105 if (this->cursor_cache.Contains(cs.image.sprite)) {
1106 const OpenGLSprite *spr = this->cursor_cache.Get(cs.image.sprite).get();
1107
1108 this->RenderOglSprite(spr, cs.image.pal,
1109 this->cursor_pos.x + cs.pos.x + UnScaleByZoom(spr->x_offs, _gui_zoom),
1110 this->cursor_pos.y + cs.pos.y + UnScaleByZoom(spr->y_offs, _gui_zoom),
1111 _gui_zoom);
1112 }
1113 }
1114}
1115
1116class OpenGLSpriteAllocator : public SpriteAllocator {
1117public:
1118 OpenGLSpriteLRUCache &lru;
1119 SpriteID sprite;
1120
1121 OpenGLSpriteAllocator(OpenGLSpriteLRUCache &lru, SpriteID sprite) : lru(lru), sprite(sprite) {}
1122protected:
1123 void *AllocatePtr(size_t) override { NOT_REACHED(); }
1124};
1125
1126void OpenGLBackend::PopulateCursorCache()
1127{
1128 if (this->clear_cursor_cache) {
1129 /* We have a pending cursor cache clear to do first. */
1130 this->clear_cursor_cache = false;
1131 this->last_sprite_pal = (PaletteID)-1;
1132
1134 }
1135
1136 this->cursor_pos = _cursor.pos;
1137 this->cursor_in_window = _cursor.in_window;
1138
1139 this->cursor_sprites.clear();
1140 for (const auto &sc : _cursor.sprites) {
1141 this->cursor_sprites.emplace_back(sc);
1142
1143 if (!this->cursor_cache.Contains(sc.image.sprite)) {
1144 OpenGLSpriteAllocator allocator(this->cursor_cache, sc.image.sprite);
1145 GetRawSprite(sc.image.sprite, SpriteType::Normal, &allocator, this);
1146 }
1147 }
1148}
1149
1154{
1155 this->cursor_cache.Clear();
1156}
1157
1162{
1163 /* If the game loop is threaded, this function might be called
1164 * from the game thread. As we can call OpenGL functions only
1165 * on the main thread, just set a flag that is handled the next
1166 * time we prepare the cursor cache for drawing. */
1167 this->clear_cursor_cache = true;
1168}
1169
1175{
1176#ifndef NO_GL_BUFFER_SYNC
1177 if (this->sync_vid_mapping != nullptr) _glClientWaitSync(this->sync_vid_mapping, GL_SYNC_FLUSH_COMMANDS_BIT, 100000000); // 100ms timeout.
1178#endif
1179
1180 if (!this->persistent_mapping_supported) {
1181 assert(this->vid_buffer == nullptr);
1182 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
1183 this->vid_buffer = _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
1184 } else if (this->vid_buffer == nullptr) {
1185 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
1186 this->vid_buffer = _glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, static_cast<GLsizeiptr>(_screen.pitch) * _screen.height * BlitterFactory::GetCurrentBlitter()->GetScreenDepth() / 8, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
1187 }
1188
1189 return this->vid_buffer;
1190}
1191
1197{
1198 if (this->anim_pbo == 0) return nullptr;
1199
1200#ifndef NO_GL_BUFFER_SYNC
1201 if (this->sync_anim_mapping != nullptr) _glClientWaitSync(this->sync_anim_mapping, GL_SYNC_FLUSH_COMMANDS_BIT, 100000000); // 100ms timeout.
1202#endif
1203
1204 if (!this->persistent_mapping_supported) {
1205 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
1206 this->anim_buffer = _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
1207 } else if (this->anim_buffer == nullptr) {
1208 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
1209 this->anim_buffer = _glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, static_cast<GLsizeiptr>(_screen.pitch) * _screen.height, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
1210 }
1211
1212 return (uint8_t *)this->anim_buffer;
1213}
1214
1220{
1221 assert(this->vid_pbo != 0);
1222
1223 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
1224 if (!this->persistent_mapping_supported) {
1225 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1226 this->vid_buffer = nullptr;
1227 }
1228
1229#ifndef NO_GL_BUFFER_SYNC
1230 if (this->persistent_mapping_supported) {
1231 _glDeleteSync(this->sync_vid_mapping);
1232 this->sync_vid_mapping = nullptr;
1233 }
1234#endif
1235
1236 /* Update changed rect of the video buffer texture. */
1237 if (!IsEmptyRect(update_rect)) {
1238 _glActiveTexture(GL_TEXTURE0);
1239 _glBindTexture(GL_TEXTURE_2D, this->vid_texture);
1240 _glPixelStorei(GL_UNPACK_ROW_LENGTH, _screen.pitch);
1241 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 8) {
1242 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)(size_t)(update_rect.top * _screen.pitch + update_rect.left));
1243 } else {
1244 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, (GLvoid*)(size_t)(update_rect.top * _screen.pitch * 4 + update_rect.left * 4));
1245 }
1246
1247#ifndef NO_GL_BUFFER_SYNC
1248 if (this->persistent_mapping_supported) this->sync_vid_mapping = _glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1249#endif
1250 }
1251}
1252
1258{
1259 if (this->anim_pbo == 0) return;
1260
1261 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
1262 if (!this->persistent_mapping_supported) {
1263 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1264 this->anim_buffer = nullptr;
1265 }
1266
1267#ifndef NO_GL_BUFFER_SYNC
1268 if (this->persistent_mapping_supported) {
1269 _glDeleteSync(this->sync_anim_mapping);
1270 this->sync_anim_mapping = nullptr;
1271 }
1272#endif
1273
1274 /* Update changed rect of the video buffer texture. */
1275 if (update_rect.left != update_rect.right) {
1276 _glActiveTexture(GL_TEXTURE0);
1277 _glBindTexture(GL_TEXTURE_2D, this->anim_texture);
1278 _glPixelStorei(GL_UNPACK_ROW_LENGTH, _screen.pitch);
1279 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_RED, GL_UNSIGNED_BYTE, (GLvoid *)(size_t)(update_rect.top * _screen.pitch + update_rect.left));
1280
1281#ifndef NO_GL_BUFFER_SYNC
1282 if (this->persistent_mapping_supported) this->sync_anim_mapping = _glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1283#endif
1284 }
1285}
1286
1287/* virtual */ Sprite *OpenGLBackend::Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
1288{
1289 /* This encoding is only called for mouse cursors. We don't need real sprites but OpenGLSprites to show as cursor. These need to be put in the LRU cache. */
1290 OpenGLSpriteAllocator &gl_allocator = static_cast<OpenGLSpriteAllocator&>(allocator);
1291 gl_allocator.lru.Insert(gl_allocator.sprite, std::make_unique<OpenGLSprite>(sprite_type, sprite));
1292
1293 return nullptr;
1294}
1295
1304void OpenGLBackend::RenderOglSprite(const OpenGLSprite *gl_sprite, PaletteID pal, int x, int y, ZoomLevel zoom)
1305{
1306 /* Set textures. */
1307 bool rgb = gl_sprite->BindTextures();
1308 _glActiveTexture(GL_TEXTURE0 + 1);
1309 _glBindTexture(GL_TEXTURE_1D, this->pal_texture);
1310
1311 /* Set palette remap. */
1312 _glActiveTexture(GL_TEXTURE0 + 3);
1313 if (pal != PAL_NONE) {
1314 _glBindTexture(GL_TEXTURE_1D, OpenGLSprite::pal_tex);
1315 if (pal != this->last_sprite_pal) {
1316 /* Different remap palette in use, update texture. */
1317 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, OpenGLSprite::pal_pbo);
1318 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1319
1320 _glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, 256, GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1);
1321 _glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RED, GL_UNSIGNED_BYTE, nullptr);
1322
1323 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1324
1325 this->last_sprite_pal = pal;
1326 }
1327 } else {
1328 _glBindTexture(GL_TEXTURE_1D, OpenGLSprite::pal_identity);
1329 }
1330
1331 /* Set up shader program. */
1332 Dimension dim = gl_sprite->GetSize(zoom);
1333 _glUseProgram(this->sprite_program);
1334 _glUniform4f(this->sprite_sprite_loc, (float)x, (float)y, (float)dim.width, (float)dim.height);
1335 _glUniform1f(this->sprite_zoom_loc, (float)zoom);
1336 _glUniform2f(this->sprite_screen_loc, (float)_screen.width, (float)_screen.height);
1337 _glUniform1i(this->sprite_rgb_loc, rgb ? 1 : 0);
1338 _glUniform1i(this->sprite_crash_loc, pal == PALETTE_CRASH ? 1 : 0);
1339
1340 _glBindVertexArray(this->vao_quad);
1341 _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1342}
1343
1344
1346/* static */ GLuint OpenGLSprite::pal_identity = 0;
1347/* static */ GLuint OpenGLSprite::pal_tex = 0;
1348/* static */ GLuint OpenGLSprite::pal_pbo = 0;
1349
1354/* static */ bool OpenGLSprite::Create()
1355{
1356 _glGenTextures(static_cast<GLsizei>(OpenGLSprite::dummy_tex.size()), OpenGLSprite::dummy_tex.data());
1357
1359 _glBindTexture(GL_TEXTURE_2D, OpenGLSprite::dummy_tex[t]);
1360
1361 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1362 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1363 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
1364 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1365 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1366 }
1367
1368 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1369 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1370
1371 /* Load dummy RGBA texture. */
1372 const Colour rgb_pixel(0, 0, 0);
1373 _glBindTexture(GL_TEXTURE_2D, OpenGLSprite::dummy_tex[Texture::RGBA]);
1374 _glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &rgb_pixel);
1375
1376 /* Load dummy remap texture. */
1377 const uint pal = 0;
1378 _glBindTexture(GL_TEXTURE_2D, OpenGLSprite::dummy_tex[Texture::Remap]);
1379 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &pal);
1380
1381 /* Create palette remap textures. */
1382 std::array<uint8_t, 256> identity_pal;
1383 std::iota(std::begin(identity_pal), std::end(identity_pal), 0);
1384
1385 /* Permanent texture for identity remap. */
1386 _glGenTextures(1, &OpenGLSprite::pal_identity);
1387 _glBindTexture(GL_TEXTURE_1D, OpenGLSprite::pal_identity);
1388 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1389 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1390 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
1391 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1392 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1393 _glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 256, 0, GL_RED, GL_UNSIGNED_BYTE, identity_pal.data());
1394
1395 /* Dynamically updated texture for remaps. */
1396 _glGenTextures(1, &OpenGLSprite::pal_tex);
1397 _glBindTexture(GL_TEXTURE_1D, OpenGLSprite::pal_tex);
1398 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1399 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1400 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
1401 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1402 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1403 _glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 256, 0, GL_RED, GL_UNSIGNED_BYTE, identity_pal.data());
1404
1405 /* Pixel buffer for remap updates. */
1406 _glGenBuffers(1, &OpenGLSprite::pal_pbo);
1407 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, OpenGLSprite::pal_pbo);
1408 _glBufferData(GL_PIXEL_UNPACK_BUFFER, 256, identity_pal.data(), GL_DYNAMIC_DRAW);
1409 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1410
1411 return _glGetError() == GL_NO_ERROR;
1412}
1413
1415/* static */ void OpenGLSprite::Destroy()
1416{
1417 _glDeleteTextures(static_cast<GLsizei>(OpenGLSprite::dummy_tex.size()), OpenGLSprite::dummy_tex.data());
1418 _glDeleteTextures(1, &OpenGLSprite::pal_identity);
1419 _glDeleteTextures(1, &OpenGLSprite::pal_tex);
1420 if (_glDeleteBuffers != nullptr) _glDeleteBuffers(1, &OpenGLSprite::pal_pbo);
1421}
1422
1429{
1430 const auto &root_sprite = sprite.Root();
1431 this->dim.width = root_sprite.width;
1432 this->dim.height = root_sprite.height;
1433 this->x_offs = root_sprite.x_offs;
1434 this->y_offs = root_sprite.y_offs;
1435
1436 int levels = sprite_type == SpriteType::Font ? 1 : to_underlying(ZoomLevel::End);
1437 assert(levels > 0);
1438 (void)_glGetError();
1439
1440 this->tex = {};
1441 _glActiveTexture(GL_TEXTURE0);
1442 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1443
1445 /* Sprite component present? */
1446 if (t == Texture::RGBA && root_sprite.colours == SpriteComponent::Palette) continue;
1447 if (t == Texture::Remap && !root_sprite.colours.Test(SpriteComponent::Palette)) continue;
1448
1449 /* Allocate texture. */
1450 _glGenTextures(1, &this->tex[t]);
1451 _glBindTexture(GL_TEXTURE_2D, this->tex[t]);
1452
1453 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1454 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1455 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1);
1456 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1457 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1458
1459 /* Set size. */
1460 for (int i = 0, w = this->dim.width, h = this->dim.height; i < levels; i++, w /= 2, h /= 2) {
1461 assert(w * h != 0);
1462 if (t == Texture::Remap) {
1463 _glTexImage2D(GL_TEXTURE_2D, i, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
1464 } else {
1465 _glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
1466 }
1467 }
1468 }
1469
1470 /* Upload texture data. */
1471 for (ZoomLevel zoom = ZoomLevel::Min; zoom <= (sprite_type == SpriteType::Font ? ZoomLevel::Min : ZoomLevel::Max); ++zoom) {
1472 const auto &src_sprite = sprite[zoom];
1473 this->Update(src_sprite.width, src_sprite.height, to_underlying(zoom), src_sprite.data);
1474 }
1475
1476 assert(_glGetError() == GL_NO_ERROR);
1477}
1478
1481{
1482 _glDeleteTextures(static_cast<GLsizei>(this->tex.size()), this->tex.data());
1483}
1484
1492void OpenGLSprite::Update(uint width, uint height, uint level, const SpriteLoader::CommonPixel * data)
1493{
1494 static ReusableBuffer<Colour> buf_rgba;
1495 static ReusableBuffer<uint8_t> buf_pal;
1496
1497 _glActiveTexture(GL_TEXTURE0);
1498 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1499 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1500
1501 if (this->tex[Texture::RGBA] != 0) {
1502 /* Unpack pixel data */
1503 size_t size = static_cast<size_t>(width) * height;
1504 Colour *rgba = buf_rgba.Allocate(size);
1505 for (size_t i = 0; i < size; i++) {
1506 rgba[i].r = data[i].r;
1507 rgba[i].g = data[i].g;
1508 rgba[i].b = data[i].b;
1509 rgba[i].a = data[i].a;
1510 }
1511
1512 _glBindTexture(GL_TEXTURE_2D, this->tex[Texture::RGBA]);
1513 _glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, rgba);
1514 }
1515
1516 if (this->tex[Texture::Remap] != 0) {
1517 /* Unpack and align pixel data. */
1518 size_t pitch = Align(width, 4);
1519
1520 uint8_t *pal = buf_pal.Allocate(pitch * height);
1521 const SpriteLoader::CommonPixel *row = data;
1522 for (uint y = 0; y < height; y++, pal += pitch, row += width) {
1523 for (uint x = 0; x < width; x++) {
1524 pal[x] = row[x].m;
1525 }
1526 }
1527
1528 _glBindTexture(GL_TEXTURE_2D, this->tex[Texture::Remap]);
1529 _glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, buf_pal.GetBuffer());
1530 }
1531
1532 assert(_glGetError() == GL_NO_ERROR);
1533}
1534
1541{
1542 Dimension sd = { (uint)UnScaleByZoomLower(this->dim.width, level), (uint)UnScaleByZoomLower(this->dim.height, level) };
1543 return sd;
1544}
1545
1551{
1552 _glActiveTexture(GL_TEXTURE0);
1553 _glBindTexture(GL_TEXTURE_2D, this->tex[Texture::RGBA] != 0 ? this->tex[Texture::RGBA] : OpenGLSprite::dummy_tex[Texture::RGBA]);
1554 _glActiveTexture(GL_TEXTURE0 + 2);
1555 _glBindTexture(GL_TEXTURE_2D, this->tex[Texture::Remap] != 0 ? this->tex[Texture::Remap] : OpenGLSprite::dummy_tex[Texture::Remap]);
1556
1557 return this->tex[Texture::RGBA] != 0;
1558}
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:139
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
Iterate a range of enum values.
void Insert(const Tkey &key, Tdata &&item)
Insert a new data item with a specified key.
Definition lrucache.hpp:57
Platform-independent back-end class for OpenGL video drivers.
Definition opengl.h:29
GLint sprite_rgb_loc
Uniform location for RGB mode flag.
Definition opengl.h:60
void * anim_buffer
Pointer to the mapped animation buffer.
Definition opengl.h:46
GLuint remap_program
Shader program for blending and rendering a RGBA + remap texture.
Definition opengl.h:50
bool cursor_in_window
Cursor inside this window.
Definition opengl.h:68
void Paint()
Render video buffer to the screen.
Definition opengl.cpp:1065
GLuint pal_program
Shader program for rendering a paletted video buffer.
Definition opengl.h:41
OpenGLSpriteLRUCache cursor_cache
Cache of encoded cursor sprites.
Definition opengl.h:63
std::vector< CursorSprite > cursor_sprites
Sprites comprising cursor.
Definition opengl.h:69
GLint remap_screen_loc
Uniform location for screen size.
Definition opengl.h:52
~OpenGLBackend() override
Free allocated resources.
Definition opengl.cpp:519
static OpenGLBackend * instance
Singleton instance pointer.
Definition opengl.h:31
uint8_t * GetAnimBuffer()
Get a pointer to the memory for the separate animation buffer.
Definition opengl.cpp:1196
void * GetVideoBuffer()
Get a pointer to the memory for the video driver to draw to.
Definition opengl.cpp:1174
bool persistent_mapping_supported
Persistent pixel buffer mapping supported.
Definition opengl.h:33
GLuint vid_texture
Texture handle for the video buffer texture.
Definition opengl.h:39
GLuint vao_quad
Vertex array object storing the rendering state for the fullscreen quad.
Definition opengl.h:42
GLint sprite_zoom_loc
Uniform location for sprite zoom.
Definition opengl.h:59
GLint remap_zoom_loc
Uniform location for sprite zoom.
Definition opengl.h:53
bool Resize(int w, int h, bool force=false)
Change the size of the drawing window and allocate matching resources.
Definition opengl.cpp:939
OpenGLBackend()
Construct OpenGL back-end class.
Definition opengl.cpp:512
static std::optional< std::string_view > Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
Create and initialize the singleton back-end class.
Definition opengl.cpp:490
void * vid_buffer
Pointer to the mapped video buffer.
Definition opengl.h:37
void UpdatePalette(const Colour *pal, uint first, uint length)
Update the stored palette.
Definition opengl.cpp:1051
GLuint anim_texture
Texture handle for the animation buffer texture.
Definition opengl.h:48
void InternalClearCursorCache()
Clear all cached cursor sprites.
Definition opengl.cpp:1153
Sprite * Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override
Convert a sprite from the loader to our own format.
Definition opengl.cpp:1287
GLuint sprite_program
Shader program for blending and rendering a sprite to the video buffer.
Definition opengl.h:56
void ReleaseAnimBuffer(const Rect &update_rect)
Update animation buffer texture after the animation buffer was filled.
Definition opengl.cpp:1257
GLuint vid_pbo
Pixel buffer object storing the memory used for the video driver to draw to.
Definition opengl.h:38
GLsync sync_anim_mapping
Sync object for the persistently mapped animation buffer.
Definition opengl.h:35
GLuint vbo_quad
Vertex buffer with a fullscreen quad.
Definition opengl.h:43
bool clear_cursor_cache
A clear of the cursor cache is pending.
Definition opengl.h:65
GLint remap_rgb_loc
Uniform location for RGB mode flag.
Definition opengl.h:54
void ClearCursorCache()
Queue a request for cursor cache clear.
Definition opengl.cpp:1161
GLuint vid_program
Shader program for rendering a RGBA video buffer.
Definition opengl.h:40
GLuint pal_texture
Palette lookup texture.
Definition opengl.h:44
GLint remap_sprite_loc
Uniform location for sprite parameters.
Definition opengl.h:51
bool InitShaders()
Create all needed shader programs.
Definition opengl.cpp:831
void DrawMouseCursor()
Draw mouse cursor on screen.
Definition opengl.cpp:1097
Point cursor_pos
Cursor position.
Definition opengl.h:67
GLint sprite_crash_loc
Uniform location for crash remap mode flag.
Definition opengl.h:61
void ReleaseVideoBuffer(const Rect &update_rect)
Update video buffer texture after the video buffer was filled.
Definition opengl.cpp:1219
GLint sprite_sprite_loc
Uniform location for sprite parameters.
Definition opengl.h:57
void RenderOglSprite(const OpenGLSprite *gl_sprite, PaletteID pal, int x, int y, ZoomLevel zoom)
Render a sprite to the back buffer.
Definition opengl.cpp:1304
PaletteID last_sprite_pal
Last uploaded remap palette.
Definition opengl.h:64
GLuint anim_pbo
Pixel buffer object storing the memory used for the animation buffer.
Definition opengl.h:47
GLsync sync_vid_mapping
Sync object for the persistently mapped video buffer.
Definition opengl.h:34
std::optional< std::string_view > Init(const Dimension &screen_res)
Check for the needed OpenGL functionality and allocate all resources.
Definition opengl.cpp:556
static void Destroy()
Free resources and destroy singleton back-end class.
Definition opengl.cpp:503
GLint sprite_screen_loc
Uniform location for screen size.
Definition opengl.h:58
void * AllocatePtr(size_t) override
Allocate memory for a sprite.
Definition opengl.cpp:1123
Class that encapsulates a RGBA texture together with a paletted remap texture.
Definition opengl.h:120
bool BindTextures() const
Bind textures for rendering this sprite.
Definition opengl.cpp:1550
static EnumIndexArray< GLuint, Texture, Texture::End > dummy_tex
1x1 dummy textures to substitute for unused sprite components.
Definition opengl.h:1345
OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite)
Create an OpenGL sprite with a palette remap part.
Definition opengl.cpp:1428
Texture
Enum of all used OpenGL texture objects.
Definition opengl.h:123
@ Remap
Remap texture part.
Definition opengl.h:125
@ End
End marker.
Definition opengl.h:126
@ RGBA
RGBA texture part.
Definition opengl.h:124
Dimension GetSize(ZoomLevel level) const
Query the sprite size at a certain zoom level.
Definition opengl.cpp:1540
static bool Create()
Create all common resources for sprite rendering.
Definition opengl.cpp:1354
~OpenGLSprite()
Delete the textures we allocated.
Definition opengl.cpp:1480
static GLuint pal_pbo
Pixel buffer object for remap upload.
Definition opengl.h:138
static GLuint pal_identity
Identity texture mapping.
Definition opengl.h:136
static GLuint pal_tex
Texture for palette remap.
Definition opengl.h:137
int16_t y_offs
Number of pixels to shift the sprite downwards.
Definition opengl.h:132
int16_t x_offs
Number of pixels to shift the sprite to the right.
Definition opengl.h:131
void Update(uint width, uint height, uint level, const SpriteLoader::CommonPixel *data)
Update a single mip-map level with new pixel data.
Definition opengl.cpp:1492
EnumIndexArray< GLuint, Texture, Texture::End > tex
The texture objects.
Definition opengl.h:130
static void Destroy()
Free all common resources for sprite rendering.
Definition opengl.cpp:1415
A reusable buffer that can be used for places that temporary allocate a bit of memory and do that ver...
const T * GetBuffer() const
Get the currently allocated buffer.
T * Allocate(size_t count)
Get buffer of at least count times T.
Interface for something that can allocate memory for a sprite.
SpriteCollMap< Sprite > SpriteCollection
Type defining a collection of sprites, one for each zoom level.
Parse data from a string / buffer.
@ SKIP_ALL_SEPARATORS
Read and discard all consecutive separators, do not include any in the result.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
Read data until the first occurrence of 'str', and advance reader.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
Functions related to debugging.
bool IsVisibleSeverity(Facility facility, Severity severity)
Test if debug severity is visible for the given facility.
Definition debug.h:25
#define Debug(facility, severity, format_string,...)
Output a line of debugging information.
Definition debug.h:37
@ Driver
Driver message facility.
Definition debug_type.h:29
@ Warning
Warning, wrong but okay if you don't know.
Definition debug_type.h:17
@ Notice
Notice.
Definition debug_type.h:18
@ Critical
Critical, user should know about this.
Definition debug_type.h:15
@ Debug2
Debug #2 - Low level debug messages.
Definition debug_type.h:21
@ Trace2
Trace information #2.
Definition debug_type.h:23
@ Error
Error, but we are recovering.
Definition debug_type.h:16
@ Trace3
Trace information #3.
Definition debug_type.h:24
#define T
Climate temperate.
Definition engines.h:91
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Factory to 'query' all available blitters.
Geometry functions.
bool IsEmptyRect(const Rect &r)
Check if a rectangle is empty.
ZoomLevel _gui_zoom
GUI Zoom level.
Definition gfx.cpp:62
Functions related to the gfx engine.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
SpriteType
Types of sprites that might be loaded.
Definition gfx_type.h:404
@ Recolour
Recolour sprite.
Definition gfx_type.h:408
@ Font
A sprite used for fonts.
Definition gfx_type.h:407
@ Normal
The most basic (normal) sprite.
Definition gfx_type.h:405
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
Integer math functions.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition math_func.hpp:37
bool IsOpenGLVersionAtLeast(uint8_t major, uint8_t minor)
Check if the current OpenGL version is equal or higher than a given one.
Definition opengl.cpp:204
static bool BindBasicOpenGLProcs()
Bind OpenGL 1.0 and 1.1 functions.
Definition opengl.cpp:240
static void ClearPixelBuffer(size_t len, T data)
Clear the bound pixel buffer to a specific value.
Definition opengl.cpp:923
static const int MAX_CACHED_CURSORS
Maximum number of cursor sprites to cache.
Definition opengl.cpp:130
static bool IsOpenGLExtensionSupported(std::string_view extension)
Check if an OpenGL extension is supported by the current context.
Definition opengl.cpp:165
static bool BindPersistentBufferExtensions()
Bind extension functions for persistent buffer mapping.
Definition opengl.cpp:405
static bool VerifyProgram(GLuint program)
Check a program for link errors and log them if necessary.
Definition opengl.cpp:809
static uint8_t _gl_major_ver
Major OpenGL version.
Definition opengl.cpp:194
static bool BindGLProc(F &f, const char *name)
Try loading an OpenGL function.
Definition opengl.cpp:217
static bool BindVBAExtension()
Bind vertex array object extension functions.
Definition opengl.cpp:314
void SetupDebugOutput()
Enable OpenGL debug messages if supported.
Definition opengl.cpp:455
static uint8_t _gl_minor_ver
Minor OpenGL version.
Definition opengl.cpp:195
static bool BindShaderExtensions()
Bind extension functions for shader support.
Definition opengl.cpp:336
static bool BindBasicInfoProcs()
Bind basic information functions.
Definition opengl.cpp:227
bool HasStringInExtensionList(std::string_view string, std::string_view substring)
Find a substring in a string made of space delimited elements.
Definition opengl.cpp:150
static bool BindTextureExtensions()
Bind texture-related extension functions.
Definition opengl.cpp:266
static bool VerifyShader(GLuint shader)
Check a shader for compilation errors and log them if necessary.
Definition opengl.cpp:786
void DebugOutputCallback(GLenum, GLenum type, GLuint, GLenum severity, GLsizei, const GLchar *message, const void *)
Callback to receive OpenGL debug messages.
Definition opengl.cpp:431
static bool BindVBOExtension()
Bind vertex buffer object extension functions.
Definition opengl.cpp:281
OpenGL video driver support.
bool IsOpenGLVersionAtLeast(uint8_t major, uint8_t minor)
Check if the current OpenGL version is equal or higher than a given one.
Definition opengl.cpp:204
OpenGL shader programs.
static const char * _vertex_shader_sprite[]
Vertex shader that positions a sprite on screen.
static const char * _frag_shader_palette_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_direct[]
Fragment shader that reads the fragment colour from a 32bpp texture.
static const char * _frag_shader_rgb_mask_blend[]
Fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_palette[]
Fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_rgb_mask_blend_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_direct_150[]
GLSL 1.50 fragment shader that reads the fragment colour from a 32bpp texture.
static const char * _frag_shader_sprite_blend_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from a sprite texture.
static const char * _frag_shader_sprite_blend[]
Fragment shader that performs a palette lookup to read the colour from a sprite texture.
static const char * _vertex_shader_sprite_150[]
GLSL 1.50 vertex shader that positions a sprite on screen.
A number of safeguards to prevent using unsafe methods.
void * GetRawSprite(SpriteID sprite, SpriteType type, SpriteAllocator *allocator, SpriteEncoder *encoder)
Reads a sprite (from disk or sprite cache).
@ Palette
Sprite has palette data.
This file contains all sprite-related enums and defines.
static constexpr uint8_t PALETTE_WIDTH
number of bits of the sprite containing the recolour palette
Definition sprites.h:1721
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1794
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:261
Parse strings.
std::vector< CursorSprite > sprites
Sprites comprising cursor.
Definition gfx_type.h:136
Point pos
logical mouse position
Definition gfx_type.h:125
bool in_window
mouse inside this window, determines drawing logic
Definition gfx_type.h:147
Dimensions (a width and height) of a rectangle in 2D.
Specification of a rectangle with absolute coordinates of all edges.
A simple 2D vertex with just position and texture.
Definition opengl.cpp:124
Definition of a common pixel in OpenTTD's realm.
uint8_t m
Remap-channel.
uint8_t b
Blue-channel.
uint8_t r
Red-channel.
uint8_t g
Green-channel.
uint8_t a
Alpha-channel.
Data structure describing a sprite.
uint16_t width
Width of the sprite.
Functions related to zooming.
int UnScaleByZoomLower(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min).
Definition zoom_func.h:67
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:34
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:20
@ Max
Maximum zoom level.
Definition zoom_type.h:30
@ Min
Minimum zoom level.
Definition zoom_type.h:23
@ End
End for iteration.
Definition zoom_type.h:31