GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/graphicsmanager.cpp Lines: 28 723 3.9 %
Date: 2021-03-17 Branches: 19 1269 1.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "graphicsmanager.h"
23
24
#ifdef USE_OPENGL
25
#ifndef WIN32
26
27
#ifdef ANDROID
28
#include <GLES2/gl2.h>
29
#include <GLES/glext.h>
30
#include <EGL/egl.h>
31
32
#ifndef USE_SDL2
33
PRAGMA48(GCC diagnostic push)
34
PRAGMA48(GCC diagnostic ignored "-Wshadow")
35
#include <SDL_android.h>
36
PRAGMA48(GCC diagnostic pop)
37
#endif  // USE_SDL2
38
#elif defined(__native_client__)
39
#include <GL/Regal.h>
40
#include "render/opengl/naclglfunctions.h"
41
#else  // ANDROID
42
#ifdef USE_X11
43
#include <GL/glx.h>
44
#endif  // USE_X11
45
#endif  // ANDROID
46
#endif  // WIN32
47
#endif  // USE_OPENGL
48
49
#include "settings.h"
50
51
#ifdef USE_OPENGL
52
#include "render/mobileopengl2graphics.h"
53
#include "render/mobileopenglgraphics.h"
54
#include "render/modernopenglgraphics.h"
55
#include "render/normalopenglgraphics.h"
56
#include "render/safeopenglgraphics.h"
57
58
#include "render/opengl/mgl.h"
59
#include "render/opengl/mglcheck.h"
60
#include "render/opengl/mglemu.h"
61
#endif  // USE_OPENGL
62
63
#include "render/sdlgraphics.h"
64
65
#ifdef USE_OPENGL
66
#include "resources/openglimagehelper.h"
67
#include "resources/openglscreenshothelper.h"
68
#ifndef ANDROID
69
#include "resources/mobileopenglscreenshothelper.h"
70
#include "resources/safeopenglimagehelper.h"
71
#endif  // ANDROID
72
#include "render/opengl/mglfunctions.h"
73
#endif  // USE_OPENGL
74
75
#include "resources/sdlimagehelper.h"
76
#include "resources/sdlscreenshothelper.h"
77
78
#ifdef USE_SDL2
79
#include "render/sdl2softwaregraphics.h"
80
81
#include "resources/sdl2softwareimagehelper.h"
82
#include "resources/sdl2softwarescreenshothelper.h"
83
#include "resources/surfaceimagehelper.h"
84
#endif  // USE_SDL2
85
86
#include "utils/delete2.h"
87
#include "utils/sdlhelper.h"
88
89
#ifdef USE_OPENGL
90
#include "test/testmain.h"
91
#else  // USE_OPENGL
92
#include "configuration.h"
93
94
#include "render/renderers.h"
95
#endif  // USE_OPENGL
96
97
PRAGMA48(GCC diagnostic push)
98
PRAGMA48(GCC diagnostic ignored "-Wshadow")
99
#include <SDL_syswm.h>
100
PRAGMA48(GCC diagnostic pop)
101
102
#include "debug.h"
103
104
#ifdef USE_OPENGL
105
#ifndef GL_MAX_RENDERBUFFER_SIZE
106
#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
107
#endif  // GL_MAX_RENDERBUFFER_SIZE
108
#define useCompression(name) \
109
    { \
110
        OpenGLImageHelper::setInternalTextureType(name); \
111
        logger->log("using " #name " texture compression"); \
112
    }
113
#endif  // USE_OPENGL
114
115
1
GraphicsManager graphicsManager;
116
117
RenderType openGLMode = RENDER_SOFTWARE;
118
119
ScreenshotHelper *screenshortHelper = nullptr;
120
121
const int densitySize = 6;
122
123
3
const std::string densityNames[] =
124
{
125
    "low",
126
    "medium",
127
    "tv",
128
    "high",
129
    "xhigh",
130
    "xxhigh"
131



7
};
132
133
#ifdef USE_OPENGL
134
GLenum GraphicsManager::mLastError(GL_NO_ERROR);
135
#endif  // USE_OPENGL
136
137
1
GraphicsManager::GraphicsManager() :
138
    mExtensions(),
139
    mPlatformExtensions(),
140
    mGlVersionString(),
141
    mGlVendor(),
142
    mGlRenderer(),
143
    mGlShaderVersionString(),
144
    mMinor(0),
145
    mMajor(0),
146
    mSLMinor(0),
147
    mSLMajor(0),
148
    mPlatformMinor(0),
149
    mPlatformMajor(0),
150
    mMaxVertices(500),
151
    mMaxFboSize(0),
152
    mMaxWidth(0),
153
    mMaxHeight(0),
154
    mWidthMM(0),
155
    mHeightMM(0),
156
    mDensity(-1),
157
#ifdef USE_OPENGL
158
    mUseTextureSampler(true),
159
    mTextureSampler(0),
160
    mSupportDebug(0),
161
    mSupportModernOpengl(false),
162
    mGles(false),
163
#endif  // USE_OPENGL
164
7
    mUseAtlases(false)
165
{
166
1
}
167
168
8
GraphicsManager::~GraphicsManager()
169
{
170
#ifdef USE_OPENGL
171

1
    if (isGLNotNull(mglGenSamplers) && mTextureSampler)
172
        mglDeleteSamplers(1, &mTextureSampler);
173
#endif  // USE_OPENGL
174
1
}
175
176
#ifdef USE_OPENGL
177
TestMain *GraphicsManager::startDetection()
178
{
179
    TestMain *const test = new TestMain;
180
    test->exec(false);
181
    return test;
182
}
183
184
int GraphicsManager::detectGraphics()
185
{
186
    logger->log1("start detecting best mode...");
187
    logger->log1("enable opengl mode");
188
    int textureSampler = 0;
189
    int compressTextures = 0;
190
#if !defined(ANDROID) && !defined(__native_client__) && !defined(__SWITCH__)
191
    mainGraphics = new NormalOpenGLGraphics;
192
#endif  // !defined(ANDROID) && !defined(__native_client__)
193
194
    SDL_Window *const window = createWindow(100, 100, 0,
195
        SDL_ANYFORMAT | SDL_OPENGL);
196
    mainGraphics->setWindow(window, 100, 100);
197
    mainGraphics->createGLContext(false);
198
199
    initOpenGL();
200
    logVersion();
201
202
    RenderType mode = RENDER_NORMAL_OPENGL;
203
204
    // detecting features by known renderers or vendors
205
    if (findI(mGlRenderer, "gdi generic") != std::string::npos)
206
    {
207
        // windows gdi OpenGL emulation
208
        logger->log("detected gdi drawing");
209
        logger->log("disable OpenGL");
210
        mode = RENDER_SOFTWARE;
211
    }
212
    else if (findI(mGlRenderer, "Software Rasterizer") != std::string::npos)
213
    {
214
        // software OpenGL emulation
215
        logger->log("detected software drawing");
216
        logger->log("disable OpenGL");
217
        mode = RENDER_SOFTWARE;
218
    }
219
    else if (findI(mGlRenderer, "Indirect") != std::string::npos)
220
    {
221
        // indirect OpenGL drawing
222
        logger->log("detected indirect drawing");
223
        logger->log("disable OpenGL");
224
        mode = RENDER_SOFTWARE;
225
    }
226
    else if (findI(mGlVendor, "VMWARE") != std::string::npos)
227
    {
228
        // vmware emulation
229
        logger->log("detected VMWARE driver");
230
        logger->log("disable OpenGL");
231
        mode = RENDER_SOFTWARE;
232
    }
233
    else if (findI(mGlVendor, "NVIDIA") != std::string::npos)
234
    {
235
        // hope it can work well
236
        logger->log("detected NVIDIA driver");
237
        config.setValue("useTextureSampler", true);
238
        textureSampler = 1;
239
        mode = RENDER_NORMAL_OPENGL;
240
    }
241
242
    // detecting feature based on OpenGL version
243
    if (!checkGLVersion(1, 1))
244
    {
245
        // very old OpenGL version
246
        logger->log("OpenGL version too old");
247
        mode = RENDER_SOFTWARE;
248
    }
249
250
    if (mode != RENDER_SOFTWARE && findI(mGlVersionString, "Mesa")
251
        != std::string::npos)
252
    {
253
        // Mesa detected. In latest Mesa look like compression broken.
254
        config.setValue("compresstextures", false);
255
        compressTextures = 0;
256
    }
257
258
    config.setValue("opengl", CAST_S32(mode));
259
    config.setValue("videoconfigured", true);
260
    config.write();
261
262
    logger->log("detection complete");
263
    return CAST_U32(mode)
264
        | (1024 * textureSampler) | (2048 * compressTextures);
265
}
266
267
#ifdef USE_SDL2
268
#define RENDER_SOFTWARE_INIT \
269
    imageHelper = new SDL2SoftwareImageHelper; \
270
    surfaceImageHelper = new SurfaceImageHelper; \
271
    mainGraphics = new SDL2SoftwareGraphics; \
272
    screenshortHelper = new Sdl2SoftwareScreenshotHelper;
273
#define RENDER_SDL2_DEFAULT_INIT \
274
    imageHelper = new SDLImageHelper; \
275
    surfaceImageHelper = new SurfaceImageHelper; \
276
    mainGraphics = new SDLGraphics; \
277
    screenshortHelper = new SdlScreenshotHelper; \
278
    mainGraphics->setRendererFlags(SDL_RENDERER_ACCELERATED); \
279
    mUseTextureSampler = false;
280
#else  // USE_SDL2
281
#define RENDER_SOFTWARE_INIT \
282
    imageHelper = new SDLImageHelper; \
283
    surfaceImageHelper = imageHelper; \
284
    mainGraphics = new SDLGraphics; \
285
    screenshortHelper = new SdlScreenshotHelper;
286
#define RENDER_SDL2_DEFAULT_INIT
287
#endif  // USE_SDL2
288
289
#if defined(ANDROID) || defined(__native_client__) || defined(__SWITCH__)
290
#define RENDER_NORMAL_OPENGL_INIT
291
#define RENDER_MODERN_OPENGL_INIT
292
#else  // defined(ANDROID) || defined(__native_client__)
293
#define RENDER_NORMAL_OPENGL_INIT \
294
    imageHelper = new OpenGLImageHelper; \
295
    surfaceImageHelper = new SurfaceImageHelper; \
296
    mainGraphics = new NormalOpenGLGraphics; \
297
    screenshortHelper = new OpenGLScreenshotHelper; \
298
    mUseTextureSampler = true;
299
#define RENDER_MODERN_OPENGL_INIT \
300
    imageHelper = new OpenGLImageHelper; \
301
    surfaceImageHelper = new SurfaceImageHelper; \
302
    mainGraphics = new ModernOpenGLGraphics; \
303
    screenshortHelper = new OpenGLScreenshotHelper; \
304
    mUseTextureSampler = true;
305
#endif  // defined(ANDROID) || defined(__native_client__)
306
307
#if defined(ANDROID)
308
#define RENDER_SAFE_OPENGL_INIT
309
#define RENDER_GLES2_OPENGL_INIT
310
#else  // defined(ANDROID)
311
#ifdef __SWITCH__
312
#define RENDER_SAFE_OPENGL_INIT
313
#else
314
#define RENDER_SAFE_OPENGL_INIT \
315
    imageHelper = new SafeOpenGLImageHelper; \
316
    surfaceImageHelper = new SurfaceImageHelper; \
317
    mainGraphics = new SafeOpenGLGraphics; \
318
    screenshortHelper = new OpenGLScreenshotHelper; \
319
    mUseTextureSampler = false;
320
#endif
321
#define RENDER_GLES2_OPENGL_INIT \
322
    imageHelper = new OpenGLImageHelper; \
323
    surfaceImageHelper = new SurfaceImageHelper; \
324
    mainGraphics = new MobileOpenGL2Graphics; \
325
    screenshortHelper = new MobileOpenGLScreenshotHelper; \
326
    mUseTextureSampler = false;
327
#endif  // defined(ANDROID)
328
329
#if defined(__native_client__) || defined(__SWITCH__)
330
#define RENDER_GLES_OPENGL_INIT
331
#else  // defined(__native_client__)
332
#define RENDER_GLES_OPENGL_INIT \
333
    imageHelper = new OpenGLImageHelper; \
334
    surfaceImageHelper = new SurfaceImageHelper; \
335
    mainGraphics = new MobileOpenGLGraphics; \
336
    screenshortHelper = new OpenGLScreenshotHelper; \
337
    mUseTextureSampler = false;
338
#endif  // defined(__native_client__)
339
340
void GraphicsManager::createRenderers()
341
{
342
    RenderType useOpenGL = RENDER_SOFTWARE;
343
    if (!settings.options.noOpenGL)
344
    {
345
        if (settings.options.renderer < 0)
346
        {
347
            useOpenGL = intToRenderType(config.getIntValue("opengl"));
348
            settings.options.renderer = CAST_S32(useOpenGL);
349
        }
350
        else
351
        {
352
            useOpenGL = intToRenderType(settings.options.renderer);
353
        }
354
    }
355
356
    // Setup image loading for the right image format
357
    ImageHelper::setOpenGlMode(useOpenGL);
358
359
    // Create the graphics context
360
    switch (useOpenGL)
361
    {
362
        case RENDER_SOFTWARE:
363
            RENDER_SOFTWARE_INIT
364
            mUseTextureSampler = false;
365
            break;
366
        case RENDER_LAST:
367
        case RENDER_NULL:
368
        default:
369
            break;
370
        case RENDER_NORMAL_OPENGL:
371
            RENDER_NORMAL_OPENGL_INIT
372
            break;
373
        case RENDER_SAFE_OPENGL:
374
            RENDER_SAFE_OPENGL_INIT
375
            break;
376
        case RENDER_MODERN_OPENGL:
377
            RENDER_MODERN_OPENGL_INIT
378
            break;
379
        case RENDER_GLES2_OPENGL:
380
            RENDER_GLES2_OPENGL_INIT
381
            break;
382
        case RENDER_GLES_OPENGL:
383
            RENDER_GLES_OPENGL_INIT
384
            break;
385
        case RENDER_SDL2_DEFAULT:
386
            RENDER_SDL2_DEFAULT_INIT
387
            break;
388
    }
389
    mUseAtlases = (useOpenGL == RENDER_NORMAL_OPENGL ||
390
        useOpenGL == RENDER_SAFE_OPENGL ||
391
        useOpenGL == RENDER_MODERN_OPENGL ||
392
        useOpenGL == RENDER_GLES_OPENGL ||
393
        useOpenGL == RENDER_GLES2_OPENGL) &&
394
        config.getBoolValue("useAtlases");
395
396
#else  // USE_OPENGL
397
398
void GraphicsManager::createRenderers()
399
{
400
    RenderType useOpenGL = RENDER_SOFTWARE;
401
    if (!settings.options.noOpenGL)
402
        useOpenGL = intToRenderType(config.getIntValue("opengl"));
403
404
    // Setup image loading for the right image format
405
    ImageHelper::setOpenGlMode(useOpenGL);
406
407
    // Create the graphics context
408
    switch (useOpenGL)
409
    {
410
        case RENDER_SOFTWARE:
411
        case RENDER_SAFE_OPENGL:
412
        case RENDER_GLES_OPENGL:
413
        case RENDER_GLES2_OPENGL:
414
        case RENDER_MODERN_OPENGL:
415
        case RENDER_NORMAL_OPENGL:
416
        case RENDER_NULL:
417
        case RENDER_LAST:
418
        default:
419
#ifndef USE_SDL2
420
        case RENDER_SDL2_DEFAULT:
421
            imageHelper = new SDLImageHelper;
422
            surfaceImageHelper = imageHelper;
423
            mainGraphics = new SDLGraphics;
424
            screenshortHelper = new SdlScreenshotHelper;
425
#else  // USE_SDL2
426
427
            imageHelper = new SDL2SoftwareImageHelper;
428
            surfaceImageHelper = new SurfaceImageHelper;
429
            mainGraphics = new SDL2SoftwareGraphics;
430
            screenshortHelper = new Sdl2SoftwareScreenshotHelper;
431
432
#endif  // USE_SDL2
433
434
            break;
435
#ifdef USE_SDL2
436
        case RENDER_SDL2_DEFAULT:
437
            imageHelper = new SDLImageHelper;
438
            surfaceImageHelper = new SurfaceImageHelper;
439
            mainGraphics = new SDLGraphics;
440
            mainGraphics->setRendererFlags(SDL_RENDERER_ACCELERATED);
441
            screenshortHelper = new SdlScreenshotHelper;
442
            break;
443
#endif  // USE_SDL2
444
    };
445
#endif  // USE_OPENGL
446
}
447
448
234
void GraphicsManager::deleteRenderers()
449
{
450
234
    delete2(mainGraphics)
451
234
    if (imageHelper != surfaceImageHelper)
452
234
        delete surfaceImageHelper;
453
234
    surfaceImageHelper = nullptr;
454
234
    delete2(imageHelper)
455
234
}
456
457
void GraphicsManager::setVideoMode()
458
{
459
    const int bpp = 0;
460
    const bool fullscreen = config.getBoolValue("screen");
461
    const bool hwaccel = config.getBoolValue("hwaccel");
462
    const bool enableResize = config.getBoolValue("enableresize");
463
    const bool noFrame = config.getBoolValue("noframe");
464
    const bool allowHighDPI = config.getBoolValue("allowHighDPI");
465
466
#ifdef ANDROID
467
//    int width = config.getValue("screenwidth", 0);
468
//    int height = config.getValue("screenheight", 0);
469
    StringVect videoModes;
470
    SDL::getAllVideoModes(videoModes);
471
    if (videoModes.empty())
472
        logger->error("no video modes detected");
473
    STD_VECTOR<int> res;
474
    splitToIntVector(res, videoModes[0], 'x');
475
    if (res.size() != 2)
476
        logger->error("no video modes detected");
477
478
    int width = res[0];
479
    int height = res[1];
480
#elif defined __native_client__
481
#ifdef USE_SDL2
482
    // not implemented
483
#else  // USE_SDL2
484
485
    const SDL_VideoInfo* info = SDL_GetVideoInfo();
486
    int width = info->current_w;
487
    int height = info->current_h;
488
#endif  // USE_SDL2
489
#elif defined __SWITCH__
490
    int width = 1280;
491
    int height = 720;
492
#else  // defined __native_client__
493
494
    int width = config.getIntValue("screenwidth");
495
    int height = config.getIntValue("screenheight");
496
#endif  // defined __native_client__
497
498
    const int scale = config.getIntValue("scale");
499
500
    // Try to set the desired video mode
501
    if (!mainGraphics->setVideoMode(width, height, scale, bpp,
502
        fullscreen, hwaccel, enableResize, noFrame, allowHighDPI))
503
    {
504
        logger->log(strprintf("Couldn't set %dx%dx%d video mode: %s",
505
            width, height, bpp, SDL_GetError()));
506
507
        const int oldWidth = config.getValueInt("oldscreenwidth", -1);
508
        const int oldHeight = config.getValueInt("oldscreenheight", -1);
509
        const int oldFullscreen = config.getValueInt("oldscreen", -1);
510
        if (oldWidth != -1 && oldHeight != -1 && oldFullscreen != -1)
511
        {
512
            config.deleteKey("oldscreenwidth");
513
            config.deleteKey("oldscreenheight");
514
            config.deleteKey("oldscreen");
515
516
            config.setValueInt("screenwidth", oldWidth);
517
            config.setValueInt("screenheight", oldHeight);
518
            config.setValue("screen", oldFullscreen == 1);
519
            if (!mainGraphics->setVideoMode(oldWidth, oldHeight,
520
                scale,
521
                bpp,
522
                oldFullscreen != 0,
523
                hwaccel,
524
                enableResize,
525
                noFrame,
526
                allowHighDPI))
527
            {
528
                logger->safeError(strprintf("Couldn't restore %dx%dx%d "
529
                    "video mode: %s", oldWidth, oldHeight, bpp,
530
                    SDL_GetError()));
531
            }
532
        }
533
    }
534
}
535
536
void GraphicsManager::initGraphics()
537
{
538
    openGLMode = intToRenderType(config.getIntValue("opengl"));
539
#ifdef USE_OPENGL
540
    OpenGLImageHelper::setBlur(config.getBoolValue("blur"));
541
#if !defined(ANDROID) && !defined(__SWITCH__)
542
    SafeOpenGLImageHelper::setBlur(config.getBoolValue("blur"));
543
#endif  // ANDROID
544
    SurfaceImageHelper::SDLSetEnableAlphaCache(
545
        config.getBoolValue("alphaCache") &&
546
        openGLMode == RENDER_SOFTWARE);
547
    ImageHelper::setEnableAlpha((config.getFloatValue("guialpha") != 1.0F ||
548
        openGLMode != RENDER_SOFTWARE) &&
549
        config.getBoolValue("enableGuiOpacity"));
550
#else  // USE_OPENGL
551
    SurfaceImageHelper::SDLSetEnableAlphaCache(
552
        config.getBoolValue("alphaCache"));
553
    ImageHelper::setEnableAlpha(config.getFloatValue("guialpha") != 1.0F &&
554
        config.getBoolValue("enableGuiOpacity"));
555
#endif  // USE_OPENGL
556
    createRenderers();
557
    setVideoMode();
558
    detectPixelSize();
559
#ifdef USE_OPENGL
560
    if (config.getBoolValue("checkOpenGLVersion") == true)
561
    {
562
        const RenderType oldOpenGLMode = openGLMode;
563
        if (openGLMode == RENDER_MODERN_OPENGL)
564
        {
565
            if (!mSupportModernOpengl || !checkGLVersion(3, 0))
566
            {
567
                logger->log("Fallback to normal OpenGL mode");
568
                openGLMode = RENDER_NORMAL_OPENGL;
569
            }
570
        }
571
        if (openGLMode == RENDER_NORMAL_OPENGL)
572
        {
573
            if (!checkGLVersion(2, 0))
574
            {
575
                logger->log("Fallback to safe OpenGL mode");
576
                openGLMode = RENDER_SAFE_OPENGL;
577
            }
578
        }
579
        if (openGLMode == RENDER_GLES_OPENGL)
580
        {
581
            if (!checkGLVersion(2, 0) && !checkGLesVersion(1, 0))
582
            {
583
                logger->log("Fallback to safe OpenGL mode");
584
                openGLMode = RENDER_SAFE_OPENGL;
585
            }
586
        }
587
        if (openGLMode == RENDER_GLES2_OPENGL)
588
        {
589
            // +++ here need check also not implemented gles flag
590
            if (!checkGLVersion(2, 0))
591
            {
592
                logger->log("Fallback to software mode");
593
                openGLMode = RENDER_SOFTWARE;
594
            }
595
        }
596
597
        if (openGLMode != oldOpenGLMode)
598
        {
599
            deleteRenderers();
600
            settings.options.renderer = CAST_S32(openGLMode);
601
            config.setValue("opengl", settings.options.renderer);
602
            createRenderers();
603
            setVideoMode();
604
            detectPixelSize();
605
        }
606
    }
607
#if !defined(ANDROID) && !defined(__APPLE__)
608
    const std::string str = config.getStringValue("textureSize");
609
    STD_VECTOR<int> sizes;
610
    splitToIntVector(sizes, str, ',');
611
    const size_t pos = CAST_SIZE(openGLMode);
612
    if (sizes.size() <= pos)
613
        settings.textureSize = 1024;
614
    else
615
        settings.textureSize = sizes[pos];
616
    logger->log("Detected max texture size: %u", settings.textureSize);
617
#endif  // !defined(ANDROID) && !defined(__APPLE__)
618
#endif  // USE_OPENGL
619
}
620
621
#ifdef USE_SDL2
622
311
SDL_Window *GraphicsManager::createWindow(const int w, const int h,
623
                                          const int bpp A_UNUSED,
624
                                          const int flags)
625
{
626
311
    return SDL_CreateWindow("ManaPlus", SDL_WINDOWPOS_UNDEFINED,
627
311
        SDL_WINDOWPOS_UNDEFINED, w, h, flags);
628
}
629
630
311
SDL_Renderer *GraphicsManager::createRenderer(SDL_Window *const window,
631
                                              const int flags)
632
{
633

1555
    SDL::setRendererHint(config.getStringValue("sdlDriver"));
634
311
    SDL_Renderer *const renderer = SDL_CreateRenderer(window, -1, flags);
635
311
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
636
311
    return renderer;
637
}
638
#else  // USE_SDL2
639
640
SDL_Window *GraphicsManager::createWindow(const int w, const int h,
641
                                          const int bpp, const int flags)
642
{
643
    return SDL_SetVideoMode(w, h, bpp, flags);
644
}
645
#endif  // USE_SDL2
646
647
#ifdef USE_OPENGL
648
void GraphicsManager::updateExtensions()
649
{
650
    mExtensions.clear();
651
    logger->log1("opengl extensions: ");
652
    if (checkGLVersion(3, 0))
653
    {   // get extensions in new way
654
        assignFunction2(glGetStringi, "glGetStringi")
655
        std::string extList;
656
        int num = 0;
657
        glGetIntegerv(GL_NUM_EXTENSIONS, &num);
658
        for (int f = 0; f < num; f ++)
659
        {
660
            std::string str = reinterpret_cast<const char*>(
661
                mglGetStringi(GL_EXTENSIONS, f));
662
            mExtensions.insert(str);
663
            extList.append(str).append(" ");
664
        }
665
        logger->log1(extList.c_str());
666
    }
667
    else
668
    {   // get extensions in old way
669
        char const *extensions = reinterpret_cast<char const *>(
670
            mglGetString(GL_EXTENSIONS));
671
        if (extensions)
672
        {
673
            logger->log1(extensions);
674
            splitToStringSet(mExtensions, extensions, ' ');
675
        }
676
    }
677
}
678
679
void GraphicsManager::updatePlanformExtensions()
680
{
681
    SDL_SysWMinfo info;
682
    SDL_VERSION(&info.version)
683
    if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info))
684
    {
685
#ifdef WIN32
686
        if (!mwglGetExtensionsString)
687
            return;
688
689
        HDC hdc = GetDC(info.window);
690
        if (hdc)
691
        {
692
            const char *const extensions = mwglGetExtensionsString(hdc);
693
            if (extensions)
694
            {
695
                logger->log1("wGL extensions:");
696
                logger->log1(extensions);
697
                splitToStringSet(mPlatformExtensions, extensions, ' ');
698
            }
699
        }
700
#elif defined USE_X11
701
        Display *const display = info.info.x11.display;
702
        if (display)
703
        {
704
            Screen *const screen = XDefaultScreenOfDisplay(display);
705
            if (!screen)
706
                return;
707
708
            const int screenNum = XScreenNumberOfScreen(screen);
709
            const char *const extensions = glXQueryExtensionsString(
710
                display, screenNum);
711
            if (extensions)
712
            {
713
                logger->log1("glx extensions:");
714
                logger->log1(extensions);
715
                splitToStringSet(mPlatformExtensions, extensions, ' ');
716
            }
717
            glXQueryVersion(display, &mPlatformMajor, &mPlatformMinor);
718
            if (checkPlatformVersion(1, 1))
719
            {
720
                const char *const vendor1 = glXQueryServerString(
721
                    display, screenNum, GLX_VENDOR);
722
                if (vendor1)
723
                    logger->log("glx server vendor: %s", vendor1);
724
                const char *const version1 = glXQueryServerString(
725
                    display, screenNum, GLX_VERSION);
726
                if (version1)
727
                    logger->log("glx server version: %s", version1);
728
                const char *const extensions1 = glXQueryServerString(
729
                    display, screenNum, GLX_EXTENSIONS);
730
                if (extensions1)
731
                {
732
                    logger->log1("glx server extensions:");
733
                    logger->log1(extensions1);
734
                }
735
736
                const char *const vendor2 = glXGetClientString(
737
                    display, GLX_VENDOR);
738
                if (vendor2)
739
                    logger->log("glx client vendor: %s", vendor2);
740
                const char *const version2 = glXGetClientString(
741
                    display, GLX_VERSION);
742
                if (version2)
743
                    logger->log("glx client version: %s", version2);
744
                const char *const extensions2 = glXGetClientString(
745
                    display, GLX_EXTENSIONS);
746
                if (extensions2)
747
                {
748
                    logger->log1("glx client extensions:");
749
                    logger->log1(extensions2);
750
                }
751
            }
752
            logger->log("width=%d", DisplayWidth(display, screenNum));
753
        }
754
#endif  // WIN32
755
    }
756
}
757
758
bool GraphicsManager::supportExtension(const std::string &ext) const
759
{
760
    return mExtensions.find(ext) != mExtensions.end();
761
}
762
763
void GraphicsManager::updateTextureCompressionFormat() const
764
{
765
    const int compressionFormat = config.getIntValue("compresstextures");
766
    // using extensions if can
767
    if (checkGLVersion(3, 1) ||
768
        checkGLesVersion(2, 0) ||
769
        supportExtension("GL_ARB_texture_compression"))
770
    {
771
        GLint num = 0;
772
        mglGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num);
773
        logger->log("support %d compressed formats", num);
774
        GLint *const formats = new GLint[num > 10
775
            ? CAST_SIZE(num) : 10];
776
        mglGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
777
        for (int f = 0; f < num; f ++)
778
            logger->log(" 0x%x", CAST_U32(formats[f]));
779
780
        if (compressionFormat)
781
        {
782
            for (int f = 0; f < num; f ++)
783
            {
784
                switch (formats[f])
785
                {
786
                    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
787
                        if (compressionFormat == 1)
788
                        {
789
                            delete []formats;
790
                            useCompression(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
791
                            return;
792
                        }
793
                        break;
794
                    case GL_COMPRESSED_RGBA_FXT1_3DFX:
795
                        if (compressionFormat == 2)
796
                        {
797
                            delete []formats;
798
                            useCompression(GL_COMPRESSED_RGBA_FXT1_3DFX)
799
                            return;
800
                        }
801
                        break;
802
                    case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
803
                        if (compressionFormat == 4)
804
                        {
805
                            delete []formats;
806
                            useCompression(GL_COMPRESSED_RGBA_BPTC_UNORM_ARB)
807
                            return;
808
                        }
809
                        break;
810
                    default:
811
                        break;
812
                }
813
            }
814
            if (compressionFormat == 3)
815
            {
816
                delete []formats;
817
                useCompression(GL_COMPRESSED_RGBA_ARB)
818
                return;
819
            }
820
821
            // workaround for MESA bptc compression detection
822
            if (compressionFormat == 4
823
                && supportExtension("GL_ARB_texture_compression_bptc"))
824
            {
825
                delete []formats;
826
                useCompression(GL_COMPRESSED_RGBA_BPTC_UNORM_ARB)
827
                return;
828
            }
829
        }
830
        delete []formats;
831
        if (compressionFormat)
832
            logger->log1("no correct compression format found");
833
    }
834
    else
835
    {
836
        if (compressionFormat)
837
            logger->log1("no correct compression format found");
838
    }
839
}
840
841
void GraphicsManager::updateTextureFormat()
842
{
843
    const int renderer = settings.options.renderer;
844
845
    // using default formats
846
    if (renderer == RENDER_MODERN_OPENGL ||
847
        renderer == RENDER_GLES_OPENGL ||
848
        renderer == RENDER_GLES2_OPENGL ||
849
        config.getBoolValue("newtextures"))
850
    {
851
        OpenGLImageHelper::setInternalTextureType(GL_RGBA);
852
#if !defined(ANDROID) && !defined(__SWITCH__)
853
        SafeOpenGLImageHelper::setInternalTextureType(GL_RGBA);
854
#endif  // ANDROID
855
856
        logger->log1("using RGBA texture format");
857
    }
858
    else
859
    {
860
        OpenGLImageHelper::setInternalTextureType(4);
861
#if !defined(ANDROID) && !defined(__SWITCH__)
862
        SafeOpenGLImageHelper::setInternalTextureType(4);
863
#endif  // ANDROID
864
865
        logger->log1("using 4 texture format");
866
    }
867
}
868
869
void GraphicsManager::logString(const char *const format, const int num)
870
{
871
    const char *str = reinterpret_cast<const char*>(mglGetString(num));
872
    if (!str)
873
        logger->log(format, "?");
874
    else
875
        logger->log(format, str);
876
}
877
878
std::string GraphicsManager::getGLString(const int num)
879
{
880
    const char *str = reinterpret_cast<const char*>(mglGetString(num));
881
    return str ? str : "";
882
}
883
884
void GraphicsManager::setGLVersion()
885
{
886
    mGlVersionString = getGLString(GL_VERSION);
887
    std::string version = mGlVersionString;
888
    if (findCutFirst(version, "OpenGL ES "))
889
        mGles = true;
890
    sscanf(version.c_str(), "%5d.%5d", &mMajor, &mMinor);
891
    logger->log("Detected gl version: %d.%d", mMajor, mMinor);
892
    mGlVendor = getGLString(GL_VENDOR);
893
    mGlRenderer = getGLString(GL_RENDERER);
894
    mGlShaderVersionString = getGLString(GL_SHADING_LANGUAGE_VERSION);
895
    version = mGlShaderVersionString;
896
    cutFirst(version, "OpenGL ES GLSL ES ");
897
    cutFirst(version, "OpenGL ES GLSL ");
898
    cutFirst(version, "OpenGL ES ");
899
    sscanf(version.c_str(), "%5d.%5d", &mSLMajor, &mSLMinor);
900
    logger->log("Detected glsl version: %d.%d", mSLMajor, mSLMinor);
901
#ifdef ANDROID
902
    if (!mMajor && !mMinor)
903
    {
904
        logger->log("Overriding detected OpenGL version on Android to 1.0");
905
        mGles = true;
906
        mMajor = 1;
907
        mMinor = 0;
908
    }
909
#endif  // ANDROID
910
}
911
912
void GraphicsManager::logVersion() const
913
{
914
    logger->log("gl vendor: " + mGlVendor);
915
    logger->log("gl renderer: " + mGlRenderer);
916
    logger->log("gl version: " + mGlVersionString);
917
    logger->log("glsl version: " + mGlShaderVersionString);
918
}
919
920
bool GraphicsManager::checkGLVersion(const int major, const int minor) const
921
{
922
    return mMajor > major || (mMajor == major && mMinor >= minor);
923
}
924
925
bool GraphicsManager::checkSLVersion(const int major, const int minor) const
926
{
927
    return mSLMajor > major || (mSLMajor == major && mSLMinor >= minor);
928
}
929
930
bool GraphicsManager::checkGLesVersion(const int major, const int minor) const
931
{
932
    return mGles && (mMajor > major || (mMajor == major && mMinor >= minor));
933
}
934
935
bool GraphicsManager::checkPlatformVersion(const int major,
936
                                           const int minor) const
