GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/graphicsmanager.cpp Lines: 22 740 3.0 %
Date: 2017-11-29 Branches: 17 1306 1.3 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2017  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
    OpenGLImageHelper::setInternalTextureType(name); \
109
    logger->log("using " #name " texture compression");
110
#endif  // USE_OPENGL
111
112
2
GraphicsManager graphicsManager;
113
114
RenderType openGLMode = RENDER_SOFTWARE;
115
116
ScreenshotHelper *screenshortHelper = nullptr;
117
118
const int densitySize = 6;
119
120
6
const std::string densityNames[] =
121
{
122
    "low",
123
    "medium",
124
    "tv",
125
    "high",
126
    "xhigh",
127
    "xxhigh"
128



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

2
    if (isGLNotNull(mglGenSamplers) && mTextureSampler)
169
        mglDeleteSamplers(1, &mTextureSampler);
170
#endif  // USE_OPENGL
171
2
}
172
173
#ifdef USE_OPENGL
174
TestMain *GraphicsManager::startDetection()
175
{
176
    TestMain *const test = new TestMain;
177
    test->exec(false);
178
    return test;
179
}
180
181
int GraphicsManager::detectGraphics()
182
{
183
    logger->log1("start detecting best mode...");
184
    logger->log1("enable opengl mode");
185
    int textureSampler = 0;
186
    int compressTextures = 0;
187
#if !defined(ANDROID) && !defined(__native_client__)
188
    mainGraphics = new NormalOpenGLGraphics;
189
#endif  // !defined(ANDROID) && !defined(__native_client__)
190
191
    SDL_Window *const window = createWindow(100, 100, 0,
192
        SDL_ANYFORMAT | SDL_OPENGL);
193
    mainGraphics->setWindow(window, 100, 100);
194
    mainGraphics->createGLContext(false);
195
196
    initOpenGL();
197
    logVersion();
198
199
    RenderType mode = RENDER_NORMAL_OPENGL;
200
201
    // detecting features by known renderers or vendors
202
    if (findI(mGlRenderer, "gdi generic") != std::string::npos)
203
    {
204
        // windows gdi OpenGL emulation
205
        logger->log("detected gdi drawing");
206
        logger->log("disable OpenGL");
207
        mode = RENDER_SOFTWARE;
208
    }
209
    else if (findI(mGlRenderer, "Software Rasterizer") != std::string::npos)
210
    {
211
        // software OpenGL emulation
212
        logger->log("detected software drawing");
213
        logger->log("disable OpenGL");
214
        mode = RENDER_SOFTWARE;
215
    }
216
    else if (findI(mGlRenderer, "Indirect") != std::string::npos)
217
    {
218
        // indirect OpenGL drawing
219
        logger->log("detected indirect drawing");
220
        logger->log("disable OpenGL");
221
        mode = RENDER_SOFTWARE;
222
    }
223
    else if (findI(mGlVendor, "VMWARE") != std::string::npos)
224
    {
225
        // vmware emulation
226
        logger->log("detected VMWARE driver");
227
        logger->log("disable OpenGL");
228
        mode = RENDER_SOFTWARE;
229
    }
230
    else if (findI(mGlVendor, "NVIDIA") != std::string::npos)
231
    {
232
        // hope it can work well
233
        logger->log("detected NVIDIA driver");
234
        config.setValue("useTextureSampler", true);
235
        textureSampler = 1;
236
        mode = RENDER_NORMAL_OPENGL;
237
    }
238
239
    // detecting feature based on OpenGL version
240
    if (!checkGLVersion(1, 1))
241
    {
242
        // very old OpenGL version
243
        logger->log("OpenGL version too old");
244
        mode = RENDER_SOFTWARE;
245
    }
246
247
    if (mode != RENDER_SOFTWARE && findI(mGlVersionString, "Mesa")
248
        != std::string::npos)
249
    {
250
        // Mesa detected. In latest Mesa look like compression broken.
251
        config.setValue("compresstextures", false);
252
        compressTextures = 0;
253
    }
254
255
    config.setValue("opengl", CAST_S32(mode));
256
    config.setValue("videoconfigured", true);
257
    config.write();
258
259
    logger->log("detection complete");
260
    return CAST_U32(mode)
261
        | (1024 * textureSampler) | (2048 * compressTextures);
262
}
263
264
#ifdef USE_SDL2
265
#define RENDER_SOFTWARE_INIT \
266
    imageHelper = new SDL2SoftwareImageHelper; \
267
    surfaceImageHelper = new SurfaceImageHelper; \
268
    mainGraphics = new SDL2SoftwareGraphics; \
269
    screenshortHelper = new Sdl2SoftwareScreenshotHelper;
270
#define RENDER_SDL2_DEFAULT_INIT \
271
    imageHelper = new SDLImageHelper; \
272
    surfaceImageHelper = new SurfaceImageHelper; \
273
    mainGraphics = new SDLGraphics; \
274
    screenshortHelper = new SdlScreenshotHelper; \
275
    mainGraphics->setRendererFlags(SDL_RENDERER_ACCELERATED); \
276
    mUseTextureSampler = false;
277
#else  // USE_SDL2
278
#define RENDER_SOFTWARE_INIT \
279
    imageHelper = new SDLImageHelper; \
280
    surfaceImageHelper = imageHelper; \
281
    mainGraphics = new SDLGraphics; \
282
    screenshortHelper = new SdlScreenshotHelper;
283
#define RENDER_SDL2_DEFAULT_INIT
284
#endif  // USE_SDL2
285
286
#if defined(ANDROID) || defined(__native_client__)
287
#define RENDER_NORMAL_OPENGL_INIT
288
#define RENDER_MODERN_OPENGL_INIT
289
#else  // defined(ANDROID) || defined(__native_client__)
290
#define RENDER_NORMAL_OPENGL_INIT \
291
    imageHelper = new OpenGLImageHelper; \
292
    surfaceImageHelper = new SurfaceImageHelper; \
293
    mainGraphics = new NormalOpenGLGraphics; \
294
    screenshortHelper = new OpenGLScreenshotHelper; \
295
    mUseTextureSampler = true;
296
#define RENDER_MODERN_OPENGL_INIT \
297
    imageHelper = new OpenGLImageHelper; \
298
    surfaceImageHelper = new SurfaceImageHelper; \
299
    mainGraphics = new ModernOpenGLGraphics; \
300
    screenshortHelper = new OpenGLScreenshotHelper; \
301
    mUseTextureSampler = true;
302
#endif  // defined(ANDROID) || defined(__native_client__)
303
304
#if defined(ANDROID)
305
#define RENDER_SAFE_OPENGL_INIT
306
#define RENDER_GLES2_OPENGL_INIT
307
#else  // defined(ANDROID)
308
#define RENDER_SAFE_OPENGL_INIT \
309
    imageHelper = new SafeOpenGLImageHelper; \
310
    surfaceImageHelper = new SurfaceImageHelper; \
311
    mainGraphics = new SafeOpenGLGraphics; \
312
    screenshortHelper = new OpenGLScreenshotHelper; \
313
    mUseTextureSampler = false;
314
#define RENDER_GLES2_OPENGL_INIT \
315
    imageHelper = new OpenGLImageHelper; \
316
    surfaceImageHelper = new SurfaceImageHelper; \
317
    mainGraphics = new MobileOpenGL2Graphics; \
318
    screenshortHelper = new MobileOpenGLScreenshotHelper; \
319
    mUseTextureSampler = false;
320
#endif  // defined(ANDROID)
321
322
#if defined(__native_client__)
323
#define RENDER_GLES_OPENGL_INIT
324
#else  // defined(__native_client__)
325
#define RENDER_GLES_OPENGL_INIT \
326
    imageHelper = new OpenGLImageHelper; \
327
    surfaceImageHelper = new SurfaceImageHelper; \
328
    mainGraphics = new MobileOpenGLGraphics; \
329
    screenshortHelper = new OpenGLScreenshotHelper; \
330
    mUseTextureSampler = false;
331
#endif  // defined(__native_client__)
332
333
void GraphicsManager::createRenderers()
334
{
335
    RenderType useOpenGL = RENDER_SOFTWARE;
336
    if (!settings.options.noOpenGL)
337
    {
338
        if (settings.options.renderer < 0)
339
        {
340
            useOpenGL = intToRenderType(config.getIntValue("opengl"));
341
            settings.options.renderer = CAST_S32(useOpenGL);
342
        }
343
        else
344
        {
345
            useOpenGL = intToRenderType(settings.options.renderer);
346
        }
347
    }
348
349
    // Setup image loading for the right image format
350
    ImageHelper::setOpenGlMode(useOpenGL);
351
352
    // Create the graphics context
353
    switch (useOpenGL)
354
    {
355
        case RENDER_SOFTWARE:
356
            RENDER_SOFTWARE_INIT
357
            mUseTextureSampler = false;
358
            break;
359
        case RENDER_LAST:
360
        case RENDER_NULL:
361
        default:
362
            break;
363
        case RENDER_NORMAL_OPENGL:
364
            RENDER_NORMAL_OPENGL_INIT
365
            break;
366
        case RENDER_SAFE_OPENGL:
367
            RENDER_SAFE_OPENGL_INIT
368
            break;
369
        case RENDER_MODERN_OPENGL:
370
            RENDER_MODERN_OPENGL_INIT
371
            break;
372
        case RENDER_GLES2_OPENGL:
373
            RENDER_GLES2_OPENGL_INIT
374
            break;
375
        case RENDER_GLES_OPENGL:
376
            RENDER_GLES_OPENGL_INIT
377
            break;
378
        case RENDER_SDL2_DEFAULT:
379
            RENDER_SDL2_DEFAULT_INIT
380
            break;
381
    };
382
    mUseAtlases = (useOpenGL == RENDER_NORMAL_OPENGL ||
383
        useOpenGL == RENDER_SAFE_OPENGL ||
384
        useOpenGL == RENDER_MODERN_OPENGL ||
385
        useOpenGL == RENDER_GLES_OPENGL ||
386
        useOpenGL == RENDER_GLES2_OPENGL) &&
387
        config.getBoolValue("useAtlases");
388
389
#else  // USE_OPENGL
390
391
void GraphicsManager::createRenderers()
392
{
393
    RenderType useOpenGL = RENDER_SOFTWARE;
394
    if (!settings.options.noOpenGL)
395
        useOpenGL = intToRenderType(config.getIntValue("opengl"));
396
397
    // Setup image loading for the right image format
398
    ImageHelper::setOpenGlMode(useOpenGL);
399
400
    // Create the graphics context
401
    switch (useOpenGL)
402
    {
403
        case RENDER_SOFTWARE:
404
        case RENDER_SAFE_OPENGL:
405
        case RENDER_GLES_OPENGL:
406
        case RENDER_GLES2_OPENGL:
407
        case RENDER_MODERN_OPENGL:
408
        case RENDER_NORMAL_OPENGL:
409
        case RENDER_NULL:
410
        case RENDER_LAST:
411
        default:
412
#ifndef USE_SDL2
413
        case RENDER_SDL2_DEFAULT:
414
            imageHelper = new SDLImageHelper;
415
            surfaceImageHelper = imageHelper;
416
            mainGraphics = new SDLGraphics;
417
            screenshortHelper = new SdlScreenshotHelper;
418
#else  // USE_SDL2
419
420
            imageHelper = new SDL2SoftwareImageHelper;
421
            surfaceImageHelper = new SurfaceImageHelper;
422
            mainGraphics = new SDL2SoftwareGraphics;
423
            screenshortHelper = new Sdl2SoftwareScreenshotHelper;
424
425
#endif  // USE_SDL2
426
427
            break;
428
#ifdef USE_SDL2
429
        case RENDER_SDL2_DEFAULT:
430
            imageHelper = new SDLImageHelper;
431
            surfaceImageHelper = new SurfaceImageHelper;
432
            mainGraphics = new SDLGraphics;
433
            mainGraphics->setRendererFlags(SDL_RENDERER_ACCELERATED);
434
            screenshortHelper = new SdlScreenshotHelper;
435
            break;
436
#endif  // USE_SDL2
437
    };
438
#endif  // USE_OPENGL
439
}
440
441
444
void GraphicsManager::deleteRenderers()
442
{
443
444
    delete2(mainGraphics);
444
444
    if (imageHelper != surfaceImageHelper)
445
444
        delete surfaceImageHelper;
446
444
    surfaceImageHelper = nullptr;
447
444
    delete2(imageHelper);
448
444
}
449
450
void GraphicsManager::setVideoMode()
451
{
452
    const int bpp = 0;
453
    const bool fullscreen = config.getBoolValue("screen");
454
    const bool hwaccel = config.getBoolValue("hwaccel");
455
    const bool enableResize = config.getBoolValue("enableresize");
456
    const bool noFrame = config.getBoolValue("noframe");
457
    const bool allowHighDPI = config.getBoolValue("allowHighDPI");
458
459
#ifdef ANDROID
460
//    int width = config.getValue("screenwidth", 0);
461
//    int height = config.getValue("screenheight", 0);
462
    StringVect videoModes;
463
    SDL::getAllVideoModes(videoModes);
464
    if (videoModes.empty())
465
        logger->error("no video modes detected");
466
    STD_VECTOR<int> res;
467
    splitToIntVector(res, videoModes[0], 'x');
468
    if (res.size() != 2)
469
        logger->error("no video modes detected");
470
471
    int width = res[0];
472
    int height = res[1];
473
#elif defined __native_client__
474
#ifdef USE_SDL2
475
    // not implemented
476
#else  // USE_SDL2
477
478
    const SDL_VideoInfo* info = SDL_GetVideoInfo();
479
    int width = info->current_w;
480
    int height = info->current_h;
481
#endif  // USE_SDL2
482
#else  // defined __native_client__
483
484
    int width = config.getIntValue("screenwidth");
485
    int height = config.getIntValue("screenheight");
486
#endif  // defined __native_client__
487
488
    const int scale = config.getIntValue("scale");
489
490
    // Try to set the desired video mode
491
    if (!mainGraphics->setVideoMode(width, height, scale, bpp,
492
        fullscreen, hwaccel, enableResize, noFrame, allowHighDPI))
493
    {
494
        logger->log(strprintf("Couldn't set %dx%dx%d video mode: %s",
495
            width, height, bpp, SDL_GetError()));
496
497
        const int oldWidth = config.getValueInt("oldscreenwidth", -1);
498
        const int oldHeight = config.getValueInt("oldscreenheight", -1);
499
        const int oldFullscreen = config.getValueInt("oldscreen", -1);
500
        if (oldWidth != -1 && oldHeight != -1 && oldFullscreen != -1)
501
        {
502
            config.deleteKey("oldscreenwidth");
503
            config.deleteKey("oldscreenheight");
504
            config.deleteKey("oldscreen");
505
506
            config.setValueInt("screenwidth", oldWidth);
507
            config.setValueInt("screenheight", oldHeight);
508
            config.setValue("screen", oldFullscreen == 1);
509
            if (!mainGraphics->setVideoMode(oldWidth, oldHeight,
510
                scale,
511
                bpp,
512
                oldFullscreen != 0,
513
                hwaccel,
514
                enableResize,
515
                noFrame,
516
                allowHighDPI))
517
            {
518
                logger->safeError(strprintf("Couldn't restore %dx%dx%d "
519
                    "video mode: %s", oldWidth, oldHeight, bpp,
520
                    SDL_GetError()));
521
            }
522
        }
523
    }
524
}
525
526
void GraphicsManager::initGraphics()
527
{
528
    openGLMode = intToRenderType(config.getIntValue("opengl"));
529
#ifdef USE_OPENGL
530
    OpenGLImageHelper::setBlur(config.getBoolValue("blur"));
531
#ifndef ANDROID
532
    SafeOpenGLImageHelper::setBlur(config.getBoolValue("blur"));
533
#endif  // ANDROID
534
    SurfaceImageHelper::SDLSetEnableAlphaCache(
535
        config.getBoolValue("alphaCache") &&
536
        openGLMode == RENDER_SOFTWARE);
537
    ImageHelper::setEnableAlpha((config.getFloatValue("guialpha") != 1.0F ||
538
        openGLMode != RENDER_SOFTWARE) &&
539
        config.getBoolValue("enableGuiOpacity"));
540
#else  // USE_OPENGL
541
    SurfaceImageHelper::SDLSetEnableAlphaCache(
542
        config.getBoolValue("alphaCache"));
543
    ImageHelper::setEnableAlpha(config.getFloatValue("guialpha") != 1.0F &&
544
        config.getBoolValue("enableGuiOpacity"));
545
#endif  // USE_OPENGL
546
    createRenderers();
547
    setVideoMode();
548
    detectPixelSize();
549
#ifdef USE_OPENGL
550
    if (config.getBoolValue("checkOpenGLVersion") == true)
551
    {
552
        const RenderType oldOpenGLMode = openGLMode;
553
        if (openGLMode == RENDER_MODERN_OPENGL)
554
        {
555
            if (!mSupportModernOpengl || !checkGLVersion(3, 0))
556
            {
557
                logger->log("Fallback to normal OpenGL mode");
558
                openGLMode = RENDER_NORMAL_OPENGL;
559
            }
560
        }
561
        if (openGLMode == RENDER_NORMAL_OPENGL)
562
        {
563
            if (!checkGLVersion(2, 0))
564
            {
565
                logger->log("Fallback to safe OpenGL mode");
566
                openGLMode = RENDER_SAFE_OPENGL;
567
            }
568
        }
569
        if (openGLMode == RENDER_GLES_OPENGL)
570
        {
571
            if (!checkGLVersion(2, 0) && !checkGLesVersion(1, 0))
572
            {
573
                logger->log("Fallback to safe OpenGL mode");
574
                openGLMode = RENDER_SAFE_OPENGL;
575
            }
576
        }
577
        if (openGLMode == RENDER_GLES2_OPENGL)
578
        {
579
            // +++ here need check also not implemented gles flag
580
            if (!checkGLVersion(2, 0))
581
            {
582
                logger->log("Fallback to software mode");
583
                openGLMode = RENDER_SOFTWARE;
584
            }
585
        }
586
587
        if (openGLMode != oldOpenGLMode)
588
        {
589
            deleteRenderers();
590
            settings.options.renderer = CAST_S32(openGLMode);
591
            config.setValue("opengl", settings.options.renderer);
592
            createRenderers();
593
            setVideoMode();
594
            detectPixelSize();
595
        }
596
    }
597
#if !defined(ANDROID) && !defined(__APPLE__)
598
    const std::string str = config.getStringValue("textureSize");
599
    STD_VECTOR<int> sizes;
600
    splitToIntVector(sizes, str, ',');
601
    const size_t pos = CAST_SIZE(openGLMode);
602
    if (sizes.size() <= pos)
603
        settings.textureSize = 1024;
604
    else
605
        settings.textureSize = sizes[pos];
606
    logger->log("Detected max texture size: %u", settings.textureSize);
607
#endif  // !defined(ANDROID) && !defined(__APPLE__)
608
#endif  // USE_OPENGL
609
}
610
611
#ifdef USE_SDL2
612
SDL_Window *GraphicsManager::createWindow(const int w, const int h,
613
                                          const int bpp A_UNUSED,
614
                                          const int flags)
615
{
616
    return SDL_CreateWindow("ManaPlus", SDL_WINDOWPOS_UNDEFINED,
617
        SDL_WINDOWPOS_UNDEFINED, w, h, flags);
618
}
619
620
SDL_Renderer *GraphicsManager::createRenderer(SDL_Window *const window,
621
                                              const int flags)
622
{
623
    SDL::setRendererHint(config.getStringValue("sdlDriver"));
624
    SDL_Renderer *const renderer = SDL_CreateRenderer(window, -1, flags);
625
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
626
    return renderer;
627
}
628
#else  // USE_SDL2
629
630
596
SDL_Window *GraphicsManager::createWindow(const int w, const int h,
631
                                          const int bpp, const int flags)
632
{
633
596
    return SDL_SetVideoMode(w, h, bpp, flags);
634
}
635
#endif  // USE_SDL2
636
637
#ifdef USE_OPENGL
638
void GraphicsManager::updateExtensions()
639
{
640
    mExtensions.clear();
641
    logger->log1("opengl extensions: ");
642
    if (checkGLVersion(3, 0))
643
    {   // get extensions in new way
644
        assignFunction2(glGetStringi, "glGetStringi");
645
        std::string extList;
646
        int num = 0;
647
        glGetIntegerv(GL_NUM_EXTENSIONS, &num);
648
        for (int f = 0; f < num; f ++)
649
        {
650
            std::string str = reinterpret_cast<const char*>(
651
                mglGetStringi(GL_EXTENSIONS, f));
652
            mExtensions.insert(str);
653
            extList.append(str).append(" ");
654
        }
655
        logger->log1(extList.c_str());
656
    }
657
    else
658
    {   // get extensions in old way
659
        char const *extensions = reinterpret_cast<char const *>(
660
            mglGetString(GL_EXTENSIONS));
661
        if (extensions)
662
        {
663
            logger->log1(extensions);
664
            splitToStringSet(mExtensions, extensions, ' ');
665
        }
666
    }
667
}
668
669
void GraphicsManager::updatePlanformExtensions()
670
{
671
    SDL_SysWMinfo info;
672
    SDL_VERSION(&info.version);
673
    if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info))
674
    {
675
#ifdef WIN32
676
        if (!mwglGetExtensionsString)
677
            return;
678
679
        HDC hdc = GetDC(info.window);
680
        if (hdc)
681
        {
682
            const char *const extensions = mwglGetExtensionsString(hdc);
683
            if (extensions)
684
            {
685
                logger->log1("wGL extensions:");
686
                logger->log1(extensions);
687
                splitToStringSet(mPlatformExtensions, extensions, ' ');
688
            }
689
        }
690
#elif defined USE_X11
691
        Display *const display = info.info.x11.display;
692
        if (display)
693
        {
694
            Screen *const screen = XDefaultScreenOfDisplay(display);
695
            if (!screen)
696
                return;
697
698
            const int screenNum = XScreenNumberOfScreen(screen);
699
            const char *const extensions = glXQueryExtensionsString(
700
                display, screenNum);
701
            if (extensions)
702
            {
703
                logger->log1("glx extensions:");
704
                logger->log1(extensions);
705
                splitToStringSet(mPlatformExtensions, extensions, ' ');
706
            }
707
            glXQueryVersion(display, &mPlatformMajor, &mPlatformMinor);
708
            if (checkPlatformVersion(1, 1))
709
            {
710
                const char *const vendor1 = glXQueryServerString(
711
                    display, screenNum, GLX_VENDOR);
712
                if (vendor1)
713
                    logger->log("glx server vendor: %s", vendor1);
714
                const char *const version1 = glXQueryServerString(
715
                    display, screenNum, GLX_VERSION);
716
                if (version1)
717
                    logger->log("glx server version: %s", version1);
718
                const char *const extensions1 = glXQueryServerString(
719
                    display, screenNum, GLX_EXTENSIONS);
720
                if (extensions1)
721
                {
722
                    logger->log1("glx server extensions:");
723
                    logger->log1(extensions1);
724
                }
725
726
                const char *const vendor2 = glXGetClientString(
727
                    display, GLX_VENDOR);
728
                if (vendor2)
729
                    logger->log("glx client vendor: %s", vendor2);
730
                const char *const version2 = glXGetClientString(
731
                    display, GLX_VERSION);
732
                if (version2)
733
                    logger->log("glx client version: %s", version2);
734
                const char *const extensions2 = glXGetClientString(
735
                    display, GLX_EXTENSIONS);
736
                if (extensions2)
737
                {
738
                    logger->log1("glx client extensions:");
739
                    logger->log1(extensions2);
740
                }
741
            }
742
            logger->log("width=%d", DisplayWidth(display, screenNum));
743
        }
744
#endif  // WIN32
745
    }
746
}
747
748
bool GraphicsManager::supportExtension(const std::string &ext) const
749
{
750
    return mExtensions.find(ext) != mExtensions.end();
751
}
752
753
void GraphicsManager::updateTextureCompressionFormat() const
754
{
755
    const int compressionFormat = config.getIntValue("compresstextures");
756
    // using extensions if can
757
    if (checkGLVersion(3, 1) ||
758
        checkGLesVersion(2, 0) ||
759
        supportExtension("GL_ARB_texture_compression"))
760
    {
761
        GLint num = 0;
762
        mglGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num);
763
        logger->log("support %d compressed formats", num);
764
        GLint *const formats = new GLint[num > 10
765
            ? CAST_SIZE(num) : 10];
766
        mglGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
767
        for (int f = 0; f < num; f ++)
768
            logger->log(" 0x%x", CAST_U32(formats[f]));
769
770
        if (compressionFormat)
771
        {
772
            for (int f = 0; f < num; f ++)
773
            {
774
                switch (formats[f])
775
                {
776
                    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
777
                        if (compressionFormat == 1)
778
                        {
779
                            delete []formats;
780
                            useCompression(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
781
                            return;
782
                        }
783
                        break;
784
                    case GL_COMPRESSED_RGBA_FXT1_3DFX:
785
                        if (compressionFormat == 2)
786
                        {
787
                            delete []formats;
788
                            useCompression(GL_COMPRESSED_RGBA_FXT1_3DFX);
789
                            return;
790
                        }
791
                        break;
792
                    case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
793
                        if (compressionFormat == 4)
794
                        {
795
                            delete []formats;
796
                            useCompression(GL_COMPRESSED_RGBA_BPTC_UNORM_ARB);
797
                            return;
798
                        }
799
                        break;
800
                    default:
801
                        break;
802
                }
803
            }
804
            if (compressionFormat == 3)
805
            {
806
                delete []formats;
807
                useCompression(GL_COMPRESSED_RGBA_ARB);
808
                return;
809
            }
810
811
            // workaround for MESA bptc compression detection
812
            if (compressionFormat == 4
813
                && supportExtension("GL_ARB_texture_compression_bptc"))
814
            {
815
                delete []formats;
816
                useCompression(GL_COMPRESSED_RGBA_BPTC_UNORM_ARB);
817
                return;
818
            }
819
        }
820
        delete []formats;
821
        if (compressionFormat)
822
            logger->log1("no correct compression format found");
823
    }
824
    else
825
    {
826
        if (compressionFormat)
827
            logger->log1("no correct compression format found");
828
    }
829
}
830
831
void GraphicsManager::updateTextureFormat()
832
{
833
    const int renderer = settings.options.renderer;
834
835
    // using default formats
836
    if (renderer == RENDER_MODERN_OPENGL ||
837
        renderer == RENDER_GLES_OPENGL ||
838
        renderer == RENDER_GLES2_OPENGL ||
839
        config.getBoolValue("newtextures"))
840
    {
841
        OpenGLImageHelper::setInternalTextureType(GL_RGBA);
842
#ifndef ANDROID
843
        SafeOpenGLImageHelper::setInternalTextureType(GL_RGBA);
844
#endif  // ANDROID
845
846
        logger->log1("using RGBA texture format");
847
    }
848
    else
849
    {
850
        OpenGLImageHelper::setInternalTextureType(4);
851
#ifndef ANDROID
852
        SafeOpenGLImageHelper::setInternalTextureType(4);
853
#endif  // ANDROID
854
855
        logger->log1("using 4 texture format");
856
    }
857
}
858
859
void GraphicsManager::logString(const char *const format, const int num)
860
{
861
    const char *str = reinterpret_cast<const char*>(mglGetString(num));
862
    if (!str)
863
        logger->log(format, "?");
864
    else
865
        logger->log(format, str);
866
}
867
868
std::string GraphicsManager::getGLString(const int num)
869
{
870
    const char *str = reinterpret_cast<const char*>(mglGetString(num));
871
    return str ? str : "";
872
}
873
874
void GraphicsManager::setGLVersion()
875
{
876
    mGlVersionString = getGLString(GL_VERSION);
877
    std::string version = mGlVersionString;
878
    if (findCutFirst(version, "OpenGL ES "))
879
        mGles = true;
880
    sscanf(version.c_str(), "%5d.%5d", &mMajor, &mMinor);
881
    logger->log("Detected gl version: %d.%d", mMajor, mMinor);
882
    mGlVendor = getGLString(GL_VENDOR);
883
    mGlRenderer = getGLString(GL_RENDERER);
884
    mGlShaderVersionString = getGLString(GL_SHADING_LANGUAGE_VERSION);
885
    version = mGlShaderVersionString;
886
    cutFirst(version, "OpenGL ES GLSL ES ");
887
    cutFirst(version, "OpenGL ES GLSL ");
888
    cutFirst(version, "OpenGL ES ");
889
    sscanf(version.c_str(), "%5d.%5d", &mSLMajor, &mSLMinor);
890
    logger->log("Detected glsl version: %d.%d", mSLMajor, mSLMinor);
891
#ifdef ANDROID
892
    if (!mMajor && !mMinor)
893
    {
894
        logger->log("Overriding detected OpenGL version on Android to 1.0");
895
        mGles = true;
896
        mMajor = 1;
897
        mMinor = 0;
898
    }
899
#endif  // ANDROID
900
}
901
902
void GraphicsManager::logVersion() const
903
{
904
    logger->log("gl vendor: " + mGlVendor);
905
    logger->log("gl renderer: " + mGlRenderer);
906
    logger->log("gl version: " + mGlVersionString);
907
    logger->log("glsl version: " + mGlShaderVersionString);
908
}
909
910
bool GraphicsManager::checkGLVersion(const int major, const int minor) const
911
{
912
    return mMajor > major || (mMajor == major && mMinor >= minor);
913
}
914
915
bool GraphicsManager::checkSLVersion(const int major, const int minor) const
916
{
917
    return mSLMajor > major || (mSLMajor == major && mSLMinor >= minor);
918
}
919
920
bool GraphicsManager::checkGLesVersion(const int major, const int minor) const
921
{
922
    return mGles && (mMajor > major || (mMajor == major && mMinor >= minor));
923
}
924
925
bool GraphicsManager::checkPlatformVersion(const int major,
926
                                           const int minor) const
