1#include "backend_opengl.h"
2
3#include <base/detect.h>
4#include <base/log.h>
5#include <base/system.h>
6
7#include <engine/client/backend_sdl.h>
8#include <engine/graphics.h>
9
10#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
11
12#include <engine/client/backend/glsl_shader_compiler.h>
13#include <engine/client/backend/opengl/opengl_sl.h>
14#include <engine/client/backend/opengl/opengl_sl_program.h>
15#include <engine/client/blocklist_driver.h>
16#include <engine/gfx/image_manipulation.h>
17
18#ifndef BACKEND_AS_OPENGL_ES
19#include <GL/glew.h>
20#else
21#include <GLES3/gl3.h>
22#define GL_TEXTURE_2D_ARRAY_EXT GL_TEXTURE_2D_ARRAY
23// GLES doesn't support GL_QUADS, but the code is also never executed
24#define GL_QUADS GL_TRIANGLES
25#ifndef CONF_BACKEND_OPENGL_ES3
26#include <GLES/gl.h>
27#define glOrtho glOrthof
28#else
29#define BACKEND_GL_MODERN_API 1
30#endif
31#endif
32
33// ------------ CCommandProcessorFragment_OpenGL
34void CCommandProcessorFragment_OpenGL::Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand)
35{
36 if(pCommand->m_ByResize)
37 {
38 m_CanvasWidth = (uint32_t)pCommand->m_Width;
39 m_CanvasHeight = (uint32_t)pCommand->m_Height;
40 }
41 glViewport(x: pCommand->m_X, y: pCommand->m_Y, width: pCommand->m_Width, height: pCommand->m_Height);
42}
43
44size_t CCommandProcessorFragment_OpenGL::GLFormatToPixelSize(int GLFormat)
45{
46 switch(GLFormat)
47 {
48 case GL_RGBA: return 4;
49 case GL_RGB: return 3;
50 case GL_RED: return 1;
51 case GL_ALPHA: return 1;
52 default: return 4;
53 }
54}
55
56bool CCommandProcessorFragment_OpenGL::IsTexturedState(const CCommandBuffer::SState &State)
57{
58 return State.m_Texture >= 0 && State.m_Texture < (int)m_vTextures.size();
59}
60
61void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State, bool Use2DArrayTextures)
62{
63#ifndef BACKEND_GL_MODERN_API
64 // blend
65 switch(State.m_BlendMode)
66 {
67 case EBlendMode::NONE:
68 glDisable(GL_BLEND);
69 break;
70 case EBlendMode::ALPHA:
71 glEnable(GL_BLEND);
72 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
73 break;
74 case EBlendMode::ADDITIVE:
75 glEnable(GL_BLEND);
76 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
77 break;
78 default:
79 dbg_assert_failed("Invalid blend mode: %d", (int)State.m_BlendMode);
80 };
81 m_LastBlendMode = State.m_BlendMode;
82
83 // clip
84 if(State.m_ClipEnable)
85 {
86 glScissor(x: State.m_ClipX, y: State.m_ClipY, width: State.m_ClipW, height: State.m_ClipH);
87 glEnable(GL_SCISSOR_TEST);
88 m_LastClipEnable = true;
89 }
90 else if(m_LastClipEnable)
91 {
92 // Don't disable it always
93 glDisable(GL_SCISSOR_TEST);
94 m_LastClipEnable = false;
95 }
96
97 glDisable(GL_TEXTURE_2D);
98 if(!m_HasShaders)
99 {
100 if(m_Has3DTextures)
101 glDisable(GL_TEXTURE_3D);
102 if(m_Has2DArrayTextures)
103 {
104 glDisable(cap: m_2DArrayTarget);
105 }
106 }
107
108 if(m_HasShaders && IsNewApi())
109 {
110 glBindSampler(0, 0);
111 }
112
113 // texture
114 if(IsTexturedState(State))
115 {
116 if(!Use2DArrayTextures)
117 {
118 glEnable(GL_TEXTURE_2D);
119 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[State.m_Texture].m_Tex);
120
121 if(m_vTextures[State.m_Texture].m_LastWrapMode != State.m_WrapMode)
122 {
123 switch(State.m_WrapMode)
124 {
125 case EWrapMode::REPEAT:
126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
128 break;
129 case EWrapMode::CLAMP:
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
132 break;
133 default:
134 dbg_assert_failed("Invalid wrap mode: %d", (int)State.m_WrapMode);
135 };
136 m_vTextures[State.m_Texture].m_LastWrapMode = State.m_WrapMode;
137 }
138 }
139 else if(m_Has2DArrayTextures)
140 {
141 if(!m_HasShaders)
142 glEnable(cap: m_2DArrayTarget);
143 glBindTexture(target: m_2DArrayTarget, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
144 }
145 else if(m_Has3DTextures)
146 {
147 if(!m_HasShaders)
148 glEnable(GL_TEXTURE_3D);
149 glBindTexture(GL_TEXTURE_3D, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
150 }
151 else
152 {
153 dbg_assert_failed("Should have either 2D, 3D or no texture array support");
154 }
155 }
156
157 // screen mapping
158 glMatrixMode(GL_PROJECTION);
159 glLoadIdentity();
160 glOrtho(left: State.m_ScreenTL.x, right: State.m_ScreenBR.x, bottom: State.m_ScreenBR.y, top: State.m_ScreenTL.y, zNear: -10.0f, zFar: 10.f);
161#endif
162}
163
164static void ParseVersionString(EBackendType BackendType, const char *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch)
165{
166 if(pStr)
167 {
168 // if backend is GLES, it starts with "OpenGL ES " or OpenGL ES-CM for older contexts, rest is the same
169 if(BackendType == BACKEND_TYPE_OPENGL_ES)
170 {
171 int StrLenGLES = str_length(str: "OpenGL ES ");
172 int StrLenGLESCM = str_length(str: "OpenGL ES-CM ");
173 if(str_comp_num(a: pStr, b: "OpenGL ES ", num: StrLenGLES) == 0)
174 pStr += StrLenGLES;
175 else if(str_comp_num(a: pStr, b: "OpenGL ES-CM ", num: StrLenGLESCM) == 0)
176 pStr += StrLenGLESCM;
177 }
178
179 char aCurNumberStr[32];
180 size_t CurNumberStrLen = 0;
181 size_t TotalNumbersPassed = 0;
182 int aNumbers[3] = {0};
183 bool LastWasNumber = false;
184 while(*pStr && TotalNumbersPassed < 3)
185 {
186 if(str_isnum(c: *pStr))
187 {
188 aCurNumberStr[CurNumberStrLen++] = (char)*pStr;
189 LastWasNumber = true;
190 }
191 else if(LastWasNumber && (*pStr == '.' || *pStr == ' '))
192 {
193 if(CurNumberStrLen > 0)
194 {
195 aCurNumberStr[CurNumberStrLen] = 0;
196 aNumbers[TotalNumbersPassed++] = str_toint(str: aCurNumberStr);
197 CurNumberStrLen = 0;
198 }
199
200 LastWasNumber = false;
201
202 if(*pStr != '.')
203 break;
204 }
205 else
206 {
207 break;
208 }
209
210 ++pStr;
211 }
212
213 VersionMajor = aNumbers[0];
214 VersionMinor = aNumbers[1];
215 VersionPatch = aNumbers[2];
216 }
217}
218
219#ifndef BACKEND_AS_OPENGL_ES
220static LEVEL GetLogSeverity(GLenum Severity)
221{
222 switch(Severity)
223 {
224 case GL_DEBUG_SEVERITY_HIGH: return LEVEL_ERROR;
225 case GL_DEBUG_SEVERITY_MEDIUM: return LEVEL_WARN;
226 case GL_DEBUG_SEVERITY_LOW: return LEVEL_INFO;
227 case GL_DEBUG_SEVERITY_NOTIFICATION: return LEVEL_DEBUG;
228 default: dbg_assert_failed("Severity invalid: %d", (int)Severity);
229 }
230}
231
232static const char *GetErrorName(GLenum Type)
233{
234 switch(Type)
235 {
236 case GL_DEBUG_TYPE_ERROR: return "ERROR";
237 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "DEPRECATED BEHAVIOR";
238 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "UNDEFINED BEHAVIOR";
239 case GL_DEBUG_TYPE_PORTABILITY: return "PORTABILITY";
240 case GL_DEBUG_TYPE_PERFORMANCE: return "PERFORMANCE";
241 case GL_DEBUG_TYPE_OTHER: return "OTHER";
242 case GL_DEBUG_TYPE_MARKER: return "MARKER";
243 case GL_DEBUG_TYPE_PUSH_GROUP: return "PUSH_GROUP";
244 case GL_DEBUG_TYPE_POP_GROUP: return "POP_GROUP";
245 default: return "UNKNOWN";
246 }
247}
248
249static const char *GetSeverityString(GLenum Severity)
250{
251 switch(Severity)
252 {
253 // All OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior
254 case GL_DEBUG_SEVERITY_HIGH: return "high";
255 // Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality
256 case GL_DEBUG_SEVERITY_MEDIUM: return "medium";
257 // Redundant state change performance warning, or unimportant undefined behavior
258 case GL_DEBUG_SEVERITY_LOW: return "low";
259 // Anything that isn't an error or performance issue.
260 case GL_DEBUG_SEVERITY_NOTIFICATION: return "notification";
261 default: dbg_assert_failed("Severity invalid: %d", (int)Severity);
262 }
263}
264
265static void GLAPIENTRY
266GfxOpenGLMessageCallback(GLenum Source,
267 GLenum Type,
268 GLuint Id,
269 GLenum Severity,
270 GLsizei Length,
271 const GLchar *pMsg,
272 const void *pUserParam)
273{
274 log_log(level: GetLogSeverity(Severity), sys: "gfx/opengl", fmt: "[%s] (importance: %s) %s", GetErrorName(Type), GetSeverityString(Severity), pMsg);
275}
276#endif
277
278bool CCommandProcessorFragment_OpenGL::GetPresentedImageData(uint32_t &Width, uint32_t &Height, CImageInfo::EImageFormat &Format, std::vector<uint8_t> &vDstData)
279{
280 if(m_CanvasWidth == 0 || m_CanvasHeight == 0)
281 {
282 return false;
283 }
284 else
285 {
286 Width = m_CanvasWidth;
287 Height = m_CanvasHeight;
288 Format = CImageInfo::FORMAT_RGBA;
289 vDstData.resize(new_size: (size_t)Width * (Height + 1) * 4); // +1 for flipping image
290 glReadBuffer(GL_FRONT);
291 GLint Alignment;
292 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
293 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
294 glReadPixels(x: 0, y: 0, width: m_CanvasWidth, height: m_CanvasHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels: vDstData.data());
295 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
296
297 uint8_t *pTempRow = vDstData.data() + Width * Height * 4;
298 for(uint32_t Y = 0; Y < Height / 2; ++Y)
299 {
300 mem_copy(dest: pTempRow, source: vDstData.data() + Y * Width * 4, size: Width * 4);
301 mem_copy(dest: vDstData.data() + Y * Width * 4, source: vDstData.data() + ((Height - Y) - 1) * Width * 4, size: Width * 4);
302 mem_copy(dest: vDstData.data() + ((Height - Y) - 1) * Width * 4, source: pTempRow, size: Width * 4);
303 }
304
305 return true;
306 }
307}
308
309bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
310{
311 m_IsOpenGLES = pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES;
312
313 *pCommand->m_pReadPresentedImageDataFunc = [this](uint32_t &Width, uint32_t &Height, CImageInfo::EImageFormat &Format, std::vector<uint8_t> &vDstData) {
314 return GetPresentedImageData(Width, Height, Format, vDstData);
315 };
316
317 const char *pVendorString = (const char *)glGetString(GL_VENDOR);
318 log_info("gfx/opengl", "Vendor string: %s", pVendorString);
319
320 // check what this context can do
321 const char *pVersionString = (const char *)glGetString(GL_VERSION);
322 log_info("gfx/opengl", "Version string: %s", pVersionString);
323
324 const char *pRendererString = (const char *)glGetString(GL_RENDERER);
325
326 str_copy(dst: pCommand->m_pVendorString, src: pVendorString, dst_size: GPU_INFO_STRING_SIZE);
327 str_copy(dst: pCommand->m_pVersionString, src: pVersionString, dst_size: GPU_INFO_STRING_SIZE);
328 str_copy(dst: pCommand->m_pRendererString, src: pRendererString, dst_size: GPU_INFO_STRING_SIZE);
329
330 // parse version string
331 ParseVersionString(BackendType: pCommand->m_RequestedBackend, pStr: pVersionString, VersionMajor&: pCommand->m_pCapabilities->m_ContextMajor, VersionMinor&: pCommand->m_pCapabilities->m_ContextMinor, VersionPatch&: pCommand->m_pCapabilities->m_ContextPatch);
332
333 *pCommand->m_pInitError = 0;
334
335 int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1;
336 bool RequiresWarning = false;
337 const char *pErrString = ParseBlocklistDriverVersions(pVendorStr: pVendorString, pVersionStr: pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch, RequiresWarning);
338 // if the driver is buggy, and the requested GL version is the default, fallback
339 if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0)
340 {
341 // if not already in the error state, set the GL version
342 if(g_Config.m_GfxDriverIsBlocked == 0)
343 {
344 // fallback to known good GL version
345 pCommand->m_pCapabilities->m_ContextMajor = BlocklistMajor;
346 pCommand->m_pCapabilities->m_ContextMinor = BlocklistMinor;
347 pCommand->m_pCapabilities->m_ContextPatch = BlocklistPatch;
348
349 // set backend error string
350 if(RequiresWarning)
351 *pCommand->m_pErrStringPtr = pErrString;
352 *pCommand->m_pInitError = -2;
353
354 g_Config.m_GfxDriverIsBlocked = 1;
355 }
356 }
357 // if the driver was in a blocked error state, but is not anymore, reset all config variables
358 else if(pErrString == NULL && g_Config.m_GfxDriverIsBlocked == 1)
359 {
360 pCommand->m_pCapabilities->m_ContextMajor = 3;
361 pCommand->m_pCapabilities->m_ContextMinor = 0;
362 pCommand->m_pCapabilities->m_ContextPatch = 0;
363
364 // tell the caller to reinitialize the context
365 *pCommand->m_pInitError = -2;
366
367 g_Config.m_GfxDriverIsBlocked = 0;
368 }
369
370 int MajorV = pCommand->m_pCapabilities->m_ContextMajor;
371
372 if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL)
373 {
374#ifndef BACKEND_AS_OPENGL_ES
375 int MinorV = pCommand->m_pCapabilities->m_ContextMinor;
376 if(*pCommand->m_pInitError == 0)
377 {
378 if(MajorV < pCommand->m_RequestedMajor)
379 {
380 *pCommand->m_pInitError = -2;
381 }
382 else if(MajorV == pCommand->m_RequestedMajor)
383 {
384 if(MinorV < pCommand->m_RequestedMinor)
385 {
386 *pCommand->m_pInitError = -2;
387 }
388 else if(MinorV == pCommand->m_RequestedMinor)
389 {
390 int PatchV = pCommand->m_pCapabilities->m_ContextPatch;
391 if(PatchV < pCommand->m_RequestedPatch)
392 {
393 *pCommand->m_pInitError = -2;
394 }
395 }
396 }
397 }
398
399 if(*pCommand->m_pInitError == 0)
400 {
401 MajorV = pCommand->m_RequestedMajor;
402 MinorV = pCommand->m_RequestedMinor;
403
404 pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false;
405 pCommand->m_pCapabilities->m_NPOTTextures = true;
406 pCommand->m_pCapabilities->m_TrianglesAsQuads = false;
407
408 if(MajorV >= 4 || (MajorV == 3 && MinorV == 3))
409 {
410 pCommand->m_pCapabilities->m_TileBuffering = true;
411 pCommand->m_pCapabilities->m_QuadBuffering = true;
412 pCommand->m_pCapabilities->m_TextBuffering = true;
413 pCommand->m_pCapabilities->m_QuadContainerBuffering = true;
414 pCommand->m_pCapabilities->m_ShaderSupport = true;
415
416 pCommand->m_pCapabilities->m_MipMapping = true;
417 pCommand->m_pCapabilities->m_3DTextures = true;
418 pCommand->m_pCapabilities->m_2DArrayTextures = true;
419
420 pCommand->m_pCapabilities->m_TrianglesAsQuads = true;
421 }
422 else if(MajorV == 3)
423 {
424 pCommand->m_pCapabilities->m_MipMapping = true;
425 // check for context native 2D array texture size
426 pCommand->m_pCapabilities->m_3DTextures = false;
427 pCommand->m_pCapabilities->m_2DArrayTextures = false;
428 pCommand->m_pCapabilities->m_ShaderSupport = true;
429
430 int TextureLayers = 0;
431 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, params: &TextureLayers);
432 if(TextureLayers >= 256)
433 {
434 pCommand->m_pCapabilities->m_2DArrayTextures = true;
435 }
436
437 int Texture3DSize = 0;
438 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, params: &Texture3DSize);
439 if(Texture3DSize >= 256)
440 {
441 pCommand->m_pCapabilities->m_3DTextures = true;
442 }
443
444 if(!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures)
445 {
446 *pCommand->m_pInitError = -2;
447 pCommand->m_pCapabilities->m_ContextMajor = 1;
448 pCommand->m_pCapabilities->m_ContextMinor = 5;
449 pCommand->m_pCapabilities->m_ContextPatch = 0;
450 }
451
452 pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures;
453 pCommand->m_pCapabilities->m_QuadBuffering = false;
454 pCommand->m_pCapabilities->m_TextBuffering = false;
455 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
456 }
457 else if(MajorV == 2)
458 {
459 pCommand->m_pCapabilities->m_MipMapping = true;
460 // check for context extension: 2D array texture and its max size
461 pCommand->m_pCapabilities->m_3DTextures = false;
462 pCommand->m_pCapabilities->m_2DArrayTextures = false;
463
464 pCommand->m_pCapabilities->m_ShaderSupport = false;
465
466 int Texture3DSize = 0;
467 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, params: &Texture3DSize);
468 if(Texture3DSize >= 256)
469 {
470 pCommand->m_pCapabilities->m_3DTextures = true;
471 }
472
473 pCommand->m_pCapabilities->m_TileBuffering = false;
474 pCommand->m_pCapabilities->m_QuadBuffering = false;
475 pCommand->m_pCapabilities->m_TextBuffering = false;
476 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
477
478 pCommand->m_pCapabilities->m_NPOTTextures = GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2;
479
480 if(!pCommand->m_pCapabilities->m_NPOTTextures || (!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures))
481 {
482 *pCommand->m_pInitError = -2;
483 pCommand->m_pCapabilities->m_ContextMajor = 1;
484 pCommand->m_pCapabilities->m_ContextMinor = 5;
485 pCommand->m_pCapabilities->m_ContextPatch = 0;
486 }
487 }
488 else if(MajorV < 2)
489 {
490 pCommand->m_pCapabilities->m_TileBuffering = false;
491 pCommand->m_pCapabilities->m_QuadBuffering = false;
492 pCommand->m_pCapabilities->m_TextBuffering = false;
493 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
494 pCommand->m_pCapabilities->m_ShaderSupport = false;
495
496 pCommand->m_pCapabilities->m_MipMapping = false;
497 pCommand->m_pCapabilities->m_3DTextures = false;
498 pCommand->m_pCapabilities->m_2DArrayTextures = false;
499 pCommand->m_pCapabilities->m_NPOTTextures = false;
500 }
501 }
502#endif
503 }
504 else if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES)
505 {
506 if(MajorV < 3)
507 {
508 pCommand->m_pCapabilities->m_TileBuffering = false;
509 pCommand->m_pCapabilities->m_QuadBuffering = false;
510 pCommand->m_pCapabilities->m_TextBuffering = false;
511 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
512 pCommand->m_pCapabilities->m_ShaderSupport = false;
513
514 pCommand->m_pCapabilities->m_MipMapping = false;
515 pCommand->m_pCapabilities->m_3DTextures = false;
516 pCommand->m_pCapabilities->m_2DArrayTextures = false;
517 pCommand->m_pCapabilities->m_NPOTTextures = false;
518
519 pCommand->m_pCapabilities->m_TrianglesAsQuads = false;
520 }
521 else
522 {
523 pCommand->m_pCapabilities->m_TileBuffering = true;
524 pCommand->m_pCapabilities->m_QuadBuffering = true;
525 pCommand->m_pCapabilities->m_TextBuffering = true;
526 pCommand->m_pCapabilities->m_QuadContainerBuffering = true;
527 pCommand->m_pCapabilities->m_ShaderSupport = true;
528
529 pCommand->m_pCapabilities->m_MipMapping = true;
530 pCommand->m_pCapabilities->m_3DTextures = true;
531 pCommand->m_pCapabilities->m_2DArrayTextures = true;
532 pCommand->m_pCapabilities->m_NPOTTextures = true;
533
534 pCommand->m_pCapabilities->m_TrianglesAsQuads = true;
535 }
536 }
537
538 if(*pCommand->m_pInitError != -2)
539 {
540 // set some default settings
541 glEnable(GL_BLEND);
542 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
543 glDisable(GL_CULL_FACE);
544 glDisable(GL_DEPTH_TEST);
545
546#ifndef BACKEND_GL_MODERN_API
547 if(!IsNewApi())
548 {
549 glAlphaFunc(GL_GREATER, ref: 0);
550 glEnable(GL_ALPHA_TEST);
551 }
552#endif
553
554 glDepthMask(flag: 0);
555
556#ifndef BACKEND_AS_OPENGL_ES
557 if(g_Config.m_DbgGfx != DEBUG_GFX_MODE_NONE)
558 {
559 if(GLEW_KHR_debug || GLEW_ARB_debug_output)
560 {
561 // During init, enable debug output
562 if(GLEW_KHR_debug)
563 {
564 glEnable(GL_DEBUG_OUTPUT);
565 glDebugMessageCallback((GLDEBUGPROC)GfxOpenGLMessageCallback, 0);
566 }
567 else if(GLEW_ARB_debug_output)
568 {
569 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
570 glDebugMessageCallbackARB((GLDEBUGPROC)GfxOpenGLMessageCallback, 0);
571 }
572 log_info("gfx/opengl", "Enabled OpenGL debug mode");
573 }
574 else
575 {
576 log_warn("gfx/opengl", "Requested OpenGL debug mode, but the driver does not support the required extension");
577 }
578 }
579#endif
580
581 return true;
582 }
583 else
584 return false;
585}
586
587bool CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
588{
589 if(!InitOpenGL(pCommand))
590 return false;
591
592 m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
593 m_pTextureMemoryUsage->store(i: 0, m: std::memory_order_relaxed);
594 m_MaxTexSize = -1;
595
596 m_OpenGLTextureLodBIAS = 0;
597
598 m_Has2DArrayTextures = pCommand->m_pCapabilities->m_2DArrayTextures;
599 if(pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension)
600 {
601 m_Has2DArrayTexturesAsExtension = true;
602 m_2DArrayTarget = GL_TEXTURE_2D_ARRAY_EXT;
603 }
604 else
605 {
606 m_Has2DArrayTexturesAsExtension = false;
607 m_2DArrayTarget = GL_TEXTURE_2D_ARRAY;
608 }
609
610 m_Has3DTextures = pCommand->m_pCapabilities->m_3DTextures;
611 m_HasMipMaps = pCommand->m_pCapabilities->m_MipMapping;
612 m_HasNPOTTextures = pCommand->m_pCapabilities->m_NPOTTextures;
613
614 m_LastBlendMode = EBlendMode::ALPHA;
615 m_LastClipEnable = false;
616
617 return true;
618}
619
620void CCommandProcessorFragment_OpenGL::TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, uint8_t *pTexData)
621{
622 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
623
624 if(!m_HasNPOTTextures)
625 {
626 float ResizeW = m_vTextures[Slot].m_ResizeWidth;
627 float ResizeH = m_vTextures[Slot].m_ResizeHeight;
628 if(ResizeW > 0 && ResizeH > 0)
629 {
630 int ResizedW = (int)(Width * ResizeW);
631 int ResizedH = (int)(Height * ResizeH);
632
633 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: ResizedW, NewHeight: ResizedH, BPP: GLFormatToPixelSize(GLFormat));
634 free(ptr: pTexData);
635 pTexData = pTmpData;
636
637 Width = ResizedW;
638 Height = ResizedH;
639 }
640 }
641
642 if(m_vTextures[Slot].m_RescaleCount > 0)
643 {
644 int OldWidth = Width;
645 int OldHeight = Height;
646 for(int i = 0; i < m_vTextures[Slot].m_RescaleCount; ++i)
647 {
648 Width >>= 1;
649 Height >>= 1;
650
651 X /= 2;
652 Y /= 2;
653 }
654
655 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width: OldWidth, Height: OldHeight, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
656 free(ptr: pTexData);
657 pTexData = pTmpData;
658 }
659
660 glTexSubImage2D(GL_TEXTURE_2D, level: 0, xoffset: X, yoffset: Y, width: Width, height: Height, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
661 free(ptr: pTexData);
662}
663
664void CCommandProcessorFragment_OpenGL::DestroyTexture(int Slot)
665{
666 m_pTextureMemoryUsage->store(i: m_pTextureMemoryUsage->load(m: std::memory_order_relaxed) - m_vTextures[Slot].m_MemSize, m: std::memory_order_relaxed);
667
668 if(m_vTextures[Slot].m_Tex != 0)
669 {
670 glDeleteTextures(n: 1, textures: &m_vTextures[Slot].m_Tex);
671 }
672
673 if(m_vTextures[Slot].m_Tex2DArray != 0)
674 {
675 glDeleteTextures(n: 1, textures: &m_vTextures[Slot].m_Tex2DArray);
676 }
677
678 if(IsNewApi())
679 {
680 if(m_vTextures[Slot].m_Sampler != 0)
681 {
682 glDeleteSamplers(1, &m_vTextures[Slot].m_Sampler);
683 }
684 if(m_vTextures[Slot].m_Sampler2DArray != 0)
685 {
686 glDeleteSamplers(1, &m_vTextures[Slot].m_Sampler2DArray);
687 }
688 }
689
690 m_vTextures[Slot].m_Tex = 0;
691 m_vTextures[Slot].m_Sampler = 0;
692 m_vTextures[Slot].m_Tex2DArray = 0;
693 m_vTextures[Slot].m_Sampler2DArray = 0;
694 m_vTextures[Slot].m_LastWrapMode = EWrapMode::REPEAT;
695}
696
697void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
698{
699 DestroyTexture(Slot: pCommand->m_Slot);
700}
701
702void CCommandProcessorFragment_OpenGL::TextureCreate(int Slot, int Width, int Height, int GLFormat, int GLStoreFormat, int Flags, uint8_t *pTexData)
703{
704#ifndef BACKEND_GL_MODERN_API
705
706 if(m_MaxTexSize == -1)
707 {
708 // fix the alignment to allow even 1byte changes, e.g. for alpha components
709 glPixelStorei(GL_UNPACK_ALIGNMENT, param: 1);
710 glGetIntegerv(GL_MAX_TEXTURE_SIZE, params: &m_MaxTexSize);
711 }
712
713 while(Slot >= (int)m_vTextures.size())
714 m_vTextures.resize(new_size: m_vTextures.size() * 2);
715
716 m_vTextures[Slot].m_ResizeWidth = -1.f;
717 m_vTextures[Slot].m_ResizeHeight = -1.f;
718
719 if(!m_HasNPOTTextures)
720 {
721 int PowerOfTwoWidth = HighestBit(OfVar: Width);
722 int PowerOfTwoHeight = HighestBit(OfVar: Height);
723 if(Width != PowerOfTwoWidth || Height != PowerOfTwoHeight)
724 {
725 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: PowerOfTwoWidth, NewHeight: PowerOfTwoHeight, BPP: GLFormatToPixelSize(GLFormat));
726 free(ptr: pTexData);
727 pTexData = pTmpData;
728
729 m_vTextures[Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width;
730 m_vTextures[Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height;
731
732 Width = PowerOfTwoWidth;
733 Height = PowerOfTwoHeight;
734 }
735 }
736
737 int RescaleCount = 0;
738 if(GLFormat == GL_RGBA)
739 {
740 int OldWidth = Width;
741 int OldHeight = Height;
742 bool NeedsResize = false;
743
744 if(Width > m_MaxTexSize || Height > m_MaxTexSize)
745 {
746 do
747 {
748 Width >>= 1;
749 Height >>= 1;
750 ++RescaleCount;
751 } while(Width > m_MaxTexSize || Height > m_MaxTexSize);
752 NeedsResize = true;
753 }
754
755 if(NeedsResize)
756 {
757 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width: OldWidth, Height: OldHeight, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
758 free(ptr: pTexData);
759 pTexData = pTmpData;
760 }
761 }
762 m_vTextures[Slot].m_Width = Width;
763 m_vTextures[Slot].m_Height = Height;
764 m_vTextures[Slot].m_RescaleCount = RescaleCount;
765
766 const size_t PixelSize = GLFormatToPixelSize(GLFormat);
767
768 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
769 {
770 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex);
771 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
772 }
773
774 if(Flags & TextureFlag::NO_MIPMAPS || !m_HasMipMaps)
775 {
776 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
777 {
778 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
779 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
780 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
781 }
782 }
783 else
784 {
785 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
786 {
787 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
788 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
789 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
790
791#ifndef BACKEND_AS_OPENGL_ES
792 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
793 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, param: ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
794#endif
795
796 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
797 }
798
799 int Flag2DArrayTexture = TextureFlag::TO_2D_ARRAY_TEXTURE;
800 int Flag3DTexture = TextureFlag::TO_3D_TEXTURE;
801 if((Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0)
802 {
803 bool Is3DTexture = (Flags & Flag3DTexture) != 0;
804
805 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex2DArray);
806
807 GLenum Target = GL_TEXTURE_3D;
808
809 if(Is3DTexture)
810 {
811 Target = GL_TEXTURE_3D;
812 }
813 else
814 {
815 Target = m_2DArrayTarget;
816 }
817
818 glBindTexture(target: Target, texture: m_vTextures[Slot].m_Tex2DArray);
819
820 if(IsNewApi())
821 {
822 glGenSamplers(1, &m_vTextures[Slot].m_Sampler2DArray);
823 glBindSampler(0, m_vTextures[Slot].m_Sampler2DArray);
824 }
825
826 glTexParameteri(target: Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
827 if(Is3DTexture)
828 {
829 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
830 if(IsNewApi())
831 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
832 }
833 else
834 {
835 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
836 glTexParameteri(target: Target, GL_GENERATE_MIPMAP, GL_TRUE);
837 if(IsNewApi())
838 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
839 }
840
841 glTexParameteri(target: Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
842 glTexParameteri(target: Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
843 glTexParameteri(target: Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
844
845#ifndef BACKEND_AS_OPENGL_ES
846 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
847 glTexParameterf(target: Target, GL_TEXTURE_LOD_BIAS, param: ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
848#endif
849
850 if(IsNewApi())
851 {
852 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
853 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
854 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
855
856#ifndef BACKEND_AS_OPENGL_ES
857 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
858 glSamplerParameterf(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
859#endif
860
861 glBindSampler(0, 0);
862 }
863
864 uint8_t *pImageData3D = static_cast<uint8_t *>(malloc(size: (size_t)Width * Height * PixelSize));
865 int Image3DWidth, Image3DHeight;
866
867 int ConvertWidth = Width;
868 int ConvertHeight = Height;
869
870 if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0)
871 {
872 int NewWidth = maximum<int>(a: HighestBit(OfVar: ConvertWidth), b: 16);
873 int NewHeight = maximum<int>(a: HighestBit(OfVar: ConvertHeight), b: 16);
874 uint8_t *pNewTexData = ResizeImage(pImageData: pTexData, Width: ConvertWidth, Height: ConvertHeight, NewWidth, NewHeight, BPP: GLFormatToPixelSize(GLFormat));
875 log_debug("gfx/opengl", "3D/2D array texture was resized");
876
877 ConvertWidth = NewWidth;
878 ConvertHeight = NewHeight;
879
880 free(ptr: pTexData);
881 pTexData = pNewTexData;
882 }
883
884 if(Texture2DTo3D(pImageBuffer: pTexData, ImageWidth: ConvertWidth, ImageHeight: ConvertHeight, PixelSize, SplitCountWidth: 16, SplitCountHeight: 16, pTarget3DImageData: pImageData3D, Target3DImageWidth&: Image3DWidth, Target3DImageHeight&: Image3DHeight))
885 {
886 glTexImage3D(Target, 0, GLStoreFormat, Image3DWidth, Image3DHeight, 256, 0, GLFormat, GL_UNSIGNED_BYTE, pImageData3D);
887 }
888
889 free(ptr: pImageData3D);
890 }
891 }
892
893 // This is the initial value for the wrap modes
894 m_vTextures[Slot].m_LastWrapMode = EWrapMode::REPEAT;
895
896 // calculate memory usage
897 m_vTextures[Slot].m_MemSize = (size_t)Width * Height * PixelSize;
898 while(Width > 2 && Height > 2)
899 {
900 Width >>= 1;
901 Height >>= 1;
902 m_vTextures[Slot].m_MemSize += (size_t)Width * Height * PixelSize;
903 }
904 m_pTextureMemoryUsage->store(i: m_pTextureMemoryUsage->load(m: std::memory_order_relaxed) + m_vTextures[Slot].m_MemSize, m: std::memory_order_relaxed);
905
906 free(ptr: pTexData);
907#endif
908}
909
910void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
911{
912 TextureCreate(Slot: pCommand->m_Slot, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_RGBA, GL_RGBA, Flags: pCommand->m_Flags, pTexData: pCommand->m_pData);
913}
914
915void CCommandProcessorFragment_OpenGL::Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand)
916{
917 TextureUpdate(Slot: pCommand->m_Slot, X: pCommand->m_X, Y: pCommand->m_Y, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, pTexData: pCommand->m_pData);
918}
919
920void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand)
921{
922 DestroyTexture(Slot: pCommand->m_Slot);
923 DestroyTexture(Slot: pCommand->m_SlotOutline);
924}
925
926void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand)
927{
928 TextureCreate(Slot: pCommand->m_Slot, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, GL_ALPHA, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextData);
929 TextureCreate(Slot: pCommand->m_SlotOutline, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, GL_ALPHA, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextOutlineData);
930}
931
932void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
933{
934 // if clip is still active, force disable it for clearing, enable it again afterwards
935 bool ClipWasEnabled = m_LastClipEnable;
936 if(ClipWasEnabled)
937 {
938 glDisable(GL_SCISSOR_TEST);
939 }
940 glClearColor(red: pCommand->m_Color.r, green: pCommand->m_Color.g, blue: pCommand->m_Color.b, alpha: 0.0f);
941 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
942 if(ClipWasEnabled)
943 {
944 glEnable(GL_SCISSOR_TEST);
945 }
946}
947
948void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand)
949{
950#ifndef BACKEND_GL_MODERN_API
951 SetState(State: pCommand->m_State);
952
953 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices);
954 glTexCoordPointer(size: 2, GL_FLOAT, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices + sizeof(float) * 2);
955 glColorPointer(size: 4, GL_UNSIGNED_BYTE, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices + sizeof(float) * 4);
956 glEnableClientState(GL_VERTEX_ARRAY);
957 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
958 glEnableClientState(GL_COLOR_ARRAY);
959
960 switch(pCommand->m_PrimType)
961 {
962 case EPrimitiveType::QUADS:
963#ifndef BACKEND_AS_OPENGL_ES
964 glDrawArrays(GL_QUADS, first: 0, count: pCommand->m_PrimCount * 4);
965#endif
966 break;
967 case EPrimitiveType::LINES:
968 glDrawArrays(GL_LINES, first: 0, count: pCommand->m_PrimCount * 2);
969 break;
970 case EPrimitiveType::TRIANGLES:
971 glDrawArrays(GL_TRIANGLES, first: 0, count: pCommand->m_PrimCount * 3);
972 break;
973 default:
974 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
975 };
976#endif
977}
978
979void CCommandProcessorFragment_OpenGL::Cmd_ReadPixel(const CCommandBuffer::SCommand_TrySwapAndReadPixel *pCommand)
980{
981 // get size of viewport
982 GLint aViewport[4] = {0, 0, 0, 0};
983 glGetIntegerv(GL_VIEWPORT, params: aViewport);
984 const int h = aViewport[3];
985
986 // fetch the pixel
987 uint8_t aPixelData[3];
988 GLint Alignment;
989 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
990 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
991 glReadPixels(x: pCommand->m_Position.x, y: h - 1 - pCommand->m_Position.y, width: 1, height: 1, GL_RGB, GL_UNSIGNED_BYTE, pixels: aPixelData);
992 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
993
994 // fill in the information
995 *pCommand->m_pColor = ColorRGBA(aPixelData[0] / 255.0f, aPixelData[1] / 255.0f, aPixelData[2] / 255.0f, 1.0f);
996}
997
998void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_TrySwapAndScreenshot *pCommand)
999{
1000 // fetch image data
1001 GLint aViewport[4] = {0, 0, 0, 0};
1002 glGetIntegerv(GL_VIEWPORT, params: aViewport);
1003
1004 int w = aViewport[2];
1005 int h = aViewport[3];
1006
1007 // we allocate one more row to use when we are flipping the texture
1008 unsigned char *pPixelData = (unsigned char *)malloc(size: (size_t)w * (h + 1) * 4);
1009 unsigned char *pTempRow = pPixelData + w * h * 4;
1010
1011 // fetch the pixels
1012 GLint Alignment;
1013 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
1014 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
1015 glReadPixels(x: 0, y: 0, width: w, height: h, GL_RGBA, GL_UNSIGNED_BYTE, pixels: pPixelData);
1016 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
1017
1018 // flip the pixel because opengl works from bottom left corner
1019 for(int y = 0; y < h / 2; y++)
1020 {
1021 mem_copy(dest: pTempRow, source: pPixelData + y * w * 4, size: w * 4);
1022 mem_copy(dest: pPixelData + y * w * 4, source: pPixelData + (h - y - 1) * w * 4, size: w * 4);
1023 mem_copy(dest: pPixelData + (h - y - 1) * w * 4, source: pTempRow, size: w * 4);
1024 for(int x = 0; x < w; x++)
1025 {
1026 pPixelData[y * w * 4 + x * 4 + 3] = 255;
1027 pPixelData[(h - y - 1) * w * 4 + x * 4 + 3] = 255;
1028 }
1029 }
1030
1031 // fill in the information
1032 pCommand->m_pImage->m_Width = w;
1033 pCommand->m_pImage->m_Height = h;
1034 pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGBA;
1035 pCommand->m_pImage->m_pData = pPixelData;
1036}
1037
1038CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL()
1039{
1040 m_vTextures.resize(new_size: CCommandBuffer::MAX_TEXTURES);
1041 m_HasShaders = false;
1042}
1043
1044ERunCommandReturnTypes CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
1045{
1046 switch(pBaseCommand->m_Cmd)
1047 {
1048 case CCommandProcessorFragment_OpenGL::CMD_INIT:
1049 Cmd_Init(pCommand: static_cast<const SCommand_Init *>(pBaseCommand));
1050 break;
1051 case CCommandProcessorFragment_OpenGL::CMD_SHUTDOWN:
1052 Cmd_Shutdown(pCommand: static_cast<const SCommand_Shutdown *>(pBaseCommand));
1053 break;
1054 case CCommandBuffer::CMD_TEXTURE_CREATE:
1055 Cmd_Texture_Create(pCommand: static_cast<const CCommandBuffer::SCommand_Texture_Create *>(pBaseCommand));
1056 break;
1057 case CCommandBuffer::CMD_TEXTURE_DESTROY:
1058 Cmd_Texture_Destroy(pCommand: static_cast<const CCommandBuffer::SCommand_Texture_Destroy *>(pBaseCommand));
1059 break;
1060 case CCommandBuffer::CMD_TEXT_TEXTURES_CREATE:
1061 Cmd_TextTextures_Create(pCommand: static_cast<const CCommandBuffer::SCommand_TextTextures_Create *>(pBaseCommand));
1062 break;
1063 case CCommandBuffer::CMD_TEXT_TEXTURES_DESTROY:
1064 Cmd_TextTextures_Destroy(pCommand: static_cast<const CCommandBuffer::SCommand_TextTextures_Destroy *>(pBaseCommand));
1065 break;
1066 case CCommandBuffer::CMD_TEXT_TEXTURE_UPDATE:
1067 Cmd_TextTexture_Update(pCommand: static_cast<const CCommandBuffer::SCommand_TextTexture_Update *>(pBaseCommand));
1068 break;
1069 case CCommandBuffer::CMD_CLEAR:
1070 Cmd_Clear(pCommand: static_cast<const CCommandBuffer::SCommand_Clear *>(pBaseCommand));
1071 break;
1072 case CCommandBuffer::CMD_RENDER:
1073 Cmd_Render(pCommand: static_cast<const CCommandBuffer::SCommand_Render *>(pBaseCommand));
1074 break;
1075 case CCommandBuffer::CMD_RENDER_TEX3D:
1076 Cmd_RenderTex3D(pCommand: static_cast<const CCommandBuffer::SCommand_RenderTex3D *>(pBaseCommand));
1077 break;
1078 case CCommandBuffer::CMD_TRY_SWAP_AND_READ_PIXEL:
1079 Cmd_ReadPixel(pCommand: static_cast<const CCommandBuffer::SCommand_TrySwapAndReadPixel *>(pBaseCommand));
1080 break;
1081 case CCommandBuffer::CMD_TRY_SWAP_AND_SCREENSHOT:
1082 Cmd_Screenshot(pCommand: static_cast<const CCommandBuffer::SCommand_TrySwapAndScreenshot *>(pBaseCommand));
1083 break;
1084 case CCommandBuffer::CMD_UPDATE_VIEWPORT:
1085 Cmd_Update_Viewport(pCommand: static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand));
1086 break;
1087
1088 case CCommandBuffer::CMD_CREATE_BUFFER_OBJECT: Cmd_CreateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_CreateBufferObject *>(pBaseCommand)); break;
1089 case CCommandBuffer::CMD_UPDATE_BUFFER_OBJECT: Cmd_UpdateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_UpdateBufferObject *>(pBaseCommand)); break;
1090 case CCommandBuffer::CMD_RECREATE_BUFFER_OBJECT: Cmd_RecreateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_RecreateBufferObject *>(pBaseCommand)); break;
1091 case CCommandBuffer::CMD_COPY_BUFFER_OBJECT: Cmd_CopyBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_CopyBufferObject *>(pBaseCommand)); break;
1092 case CCommandBuffer::CMD_DELETE_BUFFER_OBJECT: Cmd_DeleteBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_DeleteBufferObject *>(pBaseCommand)); break;
1093
1094 case CCommandBuffer::CMD_CREATE_BUFFER_CONTAINER: Cmd_CreateBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_CreateBufferContainer *>(pBaseCommand)); break;
1095 case CCommandBuffer::CMD_UPDATE_BUFFER_CONTAINER: Cmd_UpdateBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_UpdateBufferContainer *>(pBaseCommand)); break;
1096 case CCommandBuffer::CMD_DELETE_BUFFER_CONTAINER: Cmd_DeleteBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_DeleteBufferContainer *>(pBaseCommand)); break;
1097 case CCommandBuffer::CMD_INDICES_REQUIRED_NUM_NOTIFY: Cmd_IndicesRequiredNumNotify(pCommand: static_cast<const CCommandBuffer::SCommand_IndicesRequiredNumNotify *>(pBaseCommand)); break;
1098
1099 case CCommandBuffer::CMD_RENDER_TILE_LAYER: Cmd_RenderTileLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderTileLayer *>(pBaseCommand)); break;
1100 case CCommandBuffer::CMD_RENDER_BORDER_TILE: Cmd_RenderBorderTile(pCommand: static_cast<const CCommandBuffer::SCommand_RenderBorderTile *>(pBaseCommand)); break;
1101 case CCommandBuffer::CMD_RENDER_QUAD_LAYER: Cmd_RenderQuadLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadLayer *>(pBaseCommand), Grouped: false); break;
1102 case CCommandBuffer::CMD_RENDER_QUAD_LAYER_GROUPED: Cmd_RenderQuadLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadLayer *>(pBaseCommand), Grouped: true); break;
1103 case CCommandBuffer::CMD_RENDER_TEXT: Cmd_RenderText(pCommand: static_cast<const CCommandBuffer::SCommand_RenderText *>(pBaseCommand)); break;
1104 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainer *>(pBaseCommand)); break;
1105 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainerEx *>(pBaseCommand)); break;
1106 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *>(pBaseCommand)); break;
1107 default: return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_UNHANDLED;
1108 }
1109
1110 return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_HANDLED;
1111}
1112
1113// ------------ CCommandProcessorFragment_OpenGL2
1114
1115void CCommandProcessorFragment_OpenGL2::UseProgram(CGLSLTWProgram *pProgram)
1116{
1117 pProgram->UseProgram();
1118}
1119
1120void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures)
1121{
1122 if(m_LastBlendMode == EBlendMode::NONE)
1123 {
1124 m_LastBlendMode = EBlendMode::ALPHA;
1125 glEnable(GL_BLEND);
1126 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1127 }
1128 if(State.m_BlendMode != m_LastBlendMode && State.m_BlendMode != EBlendMode::NONE)
1129 {
1130 // blend
1131 switch(State.m_BlendMode)
1132 {
1133 case EBlendMode::NONE:
1134 // We don't really need this anymore
1135 // glDisable(GL_BLEND);
1136 break;
1137 case EBlendMode::ALPHA:
1138 // glEnable(GL_BLEND);
1139 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1140 break;
1141 case EBlendMode::ADDITIVE:
1142 // glEnable(GL_BLEND);
1143 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1144 break;
1145 default:
1146 dbg_assert_failed("Invalid blend mode: %d", (int)State.m_BlendMode);
1147 };
1148
1149 m_LastBlendMode = State.m_BlendMode;
1150 }
1151
1152 // clip
1153 if(State.m_ClipEnable)
1154 {
1155 glScissor(x: State.m_ClipX, y: State.m_ClipY, width: State.m_ClipW, height: State.m_ClipH);
1156 glEnable(GL_SCISSOR_TEST);
1157 m_LastClipEnable = true;
1158 }
1159 else if(m_LastClipEnable)
1160 {
1161 // Don't disable it always
1162 glDisable(GL_SCISSOR_TEST);
1163 m_LastClipEnable = false;
1164 }
1165
1166 if(!IsNewApi())
1167 {
1168 glDisable(GL_TEXTURE_2D);
1169 if(!m_HasShaders)
1170 {
1171 if(m_Has3DTextures)
1172 glDisable(GL_TEXTURE_3D);
1173 if(m_Has2DArrayTextures)
1174 {
1175 glDisable(cap: m_2DArrayTarget);
1176 }
1177 }
1178 }
1179
1180 // texture
1181 if(IsTexturedState(State))
1182 {
1183 int Slot = 0;
1184 if(!Use2DArrayTextures)
1185 {
1186 if(!IsNewApi() && !m_HasShaders)
1187 glEnable(GL_TEXTURE_2D);
1188 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[State.m_Texture].m_Tex);
1189 if(IsNewApi())
1190 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler);
1191 }
1192 else
1193 {
1194 if(!m_Has2DArrayTextures)
1195 {
1196 if(!IsNewApi() && !m_HasShaders)
1197 glEnable(GL_TEXTURE_3D);
1198 glBindTexture(GL_TEXTURE_3D, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
1199 if(IsNewApi())
1200 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler2DArray);
1201 }
1202 else
1203 {
1204 if(!IsNewApi() && !m_HasShaders)
1205 glEnable(cap: m_2DArrayTarget);
1206 glBindTexture(target: m_2DArrayTarget, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
1207 if(IsNewApi())
1208 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler2DArray);
1209 }
1210 }
1211
1212 if(pProgram->m_LastTextureSampler != Slot)
1213 {
1214 pProgram->SetUniform(Loc: pProgram->m_LocTextureSampler, Value: Slot);
1215 pProgram->m_LastTextureSampler = Slot;
1216 }
1217
1218 if(m_vTextures[State.m_Texture].m_LastWrapMode != State.m_WrapMode && !Use2DArrayTextures)
1219 {
1220 switch(State.m_WrapMode)
1221 {
1222 case EWrapMode::REPEAT:
1223 if(IsNewApi())
1224 {
1225 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
1226 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
1227 }
1228 break;
1229 case EWrapMode::CLAMP:
1230 if(IsNewApi())
1231 {
1232 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1233 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1234 }
1235 break;
1236 default:
1237 dbg_assert_failed("Invalid wrap mode: %d", (int)State.m_WrapMode);
1238 };
1239 m_vTextures[State.m_Texture].m_LastWrapMode = State.m_WrapMode;
1240 }
1241 }
1242
1243 if(pProgram->m_LastScreenTL != State.m_ScreenTL || pProgram->m_LastScreenBR != State.m_ScreenBR)
1244 {
1245 pProgram->m_LastScreenTL = State.m_ScreenTL;
1246 pProgram->m_LastScreenBR = State.m_ScreenBR;
1247
1248 // screen mapping
1249 // orthographic projection matrix
1250 // the z coordinate is the same for every vertex, so just ignore the z coordinate and set it in the shaders
1251 float m[2 * 4] = {
1252 2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x),
1253 0,
1254 0,
1255 -((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)),
1256 0,
1257 (2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
1258 0,
1259 -((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
1260 };
1261
1262 // transpose bcs of column-major order of opengl
1263 glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m);
1264 }
1265}
1266
1267#ifndef BACKEND_GL_MODERN_API
1268bool CCommandProcessorFragment_OpenGL2::DoAnalyzeStep(size_t CheckCount, size_t VerticesCount, uint8_t aFakeTexture[], size_t SingleImageSize)
1269{
1270 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1271
1272 int Slot = 0;
1273 if(m_HasShaders)
1274 {
1275 CGLSLTWProgram *pProgram = m_pPrimitive3DProgramTextured;
1276 UseProgram(pProgram);
1277
1278 pProgram->SetUniform(Loc: pProgram->m_LocTextureSampler, Value: Slot);
1279
1280 float m[2 * 4] = {
1281 1, 0, 0, 0,
1282 0, 1, 0, 0};
1283
1284 // transpose bcs of column-major order of opengl
1285 glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m);
1286 }
1287 else
1288 {
1289 glMatrixMode(GL_PROJECTION);
1290 glLoadIdentity();
1291 glOrtho(left: -1, right: 1, bottom: -1, top: 1, zNear: -10.0f, zFar: 10.f);
1292 }
1293
1294 glEnableClientState(GL_VERTEX_ARRAY);
1295 glEnableClientState(GL_COLOR_ARRAY);
1296 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1297
1298 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: m_aStreamVertices);
1299 glColorPointer(size: 4, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2)));
1300 glTexCoordPointer(size: 3, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4)));
1301
1302 glDrawArrays(GL_QUADS, first: 0, count: VerticesCount);
1303
1304 glDisableClientState(GL_VERTEX_ARRAY);
1305 glDisableClientState(GL_COLOR_ARRAY);
1306 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1307
1308 if(m_HasShaders)
1309 {
1310 glUseProgram(0);
1311 }
1312
1313 glFinish();
1314
1315 GLint aViewport[4] = {0, 0, 0, 0};
1316 glGetIntegerv(GL_VIEWPORT, params: aViewport);
1317
1318 int w = aViewport[2];
1319 int h = aViewport[3];
1320
1321 size_t PixelDataSize = (size_t)w * h * 3;
1322 if(PixelDataSize == 0)
1323 return false;
1324 uint8_t *pPixelData = (uint8_t *)malloc(size: PixelDataSize);
1325
1326 // fetch the pixels
1327 GLint Alignment;
1328 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
1329 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
1330 glReadPixels(x: 0, y: 0, width: w, height: h, GL_RGB, GL_UNSIGNED_BYTE, pixels: pPixelData);
1331 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
1332
1333 // now analyse the image data
1334 bool CheckFailed = false;
1335 int WidthTile = w / 16;
1336 int HeightTile = h / 16;
1337 int StartX = WidthTile / 2;
1338 int StartY = HeightTile / 2;
1339 for(size_t d = 0; d < CheckCount; ++d)
1340 {
1341 int CurX = (int)d % 16;
1342 int CurY = (int)d / 16;
1343
1344 int CheckX = StartX + CurX * WidthTile;
1345 int CheckY = StartY + CurY * HeightTile;
1346
1347 ptrdiff_t OffsetPixelData = (CheckY * (w * 3)) + (CheckX * 3);
1348 ptrdiff_t OffsetFakeTexture = SingleImageSize * d;
1349 OffsetPixelData = std::clamp<ptrdiff_t>(val: OffsetPixelData, lo: 0, hi: (ptrdiff_t)PixelDataSize);
1350 OffsetFakeTexture = std::clamp<ptrdiff_t>(val: OffsetFakeTexture, lo: 0, hi: (ptrdiff_t)(SingleImageSize * CheckCount));
1351 uint8_t *pPixel = pPixelData + OffsetPixelData;
1352 uint8_t *pPixelTex = aFakeTexture + OffsetFakeTexture;
1353 for(size_t i = 0; i < 3; ++i)
1354 {
1355 if((pPixel[i] < pPixelTex[i] - 25) || (pPixel[i] > pPixelTex[i] + 25))
1356 {
1357 CheckFailed = true;
1358 break;
1359 }
1360 }
1361 }
1362
1363 free(ptr: pPixelData);
1364 return !CheckFailed;
1365}
1366
1367bool CCommandProcessorFragment_OpenGL2::IsTileMapAnalysisSucceeded()
1368{
1369 glClearColor(red: 0, green: 0, blue: 0, alpha: 1);
1370
1371 // create fake texture 1024x1024
1372 const size_t ImageWidth = 1024;
1373 const size_t ImageHeight = 1024;
1374 uint8_t *pFakeTexture = (uint8_t *)malloc(size: sizeof(uint8_t) * ImageWidth * ImageHeight * 4);
1375 // fill by colors stepping by 50 => (255 / 50 ~ 5) => 5 times 3(color channels) = 5 ^ 3 = 125 possibilities to check
1376 size_t CheckCount = 5 * 5 * 5;
1377 // always fill 4 pixels of the texture, so the sampling is accurate
1378 int aCurColor[4] = {25, 25, 25, 255};
1379 const size_t SingleImageWidth = 64;
1380 const size_t SingleImageHeight = 64;
1381 size_t SingleImageSize = SingleImageWidth * SingleImageHeight * 4;
1382 for(size_t d = 0; d < CheckCount; ++d)
1383 {
1384 uint8_t *pCurFakeTexture = pFakeTexture + (ptrdiff_t)(SingleImageSize * d);
1385
1386 uint8_t aCurColorUint8[SingleImageWidth * SingleImageHeight * 4];
1387 for(size_t y = 0; y < SingleImageHeight; ++y)
1388 {
1389 for(size_t x = 0; x < SingleImageWidth; ++x)
1390 {
1391 for(size_t i = 0; i < 4; ++i)
1392 {
1393 aCurColorUint8[(y * SingleImageWidth * 4) + (x * 4) + i] = (uint8_t)aCurColor[i];
1394 }
1395 }
1396 }
1397 mem_copy(dest: pCurFakeTexture, source: aCurColorUint8, size: sizeof(aCurColorUint8));
1398
1399 aCurColor[2] += 50;
1400 if(aCurColor[2] > 225)
1401 {
1402 aCurColor[2] -= 250;
1403 aCurColor[1] += 50;
1404 }
1405 if(aCurColor[1] > 225)
1406 {
1407 aCurColor[1] -= 250;
1408 aCurColor[0] += 50;
1409 }
1410 if(aCurColor[0] > 225)
1411 {
1412 break;
1413 }
1414 }
1415
1416 // upload the texture
1417 GLuint FakeTexture;
1418 glGenTextures(n: 1, textures: &FakeTexture);
1419
1420 GLenum Target = GL_TEXTURE_3D;
1421 if(m_Has2DArrayTextures)
1422 {
1423 Target = m_2DArrayTarget;
1424 }
1425
1426 glBindTexture(target: Target, texture: FakeTexture);
1427 glTexParameteri(target: Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1428 if(!m_Has2DArrayTextures)
1429 {
1430 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1431 }
1432 else
1433 {
1434 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1435 glTexParameteri(target: Target, GL_GENERATE_MIPMAP, GL_TRUE);
1436 }
1437
1438 glTexParameteri(target: Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1439 glTexParameteri(target: Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1440 glTexParameteri(target: Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
1441
1442 glTexImage3D(Target, 0, GL_RGBA, ImageWidth / 16, ImageHeight / 16, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pFakeTexture);
1443
1444 glEnable(GL_BLEND);
1445 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1446 glDisable(GL_SCISSOR_TEST);
1447
1448 if(!m_HasShaders)
1449 {
1450 glDisable(GL_TEXTURE_2D);
1451 if(m_Has3DTextures)
1452 glDisable(GL_TEXTURE_3D);
1453 if(m_Has2DArrayTextures)
1454 {
1455 glDisable(cap: m_2DArrayTarget);
1456 }
1457
1458 if(!m_Has2DArrayTextures)
1459 {
1460 glEnable(GL_TEXTURE_3D);
1461 glBindTexture(GL_TEXTURE_3D, texture: FakeTexture);
1462 }
1463 else
1464 {
1465 glEnable(cap: m_2DArrayTarget);
1466 glBindTexture(target: m_2DArrayTarget, texture: FakeTexture);
1467 }
1468 }
1469
1470 static_assert(sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0]) >= 256 * 4, "Keep the number of stream vertices >= 256 * 4.");
1471
1472 size_t VertexCount = 0;
1473 for(size_t i = 0; i < CheckCount; ++i)
1474 {
1475 float XPos = (float)(i % 16);
1476 float YPos = (float)(i / 16);
1477
1478 GL_SVertexTex3D *pVertex = &m_aStreamVertices[VertexCount++];
1479 GL_SVertexTex3D *pVertexBefore = pVertex;
1480 pVertex->m_Pos.x = XPos / 16.f;
1481 pVertex->m_Pos.y = YPos / 16.f;
1482 pVertex->m_Color.r = 1;
1483 pVertex->m_Color.g = 1;
1484 pVertex->m_Color.b = 1;
1485 pVertex->m_Color.a = 1;
1486 pVertex->m_Tex.u = 0;
1487 pVertex->m_Tex.v = 0;
1488
1489 pVertex = &m_aStreamVertices[VertexCount++];
1490 pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f;
1491 pVertex->m_Pos.y = YPos / 16.f;
1492 pVertex->m_Color.r = 1;
1493 pVertex->m_Color.g = 1;
1494 pVertex->m_Color.b = 1;
1495 pVertex->m_Color.a = 1;
1496 pVertex->m_Tex.u = 1;
1497 pVertex->m_Tex.v = 0;
1498
1499 pVertex = &m_aStreamVertices[VertexCount++];
1500 pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f;
1501 pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f;
1502 pVertex->m_Color.r = 1;
1503 pVertex->m_Color.g = 1;
1504 pVertex->m_Color.b = 1;
1505 pVertex->m_Color.a = 1;
1506 pVertex->m_Tex.u = 1;
1507 pVertex->m_Tex.v = 1;
1508
1509 pVertex = &m_aStreamVertices[VertexCount++];
1510 pVertex->m_Pos.x = XPos / 16.f;
1511 pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f;
1512 pVertex->m_Color.r = 1;
1513 pVertex->m_Color.g = 1;
1514 pVertex->m_Color.b = 1;
1515 pVertex->m_Color.a = 1;
1516 pVertex->m_Tex.u = 0;
1517 pVertex->m_Tex.v = 1;
1518
1519 for(size_t n = 0; n < 4; ++n)
1520 {
1521 pVertexBefore[n].m_Pos.x *= 2;
1522 pVertexBefore[n].m_Pos.x -= 1;
1523 pVertexBefore[n].m_Pos.y *= 2;
1524 pVertexBefore[n].m_Pos.y -= 1;
1525 if(m_Has2DArrayTextures)
1526 {
1527 pVertexBefore[n].m_Tex.w = i;
1528 }
1529 else
1530 {
1531 pVertexBefore[n].m_Tex.w = (i + 0.5f) / 256.f;
1532 }
1533 }
1534 }
1535
1536 // everything build up, now do the analyze steps
1537 bool NoError = DoAnalyzeStep(CheckCount, VerticesCount: VertexCount, aFakeTexture: pFakeTexture, SingleImageSize);
1538
1539 glDeleteTextures(n: 1, textures: &FakeTexture);
1540 free(ptr: pFakeTexture);
1541
1542 return NoError;
1543}
1544
1545bool CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand)
1546{
1547 if(!CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand))
1548 return false;
1549
1550 m_pTileProgram = nullptr;
1551 m_pTileProgramTextured = nullptr;
1552 m_pPrimitive3DProgram = nullptr;
1553 m_pPrimitive3DProgramTextured = nullptr;
1554
1555 m_OpenGLTextureLodBIAS = g_Config.m_GfxGLTextureLODBIAS;
1556
1557 m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport;
1558
1559 bool HasAllFunc = true;
1560#ifndef BACKEND_AS_OPENGL_ES
1561 if(m_HasShaders)
1562 {
1563 HasAllFunc &= (glUniformMatrix4x2fv != NULL) && (glGenBuffers != NULL);
1564 HasAllFunc &= (glBindBuffer != NULL) && (glBufferData != NULL);
1565 HasAllFunc &= (glEnableVertexAttribArray != NULL) && (glVertexAttribPointer != NULL) && (glVertexAttribIPointer != NULL);
1566 HasAllFunc &= (glDisableVertexAttribArray != NULL) && (glDeleteBuffers != NULL);
1567 HasAllFunc &= (glUseProgram != NULL) && (glTexImage3D != NULL);
1568 HasAllFunc &= (glBindAttribLocation != NULL) && (glTexImage3D != NULL);
1569 HasAllFunc &= (glBufferSubData != NULL) && (glGetUniformLocation != NULL);
1570 HasAllFunc &= (glUniform1i != NULL) && (glUniform1f != NULL);
1571 HasAllFunc &= (glUniform1ui != NULL) && (glUniform1i != NULL);
1572 HasAllFunc &= (glUniform1fv != NULL) && (glUniform2fv != NULL);
1573 HasAllFunc &= (glUniform4fv != NULL) && (glGetAttachedShaders != NULL);
1574 HasAllFunc &= (glGetProgramInfoLog != NULL) && (glGetProgramiv != NULL);
1575 HasAllFunc &= (glLinkProgram != NULL) && (glDetachShader != NULL);
1576 HasAllFunc &= (glAttachShader != NULL) && (glDeleteProgram != NULL);
1577 HasAllFunc &= (glCreateProgram != NULL) && (glShaderSource != NULL);
1578 HasAllFunc &= (glCompileShader != NULL) && (glGetShaderiv != NULL);
1579 HasAllFunc &= (glGetShaderInfoLog != NULL) && (glDeleteShader != NULL);
1580 HasAllFunc &= (glCreateShader != NULL);
1581 }
1582#endif
1583
1584 bool AnalysisCorrect = true;
1585 if(HasAllFunc)
1586 {
1587 if(m_HasShaders)
1588 {
1589 m_pTileProgram = new CGLSLTileProgram;
1590 m_pTileProgramTextured = new CGLSLTileProgram;
1591 m_pBorderTileProgram = new CGLSLTileProgram;
1592 m_pBorderTileProgramTextured = new CGLSLTileProgram;
1593 m_pPrimitive3DProgram = new CGLSLPrimitiveProgram;
1594 m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram;
1595
1596 CGLSLCompiler ShaderCompiler(g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
1597 ShaderCompiler.SetHasTextureArray(pCommand->m_pCapabilities->m_2DArrayTextures);
1598
1599 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1600 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1601 else
1602 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1603 {
1604 CGLSL PrimitiveVertexShader;
1605 CGLSL PrimitiveFragmentShader;
1606 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
1607 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
1608
1609 m_pPrimitive3DProgram->CreateProgram();
1610 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveVertexShader);
1611 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveFragmentShader);
1612 m_pPrimitive3DProgram->LinkProgram();
1613
1614 UseProgram(pProgram: m_pPrimitive3DProgram);
1615
1616 m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc(pName: "gPos");
1617 }
1618
1619 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1620 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1621 else
1622 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1623 {
1624 CGLSL PrimitiveVertexShader;
1625 CGLSL PrimitiveFragmentShader;
1626 ShaderCompiler.AddDefine(pDefineName: "TW_TEXTURED", pDefineValue: "");
1627 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1628 ShaderCompiler.AddDefine(pDefineName: "TW_3D_TEXTURED", pDefineValue: "");
1629 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
1630 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
1631 ShaderCompiler.ClearDefines();
1632
1633 m_pPrimitive3DProgramTextured->CreateProgram();
1634 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveVertexShader);
1635 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveFragmentShader);
1636 m_pPrimitive3DProgramTextured->LinkProgram();
1637
1638 UseProgram(pProgram: m_pPrimitive3DProgramTextured);
1639
1640 m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gPos");
1641 m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1642 }
1643 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1644 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1645 else
1646 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1647 {
1648 CGLSL VertexShader;
1649 CGLSL FragmentShader;
1650 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
1651 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
1652
1653 m_pTileProgram->CreateProgram();
1654 m_pTileProgram->AddShader(pShader: &VertexShader);
1655 m_pTileProgram->AddShader(pShader: &FragmentShader);
1656
1657 glBindAttribLocation(m_pTileProgram->GetProgramId(), 0, "inVertex");
1658
1659 m_pTileProgram->LinkProgram();
1660
1661 UseProgram(pProgram: m_pTileProgram);
1662
1663 m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc(pName: "gPos");
1664 m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc(pName: "gVertColor");
1665 }
1666 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1667 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1668 else
1669 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1670 {
1671 CGLSL VertexShader;
1672 CGLSL FragmentShader;
1673 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
1674 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1675 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_3D_TEXTURED", pDefineValue: "");
1676 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
1677 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
1678 ShaderCompiler.ClearDefines();
1679
1680 m_pTileProgramTextured->CreateProgram();
1681 m_pTileProgramTextured->AddShader(pShader: &VertexShader);
1682 m_pTileProgramTextured->AddShader(pShader: &FragmentShader);
1683
1684 glBindAttribLocation(m_pTileProgram->GetProgramId(), 0, "inVertex");
1685 glBindAttribLocation(m_pTileProgram->GetProgramId(), 1, "inVertexTexCoord");
1686
1687 m_pTileProgramTextured->LinkProgram();
1688
1689 UseProgram(pProgram: m_pTileProgramTextured);
1690
1691 m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc(pName: "gPos");
1692 m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1693 m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc(pName: "gVertColor");
1694 }
1695 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1696 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1697 else
1698 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1699 {
1700 CGLSL VertexShader;
1701 CGLSL FragmentShader;
1702 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
1703 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
1704 ShaderCompiler.ClearDefines();
1705
1706 m_pBorderTileProgram->CreateProgram();
1707 m_pBorderTileProgram->AddShader(pShader: &VertexShader);
1708 m_pBorderTileProgram->AddShader(pShader: &FragmentShader);
1709
1710 glBindAttribLocation(m_pBorderTileProgram->GetProgramId(), 0, "inVertex");
1711
1712 m_pBorderTileProgram->LinkProgram();
1713
1714 UseProgram(pProgram: m_pBorderTileProgram);
1715
1716 m_pBorderTileProgram->m_LocPos = m_pBorderTileProgram->GetUniformLoc(pName: "gPos");
1717 m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc(pName: "gVertColor");
1718 m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc(pName: "gOffset");
1719 m_pBorderTileProgram->m_LocScale = m_pBorderTileProgram->GetUniformLoc(pName: "gScale");
1720 }
1721 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1722 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1723 else
1724 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1725 {
1726 CGLSL VertexShader;
1727 CGLSL FragmentShader;
1728 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
1729 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1730 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_3D_TEXTURED", pDefineValue: "");
1731 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
1732 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
1733 ShaderCompiler.ClearDefines();
1734
1735 m_pBorderTileProgramTextured->CreateProgram();
1736 m_pBorderTileProgramTextured->AddShader(pShader: &VertexShader);
1737 m_pBorderTileProgramTextured->AddShader(pShader: &FragmentShader);
1738
1739 glBindAttribLocation(m_pBorderTileProgramTextured->GetProgramId(), 0, "inVertex");
1740 glBindAttribLocation(m_pBorderTileProgramTextured->GetProgramId(), 1, "inVertexTexCoord");
1741
1742 m_pBorderTileProgramTextured->LinkProgram();
1743
1744 UseProgram(pProgram: m_pBorderTileProgramTextured);
1745
1746 m_pBorderTileProgramTextured->m_LocPos = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gPos");
1747 m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1748 m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gVertColor");
1749 m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gOffset");
1750 m_pBorderTileProgramTextured->m_LocScale = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gScale");
1751 }
1752
1753 glUseProgram(0);
1754 }
1755
1756 if(g_Config.m_Gfx3DTextureAnalysisRan == 0 || str_comp(a: g_Config.m_Gfx3DTextureAnalysisRenderer, b: pCommand->m_pRendererString) != 0 || str_comp(a: g_Config.m_Gfx3DTextureAnalysisVersion, b: pCommand->m_pVersionString) != 0)
1757 {
1758 AnalysisCorrect = IsTileMapAnalysisSucceeded();
1759 if(AnalysisCorrect)
1760 {
1761 g_Config.m_Gfx3DTextureAnalysisRan = 1;
1762 str_copy(dst&: g_Config.m_Gfx3DTextureAnalysisRenderer, src: pCommand->m_pRendererString);
1763 str_copy(dst&: g_Config.m_Gfx3DTextureAnalysisVersion, src: pCommand->m_pVersionString);
1764 }
1765 }
1766 }
1767
1768 if(!AnalysisCorrect || !HasAllFunc)
1769 {
1770 // downgrade to opengl 1.5
1771 *pCommand->m_pInitError = -2;
1772 pCommand->m_pCapabilities->m_ContextMajor = 1;
1773 pCommand->m_pCapabilities->m_ContextMinor = 5;
1774 pCommand->m_pCapabilities->m_ContextPatch = 0;
1775
1776 return false;
1777 }
1778
1779 return true;
1780}
1781
1782void CCommandProcessorFragment_OpenGL2::Cmd_Shutdown(const SCommand_Shutdown *pCommand)
1783{
1784 // TODO: cleanup the OpenGL context too
1785 delete m_pTileProgram;
1786 delete m_pTileProgramTextured;
1787 delete m_pPrimitive3DProgram;
1788 delete m_pPrimitive3DProgramTextured;
1789 for(auto &BufferObject : m_vBufferObjectIndices)
1790 free(ptr: BufferObject.m_pData);
1791}
1792
1793void CCommandProcessorFragment_OpenGL2::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand)
1794{
1795 if(m_HasShaders)
1796 {
1797 CGLSLPrimitiveProgram *pProgram = NULL;
1798 if(IsTexturedState(State: pCommand->m_State))
1799 {
1800 pProgram = m_pPrimitive3DProgramTextured;
1801 }
1802 else
1803 pProgram = m_pPrimitive3DProgram;
1804
1805 UseProgram(pProgram);
1806
1807 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
1808 }
1809 else
1810 {
1811 CCommandProcessorFragment_OpenGL::SetState(State: pCommand->m_State, Use2DArrayTextures: true);
1812 }
1813
1814 glEnableClientState(GL_VERTEX_ARRAY);
1815 glEnableClientState(GL_COLOR_ARRAY);
1816 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1817
1818 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(pCommand->m_pVertices[0]), pointer: pCommand->m_pVertices);
1819 glColorPointer(size: 4, GL_UNSIGNED_BYTE, stride: sizeof(pCommand->m_pVertices[0]), pointer: (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2)));
1820 glTexCoordPointer(size: 3, GL_FLOAT, stride: sizeof(pCommand->m_pVertices[0]), pointer: (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(unsigned char) * 4));
1821
1822 switch(pCommand->m_PrimType)
1823 {
1824 case EPrimitiveType::QUADS:
1825 glDrawArrays(GL_QUADS, first: 0, count: pCommand->m_PrimCount * 4);
1826 break;
1827 case EPrimitiveType::TRIANGLES:
1828 glDrawArrays(GL_TRIANGLES, first: 0, count: pCommand->m_PrimCount * 3);
1829 break;
1830 default:
1831 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
1832 };
1833
1834 glDisableClientState(GL_VERTEX_ARRAY);
1835 glDisableClientState(GL_COLOR_ARRAY);
1836 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1837
1838 if(m_HasShaders)
1839 {
1840 glUseProgram(0);
1841 }
1842}
1843
1844void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand)
1845{
1846 void *pUploadData = pCommand->m_pUploadData;
1847 const int Index = pCommand->m_BufferIndex;
1848 // create necessary space
1849 if((size_t)Index >= m_vBufferObjectIndices.size())
1850 {
1851 m_vBufferObjectIndices.resize(new_size: Index + 1, x: 0);
1852 }
1853
1854 GLuint VertBufferId = 0;
1855
1856 glGenBuffers(1, &VertBufferId);
1857 glBindBuffer(GL_ARRAY_BUFFER, VertBufferId);
1858 glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
1859 glBindBuffer(GL_ARRAY_BUFFER, 0);
1860
1861 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1862 BufferObject.m_BufferObjectId = VertBufferId;
1863 BufferObject.m_DataSize = pCommand->m_DataSize;
1864 BufferObject.m_pData = static_cast<uint8_t *>(malloc(size: pCommand->m_DataSize));
1865 if(pUploadData)
1866 mem_copy(dest: BufferObject.m_pData, source: pUploadData, size: pCommand->m_DataSize);
1867
1868 if(pCommand->m_DeletePointer)
1869 free(ptr: pUploadData);
1870}
1871
1872void CCommandProcessorFragment_OpenGL2::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand)
1873{
1874 void *pUploadData = pCommand->m_pUploadData;
1875 int Index = pCommand->m_BufferIndex;
1876 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1877
1878 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
1879 glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
1880 glBindBuffer(GL_ARRAY_BUFFER, 0);
1881
1882 BufferObject.m_DataSize = pCommand->m_DataSize;
1883 free(ptr: BufferObject.m_pData);
1884 BufferObject.m_pData = static_cast<uint8_t *>(malloc(size: pCommand->m_DataSize));
1885 if(pUploadData)
1886 mem_copy(dest: BufferObject.m_pData, source: pUploadData, size: pCommand->m_DataSize);
1887
1888 if(pCommand->m_DeletePointer)
1889 free(ptr: pUploadData);
1890}
1891
1892void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand)
1893{
1894 void *pUploadData = pCommand->m_pUploadData;
1895 int Index = pCommand->m_BufferIndex;
1896 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1897
1898 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
1899 glBufferSubData(GL_ARRAY_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData);
1900 glBindBuffer(GL_ARRAY_BUFFER, 0);
1901
1902 if(pUploadData)
1903 mem_copy(dest: BufferObject.m_pData + (ptrdiff_t)pCommand->m_pOffset, source: pUploadData, size: pCommand->m_DataSize);
1904
1905 if(pCommand->m_DeletePointer)
1906 free(ptr: pUploadData);
1907}
1908
1909void CCommandProcessorFragment_OpenGL2::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand)
1910{
1911 int WriteIndex = pCommand->m_WriteBufferIndex;
1912 int ReadIndex = pCommand->m_ReadBufferIndex;
1913
1914 SBufferObject &ReadBufferObject = m_vBufferObjectIndices[ReadIndex];
1915 SBufferObject &WriteBufferObject = m_vBufferObjectIndices[WriteIndex];
1916
1917 mem_copy(dest: WriteBufferObject.m_pData + (ptrdiff_t)pCommand->m_WriteOffset, source: ReadBufferObject.m_pData + (ptrdiff_t)pCommand->m_ReadOffset, size: pCommand->m_CopySize);
1918
1919 glBindBuffer(GL_ARRAY_BUFFER, WriteBufferObject.m_BufferObjectId);
1920 glBufferSubData(GL_ARRAY_BUFFER, (GLintptr)(pCommand->m_WriteOffset), (GLsizeiptr)(pCommand->m_CopySize), WriteBufferObject.m_pData + (ptrdiff_t)pCommand->m_WriteOffset);
1921 glBindBuffer(GL_ARRAY_BUFFER, 0);
1922}
1923
1924void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand)
1925{
1926 int Index = pCommand->m_BufferIndex;
1927 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1928
1929 glDeleteBuffers(1, &BufferObject.m_BufferObjectId);
1930
1931 free(ptr: BufferObject.m_pData);
1932 BufferObject.m_pData = NULL;
1933}
1934
1935void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand)
1936{
1937 const int Index = pCommand->m_BufferContainerIndex;
1938 // create necessary space
1939 if((size_t)Index >= m_vBufferContainers.size())
1940 {
1941 SBufferContainer Container;
1942 Container.m_ContainerInfo.m_Stride = 0;
1943 Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
1944 m_vBufferContainers.resize(new_size: Index + 1, x: Container);
1945 }
1946
1947 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1948
1949 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
1950 {
1951 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: pCommand->m_pAttributes[i]);
1952 }
1953
1954 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
1955 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
1956}
1957
1958void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand)
1959{
1960 SBufferContainer &BufferContainer = m_vBufferContainers[pCommand->m_BufferContainerIndex];
1961
1962 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
1963
1964 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
1965 {
1966 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: pCommand->m_pAttributes[i]);
1967 }
1968
1969 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
1970 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
1971}
1972
1973void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand)
1974{
1975 SBufferContainer &BufferContainer = m_vBufferContainers[pCommand->m_BufferContainerIndex];
1976
1977 if(pCommand->m_DestroyAllBO)
1978 {
1979 int VertBufferId = BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex;
1980 if(VertBufferId != -1)
1981 {
1982 glDeleteBuffers(1, &m_vBufferObjectIndices[VertBufferId].m_BufferObjectId);
1983
1984 free(ptr: m_vBufferObjectIndices[VertBufferId].m_pData);
1985 m_vBufferObjectIndices[VertBufferId].m_pData = NULL;
1986 }
1987 }
1988
1989 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
1990}
1991
1992void CCommandProcessorFragment_OpenGL2::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand)
1993{
1994}
1995
1996void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand)
1997{
1998 int Index = pCommand->m_BufferContainerIndex;
1999 // if space not there return
2000 if((size_t)Index >= m_vBufferContainers.size())
2001 return;
2002
2003 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
2004
2005 CGLSLTileProgram *pProgram = NULL;
2006 if(IsTexturedState(State: pCommand->m_State))
2007 pProgram = m_pBorderTileProgramTextured;
2008 else
2009 pProgram = m_pBorderTileProgram;
2010 UseProgram(pProgram);
2011
2012 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
2013 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
2014
2015 pProgram->SetUniformVec2(Loc: pProgram->m_LocOffset, Count: 1, pValue: (float *)&pCommand->m_Offset);
2016 pProgram->SetUniformVec2(Loc: pProgram->m_LocScale, Count: 1, pValue: (float *)&pCommand->m_Scale);
2017
2018 bool IsTextured = BufferContainer.m_ContainerInfo.m_vAttributes.size() == 2;
2019
2020 SBufferObject &BufferObject = m_vBufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
2021
2022 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
2023
2024 glEnableVertexAttribArray(0);
2025 glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[0].m_pOffset);
2026 if(IsTextured)
2027 {
2028 glEnableVertexAttribArray(1);
2029 glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[1].m_pOffset);
2030 }
2031
2032 size_t RealDrawCount = pCommand->m_DrawNum * 4;
2033 GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffset)) / (6 * sizeof(unsigned int))) * 4);
2034 glDrawArrays(GL_QUADS, first: RealOffset, count: RealDrawCount);
2035
2036 glDisableVertexAttribArray(0);
2037 if(IsTextured)
2038 glDisableVertexAttribArray(1);
2039 glBindBuffer(GL_ARRAY_BUFFER, 0);
2040 glUseProgram(0);
2041}
2042
2043void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand)
2044{
2045 int Index = pCommand->m_BufferContainerIndex;
2046 // if space not there return
2047 if((size_t)Index >= m_vBufferContainers.size())
2048 return;
2049
2050 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
2051
2052 if(pCommand->m_IndicesDrawNum == 0)
2053 {
2054 return; // nothing to draw
2055 }
2056
2057 CGLSLTileProgram *pProgram = NULL;
2058 if(IsTexturedState(State: pCommand->m_State))
2059 {
2060 pProgram = m_pTileProgramTextured;
2061 }
2062 else
2063 pProgram = m_pTileProgram;
2064
2065 UseProgram(pProgram);
2066
2067 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
2068 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
2069
2070 bool IsTextured = BufferContainer.m_ContainerInfo.m_vAttributes.size() == 2;
2071
2072 SBufferObject &BufferObject = m_vBufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
2073
2074 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
2075
2076 glEnableVertexAttribArray(0);
2077 glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[0].m_pOffset);
2078 if(IsTextured)
2079 {
2080 glEnableVertexAttribArray(1);
2081 glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[1].m_pOffset);
2082 }
2083
2084 for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i)
2085 {
2086 size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4;
2087 GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4);
2088 glDrawArrays(GL_QUADS, first: RealOffset, count: RealDrawCount);
2089 }
2090
2091 glDisableVertexAttribArray(0);
2092 if(IsTextured)
2093 glDisableVertexAttribArray(1);
2094 glBindBuffer(GL_ARRAY_BUFFER, 0);
2095 glUseProgram(0);
2096}
2097
2098#undef BACKEND_GL_MODERN_API
2099
2100#endif
2101
2102#endif
2103