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

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



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

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

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

3
}