937
{
938
    return mPlatformMajor > major || (mPlatformMajor == major
939
        && mPlatformMinor >= minor);
940
}
941
942
void GraphicsManager::createFBO(const int width, const int height,
943
                                FBOInfo *const fbo)
944
{
945
    if (!fbo)
946
        return;
947
948
    // create a texture object
949
    glGenTextures(1, &fbo->textureId);
950
    glBindTexture(OpenGLImageHelper::mTextureType, fbo->textureId);
951
    glTexParameterf(OpenGLImageHelper::mTextureType,
952
        GL_TEXTURE_MAG_FILTER, GL_LINEAR);
953
    glTexParameterf(OpenGLImageHelper::mTextureType,
954
        GL_TEXTURE_MIN_FILTER, GL_LINEAR);
955
    glTexParameterf(OpenGLImageHelper::mTextureType,
956
        GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
957
    glTexParameterf(OpenGLImageHelper::mTextureType,
958
        GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
959
    glTexImage2D(OpenGLImageHelper::mTextureType, 0, GL_RGBA8, width, height,
960
        0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
961
    glBindTexture(OpenGLImageHelper::mTextureType, 0);
962
963
    // create a renderbuffer object to store depth info
964
    mglGenRenderbuffers(1, &fbo->rboId);
965
    mglBindRenderbuffer(GL_RENDERBUFFER, fbo->rboId);
966
    mglRenderbufferStorage(GL_RENDERBUFFER,
967
        GL_DEPTH_COMPONENT, width, height);
968
    mglBindRenderbuffer(GL_RENDERBUFFER, 0);
969
970
    // create a framebuffer object
971
    mglGenFramebuffers(1, &fbo->fboId);
972
    mglBindFramebuffer(GL_FRAMEBUFFER, fbo->fboId);
973
974
    // attach the texture to FBO color attachment point
975
    mglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
976
        OpenGLImageHelper::mTextureType, fbo->textureId, 0);
977
978
    // attach the renderbuffer to depth attachment point
979
    mglFramebufferRenderbuffer(GL_FRAMEBUFFER,
980
        GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->rboId);
981
982
    mglBindFramebuffer(GL_FRAMEBUFFER, fbo->fboId);
983
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
984
}
985
986
void GraphicsManager::deleteFBO(FBOInfo *const fbo)
987
{
988
    if (!fbo)
989
        return;
990
991
    mglBindFramebuffer(GL_FRAMEBUFFER, 0);
992
    if (fbo->fboId)
993
    {
994
        mglDeleteFramebuffers(1, &fbo->fboId);
995
        fbo->fboId = 0;
996
    }
997
    mglBindRenderbuffer(GL_RENDERBUFFER, 0);
998
    if (fbo->rboId)
999
    {
1000
        mglDeleteRenderbuffers(1, &fbo->rboId);
1001
        fbo->rboId = 0;
1002
    }
1003
    if (fbo->textureId)
1004
    {
1005
        glDeleteTextures(1, &fbo->textureId);
1006
        fbo->textureId = 0;
1007
    }
1008
}
1009
1010
void GraphicsManager::initOpenGLFunctions()
1011
{
1012
#ifdef __native_client__
1013
    emulateFunction(glTextureSubImage2DEXT);
1014
#else  // __native_client__
1015
1016
    const bool is10 = checkGLVersion(1, 0);
1017
    const bool is11 = checkGLVersion(1, 1);
1018
    const bool is12 = checkGLVersion(1, 2);
1019
    const bool is13 = checkGLVersion(1, 3);
1020
    const bool is15 = checkGLVersion(1, 5);
1021
    const bool is20 = checkGLVersion(2, 0);
1022
    const bool is21 = checkGLVersion(2, 1);
1023
    const bool is30 = checkGLVersion(3, 0);
1024
    const bool is33 = checkGLVersion(3, 3);
1025
    const bool is41 = checkGLVersion(4, 1);
1026
    const bool is42 = checkGLVersion(4, 2);
1027
    const bool is43 = checkGLVersion(4, 3);
1028
    const bool is44 = checkGLVersion(4, 4);
1029
    const bool is45 = checkGLVersion(4, 5);
1030
    mSupportModernOpengl = true;
1031
1032
    // Texture sampler
1033
    if (is10 && (is33 || supportExtension("GL_ARB_sampler_objects")))
1034
    {
1035
        logger->log1("found GL_ARB_sampler_objects");
1036
        assignFunction(glGenSamplers)
1037
        assignFunction(glDeleteSamplers)
1038
        assignFunction(glBindSampler)
1039
        assignFunction(glSamplerParameteri)
1040
        if (isGLNotNull(mglGenSamplers)
1041
            && config.getBoolValue("useTextureSampler"))
1042
        {
1043
            mUseTextureSampler &= true;
1044
        }
1045
        else
1046
        {
1047
            mUseTextureSampler = false;
1048
        }
1049
    }
1050
    else
1051
    {
1052
        logger->log1("texture sampler not found");
1053
        mUseTextureSampler = false;
1054
    }
1055
1056
    if (!is11)
1057
    {
1058
        mSupportModernOpengl = false;
1059
        emulateFunction(glTextureSubImage2DEXT);
1060
        return;
1061
    }
1062
1063
/*
1064
    if (findI(mGlVendor, "NVIDIA") != std::string::npos ||
1065
        mGlVersionString.find("Mesa 10.6.") != std::string::npos ||
1066
        mGlVersionString.find("Mesa 11.1.1") != std::string::npos ||
1067
        mGlVersionString.find("Mesa 11.1.2") != std::string::npos ||
1068
        mGlVersionString.find("Mesa 11.1.3") != std::string::npos ||
1069
        mGlVersionString.find("Mesa 11.2") != std::string::npos ||
1070
        (findI(mGlRenderer, "AMD Radeon HD") != std::string::npos &&
1071
        (mGlVersionString.find(
1072
        "Compatibility Profile Context 14.") != std::string::npos ||
1073
        mGlVersionString.find(
1074
        "Compatibility Profile Context 15.") != std::string::npos)))
1075
    {
1076
        logger->log1("Not checked for DSA because on "
1077
            "NVIDIA or AMD or in Mesa it broken");
1078
        emulateFunction(glTextureSubImage2DEXT);
1079
    }
1080
    else
1081
*/
1082
    {   // not for NVIDIA. in NVIDIA atleast in windows drivers DSA is broken
1083
        // Mesa 10.6.3 show support for DSA, but it broken. Works in 10.7 dev
1084
        if (config.getBoolValue("enableDSA") == true)
1085
        {
1086
            if (is45)
1087
            {
1088
                logger->log1("found GL_EXT_direct_state_access");
1089
                assignFunction(glTextureSubImage2D)
1090
            }
1091
            else if (supportExtension("GL_EXT_direct_state_access"))
1092
            {
1093
                logger->log1("found GL_EXT_direct_state_access");
1094
                assignFunctionEmu2(glTextureSubImage2DEXT,
1095
                    "glTextureSubImage2DEXT")
1096
            }
1097
            else if (supportExtension("GL_ARB_direct_state_access"))
1098
            {
1099
                logger->log1("found GL_ARB_direct_state_access");
1100
                logger->log1("GL_EXT_direct_state_access not found");
1101
                assignFunction(glTextureSubImage2D)
1102
            }
1103
            else
1104
            {
1105
                logger->log1("GL_EXT_direct_state_access not found");
1106
                logger->log1("GL_ARB_direct_state_access not found");
1107
                emulateFunction(glTextureSubImage2DEXT);
1108
            }
1109
        }
1110
        else
1111
        {
1112
            logger->log1("Direct state access disabled in settings");
1113
            emulateFunction(glTextureSubImage2DEXT);
1114
        }
1115
    }
1116
1117
    if (is12 && (is42 || supportExtension("GL_ARB_texture_storage")))
1118
    {
1119
        logger->log1("found GL_ARB_texture_storage");
1120
        assignFunction(glTexStorage2D)
1121
    }
1122
    else
1123
    {
1124
        logger->log1("GL_ARB_texture_storage not found");
1125
    }
1126
1127
    if (is13 || supportExtension("GL_ARB_multitexture"))
1128
    {
1129
        logger->log1("found GL_ARB_multitexture or OpenGL 1.3");
1130
        assignFunction(glActiveTexture)
1131
    }
1132
    else
1133
    {
1134
        emulateFunction(glActiveTexture);
1135
        logger->log1("GL_ARB_multitexture not found");
1136
    }
1137
1138
    if (is20 || supportExtension("GL_ARB_explicit_attrib_location"))
1139
    {
1140
        logger->log1("found GL_ARB_explicit_attrib_location or OpenGL 2.0");
1141
        assignFunction(glBindAttribLocation)
1142
    }
1143
    else
1144
    {
1145
        logger->log1("GL_ARB_explicit_attrib_location not found");
1146
    }
1147
1148
    if (is30 || supportExtension("GL_ARB_framebuffer_object"))
1149
    {   // frame buffer supported
1150
        logger->log1("found GL_ARB_framebuffer_object");
1151
        assignFunction(glGenRenderbuffers)
1152
        assignFunction(glBindRenderbuffer)
1153
        assignFunction(glRenderbufferStorage)
1154
        assignFunction(glGenFramebuffers)
1155
        assignFunction(glBindFramebuffer)
1156
        assignFunction(glFramebufferTexture2D)
1157
        assignFunction(glFramebufferRenderbuffer)
1158
        assignFunction(glDeleteFramebuffers)
1159
        assignFunction(glDeleteRenderbuffers)
1160
        assignFunction(glCheckFramebufferStatus)
1161
    }
1162
    else if (supportExtension("GL_EXT_framebuffer_object"))
1163
    {   // old frame buffer extension
1164
        logger->log1("found GL_EXT_framebuffer_object");
1165
        assignFunctionEXT(glGenRenderbuffers)
1166
        assignFunctionEXT(glBindRenderbuffer)
1167
        assignFunctionEXT(glRenderbufferStorage)
1168
        assignFunctionEXT(glGenFramebuffers)
1169
        assignFunctionEXT(glBindFramebuffer)
1170
        assignFunctionEXT(glFramebufferTexture2D)
1171
        assignFunctionEXT(glFramebufferRenderbuffer)
1172
        assignFunctionEXT(glDeleteFramebuffers)
1173
        assignFunctionEXT(glDeleteRenderbuffers)
1174
    }
1175
    else
1176
    {   // no frame buffer support
1177
        logger->log1("GL_ARB_framebuffer_object or "
1178
            "GL_EXT_framebuffer_object not found");
1179
        config.setValue("usefbo", false);
1180
    }
1181
1182
    // debug extensions
1183
    if (is43 || supportExtension("GL_KHR_debug"))
1184
    {
1185
        logger->log1("found GL_KHR_debug");
1186
        assignFunction(glDebugMessageControl)
1187
        assignFunction(glDebugMessageCallback)
1188
        assignFunction(glPushDebugGroup)
1189
        assignFunction(glPopDebugGroup)
1190
        assignFunction(glObjectLabel)
1191
        mSupportDebug = 2;
1192
    }
1193
    else if (supportExtension("GL_ARB_debug_output"))
1194
    {
1195
        logger->log1("found GL_ARB_debug_output");
1196
        assignFunctionARB(glDebugMessageControl)
1197
        assignFunctionARB(glDebugMessageCallback)
1198
        mSupportDebug = 1;
1199
    }
1200
    else
1201
    {
1202
        logger->log1("debug extensions not found");
1203
        mSupportDebug = 0;
1204
    }
1205
1206
    if (supportExtension("GL_GREMEDY_frame_terminator"))
1207
    {
1208
        logger->log1("found GL_GREMEDY_frame_terminator");
1209
        assignFunction2(glFrameTerminator, "glFrameTerminatorGREMEDY")
1210
    }
1211
    else
1212
    {
1213
        logger->log1("GL_GREMEDY_frame_terminator not found");
1214
    }
1215
    if (is44 || supportExtension("GL_EXT_debug_label"))
1216
    {
1217
        logger->log1("found GL_EXT_debug_label");
1218
        assignFunction2(glLabelObject, "glObjectLabel")
1219
        if (isGLNull(mglLabelObject))
1220
            assignFunctionEXT(glLabelObject)
1221
        assignFunctionEXT(glGetObjectLabel)
1222
    }
1223
    else
1224
    {
1225
        logger->log1("GL_EXT_debug_label not found");
1226
    }
1227
    if (supportExtension("GL_GREMEDY_string_marker"))
1228
    {
1229
        logger->log1("found GL_GREMEDY_string_marker");
1230
        assignFunction2(glPushGroupMarker, "glStringMarkerGREMEDY")
1231
    }
1232
    else
1233
    {
1234
        logger->log1("GL_GREMEDY_string_marker not found");
1235
    }
1236
    if (supportExtension("GL_EXT_debug_marker"))
1237
    {
1238
        logger->log1("found GL_EXT_debug_marker");
1239
        assignFunctionEXT(glInsertEventMarker)
1240
        assignFunctionEXT(glPushGroupMarker)
1241
        assignFunctionEXT(glPopGroupMarker)
1242
    }
1243
    else
1244
    {
1245
        logger->log1("GL_EXT_debug_marker not found");
1246
    }
1247
    if (is15 && (is30 || supportExtension("GL_EXT_timer_query")))
1248
    {
1249
        logger->log1("found GL_EXT_timer_query");
1250
        assignFunction(glGenQueries)
1251
        assignFunction(glBeginQuery)
1252
        assignFunction(glEndQuery)
1253
        assignFunction(glDeleteQueries)
1254
        assignFunction(glGetQueryObjectiv)
1255
        assignFunctionEXT(glGetQueryObjectui64v)
1256
    }
1257
    else
1258
    {
1259
        logger->log1("GL_EXT_timer_query not supported");
1260
    }
1261
    if (is20 && (is43 || supportExtension("GL_ARB_invalidate_subdata")))
1262
    {
1263
        logger->log1("found GL_ARB_invalidate_subdata");
1264
        assignFunction(glInvalidateTexImage)
1265
    }
1266
    else
1267
    {
1268
        logger->log1("GL_ARB_invalidate_subdata not supported");
1269
    }
1270
    if (is21 && (is30 || supportExtension("GL_ARB_vertex_array_object")))
1271
    {
1272
        logger->log1("found GL_ARB_vertex_array_object");
1273
        assignFunction(glGenVertexArrays)
1274
        assignFunction(glBindVertexArray)
1275
        assignFunction(glDeleteVertexArrays)
1276
        assignFunction(glVertexAttribPointer)
1277
        assignFunction(glEnableVertexAttribArray)
1278
        assignFunction(glDisableVertexAttribArray)
1279
        assignFunction(glVertexAttribIPointer)
1280
    }
1281
    else
1282
    {
1283
        mSupportModernOpengl = false;
1284
        logger->log1("GL_ARB_vertex_array_object not found");
1285
    }
1286
    if (is20 || supportExtension("GL_ARB_vertex_buffer_object"))
1287
    {
1288
        assignFunction(glGenBuffers)
1289
        assignFunction(glDeleteBuffers)
1290
        assignFunction(glBindBuffer)
1291
        assignFunction(glBufferData)
1292
        assignFunction(glIsBuffer)
1293
    }
1294
    else
1295
    {
1296
        mSupportModernOpengl = false;
1297
        logger->log1("buffers extension not found");
1298
    }
1299
    if (is43 || supportExtension("GL_ARB_copy_image"))
1300
    {
1301
        logger->log1("found GL_ARB_copy_image");
1302
        assignFunction(glCopyImageSubData)
1303
    }
1304
    else
1305
    {
1306
        logger->log1("GL_ARB_copy_image not found");
1307
    }
1308
    if (is44 || supportExtension("GL_ARB_clear_texture"))
1309
    {
1310
        logger->log1("found GL_ARB_clear_texture");
1311
        assignFunction(glClearTexImage)
1312
        assignFunction(glClearTexSubImage)
1313
    }
1314
    else
1315
    {
1316
        logger->log1("GL_ARB_clear_texture not found");
1317
    }
1318
    if (is20 || supportExtension("GL_ARB_shader_objects"))
1319
    {
1320
        logger->log1("found GL_ARB_shader_objects");
1321
        assignFunction(glCreateShader)
1322
        assignFunction(glDeleteShader)
1323
        assignFunction(glGetShaderiv)
1324
        assignFunction(glGetShaderInfoLog)
1325
        assignFunction(glGetShaderSource)
1326
        assignFunction(glShaderSource)
1327
        assignFunction(glCompileShader)
1328
        assignFunction(glLinkProgram)
1329
        assignFunction(glGetProgramInfoLog)
1330
        assignFunction(glDeleteProgram)
1331
        assignFunction(glCreateProgram)
1332
        assignFunction(glAttachShader)
1333
        assignFunction(glDetachShader)
1334
        assignFunction(glGetAttachedShaders)
1335
        assignFunction(glGetUniformLocation)
1336
        assignFunction(glGetActiveUniform)
1337
        assignFunction(glGetProgramiv)
1338
        assignFunction(glUseProgram)
1339
        assignFunction(glValidateProgram)
1340
        assignFunction(glGetAttribLocation)
1341
        assignFunction(glUniform1f)
1342
        assignFunction(glUniform2f)
1343
        assignFunction(glUniform3f)
1344
        assignFunction(glUniform4f)
1345
1346
        if (is30 || supportExtension("GL_EXT_gpu_shader4"))
1347
        {
1348
            logger->log1("found GL_EXT_gpu_shader4");
1349
            assignFunction(glBindFragDataLocation)
1350
        }
1351
        else
1352
        {
1353
            mSupportModernOpengl = false;
1354
            logger->log1("GL_EXT_gpu_shader4 not supported");
1355
        }
1356
        if (is41 || supportExtension("GL_ARB_separate_shader_objects"))
1357
        {
1358
            logger->log1("found GL_ARB_separate_shader_objects");
1359
            assignFunction(glProgramUniform1f)
1360
            assignFunction(glProgramUniform2f)
1361
            assignFunction(glProgramUniform3f)
1362
            assignFunction(glProgramUniform4f)
1363
        }
1364
        else
1365
        {
1366
            logger->log1("GL_ARB_separate_shader_objects not supported");
1367
        }
1368
        if (is43 || supportExtension("GL_ARB_vertex_attrib_binding"))
1369
        {
1370
            logger->log1("found GL_ARB_vertex_attrib_binding");
1371
            assignFunction(glBindVertexBuffer)
1372
            assignFunction(glVertexAttribBinding)
1373
            assignFunction(glVertexAttribFormat)
1374
            assignFunction(glVertexAttribIFormat)
1375
        }
1376
        else
1377
        {
1378
            mSupportModernOpengl = false;
1379
            logger->log1("GL_ARB_vertex_attrib_binding not supported");
1380
        }
1381
        if (is44 || supportExtension("GL_ARB_multi_bind"))
1382
        {
1383
            logger->log1("found GL_ARB_multi_bind");
1384
            assignFunction(glBindVertexBuffers)
1385
        }
1386
        else
1387
        {
1388
            logger->log1("GL_ARB_multi_bind not supported");
1389
        }
1390
    }
1391
    else
1392
    {
1393
        mSupportModernOpengl = false;
1394
        logger->log1("shaders not supported");
1395
    }
1396
1397
#ifdef WIN32
1398
    assignFunctionARB(wglGetExtensionsString)
1399
#endif  // WIN32
1400
#endif  // __native_client__
1401
}
1402
1403
void GraphicsManager::updateLimits()
1404
{
1405
    GLint value = 0;
1406
#ifdef __native_client__
1407
    mMaxVertices = 500;
1408
#else  // __native_client__
1409
1410
    glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &value);
1411
    logger->log("GL_MAX_ELEMENTS_VERTICES: %d", value);
1412
1413
    mMaxVertices = value;
1414
1415
    value = 0;
1416
    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &value);
1417
    logger->log("GL_MAX_ELEMENTS_INDICES: %d", value);
1418
    if (value < mMaxVertices)
1419
        mMaxVertices = value;
1420
    if (!mMaxVertices)
1421
    {
1422
        logger->log("Got 0 max amount of vertices or indicies. "
1423
            "Overriding to 500");
1424
        mMaxVertices = 500;
1425
    }
1426
#endif  // __native_client__
1427
1428
    value = 0;
1429
    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &value);