927
{
928
    return mPlatformMajor > major || (mPlatformMajor == major
929
        && mPlatformMinor >= minor);
930
}
931
932
void GraphicsManager::createFBO(const int width, const int height,
933
                                FBOInfo *const fbo)
934
{
935
    if (!fbo)
936
        return;
937
938
    // create a texture object
939
    glGenTextures(1, &fbo->textureId);
940
    glBindTexture(OpenGLImageHelper::mTextureType, fbo->textureId);
941
    glTexParameterf(OpenGLImageHelper::mTextureType,
942
        GL_TEXTURE_MAG_FILTER, GL_LINEAR);
943
    glTexParameterf(OpenGLImageHelper::mTextureType,
944
        GL_TEXTURE_MIN_FILTER, GL_LINEAR);
945
    glTexParameterf(OpenGLImageHelper::mTextureType,
946
        GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
947
    glTexParameterf(OpenGLImageHelper::mTextureType,
948
        GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
949
    glTexImage2D(OpenGLImageHelper::mTextureType, 0, GL_RGBA8, width, height,
950
        0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
951
    glBindTexture(OpenGLImageHelper::mTextureType, 0);
952
953
    // create a renderbuffer object to store depth info
954
    mglGenRenderbuffers(1, &fbo->rboId);
955
    mglBindRenderbuffer(GL_RENDERBUFFER, fbo->rboId);
956
    mglRenderbufferStorage(GL_RENDERBUFFER,
957
        GL_DEPTH_COMPONENT, width, height);
958
    mglBindRenderbuffer(GL_RENDERBUFFER, 0);
959
960
    // create a framebuffer object
961
    mglGenFramebuffers(1, &fbo->fboId);
962
    mglBindFramebuffer(GL_FRAMEBUFFER, fbo->fboId);
963
964
    // attach the texture to FBO color attachment point
965
    mglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
966
        OpenGLImageHelper::mTextureType, fbo->textureId, 0);
967
968
    // attach the renderbuffer to depth attachment point
969
    mglFramebufferRenderbuffer(GL_FRAMEBUFFER,
970
        GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->rboId);
971
972
    mglBindFramebuffer(GL_FRAMEBUFFER, fbo->fboId);
973
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
974
}
975
976
void GraphicsManager::deleteFBO(FBOInfo *const fbo)
977
{
978
    if (!fbo)
979
        return;
980
981
    mglBindFramebuffer(GL_FRAMEBUFFER, 0);
982
    if (fbo->fboId)
983
    {
984
        mglDeleteFramebuffers(1, &fbo->fboId);
985
        fbo->fboId = 0;
986
    }
987
    mglBindRenderbuffer(GL_RENDERBUFFER, 0);
988
    if (fbo->rboId)
989
    {
990
        mglDeleteRenderbuffers(1, &fbo->rboId);
991
        fbo->rboId = 0;
992
    }
993
    if (fbo->textureId)
994
    {
995
        glDeleteTextures(1, &fbo->textureId);
996
        fbo->textureId = 0;
997
    }
998
}
999
1000
void GraphicsManager::initOpenGLFunctions()
1001
{
1002
#ifdef __native_client__
1003
    emulateFunction(glTextureSubImage2DEXT);
1004
#else  // __native_client__
1005
1006
    const bool is10 = checkGLVersion(1, 0);
1007
    const bool is11 = checkGLVersion(1, 1);
1008
    const bool is12 = checkGLVersion(1, 2);
1009
    const bool is13 = checkGLVersion(1, 3);
1010
    const bool is15 = checkGLVersion(1, 5);
1011
    const bool is20 = checkGLVersion(2, 0);
1012
    const bool is21 = checkGLVersion(2, 1);
1013
    const bool is30 = checkGLVersion(3, 0);
1014
    const bool is33 = checkGLVersion(3, 3);
1015
    const bool is41 = checkGLVersion(4, 1);
1016
    const bool is42 = checkGLVersion(4, 2);
1017
    const bool is43 = checkGLVersion(4, 3);
1018
    const bool is44 = checkGLVersion(4, 4);
1019
    const bool is45 = checkGLVersion(4, 5);
1020
    mSupportModernOpengl = true;
1021
1022
    // Texture sampler
1023
    if (is10 && (is33 || supportExtension("GL_ARB_sampler_objects")))
1024
    {
1025
        logger->log1("found GL_ARB_sampler_objects");
1026
        assignFunction(glGenSamplers);
1027
        assignFunction(glDeleteSamplers);
1028
        assignFunction(glBindSampler);
1029
        assignFunction(glSamplerParameteri);
1030
        if (isGLNotNull(mglGenSamplers)
1031
            && config.getBoolValue("useTextureSampler"))
1032
        {
1033
            mUseTextureSampler &= true;
1034
        }
1035
        else
1036
        {
1037
            mUseTextureSampler = false;
1038
        }
1039
    }
1040
    else
1041
    {
1042
        logger->log1("texture sampler not found");
1043
        mUseTextureSampler = false;
1044
    }
1045
1046
    if (!is11)
1047
    {
1048
        mSupportModernOpengl = false;
1049
        emulateFunction(glTextureSubImage2DEXT);
1050
        return;
1051
    }
1052
1053
/*
1054
    if (findI(mGlVendor, "NVIDIA") != std::string::npos ||
1055
        mGlVersionString.find("Mesa 10.6.") != std::string::npos ||
1056
        mGlVersionString.find("Mesa 11.1.1") != std::string::npos ||
1057
        mGlVersionString.find("Mesa 11.1.2") != std::string::npos ||
1058
        mGlVersionString.find("Mesa 11.1.3") != std::string::npos ||
1059
        mGlVersionString.find("Mesa 11.2") != std::string::npos ||
1060
        (findI(mGlRenderer, "AMD Radeon HD") != std::string::npos &&
1061
        (mGlVersionString.find(
1062
        "Compatibility Profile Context 14.") != std::string::npos ||
1063
        mGlVersionString.find(
1064
        "Compatibility Profile Context 15.") != std::string::npos)))
1065
    {
1066
        logger->log1("Not checked for DSA because on "
1067
            "NVIDIA or AMD or in Mesa it broken");
1068
        emulateFunction(glTextureSubImage2DEXT);
1069
    }
1070
    else
1071
*/
1072
    {   // not for NVIDIA. in NVIDIA atleast in windows drivers DSA is broken
1073
        // Mesa 10.6.3 show support for DSA, but it broken. Works in 10.7 dev
1074
        if (config.getBoolValue("enableDSA") == true)
1075
        {
1076
            if (is45)
1077
            {
1078
                logger->log1("found GL_EXT_direct_state_access");
1079
                assignFunction(glTextureSubImage2D);
1080
            }
1081
            else if (supportExtension("GL_EXT_direct_state_access"))
1082
            {
1083
                logger->log1("found GL_EXT_direct_state_access");
1084
                assignFunctionEmu2(glTextureSubImage2DEXT,
1085
                    "glTextureSubImage2DEXT");
1086
            }
1087
            else if (supportExtension("GL_ARB_direct_state_access"))
1088
            {
1089
                logger->log1("found GL_ARB_direct_state_access");
1090
                logger->log1("GL_EXT_direct_state_access not found");
1091
                assignFunction(glTextureSubImage2D);
1092
            }
1093
            else
1094
            {
1095
                logger->log1("GL_EXT_direct_state_access not found");
1096
                logger->log1("GL_ARB_direct_state_access not found");
1097
                emulateFunction(glTextureSubImage2DEXT);
1098
            }
1099
        }
1100
        else
1101
        {
1102
            logger->log1("Direct state access disabled in settings");
1103
            emulateFunction(glTextureSubImage2DEXT);
1104
        }
1105
    }
1106
1107
    if (is12 && (is42 || supportExtension("GL_ARB_texture_storage")))
1108
    {
1109
        logger->log1("found GL_ARB_texture_storage");
1110
        assignFunction(glTexStorage2D);
1111
    }
1112
    else
1113
    {
1114
        logger->log1("GL_ARB_texture_storage not found");
1115
    }
1116
1117
    if (is13 || supportExtension("GL_ARB_multitexture"))
1118
    {
1119
        logger->log1("found GL_ARB_multitexture or OpenGL 1.3");
1120
        assignFunction(glActiveTexture);
1121
    }
1122
    else
1123
    {
1124
        emulateFunction(glActiveTexture);
1125
        logger->log1("GL_ARB_multitexture not found");
1126
    }
1127
1128
    if (is20 || supportExtension("GL_ARB_explicit_attrib_location"))
1129
    {
1130
        logger->log1("found GL_ARB_explicit_attrib_location or OpenGL 2.0");
1131
        assignFunction(glBindAttribLocation);
1132
    }
1133
    else
1134
    {
1135
        logger->log1("GL_ARB_explicit_attrib_location not found");
1136
    }
1137
1138
    if (is30 || supportExtension("GL_ARB_framebuffer_object"))
1139
    {   // frame buffer supported
1140
        logger->log1("found GL_ARB_framebuffer_object");
1141
        assignFunction(glGenRenderbuffers);
1142
        assignFunction(glBindRenderbuffer);
1143
        assignFunction(glRenderbufferStorage);
1144
        assignFunction(glGenFramebuffers);
1145
        assignFunction(glBindFramebuffer);
1146
        assignFunction(glFramebufferTexture2D);
1147
        assignFunction(glFramebufferRenderbuffer);
1148
        assignFunction(glDeleteFramebuffers);
1149
        assignFunction(glDeleteRenderbuffers);
1150
        assignFunction(glCheckFramebufferStatus);
1151
    }
1152
    else if (supportExtension("GL_EXT_framebuffer_object"))
1153
    {   // old frame buffer extension
1154
        logger->log1("found GL_EXT_framebuffer_object");
1155
        assignFunctionEXT(glGenRenderbuffers);
1156
        assignFunctionEXT(glBindRenderbuffer);
1157
        assignFunctionEXT(glRenderbufferStorage);
1158
        assignFunctionEXT(glGenFramebuffers);
1159
        assignFunctionEXT(glBindFramebuffer);
1160
        assignFunctionEXT(glFramebufferTexture2D);
1161
        assignFunctionEXT(glFramebufferRenderbuffer);
1162
        assignFunctionEXT(glDeleteFramebuffers);
1163
        assignFunctionEXT(glDeleteRenderbuffers);
1164
    }
1165
    else
1166
    {   // no frame buffer support
1167
        logger->log1("GL_ARB_framebuffer_object or "
1168
            "GL_EXT_framebuffer_object not found");
1169
        config.setValue("usefbo", false);
1170
    }
1171
1172
    // debug extensions
1173
    if (is43 || supportExtension("GL_KHR_debug"))
1174
    {
1175
        logger->log1("found GL_KHR_debug");
1176
        assignFunction(glDebugMessageControl);
1177
        assignFunction(glDebugMessageCallback);
1178
        assignFunction(glPushDebugGroup);
1179
        assignFunction(glPopDebugGroup);
1180
        assignFunction(glObjectLabel);
1181
        mSupportDebug = 2;
1182
    }
1183
    else if (supportExtension("GL_ARB_debug_output"))
1184
    {
1185
        logger->log1("found GL_ARB_debug_output");
1186
        assignFunctionARB(glDebugMessageControl);
1187
        assignFunctionARB(glDebugMessageCallback);
1188
        mSupportDebug = 1;
1189
    }
1190
    else
1191
    {
1192
        logger->log1("debug extensions not found");
1193
        mSupportDebug = 0;
1194
    }
1195
1196
    if (supportExtension("GL_GREMEDY_frame_terminator"))
1197
    {
1198
        logger->log1("found GL_GREMEDY_frame_terminator");
1199
        assignFunction2(glFrameTerminator, "glFrameTerminatorGREMEDY");
1200
    }
1201
    else
1202
    {
1203
        logger->log1("GL_GREMEDY_frame_terminator not found");
1204
    }
1205
    if (is44 || supportExtension("GL_EXT_debug_label"))
1206
    {
1207
        logger->log1("found GL_EXT_debug_label");
1208
        assignFunction2(glLabelObject, "glObjectLabel");
1209
        if (isGLNull(mglLabelObject))
1210
            assignFunctionEXT(glLabelObject);
1211
        assignFunctionEXT(glGetObjectLabel);
1212
    }
1213
    else
1214
    {
1215
        logger->log1("GL_EXT_debug_label not found");
1216
    }
1217
    if (supportExtension("GL_GREMEDY_string_marker"))
1218
    {
1219
        logger->log1("found GL_GREMEDY_string_marker");
1220
        assignFunction2(glPushGroupMarker, "glStringMarkerGREMEDY");
1221
    }
1222
    else
1223
    {
1224
        logger->log1("GL_GREMEDY_string_marker not found");
1225
    }
1226
    if (supportExtension("GL_EXT_debug_marker"))
1227
    {
1228
        logger->log1("found GL_EXT_debug_marker");
1229
        assignFunctionEXT(glInsertEventMarker);
1230
        assignFunctionEXT(glPushGroupMarker);
1231
        assignFunctionEXT(glPopGroupMarker);
1232
    }
1233
    else
1234
    {
1235
        logger->log1("GL_EXT_debug_marker not found");
1236
    }
1237
    if (is15 && (is30 || supportExtension("GL_EXT_timer_query")))
1238
    {
1239
        logger->log1("found GL_EXT_timer_query");
1240
        assignFunction(glGenQueries);
1241
        assignFunction(glBeginQuery);
1242
        assignFunction(glEndQuery);
1243
        assignFunction(glDeleteQueries);
1244
        assignFunction(glGetQueryObjectiv);
1245
        assignFunctionEXT(glGetQueryObjectui64v);
1246
    }
1247
    else
1248
    {
1249
        logger->log1("GL_EXT_timer_query not supported");
1250
    }
1251
    if (is20 && (is43 || supportExtension("GL_ARB_invalidate_subdata")))
1252
    {
1253
        logger->log1("found GL_ARB_invalidate_subdata");
1254
        assignFunction(glInvalidateTexImage);
1255
    }
1256
    else
1257
    {
1258
        logger->log1("GL_ARB_invalidate_subdata not supported");
1259
    }
1260
    if (is21 && (is30 || supportExtension("GL_ARB_vertex_array_object")))
1261
    {
1262
        logger->log1("found GL_ARB_vertex_array_object");
1263
        assignFunction(glGenVertexArrays);
1264
        assignFunction(glBindVertexArray);
1265
        assignFunction(glDeleteVertexArrays);
1266
        assignFunction(glVertexAttribPointer);
1267
        assignFunction(glEnableVertexAttribArray);
1268
        assignFunction(glDisableVertexAttribArray);
1269
        assignFunction(glVertexAttribIPointer);
1270
    }
1271
    else
1272
    {
1273
        mSupportModernOpengl = false;
1274
        logger->log1("GL_ARB_vertex_array_object not found");
1275
    }
1276
    if (is20 || supportExtension("GL_ARB_vertex_buffer_object"))
1277
    {
1278
        assignFunction(glGenBuffers);
1279
        assignFunction(glDeleteBuffers);
1280
        assignFunction(glBindBuffer);
1281
        assignFunction(glBufferData);
1282
        assignFunction(glIsBuffer);
1283
    }
1284
    else
1285
    {
1286
        mSupportModernOpengl = false;
1287
        logger->log1("buffers extension not found");
1288
    }
1289
    if (is43 || supportExtension("GL_ARB_copy_image"))
1290
    {
1291
        logger->log1("found GL_ARB_copy_image");
1292
        assignFunction(glCopyImageSubData);
1293
    }
1294
    else
1295
    {
1296
        logger->log1("GL_ARB_copy_image not found");
1297
    }
1298
    if (is44 || supportExtension("GL_ARB_clear_texture"))
1299
    {
1300
        logger->log1("found GL_ARB_clear_texture");
1301
        assignFunction(glClearTexImage);
1302
        assignFunction(glClearTexSubImage);
1303
    }
1304
    else
1305
    {
1306
        logger->log1("GL_ARB_clear_texture not found");
1307
    }
1308
    if (is20 || supportExtension("GL_ARB_shader_objects"))
1309
    {
1310
        logger->log1("found GL_ARB_shader_objects");
1311
        assignFunction(glCreateShader);
1312
        assignFunction(glDeleteShader);
1313
        assignFunction(glGetShaderiv);
1314
        assignFunction(glGetShaderInfoLog);
1315
        assignFunction(glGetShaderSource);
1316
        assignFunction(glShaderSource);
1317
        assignFunction(glCompileShader);
1318
        assignFunction(glLinkProgram);
1319
        assignFunction(glGetProgramInfoLog);
1320
        assignFunction(glDeleteProgram);
1321
        assignFunction(glCreateProgram);
1322
        assignFunction(glAttachShader);
1323
        assignFunction(glDetachShader);
1324
        assignFunction(glGetAttachedShaders);
1325
        assignFunction(glGetUniformLocation);
1326
        assignFunction(glGetActiveUniform);
1327
        assignFunction(glGetProgramiv);
1328
        assignFunction(glUseProgram);
1329
        assignFunction(glValidateProgram);
1330
        assignFunction(glGetAttribLocation);
1331
        assignFunction(glUniform1f);
1332
        assignFunction(glUniform2f);
1333
        assignFunction(glUniform3f);
1334
        assignFunction(glUniform4f);
1335
1336
        if (is30 || supportExtension("GL_EXT_gpu_shader4"))
1337
        {
1338
            logger->log1("found GL_EXT_gpu_shader4");
1339
            assignFunction(glBindFragDataLocation);
1340
        }
1341
        else
1342
        {
1343
            mSupportModernOpengl = false;
1344
            logger->log1("GL_EXT_gpu_shader4 not supported");
1345
        }
1346
        if (is41 || supportExtension("GL_ARB_separate_shader_objects"))
1347
        {
1348
            logger->log1("found GL_ARB_separate_shader_objects");
1349
            assignFunction(glProgramUniform1f);
1350
            assignFunction(glProgramUniform2f);
1351
            assignFunction(glProgramUniform3f);
1352
            assignFunction(glProgramUniform4f);
1353
        }
1354
        else
1355
        {
1356
            logger->log1("GL_ARB_separate_shader_objects not supported");
1357
        }
1358
        if (is43 || supportExtension("GL_ARB_vertex_attrib_binding"))
1359
        {
1360
            logger->log1("found GL_ARB_vertex_attrib_binding");
1361
            assignFunction(glBindVertexBuffer);
1362
            assignFunction(glVertexAttribBinding);
1363
            assignFunction(glVertexAttribFormat);
1364
            assignFunction(glVertexAttribIFormat);
1365
        }
1366
        else
1367
        {
1368
            mSupportModernOpengl = false;
1369
            logger->log1("GL_ARB_vertex_attrib_binding not supported");
1370
        }
1371
        if (is44 || supportExtension("GL_ARB_multi_bind"))
1372
        {
1373
            logger->log1("found GL_ARB_multi_bind");
1374
            assignFunction(glBindVertexBuffers);
1375
        }
1376
        else
1377
        {
1378
            logger->log1("GL_ARB_multi_bind not supported");
1379
        }
1380
    }
1381
    else
1382
    {
1383
        mSupportModernOpengl = false;
1384
        logger->log1("shaders not supported");
1385
    }
1386
1387
#ifdef WIN32
1388
    assignFunctionARB(wglGetExtensionsString);
1389
#endif  // WIN32
1390
#endif  // __native_client__
1391
}
1392
1393
void GraphicsManager::updateLimits()
1394
{
1395
    GLint value = 0;
1396
#ifdef __native_client__
1397
    mMaxVertices = 500;
1398
#else  // __native_client__
1399
1400
    glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &value);
1401
    logger->log("GL_MAX_ELEMENTS_VERTICES: %d", value);
1402
1403
    mMaxVertices = value;
1404
1405
    value = 0;
1406
    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &value);
1407
    logger->log("GL_MAX_ELEMENTS_INDICES: %d", value);
1408
    if (value < mMaxVertices)
1409
        mMaxVertices = value;
1410
    if (!mMaxVertices)
1411
    {
1412
        logger->log("Got 0 max amount of vertices or indicies. "
1413
            "Overriding to 500");
1414
        mMaxVertices = 500;
1415
    }
1416
#endif  // __native_client__
1417
1418
    value = 0;
1419
    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &value);
