1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3
4 #include "GlobalRendering.h"
5
6 #include "Rendering/GL/myGL.h"
7 #include "Rendering/GL/FBO.h"
8 #include "Sim/Misc/GlobalConstants.h"
9 #include "System/Util.h"
10 #include "System/type2.h"
11 #include "System/Config/ConfigHandler.h"
12 #include "System/Log/ILog.h"
13 #include "System/creg/creg_cond.h"
14
15 #include <string>
16
17 CONFIG(bool, CompressTextures).defaultValue(false).safemodeValue(true).description("Runtime compress most textures to save VideoRAM."); // in safemode enabled, cause it ways more likely the gpu runs out of memory than this extension cause crashes!
18 CONFIG(int, ForceShaders).defaultValue(-1).minimumValue(-1).maximumValue(1);
19 CONFIG(int, AtiHacks).defaultValue(-1).minimumValue(-1).maximumValue(1).description("Enables graphics drivers workarounds for users with ATI video cards.\n -1:=runtime detect, 0:=off, 1:=on");
20 CONFIG(bool, DualScreenMode).defaultValue(false).description("Sets whether to split the screen in half, with one half for minimap and one for main screen. Right side is for minimap unless DualScreenMiniMapOnLeft is set.");
21 CONFIG(bool, DualScreenMiniMapOnLeft).defaultValue(false).description("When set, will make the left half of the screen the minimap when DualScreenMode is set.");
22 CONFIG(bool, TeamNanoSpray).defaultValue(true);
23
24 /**
25 * @brief global rendering
26 *
27 * Global instance of CGlobalRendering
28 */
29 CGlobalRendering* globalRendering;
30
31 const float CGlobalRendering::MAX_VIEW_RANGE = 8000.0f;
32 const float CGlobalRendering::NEAR_PLANE = 2.8f;
33 const float CGlobalRendering::SMF_INTENSITY_MULT = 210.0f / 255.0f;
34
35 CR_BIND(CGlobalRendering, )
36
37 CR_REG_METADATA(CGlobalRendering, (
38 CR_MEMBER(teamNanospray),
39 CR_MEMBER(drawSky),
40 CR_MEMBER(drawWater),
41 CR_MEMBER(drawGround),
42 CR_MEMBER(drawMapMarks),
43 CR_MEMBER(drawFog),
44 CR_MEMBER(drawdebug),
45 CR_MEMBER(drawdebugtraceray),
46 CR_MEMBER(timeOffset),
47 CR_MEMBER(lastFrameTime),
48 CR_MEMBER(lastFrameStart),
49 CR_MEMBER(weightedSpeedFactor),
50 CR_MEMBER(drawFrame),
51 CR_MEMBER(FPS),
52
53 CR_IGNORED(winState),
54 CR_IGNORED(screenSizeX),
55 CR_IGNORED(screenSizeY),
56 CR_IGNORED(winPosX),
57 CR_IGNORED(winPosY),
58 CR_IGNORED(winSizeX),
59 CR_IGNORED(winSizeY),
60 CR_IGNORED(viewPosX),
61 CR_IGNORED(viewPosY),
62 CR_IGNORED(viewSizeX),
63 CR_IGNORED(viewSizeY),
64 CR_IGNORED(pixelX),
65 CR_IGNORED(pixelY),
66 CR_IGNORED(aspectRatio),
67 CR_IGNORED(zNear),
68 CR_IGNORED(viewRange),
69 CR_IGNORED(FSAA),
70
71 CR_IGNORED(maxTextureSize),
72 CR_IGNORED(teamNanospray),
73 CR_IGNORED(active),
74 CR_IGNORED(compressTextures),
75 CR_IGNORED(haveATI),
76 CR_IGNORED(haveMesa),
77 CR_IGNORED(haveIntel),
78 CR_IGNORED(haveNvidia),
79 CR_IGNORED(atiHacks),
80 CR_IGNORED(supportNPOTs),
81 CR_IGNORED(support24bitDepthBuffers),
82 CR_IGNORED(supportRestartPrimitive),
83 CR_IGNORED(haveARB),
84 CR_IGNORED(haveGLSL),
85 CR_IGNORED(maxSmoothPointSize),
86 CR_IGNORED(glslMaxVaryings),
87 CR_IGNORED(glslMaxAttributes),
88 CR_IGNORED(glslMaxDrawBuffers),
89 CR_IGNORED(glslMaxRecommendedIndices),
90 CR_IGNORED(glslMaxRecommendedVertices),
91 CR_IGNORED(glslMaxUniformBufferBindings),
92 CR_IGNORED(glslMaxUniformBufferSize),
93 CR_IGNORED(dualScreenMode),
94 CR_IGNORED(dualScreenMiniMapOnLeft),
95 CR_IGNORED(fullScreen),
96 CR_IGNORED(window)
97 ))
98
CGlobalRendering()99 CGlobalRendering::CGlobalRendering()
100 : timeOffset(0.0f)
101 , lastFrameTime(0.0f)
102 , lastFrameStart(spring_notime)
103 , weightedSpeedFactor(0.0f)
104 , drawFrame(1)
105 , FPS(GAME_SPEED)
106
107 , winState(WINSTATE_DEFAULT)
108 , screenSizeX(1)
109 , screenSizeY(1)
110
111 // window geometry
112 , winPosX(0)
113 , winPosY(0)
114 , winSizeX(1)
115 , winSizeY(1)
116
117 // viewport geometry
118 , viewPosX(0)
119 , viewPosY(0)
120 , viewSizeX(1)
121 , viewSizeY(1)
122
123 // pixel geometry
124 , pixelX(0.01f)
125 , pixelY(0.01f)
126
127 , aspectRatio(1.0f)
128
129 , zNear(NEAR_PLANE)
130 , viewRange(MAX_VIEW_RANGE)
131 , FSAA(0)
132
133 , maxTextureSize(2048)
134
135 , drawSky(true)
136 , drawWater(true)
137 , drawGround(true)
138 , drawMapMarks(true)
139 , drawFog(true)
140 , drawdebug(false)
141 , drawdebugtraceray(false)
142
143 , teamNanospray(true)
144 , active(true)
145 , compressTextures(false)
146 , haveATI(false)
147 , haveMesa(false)
148 , haveIntel(false)
149 , haveNvidia(false)
150 , atiHacks(false)
151 , supportNPOTs(false)
152 , support24bitDepthBuffers(false)
153 , supportRestartPrimitive(false)
154 , haveARB(false)
155 , haveGLSL(false)
156 , maxSmoothPointSize(1.0f)
157
158 , glslMaxVaryings(0)
159 , glslMaxAttributes(0)
160 , glslMaxDrawBuffers(0)
161 , glslMaxRecommendedIndices(0)
162 , glslMaxRecommendedVertices(0)
163 , glslMaxUniformBufferBindings(0)
164 , glslMaxUniformBufferSize(0)
165
166 , dualScreenMode(false)
167 , dualScreenMiniMapOnLeft(false)
168 , fullScreen(true)
169
170 , window(nullptr)
171 {
172 }
173
PostInit()174 void CGlobalRendering::PostInit() {
175 supportNPOTs = GLEW_ARB_texture_non_power_of_two;
176 haveARB = GLEW_ARB_vertex_program && GLEW_ARB_fragment_program;
177 haveGLSL = (glGetString(GL_SHADING_LANGUAGE_VERSION) != NULL);
178 haveGLSL &= GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader;
179 haveGLSL &= !!GLEW_VERSION_2_0; // we want OpenGL 2.0 core functions
180
181 {
182 const char* glVendor = (const char*) glGetString(GL_VENDOR);
183 const char* glRenderer = (const char*) glGetString(GL_RENDERER);
184 const std::string vendor = (glVendor != NULL)? StringToLower(std::string(glVendor)): "";
185 const std::string renderer = (glRenderer != NULL)? StringToLower(std::string(glRenderer)): "";
186
187 haveATI = (vendor.find("ati ") != std::string::npos) || (vendor.find("amd ") != std::string::npos);
188 haveMesa = (renderer.find("mesa ") != std::string::npos) || (renderer.find("gallium ") != std::string::npos);
189 haveIntel = (vendor.find("intel") != std::string::npos);
190 haveNvidia = (vendor.find("nvidia ") != std::string::npos);
191
192 const int useGlslShaders = configHandler->GetInt("ForceShaders");
193 if (useGlslShaders < 0) {
194 // disable Shaders for Mesa & Intel drivers
195 haveARB &= !haveIntel;
196 haveARB &= !haveMesa;
197 haveGLSL &= !haveIntel;
198 haveGLSL &= !haveMesa;
199 } else if (useGlslShaders == 0) {
200 haveARB = false;
201 haveGLSL = false;
202 } else if (useGlslShaders > 0) {
203 // rely on extension detection (don't force enable shaders, when the extensions aren't exposed!)
204 }
205
206 if (haveATI) {
207 // x-series doesn't support NPOTs (but hd-series does)
208 supportNPOTs = (renderer.find(" x") == std::string::npos && renderer.find(" 9") == std::string::npos);
209 }
210 }
211
212 // use some ATI bugfixes?
213 const int atiHacksCfg = configHandler->GetInt("AtiHacks");
214 atiHacks = haveATI && (atiHacksCfg < 0); // runtime detect
215 atiHacks |= (atiHacksCfg > 0); // user override
216
217 // Runtime compress textures?
218 if (GLEW_ARB_texture_compression) {
219 // we don't even need to check it, 'cos groundtextures must have that extension
220 // default to off because it reduces quality (smallest mipmap level is bigger)
221 compressTextures = configHandler->GetBool("CompressTextures");
222 }
223
224 #ifdef GLEW_NV_primitive_restart
225 supportRestartPrimitive = !!(GLEW_NV_primitive_restart);
226 #endif
227
228 // maximum 2D texture size
229 {
230 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
231 }
232
233 // retrieve maximu smoothed PointSize
234 float2 aliasedPointSizeRange, smoothPointSizeRange;
235 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, (GLfloat*)&aliasedPointSizeRange);
236 glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, (GLfloat*)&smoothPointSizeRange);
237 maxSmoothPointSize = std::min(aliasedPointSizeRange.y, smoothPointSizeRange.y);
238
239 // some GLSL relevant information
240 {
241 glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &glslMaxUniformBufferBindings);
242 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &glslMaxUniformBufferSize);
243 glGetIntegerv(GL_MAX_VARYING_FLOATS, &glslMaxVaryings);
244 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &glslMaxAttributes);
245 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &glslMaxDrawBuffers);
246 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &glslMaxRecommendedIndices);
247 glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &glslMaxRecommendedVertices);
248 glslMaxVaryings /= 4; // GL_MAX_VARYING_FLOATS returns max individual floats, we want float4
249 }
250
251 // detect if GL_DEPTH_COMPONENT24 is supported (many ATIs don't do so)
252 {
253 // ATI seems to support GL_DEPTH_COMPONENT24 for static textures, but you can't render to them
254 /*
255 GLint state = 0;
256 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 16, 16, 0, GL_LUMINANCE, GL_FLOAT, NULL);
257 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &state);
258 support24bitDepthBuffers = (state > 0);
259 */
260
261 support24bitDepthBuffers = false;
262 if (FBO::IsSupported() && !atiHacks) {
263 const int fboSizeX = 16, fboSizeY = 16;
264
265 FBO fbo;
266 fbo.Bind();
267 fbo.CreateRenderBuffer(GL_COLOR_ATTACHMENT0_EXT, GL_RGBA8, fboSizeX, fboSizeY);
268 fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT24, fboSizeX, fboSizeY);
269 const GLenum status = fbo.GetStatus();
270 fbo.Unbind();
271
272 support24bitDepthBuffers = (status == GL_FRAMEBUFFER_COMPLETE_EXT);
273 }
274 }
275
276 // print info
277 LOG(
278 "GL info:\n"
279 "\thaveARB: %i, haveGLSL: %i, ATI hacks: %i\n"
280 "\tFBO support: %i, NPOT-texture support: %i, 24bit Z-buffer support: %i\n"
281 "\tmaximum texture size: %i, compress MIP-map textures: %i\n"
282 "\tmaximum SmoothPointSize: %0.0f, maximum vec4 varying/attributes: %i/%i\n"
283 "\tmaximum drawbuffers: %i, maximum recommended indices/vertices: %i/%i\n"
284 "\tnumber of UniformBufferBindings: %i (%ikB)",
285 haveARB, haveGLSL, atiHacks,
286 FBO::IsSupported(), supportNPOTs, support24bitDepthBuffers,
287 maxTextureSize, compressTextures, maxSmoothPointSize,
288 glslMaxVaryings, glslMaxAttributes, glslMaxDrawBuffers,
289 glslMaxRecommendedIndices, glslMaxRecommendedVertices,
290 glslMaxUniformBufferBindings, glslMaxUniformBufferSize / 1024
291 );
292
293 teamNanospray = configHandler->GetBool("TeamNanoSpray");
294 }
295
SetFullScreen(bool configFullScreen,bool cmdLineWindowed,bool cmdLineFullScreen)296 void CGlobalRendering::SetFullScreen(bool configFullScreen, bool cmdLineWindowed, bool cmdLineFullScreen)
297 {
298 #ifdef _DEBUG
299 fullScreen = false;
300 #else
301 fullScreen = configFullScreen;
302 #endif
303
304 // flags
305 if (cmdLineWindowed) {
306 fullScreen = false;
307 } else if (cmdLineFullScreen) {
308 fullScreen = true;
309 }
310 }
311
SetViewSize(int vsx,int vsy)312 void CGlobalRendering::SetViewSize(int vsx, int vsy)
313 {
314 viewSizeX = vsx;
315 viewSizeY = vsy;
316 }
317
SetDualScreenParams()318 void CGlobalRendering::SetDualScreenParams() {
319 dualScreenMode = configHandler->GetBool("DualScreenMode");
320
321 if (dualScreenMode) {
322 dualScreenMiniMapOnLeft = configHandler->GetBool("DualScreenMiniMapOnLeft");
323 } else {
324 dualScreenMiniMapOnLeft = false;
325 }
326 }
327
UpdateViewPortGeometry()328 void CGlobalRendering::UpdateViewPortGeometry() {
329 // NOTE: viewPosY is not currently used (always 0)
330 if (!dualScreenMode) {
331 viewSizeX = winSizeX;
332 viewSizeY = winSizeY;
333 viewPosX = 0;
334 viewPosY = 0;
335 } else {
336 viewSizeX = winSizeX / 2;
337 viewSizeY = winSizeY;
338
339 if (dualScreenMiniMapOnLeft) {
340 viewPosX = winSizeX / 2;
341 viewPosY = 0;
342 } else {
343 viewPosX = 0;
344 viewPosY = 0;
345 }
346 }
347 }
348
UpdatePixelGeometry()349 void CGlobalRendering::UpdatePixelGeometry() {
350 pixelX = 1.0f / viewSizeX;
351 pixelY = 1.0f / viewSizeY;
352
353 aspectRatio = viewSizeX / float(viewSizeY);
354 }
355