1430
    logger->log("Max FBO size: %d", value);
1431
    mMaxFboSize = value;
1432
}
1433
1434
void GraphicsManager::initOpenGL()
1435
{
1436
    setGLVersion();
1437
    updateExtensions();
1438
    initOpenGLFunctions();
1439
    updatePlanformExtensions();
1440
    updateDebugLog();
1441
    createTextureSampler();
1442
    updateLimits();
1443
}
1444
1445
void GraphicsManager::createTextureSampler()
1446
{
1447
    GLenum err = getLastError();
1448
    if (err)
1449
        logger->log(errorToString(err));
1450
    if (mUseTextureSampler)
1451
    {
1452
        logger->log1("using texture sampler");
1453
        mglGenSamplers(1, &mTextureSampler);
1454
        if (getLastError() != GL_NO_ERROR)
1455
        {
1456
            mUseTextureSampler = false;
1457
            logger->log1("texture sampler error");
1458
            OpenGLImageHelper::setUseTextureSampler(mUseTextureSampler);
1459
            return;
1460
        }
1461
        OpenGLImageHelper::initTextureSampler(mTextureSampler);
1462
        mglBindSampler(0, mTextureSampler);
1463
        if (getLastError() != GL_NO_ERROR)
1464
        {
1465
            mUseTextureSampler = false;
1466
            logger->log1("texture sampler error");
1467
        }
1468
    }
1469
    OpenGLImageHelper::setUseTextureSampler(mUseTextureSampler);
1470
#if !defined(ANDROID) && !defined(__SWITCH__)
1471
    SafeOpenGLImageHelper::setUseTextureSampler(false);
1472
#endif  // ANDROID
1473
}
1474
1475
GLenum GraphicsManager::getLastError()
1476
{
1477
    GLenum tmp = glGetError();
1478
    GLenum error = GL_NO_ERROR;
1479
    while (tmp != GL_NO_ERROR)
1480
    {
1481
        error = tmp;
1482
        mLastError = tmp;
1483
        tmp = glGetError();
1484
    }
1485
    return error;
1486
}
1487
1488
std::string GraphicsManager::errorToString(const GLenum error)
1489
{
1490
    if (error)
1491
    {
1492
        std::string errmsg("Unknown error");
1493
        switch (error)
1494
        {
1495
            case GL_INVALID_ENUM:
1496
                errmsg = "GL_INVALID_ENUM";
1497
                break;
1498
            case GL_INVALID_VALUE:
1499
                errmsg = "GL_INVALID_VALUE";
1500
                break;
1501
            case GL_INVALID_OPERATION:
1502
                errmsg = "GL_INVALID_OPERATION";
1503
                break;
1504
            case GL_STACK_OVERFLOW:
1505
                errmsg = "GL_STACK_OVERFLOW";
1506
                break;
1507
            case GL_STACK_UNDERFLOW:
1508
                errmsg = "GL_STACK_UNDERFLOW";
1509
                break;
1510
            case GL_OUT_OF_MEMORY:
1511
                errmsg = "GL_OUT_OF_MEMORY";
1512
                break;
1513
            default:
1514
                break;
1515
        }
1516
        return "OpenGL error: " + errmsg;
1517
    }
1518
    return "";
1519
}
1520
1521
void GraphicsManager::logError()
1522
{
1523
    const GLenum error = GraphicsManager::getLastError();
1524
    if (error != GL_NO_ERROR)
1525
        logger->log(errorToString(error));
1526
}
1527
1528
void GraphicsManager::detectVideoSettings()
1529
{
1530
    config.setValue("videodetected", true);
1531
    TestMain *const test = startDetection();
1532
1533
    if (test)
1534
    {
1535
        const Configuration &conf = test->getConfig();
1536
        int val = conf.getValueInt("opengl", -1);
1537
        if (val >= 0 && val < CAST_S32(RENDER_LAST))
1538
        {
1539
            config.setValue("opengl", val);
1540
            val = conf.getValue("useTextureSampler", -1);
1541
            if (val != -1)
1542
                config.setValue("useTextureSampler", val);
1543
            val = conf.getValue("compresstextures", -1);
1544
            if (val != -1)
1545
                config.setValue("compresstextures", val);
1546
        }
1547
        config.setValue("textureSize", conf.getValue("textureSize",
1548
            "1024,1024,1024,1024,1024,1024"));
1549
        config.setValue("testInfo", conf.getValue("testInfo", ""));
1550
        config.setValue("sound", conf.getValue("sound", 0));
1551
        delete test;
1552
    }
1553
}
1554
1555
static CALLBACK void debugCallback(GLenum source,
1556
                                   GLenum type,
1557
                                   GLuint id,
1558
                                   GLenum severity,
1559
                                   GLsizei length,
1560
                                   const GLchar *text,
1561
                                   GLvoid *userParam A_UNUSED)