1420
    logger->log("Max FBO size: %d", value);
1421
    mMaxFboSize = value;
1422
}
1423
1424
void GraphicsManager::initOpenGL()
1425
{
1426
    setGLVersion();
1427
    updateExtensions();
1428
    initOpenGLFunctions();
1429
    updatePlanformExtensions();
1430
    updateDebugLog();
1431
    createTextureSampler();
1432
    updateLimits();
1433
}
1434
1435
void GraphicsManager::createTextureSampler()
1436
{
1437
    GLenum err = getLastError();
1438
    if (err)
1439
        logger->log(errorToString(err));
1440
    if (mUseTextureSampler)
1441
    {
1442
        logger->log1("using texture sampler");
1443
        mglGenSamplers(1, &mTextureSampler);
1444
        if (getLastError() != GL_NO_ERROR)
1445
        {
1446
            mUseTextureSampler = false;
1447
            logger->log1("texture sampler error");
1448
            OpenGLImageHelper::setUseTextureSampler(mUseTextureSampler);
1449
            return;
1450
        }
1451
        OpenGLImageHelper::initTextureSampler(mTextureSampler);
1452
        mglBindSampler(0, mTextureSampler);
1453
        if (getLastError() != GL_NO_ERROR)
1454
        {
1455
            mUseTextureSampler = false;
1456
            logger->log1("texture sampler error");
1457
        }
1458
    }
1459
    OpenGLImageHelper::setUseTextureSampler(mUseTextureSampler);
1460
#ifndef ANDROID
1461
    SafeOpenGLImageHelper::setUseTextureSampler(false);
1462
#endif  // ANDROID
1463
}
1464
1465
GLenum GraphicsManager::getLastError()
1466
{
1467
    GLenum tmp = glGetError();
1468
    GLenum error = GL_NO_ERROR;
1469
    while (tmp != GL_NO_ERROR)
1470
    {
1471
        error = tmp;
1472
        mLastError = tmp;
1473
        tmp = glGetError();
1474
    }
1475
    return error;
1476
}
1477
1478
std::string GraphicsManager::errorToString(const GLenum error)
1479
{
1480
    if (error)
1481
    {
1482
        std::string errmsg("Unknown error");
1483
        switch (error)
1484
        {
1485
            case GL_INVALID_ENUM:
1486
                errmsg = "GL_INVALID_ENUM";
1487
                break;
1488
            case GL_INVALID_VALUE:
1489
                errmsg = "GL_INVALID_VALUE";
1490
                break;
1491
            case GL_INVALID_OPERATION:
1492
                errmsg = "GL_INVALID_OPERATION";
1493
                break;
1494
            case GL_STACK_OVERFLOW:
1495
                errmsg = "GL_STACK_OVERFLOW";
1496
                break;
1497
            case GL_STACK_UNDERFLOW:
1498
                errmsg = "GL_STACK_UNDERFLOW";
1499
                break;
1500
            case GL_OUT_OF_MEMORY:
1501
                errmsg = "GL_OUT_OF_MEMORY";
1502
                break;
1503
            default:
1504
                break;
1505
        }
1506
        return "OpenGL error: " + errmsg;
1507
    }
1508
    return "";
1509
}
1510
1511
void GraphicsManager::logError()
1512
{
1513
    const GLenum error = GraphicsManager::getLastError();
1514
    if (error != GL_NO_ERROR)
1515
        logger->log(errorToString(error));
1516
}
1517
1518
void GraphicsManager::detectVideoSettings()
1519
{
1520
    config.setValue("videodetected", true);
1521
    TestMain *const test = startDetection();
1522
1523
    if (test)
1524
    {
1525
        const Configuration &conf = test->getConfig();
1526
        int val = conf.getValueInt("opengl", -1);
1527
        if (val >= 0 && val < CAST_S32(RENDER_LAST))
1528
        {
1529
            config.setValue("opengl", val);
1530
            val = conf.getValue("useTextureSampler", -1);
1531
            if (val != -1)
1532
                config.setValue("useTextureSampler", val);
1533
            val = conf.getValue("compresstextures", -1);
1534
            if (val != -1)
1535
                config.setValue("compresstextures", val);
1536
        }
1537
        config.setValue("textureSize", conf.getValue("textureSize",
1538
            "1024,1024,1024,1024,1024,1024"));
1539
        config.setValue("testInfo", conf.getValue("testInfo", ""));
1540
        config.setValue("sound", conf.getValue("sound", 0));
1541
        delete test;
1542
    }
1543
}
1544
1545
static CALLBACK void debugCallback(GLenum source, GLenum type, GLuint id,
1546
                          GLenum severity, GLsizei length,
1547
                          const GLchar *text, GLvoid *userParam A_UNUSED)
