1 |
|
|
/* |
2 |
|
|
* The ManaPlus Client |
3 |
|
|
* Copyright (C) 2004-2009 The Mana World Development Team |
4 |
|
|
* Copyright (C) 2009-2010 The Mana Developers |
5 |
|
|
* Copyright (C) 2011-2019 The ManaPlus Developers |
6 |
|
|
* Copyright (C) 2019-2021 Andrei Karas |
7 |
|
|
* |
8 |
|
|
* This file is part of The ManaPlus Client. |
9 |
|
|
* |
10 |
|
|
* This program is free software; you can redistribute it and/or modify |
11 |
|
|
* it under the terms of the GNU General Public License as published by |
12 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
13 |
|
|
* any later version. |
14 |
|
|
* |
15 |
|
|
* This program is distributed in the hope that it will be useful, |
16 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
|
|
* GNU General Public License for more details. |
19 |
|
|
* |
20 |
|
|
* You should have received a copy of the GNU General Public License |
21 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
/* _______ __ __ __ ______ __ __ _______ __ __ |
25 |
|
|
* / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ |
26 |
|
|
* / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / |
27 |
|
|
* / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / |
28 |
|
|
* / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / |
29 |
|
|
* /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / |
30 |
|
|
* \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ |
31 |
|
|
* |
32 |
|
|
* Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson |
33 |
|
|
* |
34 |
|
|
* |
35 |
|
|
* Per Larsson a.k.a finalman |
36 |
|
|
* Olof Naessén a.k.a jansem/yakslem |
37 |
|
|
* |
38 |
|
|
* Visit: http://guichan.sourceforge.net |
39 |
|
|
* |
40 |
|
|
* License: (BSD) |
41 |
|
|
* Redistribution and use in source and binary forms, with or without |
42 |
|
|
* modification, are permitted provided that the following conditions |
43 |
|
|
* are met: |
44 |
|
|
* 1. Redistributions of source code must retain the above copyright |
45 |
|
|
* notice, this list of conditions and the following disclaimer. |
46 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
47 |
|
|
* notice, this list of conditions and the following disclaimer in |
48 |
|
|
* the documentation and/or other materials provided with the |
49 |
|
|
* distribution. |
50 |
|
|
* 3. Neither the name of Guichan nor the names of its contributors may |
51 |
|
|
* be used to endorse or promote products derived from this software |
52 |
|
|
* without specific prior written permission. |
53 |
|
|
* |
54 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
55 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
56 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
57 |
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
58 |
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
59 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
60 |
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
61 |
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
62 |
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
63 |
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
64 |
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
65 |
|
|
*/ |
66 |
|
|
|
67 |
|
|
#include "render/graphics.h" |
68 |
|
|
|
69 |
|
|
#ifdef USE_OPENGL |
70 |
|
|
#include "configuration.h" |
71 |
|
|
#include "graphicsmanager.h" |
72 |
|
|
#endif // USE_OPENGL |
73 |
|
|
|
74 |
|
|
#if defined(USE_OPENGL) && defined(USE_X11) |
75 |
|
|
#include "render/openglx/mglxinit.h" |
76 |
|
|
#endif // defined(USE_OPENGL) && defined(USE_X11) |
77 |
|
|
|
78 |
|
|
#ifdef USE_OPENGL |
79 |
|
|
#include "resources/openglimagehelper.h" |
80 |
|
|
#ifndef ANDROID |
81 |
|
|
#include "resources/safeopenglimagehelper.h" |
82 |
|
|
#endif // ANDROID |
83 |
|
|
#ifdef __native_client__ |
84 |
|
|
#include "render/nacl/naclfunctions.h" |
85 |
|
|
#include "render/nacl/naclgles.h" |
86 |
|
|
#endif // __native_client__ |
87 |
|
|
#else // USE_OPENGL |
88 |
|
|
#ifndef USE_SDL2 |
89 |
|
|
#include "resources/imagehelper.h" |
90 |
|
|
#endif // USE_SDL2 |
91 |
|
|
#endif // USE_OPENGL |
92 |
|
|
|
93 |
|
|
#ifdef USE_OPENGL |
94 |
|
|
#ifdef __APPLE__ |
95 |
|
|
#include <OpenGL/OpenGL.h> |
96 |
|
|
#endif // __APPLE__ |
97 |
|
|
#include "render/opengl/mgldefines.h" |
98 |
|
|
RENDER_OPENGL_MGLDEFINES_H |
99 |
|
|
#endif // USE_OPENGL |
100 |
|
|
|
101 |
|
|
#include "debug.h" |
102 |
|
|
|
103 |
|
|
#ifdef USE_OPENGL |
104 |
|
|
#ifndef GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX |
105 |
|
|
#define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 |
106 |
|
|
#endif // GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX |
107 |
|
|
#endif // USE_OPENGL |
108 |
|
|
|
109 |
|
|
Graphics *mainGraphics A_NONNULLPOINTER = nullptr; |
110 |
|
|
|
111 |
|
|
#ifdef USE_SDL2 |
112 |
|
|
SDL_Renderer *restrict Graphics::mRenderer = nullptr; |
113 |
|
|
#endif // USE_SDL2 |
114 |
|
|
#ifdef USE_OPENGL |
115 |
|
|
#ifdef USE_SDL2 |
116 |
|
|
SDL_GLContext Graphics::mGLContext = nullptr; |
117 |
|
|
#else // USE_SDL2 |
118 |
|
|
|
119 |
|
|
void *restrict Graphics::mGLContext = nullptr; |
120 |
|
|
#endif // USE_SDL2 |
121 |
|
|
#endif // USE_OPENGL |
122 |
|
|
|
123 |
|
201 |
Graphics::Graphics() : |
124 |
|
|
mWidth(0), |
125 |
|
|
mHeight(0), |
126 |
|
|
mActualWidth(0), |
127 |
|
|
mActualHeight(0), |
128 |
|
|
mClipStack(1000), |
129 |
|
|
mWindow(nullptr), |
130 |
|
|
mBpp(0), |
131 |
|
|
mAlpha(false), |
132 |
|
|
mFullscreen(false), |
133 |
|
|
mHWAccel(false), |
134 |
|
|
mRedraw(false), |
135 |
|
|
mDoubleBuffer(false), |
136 |
|
|
mRect(), |
137 |
|
|
mSecure(false), |
138 |
|
|
mOpenGL(RENDER_SOFTWARE), |
139 |
|
|
mEnableResize(false), |
140 |
|
|
mNoFrame(false), |
141 |
|
|
mAllowHighDPI(false), |
142 |
|
|
mName("Unknown"), |
143 |
|
|
mStartFreeMem(0), |
144 |
|
|
mSync(false), |
145 |
|
|
mScale(1), |
146 |
✓✗ |
804 |
mColor() |
147 |
|
|
{ |
148 |
|
201 |
mRect.x = 0; |
149 |
|
201 |
mRect.y = 0; |
150 |
|
201 |
mRect.w = 0; |
151 |
|
201 |
mRect.h = 0; |
152 |
|
201 |
} |
153 |
|
|
|
154 |
|
603 |
Graphics::~Graphics() |
155 |
|
|
{ |
156 |
|
201 |
endDraw(); |
157 |
|
201 |
} |
158 |
|
|
|
159 |
|
215 |
void Graphics::cleanUp() |
160 |
|
|
{ |
161 |
|
|
#ifdef USE_SDL2 |
162 |
|
|
if (mRenderer) |
163 |
|
|
{ |
164 |
|
|
SDL_DestroyRenderer(mRenderer); |
165 |
|
|
mRenderer = nullptr; |
166 |
|
|
} |
167 |
|
|
#ifdef USE_OPENGL |
168 |
|
|
if (mGLContext) |
169 |
|
|
{ |
170 |
|
|
SDL_GL_DeleteContext(mGLContext); |
171 |
|
|
mGLContext = nullptr; |
172 |
|
|
} |
173 |
|
|
#endif // USE_OPENGL |
174 |
|
|
#endif // USE_SDL2 |
175 |
|
215 |
} |
176 |
|
|
|
177 |
|
|
void Graphics::setSync(const bool sync) restrict2 |
178 |
|
|
{ |
179 |
|
|
mSync = sync; |
180 |
|
|
} |
181 |
|
|
|
182 |
|
77 |
void Graphics::setMainFlags(const int w, const int h, |
183 |
|
|
const int scale, |
184 |
|
|
const int bpp, |
185 |
|
|
const bool fs, |
186 |
|
|
const bool hwaccel, |
187 |
|
|
const bool resize, |
188 |
|
|
const bool noFrame, |
189 |
|
|
const bool allowHighDPI) restrict2 |
190 |
|
|
{ |
191 |
|
77 |
logger->log("graphics backend: %s", getName().c_str()); |
192 |
✓✗ |
77 |
logger->log("Setting video mode %dx%d %s", |
193 |
|
77 |
w, h, fs ? "fullscreen" : "windowed"); |
194 |
|
|
|
195 |
|
77 |
mBpp = bpp; |
196 |
|
77 |
mFullscreen = fs; |
197 |
|
77 |
mHWAccel = hwaccel; |
198 |
|
77 |
mEnableResize = resize; |
199 |
|
77 |
mNoFrame = noFrame; |
200 |
|
77 |
mAllowHighDPI = allowHighDPI; |
201 |
|
77 |
mActualWidth = w; |
202 |
|
77 |
mActualHeight = h; |
203 |
|
77 |
setScale(scale); |
204 |
|
77 |
} |
205 |
|
|
|
206 |
|
77 |
void Graphics::setScale(int scale) restrict2 |
207 |
|
|
{ |
208 |
✗✓ |
77 |
if (isAllowScale()) |
209 |
|
|
{ |
210 |
|
|
if (scale == 0) |
211 |
|
|
scale = 1; |
212 |
|
|
int scaleW = mActualWidth / scale; |
213 |
|
|
int scaleH = mActualHeight / scale; |
214 |
|
|
if (scaleW < 470) |
215 |
|
|
{ |
216 |
|
|
scale = mActualWidth / 470; |
217 |
|
|
if (scale < 1) |
218 |
|
|
scale = 1; |
219 |
|
|
scaleH = mActualHeight / scale; |
220 |
|
|
} |
221 |
|
|
if (scaleH < 320) |
222 |
|
|
{ |
223 |
|
|
scale = mActualHeight / 320; |
224 |
|
|
if (scale < 1) |
225 |
|
|
scale = 1; |
226 |
|
|
} |
227 |
|
|
logger->log("set scale: %d", scale); |
228 |
|
|
mScale = scale; |
229 |
|
|
mWidth = mActualWidth / mScale; |
230 |
|
|
mHeight = mActualHeight / mScale; |
231 |
|
|
} |
232 |
|
|
else |
233 |
|
|
{ |
234 |
|
77 |
mScale = 1; |
235 |
|
77 |
mWidth = mActualWidth; |
236 |
|
77 |
mHeight = mActualHeight; |
237 |
|
|
} |
238 |
|
77 |
mRect.w = static_cast<RectSize>(mWidth); |
239 |
|
77 |
mRect.h = static_cast<RectSize>(mHeight); |
240 |
|
77 |
} |
241 |
|
|
|
242 |
|
|
int Graphics::getOpenGLFlags() const restrict2 |
243 |
|
|
{ |
244 |
|
|
#ifdef USE_OPENGL |
245 |
|
|
|
246 |
|
|
#ifdef USE_SDL2 |
247 |
|
|
int displayFlags = SDL_WINDOW_OPENGL; |
248 |
|
|
if (mFullscreen) |
249 |
|
|
displayFlags |= SDL_WINDOW_FULLSCREEN; |
250 |
|
|
#if SDL_VERSION_ATLEAST(2, 0, 1) |
251 |
|
|
if (mAllowHighDPI) |
252 |
|
|
displayFlags |= SDL_WINDOW_ALLOW_HIGHDPI; |
253 |
|
|
#endif // SDL_VERSION_ATLEAST(2, 0, 1) |
254 |
|
|
#else // USE_SDL2 |
255 |
|
|
|
256 |
|
|
int displayFlags = SDL_ANYFORMAT | SDL_OPENGL; |
257 |
|
|
#endif // USE_SDL2 |
258 |
|
|
|
259 |
|
|
if (mFullscreen) |
260 |
|
|
{ |
261 |
|
|
displayFlags |= SDL_FULLSCREEN; |
262 |
|
|
} |
263 |
|
|
else |
264 |
|
|
{ |
265 |
|
|
// Resizing currently not supported on Windows, where it would require |
266 |
|
|
// reuploading all textures. |
267 |
|
|
#if !defined(_WIN32) |
268 |
|
|
if (mEnableResize) |
269 |
|
|
displayFlags |= SDL_RESIZABLE; |
270 |
|
|
#endif // !defined(_WIN32) |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
if (mNoFrame) |
274 |
|
|
displayFlags |= SDL_NOFRAME; |
275 |
|
|
|
276 |
|
|
return displayFlags; |
277 |
|
|
#else // USE_OPENGL |
278 |
|
|
|
279 |
|
|
return 0; |
280 |
|
|
#endif // USE_OPENGL |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
bool Graphics::setOpenGLMode() restrict2 |
284 |
|
|
{ |
285 |
|
|
#ifdef USE_OPENGL |
286 |
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
287 |
|
|
if ((mWindow = GraphicsManager::createWindow( |
288 |
|
|
mActualWidth, mActualHeight, |
289 |
|
|
mBpp, getOpenGLFlags())) == nullptr) |
290 |
|
|
{ |
291 |
|
|
logger->log("Window/context creation failed"); |
292 |
|
|
mRect.w = 0; |
293 |
|
|
mRect.h = 0; |
294 |
|
|
return false; |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
#if defined(USE_X11) |
298 |
|
|
Glx::initFunctions(); |
299 |
|
|
#endif // defined(USE_X11) |
300 |
|
|
#ifdef __native_client__ |
301 |
|
|
NaclGles::initGles(); |
302 |
|
|
#endif // __native_client__ |
303 |
|
|
|
304 |
|
|
#ifdef USE_SDL2 |
305 |
|
|
int w1 = 0; |
306 |
|
|
int h1 = 0; |
307 |
|
|
SDL_GetWindowSize(mWindow, &w1, &h1); |
308 |
|
|
mRect.w = CAST_S32(w1 / mScale); |
309 |
|
|
mRect.h = CAST_S32(h1 / mScale); |
310 |
|
|
|
311 |
|
|
createGLContext(config.getBoolValue("openglContext")); |
312 |
|
|
#else // USE_SDL2 |
313 |
|
|
|
314 |
|
|
createGLContext(config.getBoolValue("openglContext")); |
315 |
|
|
mRect.w = CAST_U16(mWindow->w / mScale); |
316 |
|
|
mRect.h = CAST_U16(mWindow->h / mScale); |
317 |
|
|
|
318 |
|
|
#endif // USE_SDL2 |
319 |
|
|
|
320 |
|
|
#ifdef __APPLE__ |
321 |
|
|
if (mSync) |
322 |
|
|
{ |
323 |
|
|
const GLint VBL = 1; |
324 |
|
|
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); |
325 |
|
|
} |
326 |
|
|
#endif // __APPLE__ |
327 |
|
|
|
328 |
|
|
graphicsManager.setGLVersion(); |
329 |
|
|
graphicsManager.logVersion(); |
330 |
|
|
|
331 |
|
|
// Setup OpenGL |
332 |
|
|
glViewport(0, 0, mActualWidth, mActualHeight); |
333 |
|
|
int gotDoubleBuffer = 0; |
334 |
|
|
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gotDoubleBuffer); |
335 |
|
|
logger->log("Using OpenGL %s double buffering.", |
336 |
|
|
(gotDoubleBuffer != 0 ? "with" : "without")); |
337 |
|
|
|
338 |
|
|
graphicsManager.initOpenGL(); |
339 |
|
|
initArrays(graphicsManager.getMaxVertices()); |
340 |
|
|
graphicsManager.updateTextureCompressionFormat(); |
341 |
|
|
graphicsManager.updateTextureFormat(); |
342 |
|
|
updateMemoryInfo(); |
343 |
|
|
|
344 |
|
|
GLint texSize; |
345 |
|
|
bool rectTex = graphicsManager.supportExtension( |
346 |
|
|
"GL_ARB_texture_rectangle") || |
347 |
|
|
graphicsManager.supportExtension("GL_EXT_texture_rectangle"); |
348 |
|
|
|
349 |
|
|
if (rectTex |
350 |
|
|
&& OpenGLImageHelper::getInternalTextureType() == 4 |
351 |
|
|
&& getOpenGL() != RENDER_GLES_OPENGL |
352 |
|
|
&& getOpenGL() != RENDER_GLES2_OPENGL |
353 |
|
|
&& getOpenGL() != RENDER_MODERN_OPENGL |
354 |
|
|
&& config.getBoolValue("rectangulartextures") |
355 |
|
|
&& !graphicsManager.isUseTextureSampler()) |
356 |
|
|
{ |
357 |
|
|
logger->log1("using GL_ARB_texture_rectangle"); |
358 |
|
|
OpenGLImageHelper::mTextureType = GL_TEXTURE_RECTANGLE_ARB; |
359 |
|
|
glEnable(GL_TEXTURE_RECTANGLE_ARB); |
360 |
|
|
glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texSize); |
361 |
|
|
OpenGLImageHelper::mTextureSize = texSize; |
362 |
|
|
logger->log("OpenGL texture size: %d pixels (rectangle textures)", |
363 |
|
|
OpenGLImageHelper::mTextureSize); |
364 |
|
|
#if !defined(ANDROID) && !defined(__SWITCH__) |
365 |
|
|
SafeOpenGLImageHelper::mTextureType = GL_TEXTURE_RECTANGLE_ARB; |
366 |
|
|
SafeOpenGLImageHelper::mTextureSize = texSize; |
367 |
|
|
#endif // ANDROID |
368 |
|
|
} |
369 |
|
|
else |
370 |
|
|
{ |
371 |
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); |
372 |
|
|
OpenGLImageHelper::mTextureType = GL_TEXTURE_2D; |
373 |
|
|
OpenGLImageHelper::mTextureSize = texSize; |
374 |
|
|
#if !defined(ANDROID) && !defined(__SWITCH__) |
375 |
|
|
SafeOpenGLImageHelper::mTextureType = GL_TEXTURE_2D; |
376 |
|
|
SafeOpenGLImageHelper::mTextureSize = texSize; |
377 |
|
|
#endif // ANDROID |
378 |
|
|
|
379 |
|
|
logger->log("OpenGL texture size: %d pixels", |
380 |
|
|
OpenGLImageHelper::mTextureSize); |
381 |
|
|
} |
382 |
|
|
return videoInfo(); |
383 |
|
|
#else // USE_OPENGL |
384 |
|
|
|
385 |
|
|
return false; |
386 |
|
|
#endif // USE_OPENGL |
387 |
|
|
} |
388 |
|
|
|
389 |
|
77 |
int Graphics::getSoftwareFlags() const restrict2 |
390 |
|
|
{ |
391 |
|
|
#ifdef USE_SDL2 |
392 |
|
|
int displayFlags = SDL_WINDOW_SHOWN; |
393 |
|
|
#if SDL_VERSION_ATLEAST(2, 0, 1) |
394 |
|
|
if (mAllowHighDPI) |
395 |
|
|
displayFlags |= SDL_WINDOW_ALLOW_HIGHDPI; |
396 |
|
|
#endif // SDL_VERSION_ATLEAST(2, 0, 1) |
397 |
|
|
#else // USE_SDL2 |
398 |
|
|
|
399 |
|
77 |
int displayFlags = SDL_ANYFORMAT; |
400 |
|
|
|
401 |
✓✗ |
77 |
if (mHWAccel) |
402 |
|
|
displayFlags |= SDL_HWSURFACE | SDL_DOUBLEBUF; |
403 |
|
|
else |
404 |
|
77 |
displayFlags |= SDL_SWSURFACE; |
405 |
|
|
#endif // USE_SDL2 |
406 |
|
|
|
407 |
✗✓ |
77 |
if (mFullscreen) |
408 |
|
|
displayFlags |= SDL_FULLSCREEN; |
409 |
✗✓ |
77 |
else if (mEnableResize) |
410 |
|
|
displayFlags |= SDL_RESIZABLE; |
411 |
|
|
|
412 |
✗✓ |
77 |
if (mNoFrame) |
413 |
|
|
displayFlags |= SDL_NOFRAME; |
414 |
|
77 |
return displayFlags; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
#ifdef USE_OPENGL |
418 |
|
|
void Graphics::createGLContext(const bool custom A_UNUSED) restrict2 |
419 |
|
|
{ |
420 |
|
|
#ifdef USE_SDL2 |
421 |
|
|
mGLContext = SDL_GL_CreateContext(mWindow); |
422 |
|
|
#endif // USE_SDL2 |
423 |
|
|
} |
424 |
|
|
#endif // USE_OPENGL |
425 |
|
|
|
426 |
|
|
void Graphics::updateMemoryInfo() restrict2 |
427 |
|
|
{ |
428 |
|
|
#ifdef USE_OPENGL |
429 |
|
|
if (mStartFreeMem != 0) |
430 |
|
|
return; |
431 |
|
|
|
432 |
|
|
if (graphicsManager.supportExtension("GL_NVX_gpu_memory_info")) |
433 |
|
|
{ |
434 |
|
|
glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, |
435 |
|
|
&mStartFreeMem); |
436 |
|
|
logger->log("free video memory: %d", mStartFreeMem); |
437 |
|
|
} |
438 |
|
|
#endif // USE_OPENGL |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
int Graphics::getMemoryUsage() const restrict2 |
442 |
|
|
{ |
443 |
|
|
#ifdef USE_OPENGL |
444 |
|
|
if (mStartFreeMem == 0) |
445 |
|
|
return 0; |
446 |
|
|
|
447 |
|
|
if (graphicsManager.supportExtension("GL_NVX_gpu_memory_info")) |
448 |
|
|
{ |
449 |
|
|
GLint val; |
450 |
|
|
glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, |
451 |
|
|
&val); |
452 |
|
|
return mStartFreeMem - val; |
453 |
|
|
} |
454 |
|
|
#endif // USE_OPENGL |
455 |
|
|
return 0; |
456 |
|
|
} |
457 |
|
|
|
458 |
|
|
#ifdef USE_SDL2 |
459 |
|
|
void Graphics::dumpRendererInfo(const char *restrict const str, |
460 |
|
|
const SDL_RendererInfo &restrict info) |
461 |
|
|
restrict2 |
462 |
|
|
{ |
463 |
|
|
logger->log(str, info.name); |
464 |
|
|
logger->log("flags:"); |
465 |
|
|
if (info.flags & SDL_RENDERER_SOFTWARE) |
466 |
|
|
logger->log(" software"); |
467 |
|
|
if (info.flags & SDL_RENDERER_ACCELERATED) |
468 |
|
|
logger->log(" accelerated"); |
469 |
|
|
if (info.flags & SDL_RENDERER_PRESENTVSYNC) |
470 |
|
|
logger->log(" vsync"); |
471 |
|
|
if (info.flags & SDL_RENDERER_TARGETTEXTURE) |
472 |
|
|
logger->log(" texture target"); |
473 |
|
|
logger->log("max texture size: %d,%d", |
474 |
|
|
info.max_texture_width, |
475 |
|
|
info.max_texture_height); |
476 |
|
|
const size_t sz = CAST_SIZE(info.num_texture_formats); |
477 |
|
|
logger->log("texture formats:"); |
478 |
|
|
for (size_t f = 0; f < sz; f ++) |
479 |
|
|
logger->log(" %u", info.texture_formats[f]); |
480 |
|
|
} |
481 |
|
|
#endif // USE_SDL2 |
482 |
|
|
|
483 |
|
77 |
bool Graphics::videoInfo() restrict2 |
484 |
|
|
{ |
485 |
|
77 |
logger->log("SDL video info"); |
486 |
|
|
#ifdef USE_SDL2 |
487 |
|
|
logger->log("Using video driver: %s", SDL_GetCurrentVideoDriver()); |
488 |
|
|
|
489 |
|
|
if (mRenderer) |
490 |
|
|
{ |
491 |
|
|
SDL_RendererInfo info; |
492 |
|
|
SDL_GetRendererInfo(mRenderer, &info); |
493 |
|
|
dumpRendererInfo("Current SDL renderer name: %s", info); |
494 |
|
|
|
495 |
|
|
const int num = SDL_GetNumRenderDrivers(); |
496 |
|
|
logger->log("Known renderers"); |
497 |
|
|
for (int f = 0; f < num; f ++) |
498 |
|
|
{ |
499 |
|
|
if (!SDL_GetRenderDriverInfo(f, &info)) |
500 |
|
|
dumpRendererInfo("renderer name: %s", info); |
501 |
|
|
} |
502 |
|
|
} |
503 |
|
|
#else // USE_SDL2 |
504 |
|
|
|
505 |
|
|
char videoDriverName[65]; |
506 |
✓✗ |
77 |
if (SDL_VideoDriverName(videoDriverName, 64) != nullptr) |
507 |
|
77 |
logger->log("Using video driver: %s", videoDriverName); |
508 |
|
|
else |
509 |
|
|
logger->log1("Using video driver: unknown"); |
510 |
|
77 |
mDoubleBuffer = ((mWindow->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF); |
511 |
✓✗ |
77 |
logger->log("Double buffer mode: %s", mDoubleBuffer ? "yes" : "no"); |
512 |
|
|
|
513 |
|
77 |
ImageHelper::dumpSurfaceFormat(mWindow); |
514 |
|
|
|
515 |
|
77 |
const SDL_VideoInfo *restrict const vi = SDL_GetVideoInfo(); |
516 |
✓✗ |
77 |
if (vi == nullptr) |
517 |
|
|
return false; |
518 |
|
|
|
519 |
✓✗ |
77 |
logger->log("Possible to create hardware surfaces: %s", |
520 |
|
154 |
((vi->hw_available) != 0U ? "yes" : "no")); |
521 |
✓✗ |
77 |
logger->log("Window manager available: %s", |
522 |
|
154 |
((vi->wm_available) != 0U ? "yes" : "no")); |
523 |
✓✗ |
77 |
logger->log("Accelerated hardware to hardware blits: %s", |
524 |
|
154 |
((vi->blit_hw) != 0U ? "yes" : "no")); |
525 |
✓✗ |
77 |
logger->log("Accelerated hardware to hardware colorkey blits: %s", |
526 |
|
154 |
((vi->blit_hw_CC) != 0U ? "yes" : "no")); |
527 |
✓✗ |
77 |
logger->log("Accelerated hardware to hardware alpha blits: %s", |
528 |
|
154 |
((vi->blit_hw_A) != 0U ? "yes" : "no")); |
529 |
✓✗ |
77 |
logger->log("Accelerated software to hardware blits: %s", |
530 |
|
154 |
((vi->blit_sw) != 0U ? "yes" : "no")); |
531 |
✓✗ |
77 |
logger->log("Accelerated software to hardware colorkey blits: %s", |
532 |
|
154 |
((vi->blit_sw_CC) != 0U ? "yes" : "no")); |
533 |
✓✗ |
77 |
logger->log("Accelerated software to hardware alpha blits: %s", |
534 |
|
154 |
((vi->blit_sw_A) != 0U ? "yes" : "no")); |
535 |
✓✗ |
77 |
logger->log("Accelerated color fills: %s", |
536 |
|
154 |
((vi->blit_fill) != 0U ? "yes" : "no")); |
537 |
|
|
#endif // USE_SDL2 |
538 |
|
|
|
539 |
|
|
return true; |
540 |
|
|
} |
541 |
|
|
|
542 |
|
|
bool Graphics::setFullscreen(const bool fs) restrict2 |
543 |
|
|
{ |
544 |
|
|
if (mFullscreen == fs) |
545 |
|
|
return true; |
546 |
|
|
|
547 |
|
|
return setVideoMode(mActualWidth, |
548 |
|
|
mActualHeight, |
549 |
|
|
mScale, |
550 |
|
|
mBpp, |
551 |
|
|
fs, |
552 |
|
|
mHWAccel, |
553 |
|
|
mEnableResize, |
554 |
|
|
mNoFrame, |
555 |
|
|
mAllowHighDPI); |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
bool Graphics::resizeScreen(const int width, |
559 |
|
|
const int height) restrict2 |
560 |
|
|
{ |
561 |
|
|
#ifdef USE_SDL2 |
562 |
|
|
endDraw(); |
563 |
|
|
|
564 |
|
|
mRect.w = CAST_S32(width / mScale); |
565 |
|
|
mRect.h = CAST_S32(height / mScale); |
566 |
|
|
mWidth = width / mScale; |
567 |
|
|
mHeight = height / mScale; |
568 |
|
|
mActualWidth = width; |
569 |
|
|
mActualHeight = height; |
570 |
|
|
|
571 |
|
|
#ifdef USE_OPENGL |
572 |
|
|
// +++ probably this way will not work in windows/mac |
573 |
|
|
// Setup OpenGL |
574 |
|
|
glViewport(0, 0, mActualWidth, mActualHeight); |
575 |
|
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); |
576 |
|
|
#else // USE_OPENGL |
577 |
|
|
// +++ need impliment resize in soft mode |
578 |
|
|
#endif // USE_OPENGL |
579 |
|
|
|
580 |
|
|
screenResized(); |
581 |
|
|
beginDraw(); |
582 |
|
|
return true; |
583 |
|
|
|
584 |
|
|
#else // USE_SDL2 |
585 |
|
|
|
586 |
|
|
const int prevWidth = mWidth; |
587 |
|
|
const int prevHeight = mHeight; |
588 |
|
|
|
589 |
|
|
endDraw(); |
590 |
|
|
|
591 |
|
|
bool success = true; |
592 |
|
|
#ifdef __native_client__ |
593 |
|
|
if (mOpenGL != RENDER_SOFTWARE) |
594 |
|
|
{ |
595 |
|
|
mRect.w = CAST_S32(width / mScale); |
596 |
|
|
mRect.h = CAST_S32(height / mScale); |
597 |
|
|
mWidth = width / mScale; |
598 |
|
|
mHeight = height / mScale; |
599 |
|
|
mActualWidth = width; |
600 |
|
|
mActualHeight = height; |
601 |
|
|
#ifdef USE_OPENGL |
602 |
|
|
naclResizeBuffers(mActualWidth, mActualHeight); |
603 |
|
|
glViewport(0, 0, mActualWidth, mActualHeight); |
604 |
|
|
#endif // USE_OPENGL |
605 |
|
|
} |
606 |
|
|
else |
607 |
|
|
#endif // __native_client__ |
608 |
|
|
{ |
609 |
|
|
success = setVideoMode(width, height, |
610 |
|
|
mScale, |
611 |
|
|
mBpp, |
612 |
|
|
mFullscreen, |
613 |
|
|
mHWAccel, |
614 |
|
|
mEnableResize, |
615 |
|
|
mNoFrame, |
616 |
|
|
mAllowHighDPI); |
617 |
|
|
|
618 |
|
|
// If it didn't work, try to restore the previous size. If that didn't |
619 |
|
|
// work either, bail out (but then we're in deep trouble). |
620 |
|
|
if (!success) |
621 |
|
|
{ |
622 |
|
|
if (!setVideoMode(prevWidth, prevHeight, |
623 |
|
|
mScale, |
624 |
|
|
mBpp, |
625 |
|
|
mFullscreen, |
626 |
|
|
mHWAccel, |
627 |
|
|
mEnableResize, |
628 |
|
|
mNoFrame, |
629 |
|
|
mAllowHighDPI)) |
630 |
|
|
{ |
631 |
|
|
return false; |
632 |
|
|
} |
633 |
|
|
} |
634 |
|
|
} |
635 |
|
|
|
636 |
|
|
screenResized(); |
637 |
|
|
beginDraw(); |
638 |
|
|
|
639 |
|
|
return success; |
640 |
|
|
#endif // USE_SDL2 |
641 |
|
|
} |
642 |
|
|
|
643 |
|
13 |
int Graphics::getWidth() const restrict2 |
644 |
|
|
{ |
645 |
|
13 |
return mWidth; |
646 |
|
|
} |
647 |
|
|
|
648 |
|
128 |
int Graphics::getHeight() const restrict2 |
649 |
|
|
{ |
650 |
|
128 |
return mHeight; |
651 |
|
|
} |
652 |
|
|
|
653 |
|
|
void Graphics::drawNet(const int x1, const int y1, |
654 |
|
|
const int x2, const int y2, |
655 |
|
|
const int width, const int height) restrict2 |
656 |
|
|
{ |
657 |
|
|
for (int y = y1; y < y2; y += height) |
658 |
|
|
drawLine(x1, y, x2, y); |
659 |
|
|
|
660 |
|
|
for (int x = x1; x < x2; x += width) |
661 |
|
|
drawLine(x, y1, x, y2); |
662 |
|
|
} |
663 |
|
|
|
664 |
|
|
#ifdef USE_SDL2 |
665 |
|
|
void Graphics::setWindowSize(const int width, |
666 |
|
|
const int height) restrict2 |
667 |
|
|
{ |
668 |
|
|
SDL_SetWindowSize(mWindow, width, height); |
669 |
|
|
} |
670 |
|
|
#else // USE_SDL2 |
671 |
|
|
void Graphics::setWindowSize(const int width A_UNUSED, |
672 |
|
|
const int height A_UNUSED) restrict2 |
673 |
|
|
{ |
674 |
|
|
} |
675 |
|
|
#endif // USE_SDL2 |
676 |
|
|
|
677 |
|
571 |
void Graphics::pushClipArea(const Rect &restrict area) restrict2 |
678 |
|
|
{ |
679 |
|
|
// Ignore area with a negate width or height |
680 |
|
|
// by simple pushing an empty clip area |
681 |
|
|
// to the stack. |
682 |
✓✗✗✓
|
571 |
if (area.width < 0 || area.height < 0) |
683 |
|
|
{ |
684 |
|
|
ClipRect &carea = mClipStack.push(); |
685 |
|
|
carea.x = 0; |
686 |
|
|
carea.y = 0; |
687 |
|
|
carea.width = 0; |
688 |
|
|
carea.height = 0; |
689 |
|
|
carea.xOffset = 0; |
690 |
|
|
carea.yOffset = 0; |
691 |
|
|
return; |
692 |
|
|
} |
693 |
|
|
|
694 |
✓✓ |
571 |
if (mClipStack.empty()) |
695 |
|
|
{ |
696 |
|
134 |
ClipRect &carea = mClipStack.push(); |
697 |
|
67 |
carea.x = area.x; |
698 |
|
67 |
carea.y = area.y; |
699 |
|
67 |
carea.width = area.width; |
700 |
|
67 |
carea.height = area.height; |
701 |
|
67 |
carea.xOffset = area.x; |
702 |
|
67 |
carea.yOffset = area.y; |
703 |
|
67 |
return; |
704 |
|
|
} |
705 |
|
|
|
706 |
|
504 |
const ClipRect &top = mClipStack.top(); |
707 |
|
1008 |
ClipRect &carea = mClipStack.push(); |
708 |
|
504 |
carea.x = area.x + top.xOffset; |
709 |
|
504 |
carea.y = area.y + top.yOffset; |
710 |
|
504 |
carea.width = area.width; |
711 |
|
504 |
carea.height = area.height; |
712 |
|
504 |
carea.xOffset = top.xOffset + area.x; |
713 |
|
504 |
carea.yOffset = top.yOffset + area.y; |
714 |
|
|
|
715 |
|
|
// Clamp the pushed clip rectangle. |
716 |
✓✓ |
504 |
if (carea.x < top.x) |
717 |
|
2 |
carea.x = top.x; |
718 |
|
|
|
719 |
✗✓ |
504 |
if (carea.y < top.y) |
720 |
|
|
carea.y = top.y; |
721 |
|
|
|
722 |
✓✓ |
504 |
if (carea.x + carea.width > top.x + top.width) |
723 |
|
|
{ |
724 |
|
433 |
carea.width = top.x + top.width - carea.x; |
725 |
|
|
|
726 |
✓✓ |
433 |
if (carea.width < 0) |
727 |
|
369 |
carea.width = 0; |
728 |
|
|
} |
729 |
|
|
|
730 |
✓✓ |
504 |
if (carea.y + carea.height > top.y + top.height) |
731 |
|
|
{ |
732 |
|
432 |
carea.height = top.y + top.height - carea.y; |
733 |
|
|
|
734 |
✓✓ |
432 |
if (carea.height < 0) |
735 |
|
366 |
carea.height = 0; |
736 |
|
|
} |
737 |
|
|
} |
738 |
|
|
|
739 |
|
571 |
void Graphics::popClipArea() restrict2 |
740 |
|
|
{ |
741 |
✓✗ |
571 |
if (mClipStack.empty()) |
742 |
|
|
return; |
743 |
|
|
|
744 |
|
571 |
mClipStack.pop(); |
745 |
|
|
} |
746 |
|
|
|
747 |
|
|
#ifdef USE_OPENGL |
748 |
|
|
void Graphics::setOpenGLFlags() restrict2 |
749 |
|
|
{ |
750 |
|
|
// here disable/enable probably need convert to mgl |
751 |
|
|
|
752 |
|
|
glEnable(GL_SCISSOR_TEST); |
753 |
|
|
|
754 |
|
|
glDisable(GL_MULTISAMPLE); |
755 |
|
|
glDisable(GL_DITHER); |
756 |
|
|
glDisable(GL_DEPTH_TEST); |
757 |
|
|
glDisable(GL_LINE_SMOOTH); |
758 |
|
|
glDisable(GL_POLYGON_SMOOTH); |
759 |
|
|
glDisable(GL_STENCIL_TEST); |
760 |
|
|
glDisable(GL_COLOR_LOGIC_OP); |
761 |
|
|
glDisable(GL_DEPTH_BOUNDS_TEST_EXT); |
762 |
|
|
glDisable(GL_DEPTH_CLAMP); |
763 |
|
|
glDisable(GL_RASTERIZER_DISCARD); |
764 |
|
|
glDisable(GL_SAMPLE_MASK); |
765 |
|
|
|
766 |
|
|
#ifndef ANDROID |
767 |
|
|
#ifndef __MINGW32__ |
768 |
|
|
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST); |
769 |
|
|
#endif // __MINGW32__ |
770 |
|
|
#endif // ANDROID |
771 |
|
|
|
772 |
|
|
glHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST); |
773 |
|
|
|
774 |
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
775 |
|
|
} |
776 |
|
|
#endif // USE_OPENGL |