1562
{
1563
    std::string message("OPENGL:");
1564
    switch (source)
1565
    {
1566
        case GL_DEBUG_SOURCE_API:
1567
            message.append(" API");
1568
            break;
1569
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
1570
            message.append(" WM");
1571
            break;
1572
        case GL_DEBUG_SOURCE_SHADER_COMPILER:
1573
            message.append(" SHADERS");
1574
            break;
1575
        case GL_DEBUG_SOURCE_THIRD_PARTY:
1576
            message.append(" THIRD_PARTY");
1577
            break;
1578
        case GL_DEBUG_SOURCE_APPLICATION:
1579
            message.append(" APP");
1580
            break;
1581
        case GL_DEBUG_SOURCE_OTHER:
1582
            message.append(" OTHER");
1583
            break;
1584
        default:
1585
            message.append(" ?").append(toString(source));
1586
            break;
1587
    }
1588
    switch (type)
1589
    {
1590
        case GL_DEBUG_TYPE_ERROR:
1591
            message.append(" ERROR");
1592
            break;
1593
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
1594
            message.append(" DEPRECATED");
1595
            break;
1596
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
1597
            message.append(" UNDEFINED");
1598
            break;
1599
        case GL_DEBUG_TYPE_PORTABILITY:
1600
            message.append(" PORTABILITY");
1601
            break;
1602
        case GL_DEBUG_TYPE_PERFORMANCE:
1603
            message.append(" PERFORMANCE");
1604
            break;
1605
        case GL_DEBUG_TYPE_OTHER:
1606
            message.append(" OTHER");
1607
            break;
1608
        case GL_DEBUG_TYPE_MARKER:
1609
            message.append(" MARKER");
1610
            break;
1611
        case GL_DEBUG_TYPE_PUSH_GROUP:
1612
            message.append(" PUSH GROUP");
1613
            break;
1614
        case GL_DEBUG_TYPE_POP_GROUP:
1615
            message.append(" POP GROUP");
1616
            break;
1617
        default:
1618
            message.append(" ?").append(toString(type));
1619
            break;
1620
    }
1621
    message.append(" ").append(toString(id));
1622
    switch (severity)
1623
    {
1624
        case GL_DEBUG_SEVERITY_NOTIFICATION:
1625
            message.append(" N");
1626
            break;
1627
        case GL_DEBUG_SEVERITY_HIGH:
1628
            message.append(" H");
1629
            break;
1630
        case GL_DEBUG_SEVERITY_MEDIUM:
1631
            message.append(" M");
1632
            break;
1633
        case GL_DEBUG_SEVERITY_LOW:
1634
            message.append(" L");
1635
            break;
1636
        default:
1637
            message.append(" ?").append(toString(type));
1638
            break;
1639
    }
1640
    char *const buf = new char[CAST_SIZE(length + 1)];
1641
    memcpy(buf, text, length);
1642
    buf[length] = 0;
1643
    message.append(" ").append(buf);
1644
    delete [] buf;
1645
    logger->log(message);
1646
}
1647
1648
void GraphicsManager::updateDebugLog() const
1649
{
1650
    if (mSupportDebug && config.getIntValue("debugOpenGL"))
1651
    {
1652
        logger->log1("Enable OpenGL debug log");
1653
        glEnable(GL_DEBUG_OUTPUT);
1654
        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1655
1656
        mglDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE,
1657
            0, nullptr, GL_TRUE);
1658
        mglDebugMessageCallback(&debugCallback, this);
1659
    }