1548
{
1549
    std::string message("OPENGL:");
1550
    switch (source)
1551
    {
1552
        case GL_DEBUG_SOURCE_API:
1553
            message.append(" API");
1554
            break;
1555
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
1556
            message.append(" WM");
1557
            break;
1558
        case GL_DEBUG_SOURCE_SHADER_COMPILER:
1559
            message.append(" SHADERS");
1560
            break;
1561
        case GL_DEBUG_SOURCE_THIRD_PARTY:
1562
            message.append(" THIRD_PARTY");
1563
            break;
1564
        case GL_DEBUG_SOURCE_APPLICATION:
1565
            message.append(" APP");
1566
            break;
1567
        case GL_DEBUG_SOURCE_OTHER:
1568
            message.append(" OTHER");
1569
            break;
1570
        default:
1571
            message.append(" ?").append(toString(source));
1572
            break;
1573
    }
1574
    switch (type)
1575
    {
1576
        case GL_DEBUG_TYPE_ERROR:
1577
            message.append(" ERROR");
1578
            break;
1579
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
1580
            message.append(" DEPRECATED");
1581
            break;
1582
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
1583
            message.append(" UNDEFINED");
1584
            break;
1585
        case GL_DEBUG_TYPE_PORTABILITY:
1586
            message.append(" PORTABILITY");
1587
            break;
1588
        case GL_DEBUG_TYPE_PERFORMANCE:
1589
            message.append(" PERFORMANCE");
1590
            break;
1591
        case GL_DEBUG_TYPE_OTHER:
1592
            message.append(" OTHER");
1593
            break;
1594
        case GL_DEBUG_TYPE_MARKER:
1595
            message.append(" MARKER");
1596
            break;
1597
        case GL_DEBUG_TYPE_PUSH_GROUP:
1598
            message.append(" PUSH GROUP");
1599
            break;
1600
        case GL_DEBUG_TYPE_POP_GROUP:
1601
            message.append(" POP GROUP");
1602
            break;
1603
        default:
1604
            message.append(" ?").append(toString(type));
1605
            break;
1606
    }
1607
    message.append(" ").append(toString(id));
1608
    switch (severity)
1609
    {
1610
        case GL_DEBUG_SEVERITY_NOTIFICATION:
1611
            message.append(" N");
1612
            break;
1613
        case GL_DEBUG_SEVERITY_HIGH:
1614
            message.append(" H");
1615
            break;
1616
        case GL_DEBUG_SEVERITY_MEDIUM:
1617
            message.append(" M");
1618
            break;
1619
        case GL_DEBUG_SEVERITY_LOW:
1620
            message.append(" L");
1621
            break;
1622
        default:
1623
            message.append(" ?").append(toString(type));
1624
            break;
1625
    }
1626
    char *const buf = new char[CAST_SIZE(length + 1)];
1627
    memcpy(buf, text, length);
1628
    buf[length] = 0;
1629
    message.append(" ").append(buf);
1630
    delete [] buf;
1631
    logger->log(message);
1632
}
1633
1634
void GraphicsManager::updateDebugLog() const
1635
{
1636
    if (mSupportDebug && config.getIntValue("debugOpenGL"))
1637
    {
1638
        logger->log1("Enable OpenGL debug log");
1639
        glEnable(GL_DEBUG_OUTPUT);
1640
        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1641
1642
        mglDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE,
1643
            0, nullptr, GL_TRUE);
1644
        mglDebugMessageCallback(&debugCallback, this);
1645
    }
