1#ifndef ENGINE_CLIENT_GRAPHICS_THREADED_H
2#define ENGINE_CLIENT_GRAPHICS_THREADED_H
3
4#include <base/dbg.h>
5#include <base/sphore.h>
6
7#include <engine/graphics.h>
8#include <engine/shared/config.h>
9
10#include <atomic>
11#include <cstddef>
12#include <mutex>
13#include <string>
14#include <vector>
15
16constexpr int CMD_BUFFER_DATA_BUFFER_SIZE = 1024 * 1024 * 2;
17constexpr int CMD_BUFFER_CMD_BUFFER_SIZE = 1024 * 256;
18
19namespace TextureFlag
20{
21 inline constexpr uint32_t NO_MIPMAPS = 1 << 0;
22 inline constexpr uint32_t TO_3D_TEXTURE = 1 << 1;
23 inline constexpr uint32_t TO_2D_ARRAY_TEXTURE = 1 << 2;
24 inline constexpr uint32_t NO_2D_TEXTURE = 1 << 3;
25};
26
27enum class EPrimitiveType
28{
29 LINES,
30 QUADS,
31 TRIANGLES,
32};
33
34enum class EBlendMode
35{
36 NONE,
37 ALPHA,
38 ADDITIVE,
39};
40
41enum class EWrapMode
42{
43 REPEAT,
44 CLAMP,
45};
46
47class CCommandBuffer
48{
49 class CBuffer
50 {
51 unsigned char *m_pData;
52 unsigned m_Size;
53 unsigned m_Used;
54
55 public:
56 CBuffer(unsigned BufferSize)
57 {
58 m_Size = BufferSize;
59 m_pData = new unsigned char[m_Size];
60 m_Used = 0;
61 }
62
63 ~CBuffer()
64 {
65 delete[] m_pData;
66 m_pData = nullptr;
67 m_Used = 0;
68 m_Size = 0;
69 }
70
71 void Reset()
72 {
73 m_Used = 0;
74 }
75
76 void *Alloc(unsigned Requested, unsigned Alignment = alignof(std::max_align_t))
77 {
78 size_t Offset = reinterpret_cast<uintptr_t>(m_pData + m_Used) % Alignment;
79 if(Offset)
80 Offset = Alignment - Offset;
81
82 if(Requested + Offset + m_Used > m_Size)
83 return nullptr;
84
85 void *pPtr = &m_pData[m_Used + Offset];
86 m_Used += Requested + Offset;
87 return pPtr;
88 }
89
90 unsigned char *DataPtr() { return m_pData; }
91 unsigned DataSize() const { return m_Size; }
92 unsigned DataUsed() const { return m_Used; }
93 };
94
95public:
96 CBuffer m_CmdBuffer;
97 size_t m_CommandCount = 0;
98 size_t m_RenderCallCount = 0;
99
100 CBuffer m_DataBuffer;
101
102 enum
103 {
104 MAX_TEXTURES = 1024 * 8,
105 MAX_VERTICES = 32 * 1024,
106 };
107
108 enum
109 {
110 // command groups
111 CMDGROUP_CORE = 0, // commands that everyone has to implement
112 CMDGROUP_PLATFORM_GL = 10000, // commands specific to a platform
113 CMDGROUP_PLATFORM_SDL = 20000,
114
115 CMD_FIRST = CMDGROUP_CORE,
116 };
117
118 enum ECommandBufferCMD
119 {
120 // synchronization
121 CMD_SIGNAL = CMD_FIRST,
122
123 // texture commands
124 CMD_TEXTURE_CREATE,
125 CMD_TEXTURE_DESTROY,
126 CMD_TEXT_TEXTURES_CREATE,
127 CMD_TEXT_TEXTURES_DESTROY,
128 CMD_TEXT_TEXTURE_UPDATE,
129
130 // rendering
131 CMD_CLEAR,
132 CMD_RENDER,
133 CMD_RENDER_TEX3D,
134
135 // opengl 2.0+ commands (some are just emulated and only exist in opengl 3.3+)
136 CMD_CREATE_BUFFER_OBJECT, // create vbo
137 CMD_RECREATE_BUFFER_OBJECT, // recreate vbo
138 CMD_UPDATE_BUFFER_OBJECT, // update vbo
139 CMD_COPY_BUFFER_OBJECT, // copy vbo to another
140 CMD_DELETE_BUFFER_OBJECT, // delete vbo
141
142 CMD_CREATE_BUFFER_CONTAINER, // create vao
143 CMD_DELETE_BUFFER_CONTAINER, // delete vao
144 CMD_UPDATE_BUFFER_CONTAINER, // update vao
145
146 CMD_INDICES_REQUIRED_NUM_NOTIFY, // create indices that are required
147
148 CMD_RENDER_TILE_LAYER, // render a tilelayer
149 CMD_RENDER_BORDER_TILE, // render one tile multiple times
150 CMD_RENDER_QUAD_LAYER, // render a quad layer
151 CMD_RENDER_QUAD_LAYER_GROUPED, // render a quad layer in groups meaning they all share the same envelope and offset (which can be none)
152 CMD_RENDER_TEXT, // render text
153 CMD_RENDER_QUAD_CONTAINER, // render a quad buffer container
154 CMD_RENDER_QUAD_CONTAINER_EX, // render a quad buffer container with extended parameters
155 CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE, // render a quad buffer container as sprite multiple times
156
157 // swap
158 CMD_SWAP,
159
160 // misc
161 CMD_MULTISAMPLING,
162 CMD_VSYNC,
163 CMD_TRY_SWAP_AND_READ_PIXEL,
164 CMD_TRY_SWAP_AND_SCREENSHOT,
165 CMD_UPDATE_VIEWPORT,
166
167 // in Android a window that minimizes gets destroyed
168 CMD_WINDOW_CREATE_NTF,
169 CMD_WINDOW_DESTROY_NTF,
170
171 CMD_COUNT,
172 };
173
174 typedef vec2 SPoint;
175 typedef vec2 STexCoord;
176 typedef GL_SColorf SColorf;
177 typedef GL_SColor SColor;
178 typedef GL_SVertex SVertex;
179 typedef GL_SVertexTex3D SVertexTex3D;
180 typedef GL_SVertexTex3DStream SVertexTex3DStream;
181
182 struct SCommand
183 {
184 public:
185 SCommand(unsigned Cmd) :
186 m_Cmd(Cmd), m_pNext(nullptr) {}
187 unsigned m_Cmd;
188 SCommand *m_pNext;
189 };
190
191 struct SState
192 {
193 EBlendMode m_BlendMode;
194 EWrapMode m_WrapMode;
195 int m_Texture;
196 SPoint m_ScreenTL;
197 SPoint m_ScreenBR;
198
199 // clip
200 bool m_ClipEnable;
201 int m_ClipX;
202 int m_ClipY;
203 int m_ClipW;
204 int m_ClipH;
205 };
206
207 struct SCommand_Clear : public SCommand
208 {
209 SCommand_Clear() :
210 SCommand(CMD_CLEAR) {}
211 SColorf m_Color;
212 bool m_ForceClear;
213 };
214
215 struct SCommand_Signal : public SCommand
216 {
217 SCommand_Signal() :
218 SCommand(CMD_SIGNAL) {}
219 CSemaphore *m_pSemaphore;
220 };
221
222 struct SCommand_Render : public SCommand
223 {
224 SCommand_Render() :
225 SCommand(CMD_RENDER) {}
226 SState m_State;
227 EPrimitiveType m_PrimType;
228 unsigned m_PrimCount;
229 SVertex *m_pVertices; // you should use the command buffer data to allocate vertices for this command
230 };
231
232 struct SCommand_RenderTex3D : public SCommand
233 {
234 SCommand_RenderTex3D() :
235 SCommand(CMD_RENDER_TEX3D) {}
236 SState m_State;
237 EPrimitiveType m_PrimType;
238 unsigned m_PrimCount;
239 SVertexTex3DStream *m_pVertices; // you should use the command buffer data to allocate vertices for this command
240 };
241
242 struct SCommand_CreateBufferObject : public SCommand
243 {
244 SCommand_CreateBufferObject() :
245 SCommand(CMD_CREATE_BUFFER_OBJECT) {}
246
247 int m_BufferIndex;
248
249 bool m_DeletePointer;
250 void *m_pUploadData;
251 size_t m_DataSize;
252
253 int m_Flags; // @see EBufferObjectCreateFlags
254 };
255
256 struct SCommand_RecreateBufferObject : public SCommand
257 {
258 SCommand_RecreateBufferObject() :
259 SCommand(CMD_RECREATE_BUFFER_OBJECT) {}
260
261 int m_BufferIndex;
262
263 bool m_DeletePointer;
264 void *m_pUploadData;
265 size_t m_DataSize;
266
267 int m_Flags; // @see EBufferObjectCreateFlags
268 };
269
270 struct SCommand_UpdateBufferObject : public SCommand
271 {
272 SCommand_UpdateBufferObject() :
273 SCommand(CMD_UPDATE_BUFFER_OBJECT) {}
274
275 int m_BufferIndex;
276
277 bool m_DeletePointer;
278 void *m_pOffset;
279 void *m_pUploadData;
280 size_t m_DataSize;
281 };
282
283 struct SCommand_CopyBufferObject : public SCommand
284 {
285 SCommand_CopyBufferObject() :
286 SCommand(CMD_COPY_BUFFER_OBJECT) {}
287
288 int m_WriteBufferIndex;
289 int m_ReadBufferIndex;
290
291 size_t m_ReadOffset;
292 size_t m_WriteOffset;
293 size_t m_CopySize;
294 };
295
296 struct SCommand_DeleteBufferObject : public SCommand
297 {
298 SCommand_DeleteBufferObject() :
299 SCommand(CMD_DELETE_BUFFER_OBJECT) {}
300
301 int m_BufferIndex;
302 };
303
304 struct SCommand_CreateBufferContainer : public SCommand
305 {
306 SCommand_CreateBufferContainer() :
307 SCommand(CMD_CREATE_BUFFER_CONTAINER) {}
308
309 int m_BufferContainerIndex;
310
311 int m_Stride;
312 int m_VertBufferBindingIndex;
313
314 size_t m_AttrCount;
315 SBufferContainerInfo::SAttribute *m_pAttributes;
316 };
317
318 struct SCommand_UpdateBufferContainer : public SCommand
319 {
320 SCommand_UpdateBufferContainer() :
321 SCommand(CMD_UPDATE_BUFFER_CONTAINER) {}
322
323 int m_BufferContainerIndex;
324
325 int m_Stride;
326 int m_VertBufferBindingIndex;
327
328 size_t m_AttrCount;
329 SBufferContainerInfo::SAttribute *m_pAttributes;
330 };
331
332 struct SCommand_DeleteBufferContainer : public SCommand
333 {
334 SCommand_DeleteBufferContainer() :
335 SCommand(CMD_DELETE_BUFFER_CONTAINER) {}
336
337 int m_BufferContainerIndex;
338 bool m_DestroyAllBO;
339 };
340
341 struct SCommand_IndicesRequiredNumNotify : public SCommand
342 {
343 SCommand_IndicesRequiredNumNotify() :
344 SCommand(CMD_INDICES_REQUIRED_NUM_NOTIFY) {}
345
346 unsigned int m_RequiredIndicesNum;
347 };
348
349 struct SCommand_RenderTileLayer : public SCommand
350 {
351 SCommand_RenderTileLayer() :
352 SCommand(CMD_RENDER_TILE_LAYER) {}
353 SState m_State;
354 SColorf m_Color; // the color of the whole tilelayer -- already enveloped
355
356 // the char offset of all indices that should be rendered, and the amount of renders
357 char **m_pIndicesOffsets;
358 unsigned int *m_pDrawCount;
359
360 int m_IndicesDrawNum;
361 int m_BufferContainerIndex;
362 };
363
364 struct SCommand_RenderBorderTile : public SCommand
365 {
366 SCommand_RenderBorderTile() :
367 SCommand(CMD_RENDER_BORDER_TILE) {}
368 SState m_State;
369 SColorf m_Color; // the color of the whole tilelayer -- already enveloped
370 char *m_pIndicesOffset;
371 uint32_t m_DrawNum;
372 int m_BufferContainerIndex;
373
374 vec2 m_Offset;
375 vec2 m_Scale;
376 };
377
378 struct SCommand_RenderQuadLayer : public SCommand
379 {
380 SCommand_RenderQuadLayer(bool Grouped) :
381 SCommand(Grouped ? CMD_RENDER_QUAD_LAYER_GROUPED : CMD_RENDER_QUAD_LAYER) {}
382 SState m_State;
383
384 int m_BufferContainerIndex;
385 SQuadRenderInfo *m_pQuadInfo;
386 size_t m_QuadNum;
387 int m_QuadOffset;
388 };
389
390 struct SCommand_RenderText : public SCommand
391 {
392 SCommand_RenderText() :
393 SCommand(CMD_RENDER_TEXT) {}
394 SState m_State;
395
396 int m_BufferContainerIndex;
397 int m_TextureSize;
398
399 int m_TextTextureIndex;
400 int m_TextOutlineTextureIndex;
401
402 int m_DrawNum;
403 ColorRGBA m_TextColor;
404 ColorRGBA m_TextOutlineColor;
405 };
406
407 struct SCommand_RenderQuadContainer : public SCommand
408 {
409 SCommand_RenderQuadContainer() :
410 SCommand(CMD_RENDER_QUAD_CONTAINER) {}
411 SState m_State;
412
413 int m_BufferContainerIndex;
414
415 unsigned int m_DrawNum;
416 void *m_pOffset;
417 };
418
419 struct SCommand_RenderQuadContainerEx : public SCommand
420 {
421 SCommand_RenderQuadContainerEx() :
422 SCommand(CMD_RENDER_QUAD_CONTAINER_EX) {}
423 SState m_State;
424
425 int m_BufferContainerIndex;
426
427 float m_Rotation;
428 SPoint m_Center;
429
430 SColorf m_VertexColor;
431
432 unsigned int m_DrawNum;
433 void *m_pOffset;
434 };
435
436 struct SCommand_RenderQuadContainerAsSpriteMultiple : public SCommand
437 {
438 SCommand_RenderQuadContainerAsSpriteMultiple() :
439 SCommand(CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE) {}
440 SState m_State;
441
442 int m_BufferContainerIndex;
443
444 IGraphics::SRenderSpriteInfo *m_pRenderInfo;
445
446 SPoint m_Center;
447 SColorf m_VertexColor;
448
449 unsigned int m_DrawNum;
450 unsigned int m_DrawCount;
451 void *m_pOffset;
452 };
453
454 struct SCommand_TrySwapAndReadPixel : public SCommand
455 {
456 SCommand_TrySwapAndReadPixel() :
457 SCommand(CMD_TRY_SWAP_AND_READ_PIXEL) {}
458 ivec2 m_Position;
459 SColorf *m_pColor; // processor will fill this out
460 bool *m_pSwapped; // processor may set this to true, must be initialized to false by the caller
461 };
462
463 struct SCommand_TrySwapAndScreenshot : public SCommand
464 {
465 SCommand_TrySwapAndScreenshot() :
466 SCommand(CMD_TRY_SWAP_AND_SCREENSHOT) {}
467 CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well
468 bool *m_pSwapped; // processor may set this to true, must be initialized to false by the caller
469 };
470
471 struct SCommand_Swap : public SCommand
472 {
473 SCommand_Swap() :
474 SCommand(CMD_SWAP) {}
475 };
476
477 struct SCommand_VSync : public SCommand
478 {
479 SCommand_VSync() :
480 SCommand(CMD_VSYNC) {}
481
482 int m_VSync;
483 bool *m_pRetOk;
484 };
485
486 struct SCommand_MultiSampling : public SCommand
487 {
488 SCommand_MultiSampling() :
489 SCommand(CMD_MULTISAMPLING) {}
490
491 uint32_t m_RequestedMultiSamplingCount;
492 uint32_t *m_pRetMultiSamplingCount;
493 bool *m_pRetOk;
494 };
495
496 struct SCommand_Update_Viewport : public SCommand
497 {
498 SCommand_Update_Viewport() :
499 SCommand(CMD_UPDATE_VIEWPORT) {}
500
501 int m_X;
502 int m_Y;
503 int m_Width;
504 int m_Height;
505 bool m_ByResize; // resized by an resize event.. a hint to make clear that the viewport update can be deferred if wanted
506 };
507
508 struct SCommand_Texture_Create : public SCommand
509 {
510 SCommand_Texture_Create() :
511 SCommand(CMD_TEXTURE_CREATE) {}
512
513 // texture information
514 int m_Slot;
515
516 size_t m_Width;
517 size_t m_Height;
518 int m_Flags;
519 // data must be in RGBA format
520 uint8_t *m_pData; // will be freed by the command processor
521 };
522
523 struct SCommand_Texture_Destroy : public SCommand
524 {
525 SCommand_Texture_Destroy() :
526 SCommand(CMD_TEXTURE_DESTROY) {}
527
528 // texture information
529 int m_Slot;
530 };
531
532 struct SCommand_TextTextures_Create : public SCommand
533 {
534 SCommand_TextTextures_Create() :
535 SCommand(CMD_TEXT_TEXTURES_CREATE) {}
536
537 // texture information
538 int m_Slot;
539 int m_SlotOutline;
540
541 size_t m_Width;
542 size_t m_Height;
543
544 uint8_t *m_pTextData; // will be freed by the command processor
545 uint8_t *m_pTextOutlineData; // will be freed by the command processor
546 };
547
548 struct SCommand_TextTextures_Destroy : public SCommand
549 {
550 SCommand_TextTextures_Destroy() :
551 SCommand(CMD_TEXT_TEXTURES_DESTROY) {}
552
553 // texture information
554 int m_Slot;
555 int m_SlotOutline;
556 };
557
558 struct SCommand_TextTexture_Update : public SCommand
559 {
560 SCommand_TextTexture_Update() :
561 SCommand(CMD_TEXT_TEXTURE_UPDATE) {}
562
563 // texture information
564 int m_Slot;
565
566 int m_X;
567 int m_Y;
568 size_t m_Width;
569 size_t m_Height;
570 uint8_t *m_pData; // will be freed by the command processor
571 };
572
573 struct SCommand_WindowCreateNtf : public CCommandBuffer::SCommand
574 {
575 SCommand_WindowCreateNtf() :
576 SCommand(CMD_WINDOW_CREATE_NTF) {}
577
578 uint32_t m_WindowId;
579 };
580
581 struct SCommand_WindowDestroyNtf : public CCommandBuffer::SCommand
582 {
583 SCommand_WindowDestroyNtf() :
584 SCommand(CMD_WINDOW_DESTROY_NTF) {}
585
586 uint32_t m_WindowId;
587 };
588
589 //
590 CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) :
591 m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize), m_pCmdBufferHead(nullptr), m_pCmdBufferTail(nullptr)
592 {
593 }
594
595 void *AllocData(unsigned WantedSize)
596 {
597 return m_DataBuffer.Alloc(Requested: WantedSize);
598 }
599
600 template<class T>
601 bool AddCommandUnsafe(const T &Command)
602 {
603 // make sure that we don't do something stupid like ->AddCommand(&Cmd);
604 (void)static_cast<const SCommand *>(&Command);
605
606 // allocate and copy the command into the buffer
607 T *pCmd = (T *)m_CmdBuffer.Alloc(Requested: sizeof(*pCmd), Alignment: alignof(T));
608 if(!pCmd)
609 return false;
610 *pCmd = Command;
611 pCmd->m_pNext = nullptr;
612
613 if(m_pCmdBufferTail)
614 m_pCmdBufferTail->m_pNext = pCmd;
615 if(!m_pCmdBufferHead)
616 m_pCmdBufferHead = pCmd;
617 m_pCmdBufferTail = pCmd;
618
619 ++m_CommandCount;
620
621 return true;
622 }
623
624 const SCommand *Head() const { return m_pCmdBufferHead; }
625 SCommand *Head() { return m_pCmdBufferHead; }
626
627 void Reset()
628 {
629 m_pCmdBufferHead = m_pCmdBufferTail = nullptr;
630 m_CmdBuffer.Reset();
631 m_DataBuffer.Reset();
632
633 m_CommandCount = 0;
634 m_RenderCallCount = 0;
635 }
636
637 void AddRenderCalls(size_t RenderCallCountToAdd)
638 {
639 m_RenderCallCount += RenderCallCountToAdd;
640 }
641
642private:
643 SCommand *m_pCmdBufferHead;
644 SCommand *m_pCmdBufferTail;
645};
646
647enum EGraphicsBackendErrorCodes
648{
649 GRAPHICS_BACKEND_ERROR_CODE_NONE = 0,
650 GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED,
651 GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED,
652 GRAPHICS_BACKEND_ERROR_CODE_GLEW_INIT_FAILED,
653 GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED,
654 GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED,
655 GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED,
656 GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED,
657 GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED,
658};
659
660// interface for the graphics backend
661// all these functions are called on the main thread
662class IGraphicsBackend
663{
664public:
665 enum
666 {
667 INITFLAG_FULLSCREEN = 1 << 0,
668 INITFLAG_VSYNC = 1 << 1,
669 INITFLAG_RESIZABLE = 1 << 2,
670 INITFLAG_BORDERLESS = 1 << 3,
671 INITFLAG_DESKTOP_FULLSCREEN = 1 << 4,
672 };
673
674 virtual ~IGraphicsBackend() = default;
675
676 virtual int Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int *pFsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage) = 0;
677 virtual int Shutdown() = 0;
678
679 virtual uint64_t TextureMemoryUsage() const = 0;
680 virtual uint64_t BufferMemoryUsage() const = 0;
681 virtual uint64_t StreamedMemoryUsage() const = 0;
682 virtual uint64_t StagingMemoryUsage() const = 0;
683
684 virtual const TTwGraphicsGpuList &GetGpus() const = 0;
685
686 virtual void GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, float HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0;
687 virtual void GetCurrentVideoMode(CVideoMode &CurMode, float HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0;
688
689 virtual int GetNumScreens() const = 0;
690 virtual const char *GetScreenName(int Screen) const = 0;
691
692 virtual void Minimize() = 0;
693 virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
694 virtual bool SetWindowScreen(int Index, bool MoveToCenter) = 0;
695 virtual bool UpdateDisplayMode(int Index) = 0;
696 virtual int GetWindowScreen() = 0;
697 virtual int WindowActive() = 0;
698 virtual int WindowOpen() = 0;
699 virtual void SetWindowGrab(bool Grab) = 0;
700 // returns true, if the video mode changed
701 virtual bool ResizeWindow(int w, int h, int RefreshRate) = 0;
702 virtual void GetViewportSize(int &w, int &h) = 0;
703 virtual void NotifyWindow() = 0;
704 virtual bool IsScreenKeyboardShown() = 0;
705
706 virtual void WindowDestroyNtf(uint32_t WindowId) = 0;
707 virtual void WindowCreateNtf(uint32_t WindowId) = 0;
708
709 virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
710 virtual void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer) = 0;
711 virtual bool IsIdle() const = 0;
712 virtual void WaitForIdle() = 0;
713
714 virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0;
715 // checks if the current values of the config are a graphics modern API
716 virtual bool IsConfigModernAPI() { return false; }
717 virtual bool UseTrianglesAsQuad() { return false; }
718 virtual bool HasTileBuffering() { return false; }
719 virtual bool HasQuadBuffering() { return false; }
720 virtual bool HasTextBuffering() { return false; }
721 virtual bool HasQuadContainerBuffering() { return false; }
722 virtual bool Uses2DTextureArrays() { return false; }
723 virtual bool HasTextureArraysSupport() { return false; }
724 virtual const char *GetErrorString() { return nullptr; }
725
726 virtual const char *GetVendorString() = 0;
727 virtual const char *GetVersionString() = 0;
728 virtual const char *GetRendererString() = 0;
729
730 // be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing
731 virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0;
732
733 virtual const char *GetFatalError() const = 0;
734 virtual bool GetWarning(std::vector<std::string> &WarningStrings) = 0;
735
736 /**
737 * @see IGraphics::ShowMessageBox
738 */
739 virtual std::optional<int> ShowMessageBox(const IGraphics::CMessageBox &MessageBox) = 0;
740};
741
742class CGraphics_Threaded : public IEngineGraphics
743{
744 enum class EDrawing
745 {
746 NONE,
747 QUADS,
748 LINES,
749 TRIANGLES,
750 };
751
752 CCommandBuffer::SState m_State;
753 IGraphicsBackend *m_pBackend;
754 bool m_GLTileBufferingEnabled;
755 bool m_GLQuadBufferingEnabled;
756 bool m_GLTextBufferingEnabled;
757 bool m_GLQuadContainerBufferingEnabled;
758 bool m_GLUses2DTextureArrays;
759 bool m_GLHasTextureArraysSupport;
760 bool m_GLUseTrianglesAsQuad;
761
762 CCommandBuffer *m_apCommandBuffers[2];
763 CCommandBuffer *m_pCommandBuffer;
764 unsigned m_CurrentCommandBuffer;
765
766 //
767 class IStorage *m_pStorage;
768 class IEngine *m_pEngine;
769
770 int m_CurIndex;
771
772 CCommandBuffer::SVertex m_aVertices[CCommandBuffer::MAX_VERTICES];
773 CCommandBuffer::SVertexTex3DStream m_aVerticesTex3D[CCommandBuffer::MAX_VERTICES];
774 int m_NumVertices;
775
776 CCommandBuffer::SColor m_aColor[4];
777 CCommandBuffer::STexCoord m_aTexture[4];
778
779 bool m_RenderEnable;
780
781 float m_Rotation;
782 EDrawing m_Drawing;
783 bool m_DoScreenshot;
784 char m_aScreenshotName[IO_MAX_PATH_LENGTH];
785
786 CTextureHandle m_NullTexture;
787
788 std::vector<int> m_vTextureIndices;
789 size_t m_FirstFreeTexture;
790 int m_TextureMemoryUsage;
791
792 std::atomic<bool> m_WarnPngliteIncompatibleImages = false;
793
794 std::mutex m_WarningsMutex;
795 std::vector<SWarning> m_vWarnings;
796
797 // is a non full windowed (in a sense that the viewport won't include the whole window),
798 // forced viewport, so that it justifies our UI ratio needs
799 bool m_IsForcedViewport = false;
800
801 struct SVertexArrayInfo
802 {
803 SVertexArrayInfo() :
804 m_FreeIndex(-1) {}
805 // keep a reference to it, so we can free the ID
806 int m_AssociatedBufferObjectIndex;
807
808 int m_FreeIndex;
809 };
810 std::vector<SVertexArrayInfo> m_vVertexArrayInfo;
811 int m_FirstFreeVertexArrayInfo;
812
813 std::vector<int> m_vBufferObjectIndices;
814 int m_FirstFreeBufferObjectIndex;
815
816 struct SQuadContainer
817 {
818 SQuadContainer(bool AutomaticUpload = true)
819 {
820 m_vQuads.clear();
821 m_QuadBufferObjectIndex = m_QuadBufferContainerIndex = -1;
822 m_FreeIndex = -1;
823
824 m_AutomaticUpload = AutomaticUpload;
825 }
826
827 struct SQuad
828 {
829 CCommandBuffer::SVertex m_aVertices[4];
830 };
831
832 std::vector<SQuad> m_vQuads;
833
834 int m_QuadBufferObjectIndex;
835 int m_QuadBufferContainerIndex;
836
837 int m_FreeIndex;
838
839 bool m_AutomaticUpload;
840 };
841 std::vector<SQuadContainer> m_vQuadContainers;
842 int m_FirstFreeQuadContainer;
843
844 std::vector<WINDOW_RESIZE_FUNC> m_vResizeListeners;
845 std::vector<WINDOW_PROPS_CHANGED_FUNC> m_vPropChangeListeners;
846
847 void *AllocCommandBufferData(size_t AllocSize);
848
849 void AddVertices(int Count);
850 void AddVertices(int Count, CCommandBuffer::SVertex *pVertices);
851 void AddVertices(int Count, CCommandBuffer::SVertexTex3DStream *pVertices);
852
853 template<typename TName>
854 void Rotate(const CCommandBuffer::SPoint &Center, TName *pPoints, int NumPoints)
855 {
856 float c = std::cos(x: m_Rotation);
857 float s = std::sin(x: m_Rotation);
858 float x, y;
859 int i;
860
861 TName *pVertices = pPoints;
862 for(i = 0; i < NumPoints; i++)
863 {
864 x = pVertices[i].m_Pos.x - Center.x;
865 y = pVertices[i].m_Pos.y - Center.y;
866 pVertices[i].m_Pos.x = x * c - y * s + Center.x;
867 pVertices[i].m_Pos.y = x * s + y * c + Center.y;
868 }
869 }
870
871 template<typename TName>
872 void AddCmd(
873 TName &Cmd, const std::function<bool()> &FailFunc = [] { return true; })
874 {
875 if(m_pCommandBuffer->AddCommandUnsafe(Cmd))
876 return;
877
878 // kick command buffer and try again
879 KickCommandBuffer();
880
881 dbg_assert(FailFunc(), "graphics: failed to run fail handler for command '%s'", typeid(TName).name());
882 dbg_assert(m_pCommandBuffer->AddCommandUnsafe(Cmd), "graphics: failed to add command '%s' to command buffer", typeid(TName).name());
883 }
884
885 void KickCommandBuffer();
886
887 void AddBackEndWarningIfExists();
888
889 void AdjustViewport(bool SendViewportChangeToBackend);
890
891 ivec2 m_ReadPixelPosition = ivec2(0, 0);
892 ColorRGBA *m_pReadPixelColor = nullptr;
893 void ReadPixelDirect(bool *pSwapped);
894 void ScreenshotDirect(bool *pSwapped);
895
896 int IssueInit();
897 int InitWindow();
898
899public:
900 CGraphics_Threaded();
901
902 void ClipEnable(int x, int y, int w, int h) override;
903 void ClipDisable() override;
904
905 void BlendNone() override;
906 void BlendNormal() override;
907 void BlendAdditive() override;
908
909 void WrapNormal() override;
910 void WrapClamp() override;
911
912 uint64_t TextureMemoryUsage() const override;
913 uint64_t BufferMemoryUsage() const override;
914 uint64_t StreamedMemoryUsage() const override;
915 uint64_t StagingMemoryUsage() const override;
916
917 const TTwGraphicsGpuList &GetGpus() const override;
918
919 void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) override;
920 void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) const override;
921
922 void LinesBegin() override;
923 void LinesEnd() override;
924 void LinesDraw(const CLineItem *pArray, size_t Num) override;
925
926 void LinesBatchBegin(CLineItemBatch *pBatch) override;
927 void LinesBatchEnd(CLineItemBatch *pBatch) override;
928 void LinesBatchDraw(CLineItemBatch *pBatch, const CLineItem *pArray, size_t Num) override;
929
930 IGraphics::CTextureHandle FindFreeTextureIndex();
931 void FreeTextureIndex(CTextureHandle *pIndex);
932 void UnloadTexture(IGraphics::CTextureHandle *pIndex) override;
933 void LoadTextureAddWarning(size_t Width, size_t Height, int Flags, const char *pTexName);
934 IGraphics::CTextureHandle LoadTextureRaw(const CImageInfo &Image, int Flags, const char *pTexName = nullptr) override;
935 IGraphics::CTextureHandle LoadTextureRawMove(CImageInfo &Image, int Flags, const char *pTexName = nullptr) override;
936
937 bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override;
938 bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
939 bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) override;
940
941 CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override;
942
943 bool IsImageSubFullyTransparent(const CImageInfo &FromImageInfo, int x, int y, int w, int h) override;
944 bool IsSpriteTextureFullyTransparent(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override;
945
946 // simple uncompressed RGBA loaders
947 IGraphics::CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) override;
948 bool LoadPng(CImageInfo &Image, const char *pFilename, int StorageType) override;
949 bool LoadPng(CImageInfo &Image, const uint8_t *pData, size_t DataSize, const char *pContextName) override;
950
951 bool CheckImageDivisibility(const char *pContextName, CImageInfo &Image, int DivX, int DivY, bool AllowResize) override;
952 bool IsImageFormatRgba(const char *pContextName, const CImageInfo &Image) override;
953
954 void TextureSet(CTextureHandle TextureId) override;
955
956 void Clear(float r, float g, float b, bool ForceClearNow = false) override;
957
958 void QuadsBegin() override;
959 void QuadsEnd() override;
960 void QuadsTex3DBegin() override;
961 void QuadsTex3DEnd() override;
962 void TrianglesBegin() override;
963 void TrianglesEnd() override;
964 void QuadsEndKeepVertices() override;
965 void QuadsDrawCurrentVertices(bool KeepVertices = true) override;
966 void QuadsSetRotation(float Angle) override;
967
968 template<typename TName>
969 void SetColor(TName *pVertex, int ColorIndex)
970 {
971 TName *pVert = pVertex;
972 pVert->m_Color = m_aColor[ColorIndex];
973 }
974
975 void SetColorVertex(const CColorVertex *pArray, size_t Num) override;
976 void SetColor(float r, float g, float b, float a) override;
977 void SetColor(ColorRGBA Color) override;
978 void SetColor4(ColorRGBA TopLeft, ColorRGBA TopRight, ColorRGBA BottomLeft, ColorRGBA BottomRight) override;
979
980 // go through all vertices and change their color (only works for quads)
981 void ChangeColorOfCurrentQuadVertices(float r, float g, float b, float a) override;
982 void ChangeColorOfQuadVertices(size_t QuadOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a) override;
983
984 void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV) override;
985 void QuadsSetSubsetFree(
986 float x0, float y0, float x1, float y1,
987 float x2, float y2, float x3, float y3, int Index = -1) override;
988
989 void QuadsDraw(CQuadItem *pArray, int Num) override;
990
991 template<typename TName>
992 void QuadsDrawTLImpl(TName *pVertices, const CQuadItem *pArray, int Num)
993 {
994 CCommandBuffer::SPoint Center;
995
996 dbg_assert(m_Drawing == EDrawing::QUADS, "called Graphics()->QuadsDrawTL without begin");
997
998 if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
999 {
1000 for(int i = 0; i < Num; ++i)
1001 {
1002 // first triangle
1003 pVertices[m_NumVertices + 6 * i].m_Pos.x = pArray[i].m_X;
1004 pVertices[m_NumVertices + 6 * i].m_Pos.y = pArray[i].m_Y;
1005 pVertices[m_NumVertices + 6 * i].m_Tex = m_aTexture[0];
1006 SetColor(&pVertices[m_NumVertices + 6 * i], 0);
1007
1008 pVertices[m_NumVertices + 6 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width;
1009 pVertices[m_NumVertices + 6 * i + 1].m_Pos.y = pArray[i].m_Y;
1010 pVertices[m_NumVertices + 6 * i + 1].m_Tex = m_aTexture[1];
1011 SetColor(&pVertices[m_NumVertices + 6 * i + 1], 1);
1012
1013 pVertices[m_NumVertices + 6 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width;
1014 pVertices[m_NumVertices + 6 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height;
1015 pVertices[m_NumVertices + 6 * i + 2].m_Tex = m_aTexture[2];
1016 SetColor(&pVertices[m_NumVertices + 6 * i + 2], 2);
1017
1018 // second triangle
1019 pVertices[m_NumVertices + 6 * i + 3].m_Pos.x = pArray[i].m_X;
1020 pVertices[m_NumVertices + 6 * i + 3].m_Pos.y = pArray[i].m_Y;
1021 pVertices[m_NumVertices + 6 * i + 3].m_Tex = m_aTexture[0];
1022 SetColor(&pVertices[m_NumVertices + 6 * i + 3], 0);
1023
1024 pVertices[m_NumVertices + 6 * i + 4].m_Pos.x = pArray[i].m_X + pArray[i].m_Width;
1025 pVertices[m_NumVertices + 6 * i + 4].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height;
1026 pVertices[m_NumVertices + 6 * i + 4].m_Tex = m_aTexture[2];
1027 SetColor(&pVertices[m_NumVertices + 6 * i + 4], 2);
1028
1029 pVertices[m_NumVertices + 6 * i + 5].m_Pos.x = pArray[i].m_X;
1030 pVertices[m_NumVertices + 6 * i + 5].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height;
1031 pVertices[m_NumVertices + 6 * i + 5].m_Tex = m_aTexture[3];
1032 SetColor(&pVertices[m_NumVertices + 6 * i + 5], 3);
1033
1034 if(m_Rotation != 0)
1035 {
1036 Center.x = pArray[i].m_X + pArray[i].m_Width / 2;
1037 Center.y = pArray[i].m_Y + pArray[i].m_Height / 2;
1038
1039 Rotate(Center, &pVertices[m_NumVertices + 6 * i], 6);
1040 }
1041 }
1042
1043 AddVertices(3 * 2 * Num, pVertices);
1044 }
1045 else
1046 {
1047 for(int i = 0; i < Num; ++i)
1048 {
1049 pVertices[m_NumVertices + 4 * i].m_Pos.x = pArray[i].m_X;
1050 pVertices[m_NumVertices + 4 * i].m_Pos.y = pArray[i].m_Y;
1051 pVertices[m_NumVertices + 4 * i].m_Tex = m_aTexture[0];
1052 SetColor(&pVertices[m_NumVertices + 4 * i], 0);
1053
1054 pVertices[m_NumVertices + 4 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width;
1055 pVertices[m_NumVertices + 4 * i + 1].m_Pos.y = pArray[i].m_Y;
1056 pVertices[m_NumVertices + 4 * i + 1].m_Tex = m_aTexture[1];
1057 SetColor(&pVertices[m_NumVertices + 4 * i + 1], 1);
1058
1059 pVertices[m_NumVertices + 4 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width;
1060 pVertices[m_NumVertices + 4 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height;
1061 pVertices[m_NumVertices + 4 * i + 2].m_Tex = m_aTexture[2];
1062 SetColor(&pVertices[m_NumVertices + 4 * i + 2], 2);
1063
1064 pVertices[m_NumVertices + 4 * i + 3].m_Pos.x = pArray[i].m_X;
1065 pVertices[m_NumVertices + 4 * i + 3].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height;
1066 pVertices[m_NumVertices + 4 * i + 3].m_Tex = m_aTexture[3];
1067 SetColor(&pVertices[m_NumVertices + 4 * i + 3], 3);
1068
1069 if(m_Rotation != 0)
1070 {
1071 Center.x = pArray[i].m_X + pArray[i].m_Width / 2;
1072 Center.y = pArray[i].m_Y + pArray[i].m_Height / 2;
1073
1074 Rotate(Center, &pVertices[m_NumVertices + 4 * i], 4);
1075 }
1076 }
1077
1078 AddVertices(4 * Num, pVertices);
1079 }
1080 }
1081
1082 void QuadsDrawTL(const CQuadItem *pArray, int Num) override;
1083
1084 void QuadsTex3DDrawTL(const CQuadItem *pArray, int Num) override;
1085
1086 void QuadsDrawFreeform(const CFreeformItem *pArray, int Num) override;
1087 void QuadsText(float x, float y, float Size, const char *pText) override;
1088
1089 void DrawRectExt(float x, float y, float w, float h, float r, int Corners) override;
1090 void DrawRectExt4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, float r, int Corners) override;
1091 int CreateRectQuadContainer(float x, float y, float w, float h, float r, int Corners) override;
1092 void DrawRect(float x, float y, float w, float h, ColorRGBA Color, int Corners, float Rounding) override;
1093 void DrawRect4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, int Corners, float Rounding) override;
1094 void DrawCircle(float CenterX, float CenterY, float Radius, int Segments) override;
1095
1096 int CreateQuadContainer(bool AutomaticUpload = true) override;
1097 void QuadContainerChangeAutomaticUpload(int ContainerIndex, bool AutomaticUpload) override;
1098 void QuadContainerUpload(int ContainerIndex) override;
1099 int QuadContainerAddQuads(int ContainerIndex, CQuadItem *pArray, int Num) override;
1100 int QuadContainerAddQuads(int ContainerIndex, CFreeformItem *pArray, int Num) override;
1101 void QuadContainerReset(int ContainerIndex) override;
1102 void DeleteQuadContainer(int &ContainerIndex) override;
1103 void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) override;
1104 void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum, bool ChangeWrapMode = true) override;
1105 void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override;
1106 void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override;
1107 void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) override;
1108
1109 // sprites
1110private:
1111 vec2 m_SpriteScale = vec2(-1.0f, -1.0f);
1112
1113protected:
1114 void SelectSprite(const CDataSprite *pSprite, int Flags);
1115
1116public:
1117 void SelectSprite(int Id, int Flags = 0) override;
1118 void SelectSprite7(int Id, int Flags = 0) override;
1119
1120 void GetSpriteScale(const CDataSprite *pSprite, float &ScaleX, float &ScaleY) const override;
1121 void GetSpriteScale(int Id, float &ScaleX, float &ScaleY) const override;
1122 void GetSpriteScaleImpl(int Width, int Height, float &ScaleX, float &ScaleY) const override;
1123
1124 void DrawSprite(float x, float y, float Size) override;
1125 void DrawSprite(float x, float y, float ScaledWidth, float ScaledHeight) override;
1126
1127 int QuadContainerAddSprite(int QuadContainerIndex, float x, float y, float Size) override;
1128 int QuadContainerAddSprite(int QuadContainerIndex, float Size) override;
1129 int QuadContainerAddSprite(int QuadContainerIndex, float Width, float Height) override;
1130 int QuadContainerAddSprite(int QuadContainerIndex, float X, float Y, float Width, float Height) override;
1131
1132 template<typename TName>
1133 void FlushVerticesImpl(bool KeepVertices, EPrimitiveType &PrimType, size_t &PrimCount, size_t &NumVerts, TName &Command, size_t VertSize)
1134 {
1135 Command.m_pVertices = nullptr;
1136 if(m_NumVertices == 0)
1137 return;
1138
1139 NumVerts = m_NumVertices;
1140
1141 if(!KeepVertices)
1142 m_NumVertices = 0;
1143
1144 if(m_Drawing == EDrawing::QUADS)
1145 {
1146 if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
1147 {
1148 PrimType = EPrimitiveType::TRIANGLES;
1149 PrimCount = NumVerts / 3;
1150 }
1151 else
1152 {
1153 PrimType = EPrimitiveType::QUADS;
1154 PrimCount = NumVerts / 4;
1155 }
1156 }
1157 else if(m_Drawing == EDrawing::LINES)
1158 {
1159 PrimType = EPrimitiveType::LINES;
1160 PrimCount = NumVerts / 2;
1161 }
1162 else if(m_Drawing == EDrawing::TRIANGLES)
1163 {
1164 PrimType = EPrimitiveType::TRIANGLES;
1165 PrimCount = NumVerts / 3;
1166 }
1167 else
1168 return;
1169
1170 Command.m_pVertices = (decltype(Command.m_pVertices))AllocCommandBufferData(AllocSize: VertSize * NumVerts);
1171 Command.m_State = m_State;
1172
1173 Command.m_PrimType = PrimType;
1174 Command.m_PrimCount = PrimCount;
1175
1176 AddCmd(Command, [&] {
1177 Command.m_pVertices = (decltype(Command.m_pVertices))m_pCommandBuffer->AllocData(WantedSize: VertSize * NumVerts);
1178 return Command.m_pVertices != nullptr;
1179 });
1180
1181 m_pCommandBuffer->AddRenderCalls(RenderCallCountToAdd: 1);
1182 }
1183
1184 void FlushVertices(bool KeepVertices = false) override;
1185 void FlushVerticesTex3D() override;
1186
1187 void RenderTileLayer(int BufferContainerIndex, const ColorRGBA &Color, char **pOffsets, unsigned int *pIndicedVertexDrawNum, size_t NumIndicesOffset) override;
1188 void RenderBorderTiles(int BufferContainerIndex, const ColorRGBA &Color, char *pIndexBufferOffset, const vec2 &Offset, const vec2 &Scale, uint32_t DrawNum) override;
1189 void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, size_t QuadNum, int QuadOffset, bool Grouped = false) override;
1190 void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor) override;
1191
1192 // modern GL functions
1193 int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override;
1194 void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override;
1195 void UpdateBufferObjectInternal(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false);
1196 void CopyBufferObjectInternal(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize);
1197 void DeleteBufferObject(int BufferIndex) override;
1198
1199 int CreateBufferContainer(SBufferContainerInfo *pContainerInfo) override;
1200 // destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them
1201 void DeleteBufferContainer(int &ContainerIndex, bool DestroyAllBO = true) override;
1202 void UpdateBufferContainerInternal(int ContainerIndex, SBufferContainerInfo *pContainerInfo);
1203 void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) override;
1204
1205 int GetNumScreens() const override;
1206 const char *GetScreenName(int Screen) const override;
1207
1208 void Minimize() override;
1209 void WarnPngliteIncompatibleImages(bool Warn) override;
1210 void SetWindowParams(int FullscreenMode, bool IsBorderless) override;
1211 bool SetWindowScreen(int Index, bool MoveToCenter) override;
1212 bool SwitchWindowScreen(int Index, bool MoveToCenter) override;
1213 void Move(int x, int y) override;
1214 bool Resize(int w, int h, int RefreshRate) override;
1215 void ResizeToScreen() override;
1216 void GotResized(int w, int h, int RefreshRate) override;
1217 void UpdateViewport(int X, int Y, int W, int H, bool ByResize) override;
1218 bool IsScreenKeyboardShown() override;
1219
1220 void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc) override;
1221 void AddWindowPropChangeListener(WINDOW_PROPS_CHANGED_FUNC pFunc) override;
1222 int GetWindowScreen() override;
1223
1224 void WindowDestroyNtf(uint32_t WindowId) override;
1225 void WindowCreateNtf(uint32_t WindowId) override;
1226
1227 int WindowActive() override;
1228 int WindowOpen() override;
1229
1230 void SetWindowGrab(bool Grab) override;
1231 void NotifyWindow() override;
1232
1233 int Init() override;
1234 void Shutdown() override;
1235
1236 void ReadPixel(ivec2 Position, ColorRGBA *pColor) override;
1237 void TakeScreenshot(const char *pFilename) override;
1238 void TakeCustomScreenshot(const char *pFilename) override;
1239 void Swap() override;
1240 bool SetVSync(bool State) override;
1241 bool SetMultiSampling(uint32_t ReqMultiSamplingCount, uint32_t &MultiSamplingCountBackend) override;
1242
1243 int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen) override;
1244 void GetCurrentVideoMode(CVideoMode &CurMode, int Screen) override;
1245
1246 virtual int GetDesktopScreenWidth() const { return g_Config.m_GfxDesktopWidth; }
1247 virtual int GetDesktopScreenHeight() const { return g_Config.m_GfxDesktopHeight; }
1248
1249 // synchronization
1250 void InsertSignal(CSemaphore *pSemaphore) override;
1251 bool IsIdle() const override;
1252 void WaitForIdle() override;
1253
1254 void AddWarning(const SWarning &Warning);
1255 std::optional<SWarning> CurrentWarning() override;
1256
1257 std::optional<int> ShowMessageBox(const CMessageBox &MessageBox) override;
1258
1259 bool IsBackendInitialized() override;
1260
1261 bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) override { return m_pBackend->GetDriverVersion(DriverAgeType, Major, Minor, Patch, pName, BackendType); }
1262 bool IsConfigModernAPI() override { return m_pBackend->IsConfigModernAPI(); }
1263 bool IsTileBufferingEnabled() override { return m_GLTileBufferingEnabled; }
1264 bool IsQuadBufferingEnabled() override { return m_GLQuadBufferingEnabled; }
1265 bool IsTextBufferingEnabled() override { return m_GLTextBufferingEnabled; }
1266 bool IsQuadContainerBufferingEnabled() override { return m_GLQuadContainerBufferingEnabled; }
1267 bool Uses2DTextureArrays() override { return m_GLUses2DTextureArrays; }
1268 bool HasTextureArraysSupport() override { return m_GLHasTextureArraysSupport; }
1269
1270 const char *GetVendorString() override;
1271 const char *GetVersionString() override;
1272 const char *GetRendererString() override;
1273 const char *GetFatalError() const override;
1274
1275 TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override;
1276};
1277
1278typedef std::function<const char *(const char *, const char *)> TTranslateFunc;
1279extern IGraphicsBackend *CreateGraphicsBackend(TTranslateFunc &&TranslateFunc);
1280
1281#endif // ENGINE_CLIENT_GRAPHICS_THREADED_H
1282