1660
}
1661
#endif  // USE_OPENGL
1662
1663
void GraphicsManager::detectPixelSize()
1664
{
1665
    SDL_SysWMinfo info;
1666
    SDL_VERSION(&info.version)
1667
    if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info))
1668
    {
1669
#ifdef WIN32
1670
        HDC hdc = GetDC(info.window);
1671
        if (hdc)
1672
        {
1673
//            SetProcessDPIAware();
1674
            mMaxWidth = GetDeviceCaps(hdc, HORZRES);
1675
            mMaxHeight = GetDeviceCaps(hdc, VERTRES);
1676
            mWidthMM = GetDeviceCaps(hdc, HORZSIZE);
1677
            mHeightMM = GetDeviceCaps(hdc, VERTSIZE);
1678
        }
1679
#elif defined USE_X11
1680
        Display *const display = info.info.x11.display;
1681
        if (display)
1682
        {
1683
            Screen *const screen = XDefaultScreenOfDisplay(display);
1684
            if (!screen)
1685
                return;
1686
1687
            const int screenNum = XScreenNumberOfScreen(screen);
1688
            mMaxWidth = DisplayWidth(display, screenNum);
1689
            mMaxHeight = DisplayHeight(display, screenNum);
1690
            mWidthMM = DisplayWidthMM(display, screenNum);
1691
            mHeightMM = DisplayHeightMM(display, screenNum);
1692
        }
1693
#endif  // WIN32
1694
    }