1646
}
1647
#endif  // USE_OPENGL
1648
1649
void GraphicsManager::detectPixelSize()
1650
{
1651
    SDL_SysWMinfo info;
1652
    SDL_VERSION(&info.version);
1653
    if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info))
1654
    {
1655
#ifdef WIN32
1656
        HDC hdc = GetDC(info.window);
1657
        if (hdc)
1658
        {
1659
//            SetProcessDPIAware();
1660
            mMaxWidth = GetDeviceCaps(hdc, HORZRES);
1661
            mMaxHeight = GetDeviceCaps(hdc, VERTRES);
1662
            mWidthMM = GetDeviceCaps(hdc, HORZSIZE);
1663
            mHeightMM = GetDeviceCaps(hdc, VERTSIZE);
1664
        }
1665
#elif defined USE_X11
1666
        Display *const display = info.info.x11.display;
1667
        if (display)
1668
        {
1669
            Screen *const screen = XDefaultScreenOfDisplay(display);
1670
            if (!screen)
1671
                return;
1672
1673
            const int screenNum = XScreenNumberOfScreen(screen);
1674
            mMaxWidth = DisplayWidth(display, screenNum);
1675
            mMaxHeight = DisplayHeight(display, screenNum);
1676
            mWidthMM = DisplayWidthMM(display, screenNum);
1677
            mHeightMM = DisplayHeightMM(display, screenNum);
1678
        }
1679
#endif  // WIN32
1680
    }
