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