1695
#if defined ANDROID
1696
#ifdef USE_SDL2
1697
    const int dpi = atoi(getenv("DISPLAY_DPI"));
1698
    if (dpi <= 120)
1699
        mDensity = 0;
1700
    else if (dpi <= 160)
1701
        mDensity = 1;
1702
    else if (dpi <= 213)
1703
        mDensity = 2;
1704
    else if (dpi <= 240)
1705
        mDensity = 3;
1706
    else if (dpi <= 320)
1707
        mDensity = 4;
1708
//    else if (dpi <= 480)
1709
    else
1710
        mDensity = 5;
1711
    mMaxWidth = atoi(getenv("DISPLAY_RESOLUTION_WIDTH"));
1712
    mMaxHeight = atoi(getenv("DISPLAY_RESOLUTION_HEIGHT"));
1713
    mWidthMM = atoi(getenv("DISPLAY_WIDTH_MM"));
1714
    mHeightMM = atoi(getenv("DISPLAY_HEIGHT_MM"));
1715
#else  // USE_SDL2
1716
1717
    SDL_ANDROID_GetMetrics(&mMaxWidth, &mMaxHeight,
1718
        &mWidthMM, &mHeightMM, &mDensity);
1719
#endif  // USE_SDL2
1720
#endif  // defined ANDROID
1721
1722
    logger->log("screen size in pixels: %ux%u", mMaxWidth, mMaxHeight);
1723
    logger->log("screen size in millimeters: %ux%u", mWidthMM, mHeightMM);
1724
    logger->log("actual screen density: " + getDensityString());
1725
    const int density = config.getIntValue("screenDensity");
1726
    if (density > 0 && density <= densitySize)
1727
    {
1728
        mDensity = density - 1;
1729
        logger->log("selected screen density: " + getDensityString());
1730
    }
1731
}
1732
1733
216
std::string GraphicsManager::getDensityString() const
1734
{
1735
216
    if (mDensity >= 0 && mDensity < densitySize)
1736
        return densityNames[mDensity];
1737
432
    return "";
1738

3
}