1681
#if defined ANDROID
1682
#ifdef USE_SDL2
1683
    const int dpi = atoi(getenv("DISPLAY_DPI"));
1684
    if (dpi <= 120)
1685
        mDensity = 0;
1686
    else if (dpi <= 160)
1687
        mDensity = 1;
1688
    else if (dpi <= 213)
1689
        mDensity = 2;
1690
    else if (dpi <= 240)
1691
        mDensity = 3;
1692
    else if (dpi <= 320)
1693
        mDensity = 4;
1694
//    else if (dpi <= 480)
1695
    else
1696
        mDensity = 5;
1697
    mMaxWidth = atoi(getenv("DISPLAY_RESOLUTION_WIDTH"));
1698
    mMaxHeight = atoi(getenv("DISPLAY_RESOLUTION_HEIGHT"));
1699
    mWidthMM = atoi(getenv("DISPLAY_WIDTH_MM"));
1700
    mHeightMM = atoi(getenv("DISPLAY_HEIGHT_MM"));
1701
#else  // USE_SDL2
1702
1703
    SDL_ANDROID_GetMetrics(&mMaxWidth, &mMaxHeight,
1704
        &mWidthMM, &mHeightMM, &mDensity);
1705
#endif  // USE_SDL2
1706
#endif  // defined ANDROID
1707
1708
    logger->log("screen size in pixels: %ux%u", mMaxWidth, mMaxHeight);
1709
    logger->log("screen size in millimeters: %ux%u", mWidthMM, mHeightMM);
1710
    logger->log("actual screen density: " + getDensityString());
1711
    const int density = config.getIntValue("screenDensity");
1712
    if (density > 0 && density <= densitySize)
1713
    {
1714
        mDensity = density - 1;
1715
        logger->log("selected screen density: " + getDensityString());
1716
    }
1717
}
1718
1719
408
std::string GraphicsManager::getDensityString() const
1720
{
1721
408
    if (mDensity >= 0 && mDensity < densitySize)
1722
        return densityNames[mDensity];
1723
1224
    return "";
1724

6
}