Cavalry not attacking soldiers on Jebel Barkal wasn't a successful idea.
[0ad.git] / source / lib / ogl.cpp
blobe0bea792bc062ed1638ea65b8ad01a04ab7381f9
1 /* Copyright (C) 2017 Wildfire Games.
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * OpenGL helper functions.
27 #include "precompiled.h"
28 #include "lib/ogl.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdarg.h>
34 #include "lib/external_libraries/libsdl.h"
35 #include "lib/debug.h"
36 #include "lib/sysdep/gfx.h"
37 #include "lib/res/h_mgr.h"
39 #if MSC_VERSION
40 #pragma comment(lib, "opengl32.lib")
41 #endif
44 //----------------------------------------------------------------------------
45 // extensions
46 //----------------------------------------------------------------------------
48 // define extension function pointers
49 extern "C"
51 #define FUNC(ret, name, params) ret (GL_CALL_CONV *p##name) params;
52 #define FUNC2(ret, nameARB, nameCore, version, params) ret (GL_CALL_CONV *p##nameARB) params;
53 #define FUNC3(ret, nameARB, nameCore, version, params) ret (GL_CALL_CONV *p##nameCore) params;
54 #include "lib/external_libraries/glext_funcs.h"
55 #undef FUNC3
56 #undef FUNC2
57 #undef FUNC
61 static const char* exts = NULL;
62 static bool have_30, have_21, have_20, have_15, have_14, have_13, have_12;
65 // return a C string of unspecified length containing a space-separated
66 // list of all extensions the OpenGL implementation advertises.
67 // (useful for crash logs).
68 const char* ogl_ExtensionString()
70 ENSURE(exts && "call ogl_Init before using this function");
71 return exts;
75 // paranoia: newer drivers may forget to advertise an extension
76 // indicating support for something that has been folded into the core.
77 // we therefore check for all extensions known to be offered by the
78 // GL implementation present on the user's system; ogl_HaveExtension will
79 // take this into account.
80 // the app can therefore just ask for extensions and not worry about this.
81 static bool isImplementedInCore(const char* ext)
83 #define MATCH(known_ext)\
84 if(!strcmp(ext, #known_ext))\
85 return true;
87 if(have_30)
89 MATCH(GL_EXT_gpu_shader4);
90 MATCH(GL_NV_conditional_render);
91 MATCH(GL_ARB_color_buffer_float);
92 MATCH(GL_ARB_depth_buffer_float);
93 MATCH(GL_ARB_texture_float);
94 MATCH(GL_EXT_packed_float);
95 MATCH(GL_EXT_texture_shared_exponent);
96 MATCH(GL_EXT_framebuffer_object);
97 MATCH(GL_NV_half_float);
98 MATCH(GL_ARB_half_float_pixel);
99 MATCH(GL_EXT_framebuffer_multisample);
100 MATCH(GL_EXT_framebuffer_blit);
101 MATCH(GL_EXT_texture_integer);
102 MATCH(GL_EXT_texture_array);
103 MATCH(GL_EXT_packed_depth_stencil);
104 MATCH(GL_EXT_draw_buffers2);
105 MATCH(GL_EXT_texture_compression_rgtc);
106 MATCH(GL_EXT_transform_feedback);
107 MATCH(GL_APPLE_vertex_array_object);
108 MATCH(GL_EXT_framebuffer_sRGB);
110 if(have_21)
112 MATCH(GL_ARB_pixel_buffer_object);
113 MATCH(GL_EXT_texture_sRGB);
115 if(have_20)
117 MATCH(GL_ARB_shader_objects);
118 MATCH(GL_ARB_vertex_shader);
119 MATCH(GL_ARB_fragment_shader);
120 MATCH(GL_ARB_shading_language_100);
121 MATCH(GL_ARB_draw_buffers);
122 MATCH(GL_ARB_texture_non_power_of_two);
123 MATCH(GL_ARB_point_sprite);
124 MATCH(GL_EXT_blend_equation_separate);
126 if(have_15)
128 MATCH(GL_ARB_vertex_buffer_object);
129 MATCH(GL_ARB_occlusion_query);
130 MATCH(GL_EXT_shadow_funcs);
132 if(have_14)
134 MATCH(GL_SGIS_generate_mipmap);
135 MATCH(GL_NV_blend_square);
136 MATCH(GL_ARB_depth_texture);
137 MATCH(GL_ARB_shadow);
138 MATCH(GL_EXT_fog_coord);
139 MATCH(GL_EXT_multi_draw_arrays);
140 MATCH(GL_ARB_point_parameters);
141 MATCH(GL_EXT_secondary_color);
142 MATCH(GL_EXT_blend_func_separate);
143 MATCH(GL_EXT_stencil_wrap);
144 MATCH(GL_ARB_texture_env_crossbar);
145 MATCH(GL_EXT_texture_lod_bias);
146 MATCH(GL_ARB_texture_mirrored_repeat);
147 MATCH(GL_ARB_window_pos);
149 // These extensions were added to GL 1.2, but as part of the optional
150 // imaging subset; they're only guaranteed as of GL 1.4:
151 MATCH(GL_EXT_blend_color);
152 MATCH(GL_EXT_blend_minmax);
153 MATCH(GL_EXT_blend_subtract);
155 if(have_13)
157 MATCH(GL_ARB_texture_compression);
158 MATCH(GL_ARB_texture_cube_map);
159 MATCH(GL_ARB_multisample);
160 MATCH(GL_ARB_multitexture);
161 MATCH(GL_ARB_transpose_matrix);
162 MATCH(GL_ARB_texture_env_add);
163 MATCH(GL_ARB_texture_env_combine);
164 MATCH(GL_ARB_texture_env_dot3);
165 MATCH(GL_ARB_texture_border_clamp);
167 if(have_12)
169 MATCH(GL_EXT_texture3D);
170 MATCH(GL_EXT_bgra);
171 MATCH(GL_EXT_packed_pixels);
172 MATCH(GL_EXT_rescale_normal);
173 MATCH(GL_EXT_separate_specular_color);
174 MATCH(GL_SGIS_texture_edge_clamp);
175 MATCH(GL_SGIS_texture_lod);
176 MATCH(GL_EXT_draw_range_elements);
177 // Skip the extensions that only affect the imaging subset
180 #undef MATCH
181 return false;
185 // check if the extension <ext> is supported by the OpenGL implementation.
186 // takes subsequently added core support for some extensions into account.
187 bool ogl_HaveExtension(const char* ext)
189 ENSURE(exts && "call ogl_Init before using this function");
191 if(isImplementedInCore(ext))
192 return true;
194 const char *p = exts, *end;
196 // make sure ext is valid & doesn't contain spaces
197 if(!ext || ext[0] == '\0' || strchr(ext, ' '))
198 return false;
200 for(;;)
202 p = strstr(p, ext);
203 if(!p)
204 return false; // <ext> string not found - extension not supported
205 end = p + strlen(ext); // end of current substring
207 // make sure the substring found is an entire extension string,
208 // i.e. it starts and ends with ' '
209 if((p == exts || p[-1] == ' ') && // valid start AND
210 (*end == ' ' || *end == '\0')) // valid end
211 return true;
212 p = end;
217 // check if the OpenGL implementation is at least at <version>.
218 // (format: "%d.%d" major minor)
219 bool ogl_HaveVersion(const char* desired_version)
221 int desired_major, desired_minor;
222 if(sscanf_s(desired_version, "%d.%d", &desired_major, &desired_minor) != 2)
224 DEBUG_WARN_ERR(ERR::LOGIC); // invalid version string
225 return false;
228 // guaranteed to be of the form "major.minor[.release][ vendor-specific]"
229 // or "OpenGL ES major.minor[.release][ vendor-specific]".
230 // we won't distinguish GLES 2.0 from GL 2.0, but that's okay since
231 // they're close enough.
232 const char* version = (const char*)glGetString(GL_VERSION);
233 int major, minor;
234 if(!version ||
235 (sscanf_s(version, "%d.%d", &major, &minor) != 2 &&
236 sscanf_s(version, "OpenGL ES %d.%d", &major, &minor) != 2))
238 DEBUG_WARN_ERR(ERR::LOGIC); // GL_VERSION invalid
239 return false;
242 // note: don't just compare characters - major and minor may be >= 10.
243 return (major > desired_major) ||
244 (major == desired_major && minor >= desired_minor);
248 // check if all given extension strings (passed as const char* parameters,
249 // terminated by a 0 pointer) are supported by the OpenGL implementation,
250 // as determined by ogl_HaveExtension.
251 // returns 0 if all are present; otherwise, the first extension in the
252 // list that's not supported (useful for reporting errors).
254 // note: dummy parameter is necessary to access parameter va_list.
257 // rationale: this interface is more convenient than individual
258 // ogl_HaveExtension calls and allows reporting which extension is missing.
260 // one disadvantage is that there is no way to indicate that either one
261 // of 2 extensions would be acceptable, e.g. (ARB|EXT)_texture_env_dot3.
262 // this is isn't so bad, since they wouldn't be named differently
263 // if there weren't non-trivial changes between them. for that reason,
264 // we refrain from equivalence checks (which would boil down to
265 // string-matching known extensions to their equivalents).
266 const char* ogl_HaveExtensions(int dummy, ...)
268 const char* ext;
270 va_list args;
271 va_start(args, dummy);
272 for(;;)
274 ext = va_arg(args, const char*);
275 // end of list reached; all were present => return 0.
276 if(!ext)
277 break;
279 // not found => return name of missing extension.
280 if(!ogl_HaveExtension(ext))
281 break;
283 va_end(args);
285 return ext;
289 // to help when running with no hardware acceleration and only OpenGL 1.1
290 // (e.g. testing the game in virtual machines), we define dummy versions of
291 // some extension functions which our graphics code assumes exist.
292 // it will render incorrectly but at least it shouldn't crash.
294 #if CONFIG2_GLES
296 static void enableDummyFunctions()
300 #else
302 static void GL_CALL_CONV dummy_glDrawRangeElementsEXT(GLenum mode, GLuint, GLuint, GLsizei count, GLenum type, GLvoid* indices)
304 glDrawElements(mode, count, type, indices);
307 static void GL_CALL_CONV dummy_glActiveTextureARB(int)
311 static void GL_CALL_CONV dummy_glClientActiveTextureARB(int)
315 static void GL_CALL_CONV dummy_glMultiTexCoord2fARB(int, float s, float t)
317 glTexCoord2f(s, t);
320 static void GL_CALL_CONV dummy_glMultiTexCoord3fARB(int, float s, float t, float r)
322 glTexCoord3f(s, t, r);
325 static void enableDummyFunctions()
327 // fall back to the dummy functions when extensions (or equivalent core support) are missing
329 if(!ogl_HaveExtension("GL_EXT_draw_range_elements"))
331 pglDrawRangeElementsEXT = &dummy_glDrawRangeElementsEXT;
334 if(!ogl_HaveExtension("GL_ARB_multitexture"))
336 pglActiveTextureARB = &dummy_glActiveTextureARB;
337 pglClientActiveTextureARB = &dummy_glClientActiveTextureARB;
338 pglMultiTexCoord2fARB = &dummy_glMultiTexCoord2fARB;
339 pglMultiTexCoord3fARB = &dummy_glMultiTexCoord3fARB;
343 #endif // #if CONFIG2_GLES
345 static void importExtensionFunctions()
347 // It should be safe to load the ARB function pointers even if the
348 // extension isn't advertised, since we won't actually use them without
349 // checking for the extension.
350 // (TODO: this calls ogl_HaveVersion far more times than is necessary -
351 // we should probably use the have_* variables instead)
352 // Note: the xorg-x11 implementation of glXGetProcAddress doesn't return NULL
353 // if the function is unsupported (i.e. the rare case of a driver not reporting
354 // its supported version correctly, see http://trac.wildfiregames.com/ticket/171)
355 #define FUNC(ret, name, params) p##name = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#name);
356 #define FUNC23(pname, ret, nameARB, nameCore, version, params) \
357 pname = NULL; \
358 if(ogl_HaveVersion(version)) \
359 pname = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#nameCore); \
360 if(!pname) /* use the ARB name if the driver lied about what version it supports */ \
361 pname = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#nameARB);
362 #define FUNC2(ret, nameARB, nameCore, version, params) FUNC23(p##nameARB, ret, nameARB, nameCore, version, params)
363 #define FUNC3(ret, nameARB, nameCore, version, params) FUNC23(p##nameCore, ret, nameARB, nameCore, version, params)
364 #include "lib/external_libraries/glext_funcs.h"
365 #undef FUNC3
366 #undef FUNC2
367 #undef FUNC23
368 #undef FUNC
370 enableDummyFunctions();
374 //----------------------------------------------------------------------------
376 const char* ogl_GetErrorName(GLenum err)
378 #define E(e) case e: return #e;
379 switch (err)
381 E(GL_INVALID_ENUM)
382 E(GL_INVALID_VALUE)
383 E(GL_INVALID_OPERATION)
384 #if !CONFIG2_GLES
385 E(GL_STACK_OVERFLOW)
386 E(GL_STACK_UNDERFLOW)
387 #endif
388 E(GL_OUT_OF_MEMORY)
389 E(GL_INVALID_FRAMEBUFFER_OPERATION)
390 default: return "Unknown GL error";
392 #undef E
395 static void dump_gl_error(GLenum err)
397 debug_printf("OGL| %s (%04x)\n", ogl_GetErrorName(err), err);
400 void ogl_WarnIfErrorLoc(const char *file, int line)
402 // glGetError may return multiple errors, so we poll it in a loop.
403 // the debug_printf should only happen once (if this is set), though.
404 bool error_enountered = false;
405 GLenum first_error = 0;
407 for(;;)
409 GLenum err = glGetError();
410 if(err == GL_NO_ERROR)
411 break;
413 if(!error_enountered)
414 first_error = err;
416 error_enountered = true;
417 dump_gl_error(err);
420 if(error_enountered)
421 debug_printf("%s:%d: OpenGL error(s) occurred: %s (%04x)\n", file, line, ogl_GetErrorName(first_error), (unsigned int)first_error);
425 // ignore and reset the specified error (as returned by glGetError).
426 // any other errors that have occurred are reported as ogl_WarnIfError would.
428 // this is useful for suppressing annoying error messages, e.g.
429 // "invalid enum" for GL_CLAMP_TO_EDGE even though we've already
430 // warned the user that their OpenGL implementation is too old.
431 bool ogl_SquelchError(GLenum err_to_ignore)
433 // glGetError may return multiple errors, so we poll it in a loop.
434 // the debug_printf should only happen once (if this is set), though.
435 bool error_enountered = false;
436 bool error_ignored = false;
437 GLenum first_error = 0;
439 for(;;)
441 GLenum err = glGetError();
442 if(err == GL_NO_ERROR)
443 break;
445 if(err == err_to_ignore)
447 error_ignored = true;
448 continue;
451 if(!error_enountered)
452 first_error = err;
454 error_enountered = true;
455 dump_gl_error(err);
458 if(error_enountered)
459 debug_printf("OpenGL error(s) occurred: %04x\n", (unsigned int)first_error);
461 return error_ignored;
465 //----------------------------------------------------------------------------
466 // feature and limit detect
467 //----------------------------------------------------------------------------
469 GLint ogl_max_tex_size = -1; // [pixels]
470 GLint ogl_max_tex_units = -1; // limit on GL_TEXTUREn
472 // call after each video mode change, since thereafter extension functions
473 // may have changed [address].
474 void ogl_Init()
476 // cache extension list and versions for oglHave*.
477 // note: this is less about performance (since the above are not
478 // time-critical) than centralizing the 'OpenGL is ready' check.
479 exts = (const char*)glGetString(GL_EXTENSIONS);
480 ENSURE(exts); // else: called before OpenGL is ready for use
481 have_12 = ogl_HaveVersion("1.2");
482 have_13 = ogl_HaveVersion("1.3");
483 have_14 = ogl_HaveVersion("1.4");
484 have_15 = ogl_HaveVersion("1.5");
485 have_20 = ogl_HaveVersion("2.0");
486 have_21 = ogl_HaveVersion("2.1");
487 have_30 = ogl_HaveVersion("3.0");
489 importExtensionFunctions();
491 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &ogl_max_tex_size);
492 #if !CONFIG2_GLES
493 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units);
494 #endif