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