Oolite
Loading...
Searching...
No Matches
OOOpenGLExtensionManager.m
Go to the documentation of this file.
1/*
2
3OOOpenGLExtensionManager.m
4
5
6Copyright (C) 2007-2013 Jens Ayton and contributors
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
29#import "OOLogging.h"
31#include <stdlib.h>
33
34#import "ResourceManager.h"
36#import "OORegExpMatcher.h"
37#import "OOConstToString.h"
38
39
40/* OpenGL version required, currently 1.1 or later (basic stuff like
41 glBindTexture(), glDrawArrays()). We probably have implicit requirements
42 for later versions, but I don't feel like auditing.
43 -- Ahruman
44 We need at least 3.0 for the Frame Buffer Objects now in use. Might as
45 well go all the way to 3.3.
46 -- Nikos 20220817
47*/
48enum
49{
52};
53
54
55#if OOLITE_WINDOWS
56/* Define the function pointers for the OpenGL extensions used in the game
57 (required for Windows only).
58*/
59static void OOBadOpenGLExtensionUsed(void) GCC_ATTR((noreturn, used));
60
61#if OO_SHADERS
62
63PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
64PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)&OOBadOpenGLExtensionUsed;
65PFNGLUNIFORM1IARBPROC glUniform1iARB = (PFNGLUNIFORM1IARBPROC)&OOBadOpenGLExtensionUsed;
66PFNGLUNIFORM1FARBPROC glUniform1fARB = (PFNGLUNIFORM1FARBPROC)&OOBadOpenGLExtensionUsed;
67PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)&OOBadOpenGLExtensionUsed;
68PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)&OOBadOpenGLExtensionUsed;
69PFNGLUNIFORM4FVARBPROC glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)&OOBadOpenGLExtensionUsed;
70PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)&OOBadOpenGLExtensionUsed;
71PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)&OOBadOpenGLExtensionUsed;
72PFNGLGETINFOLOGARBPROC glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)&OOBadOpenGLExtensionUsed;
73PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
74PFNGLATTACHOBJECTARBPROC glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
75PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
76PFNGLLINKPROGRAMARBPROC glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)&OOBadOpenGLExtensionUsed;
77PFNGLCOMPILESHADERARBPROC glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)&OOBadOpenGLExtensionUsed;
78PFNGLSHADERSOURCEARBPROC glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)&OOBadOpenGLExtensionUsed;
79PFNGLUNIFORM2FVARBPROC glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)&OOBadOpenGLExtensionUsed;
80PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)&OOBadOpenGLExtensionUsed;
81PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)&OOBadOpenGLExtensionUsed;
82PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)&OOBadOpenGLExtensionUsed;
83PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)&OOBadOpenGLExtensionUsed;
84PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)&OOBadOpenGLExtensionUsed;
85#endif
86
87#if OO_SHADERS || OO_MULTITEXTURE
88PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)&OOBadOpenGLExtensionUsed;
89#endif
90
91#if OO_MULTITEXTURE
92PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)&OOBadOpenGLExtensionUsed;
93#endif
94
95#if OO_USE_VBO
96PFNGLGENBUFFERSARBPROC glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)&OOBadOpenGLExtensionUsed;
97PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)&OOBadOpenGLExtensionUsed;
98PFNGLBINDBUFFERARBPROC glBindBufferARB = (PFNGLBINDBUFFERARBPROC)&OOBadOpenGLExtensionUsed;
99PFNGLBUFFERDATAARBPROC glBufferDataARB = (PFNGLBUFFERDATAARBPROC)&OOBadOpenGLExtensionUsed;
100#endif
101
102#if OO_USE_FBO
103PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
104PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
105PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
106PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
107PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)&OOBadOpenGLExtensionUsed;
108PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
109PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)&OOBadOpenGLExtensionUsed;
110PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)&OOBadOpenGLExtensionUsed;
111PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
112PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
113PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)&OOBadOpenGLExtensionUsed;
114PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)&OOBadOpenGLExtensionUsed;
115PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)&OOBadOpenGLExtensionUsed;
116PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
117PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)&OOBadOpenGLExtensionUsed;
118PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)&OOBadOpenGLExtensionUsed;
119PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)&OOBadOpenGLExtensionUsed;
120PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)&OOBadOpenGLExtensionUsed;
121PFNGLGENBUFFERSPROC glGenBuffers = (PFNGLGENBUFFERSPROC)&OOBadOpenGLExtensionUsed;
122PFNGLBINDVERTEXARRAYPROC glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)&OOBadOpenGLExtensionUsed;
123PFNGLBINDBUFFERPROC glBindBuffer = (PFNGLBINDBUFFERPROC)&OOBadOpenGLExtensionUsed;
124PFNGLBUFFERDATAPROC glBufferData = (PFNGLBUFFERDATAPROC)&OOBadOpenGLExtensionUsed;
125PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)&OOBadOpenGLExtensionUsed;
126PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)&OOBadOpenGLExtensionUsed;
127PFNGLUSEPROGRAMPROC glUseProgram = (PFNGLUSEPROGRAMPROC)&OOBadOpenGLExtensionUsed;
128PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)&OOBadOpenGLExtensionUsed;
129PFNGLUNIFORM1IPROC glUniform1i = (PFNGLUNIFORM1IPROC)&OOBadOpenGLExtensionUsed;
130PFNGLACTIVETEXTUREPROC glActiveTexture = (PFNGLACTIVETEXTUREPROC)&OOBadOpenGLExtensionUsed;
131PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)&OOBadOpenGLExtensionUsed;
132PFNGLUNIFORM1FPROC glUniform1f = (PFNGLUNIFORM1FPROC)&OOBadOpenGLExtensionUsed;
133PFNGLUNIFORM2FVPROC glUniform2fv = (PFNGLUNIFORM2FVPROC)&OOBadOpenGLExtensionUsed;
134PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)&OOBadOpenGLExtensionUsed;
135PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
136PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)&OOBadOpenGLExtensionUsed;
137PFNGLDELETEBUFFERSPROC glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
138PFNGLDRAWBUFFERSPROC glDrawBuffers = (PFNGLDRAWBUFFERSPROC)&OOBadOpenGLExtensionUsed;
139PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)&OOBadOpenGLExtensionUsed;
140PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)&OOBadOpenGLExtensionUsed;
141PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)&OOBadOpenGLExtensionUsed;
142PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)&OOBadOpenGLExtensionUsed;
143PFNGLCLAMPCOLORPROC glClampColor = (PFNGLCLAMPCOLORPROC)&OOBadOpenGLExtensionUsed;
144#endif
145#endif
146
147
148static NSString * const kOOLogOpenGLShaderSupport = @"rendering.opengl.shader.support";
149
150
152
153
154// Read integer from string, advancing string to end of read data.
155static unsigned IntegerFromString(const GLubyte **ioString);
156
157
158@interface OOOpenGLExtensionManager (OOPrivate)
159
160#if OO_SHADERS
162#endif
163
164#if OO_USE_VBO
165- (void)checkVBOSupported;
166#endif
167
168#if OO_USE_FBO
169- (void)checkFBOSupported;
170#endif
171
172#if GL_ARB_texture_env_combine
173- (void)checkTextureCombinersSupported;
174#endif
175
176- (NSDictionary *) lookUpPerGPUSettingsWithVersionString:(NSString *)version extensionsString:(NSString *)extensionsStr;
177
178@end
179
180
181static NSArray *ArrayOfExtensions(NSString *extensionString)
182{
183 NSArray *components = [extensionString componentsSeparatedByString:@" "];
184 NSMutableArray *result = [NSMutableArray arrayWithCapacity:[components count]];
185 NSString *extStr = nil;
186 foreach (extStr, components)
187 {
188 if ([extStr length] > 0) [result addObject:extStr];
189 }
190 return result;
191}
192
193
194@implementation OOOpenGLExtensionManager
195
196- (id)init
197{
198 self = [super init];
199 if (self != nil)
200 {
201#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
202 lock = [[NSLock alloc] init];
203 [lock setName:@"OOOpenGLExtensionManager extension set lock"];
204#endif
205
206 [self reset];
207 }
208
209 return self;
210}
211
212
213- (void) reset
214{
215 const GLubyte *versionString = NULL, *curr = NULL;
216
217 DESTROY(extensions);
218 DESTROY(vendor);
219 DESTROY(renderer);
220
221 NSString *extensionsStr = [NSString stringWithUTF8String:(char *)glGetString(GL_EXTENSIONS)];
222 extensions = [[NSSet alloc] initWithArray:ArrayOfExtensions(extensionsStr)];
223
224 vendor = [[NSString alloc] initWithUTF8String:(const char *)glGetString(GL_VENDOR)];
225 renderer = [[NSString alloc] initWithUTF8String:(const char *)glGetString(GL_RENDERER)];
226
227 versionString = glGetString(GL_VERSION);
228 if (versionString != NULL)
229 {
230 /* String is supposed to be "major.minorFOO" or
231 "major.minor.releaseFOO" where FOO is an empty string or
232 a string beginning with space.
233 */
234 curr = versionString;
235 major = IntegerFromString(&curr);
236 if (*curr == '.')
237 {
238 curr++;
239 minor = IntegerFromString(&curr);
240 }
241 if (*curr == '.')
242 {
243 curr++;
244 release = IntegerFromString(&curr);
245 }
246 }
247
248 /* For aesthetic reasons, cause the ResourceManager to initialize its
249 search paths here. If we don't, the search path dump ends up in
250 the middle of the OpenGL stuff.
251 */
253
254 OOLog(@"rendering.opengl.version", @"OpenGL renderer version: %u.%u.%u (\"%s\"). Vendor: \"%@\". Renderer: \"%@\".", major, minor, release, versionString, vendor, renderer);
255 OOLog(@"rendering.opengl.extensions", @"OpenGL extensions (%llu):\n%@", [extensions count], [[extensions allObjects] componentsJoinedByString:@", "]);
256
257 if (![self versionIsAtLeastMajor:kMinMajorVersion minor:kMinMinorVersion])
258 {
259 OOLog(@"rendering.opengl.version.insufficient", @"***** Oolite requires OpenGL version %u.%u or later.", kMinMajorVersion, kMinMinorVersion);
260 [NSException raise:@"OoliteOpenGLTooOldException"
261 format:@"Oolite requires at least OpenGL %u.%u. You have %u.%u (\"%s\").", kMinMajorVersion, kMinMinorVersion, major, minor, versionString];
262 }
263
264 NSString *versionStr = [[[NSString alloc] initWithUTF8String:(const char *)versionString] autorelease];
265 NSDictionary *gpuConfig = [self lookUpPerGPUSettingsWithVersionString:versionStr extensionsString:extensionsStr];
266
267#if OO_SHADERS
268 [self checkShadersSupported];
269
270 if (shadersAvailable)
271 {
272 defaultShaderSetting = OOShaderSettingFromString([gpuConfig oo_stringForKey:@"default_shader_level"
273 defaultValue:@"SHADERS_FULL"]);
274 maximumShaderSetting = OOShaderSettingFromString([gpuConfig oo_stringForKey:@"maximum_shader_level"
275 defaultValue:@"SHADERS_FULL"]);
276 if (maximumShaderSetting <= SHADERS_OFF)
277 {
278 shadersAvailable = NO;
279 maximumShaderSetting = SHADERS_NOT_SUPPORTED;
280 OOLog(kOOLogOpenGLShaderSupport, @"Shaders will not be used (disallowed for GPU type \"%@\").", [gpuConfig oo_stringForKey:@"name" defaultValue:renderer]);
281 }
282 if (maximumShaderSetting < defaultShaderSetting)
283 {
284 defaultShaderSetting = maximumShaderSetting;
285 }
286
287 if (shadersAvailable)
288 {
289 OOLog(kOOLogOpenGLShaderSupport, @"%@", @"Shaders are supported.");
290 }
291 }
292 else
293 {
294 defaultShaderSetting = SHADERS_NOT_SUPPORTED;
295 maximumShaderSetting = SHADERS_NOT_SUPPORTED;
296 }
297
298 GLint texImageUnitOverride = [gpuConfig oo_intForKey:@"texture_image_units" defaultValue:textureImageUnitCount];
299 if (texImageUnitOverride < textureImageUnitCount) textureImageUnitCount = MAX(texImageUnitOverride, 0);
300#endif
301
302#if OO_USE_VBO
303 [self checkVBOSupported];
304#endif
305#if OO_USE_FBO
306 [self checkFBOSupported];
307#endif
308#if OO_MULTITEXTURE
309 [self checkTextureCombinersSupported];
310 GLint texUnitOverride = [gpuConfig oo_intForKey:@"texture_units" defaultValue:textureUnitCount];
311 if (texUnitOverride < textureUnitCount) textureUnitCount = MAX(texUnitOverride, 0);
312#endif
313
314 usePointSmoothing = [gpuConfig oo_boolForKey:@"smooth_points" defaultValue:YES];
315 useLineSmoothing = [gpuConfig oo_boolForKey:@"smooth_lines" defaultValue:YES];
316 useDustShader = [gpuConfig oo_boolForKey:@"use_dust_shader" defaultValue:YES];
317}
318
319
320- (void)dealloc
321{
322 if (sSingleton == self) sSingleton = nil;
323
324#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
325 [lock release];
326#endif
327 DESTROY(extensions);
328 DESTROY(vendor);
329 DESTROY(renderer);
330
331 [super dealloc];
332}
333
334
335+ (OOOpenGLExtensionManager *)sharedManager
336{
337 // NOTE: assumes single-threaded first access. See header.
338 if (sSingleton == nil) sSingleton = [[self alloc] init];
339 return sSingleton;
340}
341
342
343- (BOOL)haveExtension:(NSString *)extension
344{
345// NSSet is documented as thread-safe under OS X, but I'm not sure about GNUstep. -- Ahruman
346#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
347 [lock lock];
348#endif
349
350 BOOL result = [extensions containsObject:extension];
351
352#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
353 [lock unlock];
354#endif
355
356 return result;
357}
358
359
360- (BOOL)shadersSupported
361{
362#if OO_SHADERS
363 return shadersAvailable;
364#else
365 return NO;
366#endif
367}
368
369
370- (BOOL)shadersForceDisabled
371{
372#if OO_SHADERS
373 return shadersForceDisabled;
374#else
375 return YES;
376#endif
377}
378
379
380- (OOGraphicsDetail)defaultDetailLevel
381{
382#if OO_SHADERS
383 if (defaultShaderSetting < SHADERS_FULL)
384 {
386 }
387 else
388 {
390 }
391#else
393#endif
394}
395
396
397- (OOGraphicsDetail)maximumDetailLevel
398{
399#if OO_SHADERS
400 if (maximumShaderSetting < SHADERS_FULL)
401 {
403 }
404 else
405 {
407 }
408#else
410#endif
411}
412
413
414- (GLint)textureImageUnitCount
415{
416#if OO_SHADERS
417 return textureImageUnitCount;
418#else
419 return 0;
420#endif
421}
422
423
424- (BOOL)vboSupported
425{
426#if OO_USE_VBO
427 return vboSupported;
428#else
429 return NO;
430#endif
431}
432
433
434- (BOOL)fboSupported
435{
436#if OO_USE_FBO
437 return fboSupported;
438#else
439 return NO;
440#endif
441}
442
443
444- (BOOL)textureCombinersSupported
445{
446#if OO_MULTITEXTURE
447 return textureCombinersSupported;
448#else
449 return NO;
450#endif
451}
452
453
454- (GLint)textureUnitCount
455{
456#if OO_MULTITEXTURE
457 return textureUnitCount;
458#else
459 return 0;
460#endif
461}
462
463
464- (NSUInteger)majorVersionNumber
465{
466 return major;
467}
468
469
470- (NSUInteger)minorVersionNumber
471{
472 return minor;
473}
474
475
476- (NSUInteger)releaseVersionNumber
477{
478 return release;
479}
480
481
482- (void)getVersionMajor:(unsigned *)outMajor minor:(unsigned *)outMinor release:(unsigned *)outRelease
483{
484 if (outMajor != NULL) *outMajor = major;
485 if (outMinor != NULL) *outMinor = minor;
486 if (outRelease != NULL) *outRelease = release;
487}
488
489
490- (BOOL) versionIsAtLeastMajor:(unsigned)maj minor:(unsigned)min
491{
492 return major > maj || (major == maj && minor >= min);
493}
494
495
496- (NSString *) vendorString
497{
498 return vendor;
499}
500
501
502- (NSString *) rendererString
503{
504 return renderer;
505}
506
507
508- (BOOL) usePointSmoothing
509{
510 return usePointSmoothing;
511}
512
513
514- (BOOL) useLineSmoothing
515{
516 return useLineSmoothing;
517}
518
519
520- (BOOL) useDustShader
521{
522 return useDustShader;
523}
524
525@end
526
527
528static unsigned IntegerFromString(const GLubyte **ioString)
529{
530 if (EXPECT_NOT(ioString == NULL)) return 0;
531
532 unsigned result = 0;
533 const GLubyte *curr = *ioString;
534
535 while ('0' <= *curr && *curr <= '9')
536 {
537 result = result * 10 + *curr++ - '0';
538 }
539
540 *ioString = curr;
541 return result;
542}
543
544
545@implementation OOOpenGLExtensionManager (OOPrivate)
546
547
548#if OO_SHADERS
549
555{
556 shadersAvailable = NO;
557 shadersForceDisabled = NO;
558
559 /* Some cards claim to support shaders but do so extremely
560 * badly. These are listed in gpu-settings.plist where we know
561 * about them; for those we don't being able to run with
562 * -noshaders may help get the game up and running at a frame rate
563 * where thegraphics settings can be changed. - CIM */
564 NSArray *arguments = [[NSProcessInfo processInfo] arguments];
565 NSString *arg = nil;
566 // scan for shader overrides: -noshaders || --noshaders
567 foreach (arg, arguments)
568 {
569 if ([arg isEqual:@"-noshaders"] || [arg isEqual:@"--noshaders"])
570 {
571 shadersForceDisabled = YES;
572 OOLog(kOOLogOpenGLShaderSupport, @"%@", @"Shaders will not be used (disabled on command line).");
573 return;
574 }
575 }
576
577 NSString * const requiredExtension[] =
578 {
579 @"GL_ARB_shading_language_100",
580 @"GL_ARB_fragment_shader",
581 @"GL_ARB_vertex_shader",
582 @"GL_ARB_multitexture",
583 @"GL_ARB_shader_objects",
584 nil // sentinel - don't remove!
585 };
586 NSString * const *required = NULL;
587
588 for (required = requiredExtension; *required != nil; ++required)
589 {
590 if (![self haveExtension:*required])
591 {
592 OOLog(kOOLogOpenGLShaderSupport, @"Shaders will not be used (OpenGL extension %@ is not available).", *required);
593 return;
594 }
595 }
596
597#if OOLITE_WINDOWS
598 glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
599 glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
600 glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
601 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
602 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
603 glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
604 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");
605 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
606 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
607 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
608 glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
609 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB");
610 glUniform1iARB = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB");
611 glUniform1fARB = (PFNGLUNIFORM1FARBPROC)wglGetProcAddress("glUniform1fARB");
612 glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)wglGetProcAddress("glUniformMatrix3fvARB");
613 glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)wglGetProcAddress("glUniformMatrix4fvARB");
614 glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)wglGetProcAddress("glUniform4fvARB");
615 glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)wglGetProcAddress("glUniform2fvARB");
616 glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)wglGetProcAddress("glBindAttribLocationARB");
617 glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glEnableVertexAttribArrayARB");
618 glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)wglGetProcAddress("glVertexAttribPointerARB");
619 glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glDisableVertexAttribArrayARB");
620 glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)wglGetProcAddress("glValidateProgramARB");
621#endif
622
623 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &textureImageUnitCount);
624
625 shadersAvailable = YES;
626}
627#endif
628
629
630#if OO_USE_VBO
631- (void)checkVBOSupported
632{
633 vboSupported = NO;
634
635 if ([self versionIsAtLeastMajor:1 minor:5] || [self haveExtension:@"GL_ARB_vertex_buffer_object"])
636 {
637 vboSupported = YES;
638 }
639
640#if OOLITE_WINDOWS
641 if (vboSupported)
642 {
643 glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
644 glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
645 glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
646 glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
647 }
648#endif
649}
650#endif
651
652
653#if OO_USE_FBO
654- (void)checkFBOSupported
655{
656 fboSupported = NO;
657
658 if ([self haveExtension:@"GL_EXT_framebuffer_object"])
659 {
660 fboSupported = YES;
661 }
662
663#if OOLITE_WINDOWS
664 if (fboSupported)
665 {
666 glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");
667 glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
668 glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");
669 glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
670 glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress("glRenderbufferStorageEXT");
671 glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");
672 glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
673 glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
674 glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)wglGetProcAddress("glDeleteFramebuffersEXT");
675 glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");
676 glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress("glGenRenderbuffers");
677 glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress ("glBindRenderbuffer" );
678 glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress ("glRenderbufferStorage" );
679 glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress ("glGenFramebuffers" );
680 glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress ("glBindFramebuffer" );
681 glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress ("glFramebufferRenderbuffer" );
682 glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress ("glFramebufferTexture2D" );
683 glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress ("glGenVertexArrays" );
684 glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress ("glGenBuffers" );
685 glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress ("glBindVertexArray" );
686 glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress ("glBindBuffer" );
687 glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress ("glBufferData" );
688 glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress ("glVertexAttribPointer" );
689 glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress ("glEnableVertexAttribArray" );
690 glUseProgram = (PFNGLUSEPROGRAMPROC) wglGetProcAddress ("glUseProgram" );
691 glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress ("glGetUniformLocation" );
692 glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress ("glUniform1i" );
693 glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress ("glActiveTexture" );
694 glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)wglGetProcAddress ("glBlendFuncSeparate" );
695 glUniform1f = (PFNGLUNIFORM1FPROC)wglGetProcAddress ("glUniform1f" );
696 glUniform2fv = (PFNGLUNIFORM2FVPROC)wglGetProcAddress ("glUniform2fv" );
697 glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wglGetProcAddress ("glDeleteRenderbuffer" );
698 glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress ("glDeleteFramebuffers" );
699 glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)wglGetProcAddress ("glDeleteVertexArrays" );
700 glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress ("glDeleteBuffers" );
701 glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress ("glDrawBuffers" );
702 glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress ("glCheckFramebufferStatus" );
703 glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)wglGetProcAddress ("glTexImage2DMultisample" );
704 glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)wglGetProcAddress ("glRenderbufferStorageMultisample" );
705 glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)wglGetProcAddress ("glBlitFramebuffer" );
706 glClampColor = (PFNGLCLAMPCOLORPROC)wglGetProcAddress ("glClampColor" );
707 }
708#endif
709}
710#endif
711
712
713#if OO_MULTITEXTURE
714- (void)checkTextureCombinersSupported
715{
716 textureCombinersSupported = [self haveExtension:@"GL_ARB_texture_env_combine"];
717
718 if (textureCombinersSupported)
719 {
720 OOGL(glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &textureUnitCount));
721
722#if OOLITE_WINDOWS
723 // Duplicated in checkShadersSupported. but that's not really a problem.
724 glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
725
726 glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
727#endif
728 }
729 else
730 {
731 textureUnitCount = 1;
732 }
733
734}
735#endif
736
737
738// regexps may be a single string or an array of strings (in which case results are ANDed).
739static BOOL CheckRegExps(NSString *string, id regexps)
740{
741 if (regexps == nil) return YES; // No restriction == match.
742 if ([regexps isKindOfClass:[NSString class]])
743 {
744 return [string oo_matchesRegularExpression:regexps];
745 }
746 if ([regexps isKindOfClass:[NSArray class]])
747 {
748 NSEnumerator *regexpEnum = nil;
749 NSString *regexp = nil;
750
751 for (regexpEnum = [regexps objectEnumerator]; (regexp = [regexpEnum nextObject]); )
752 {
753 if (EXPECT_NOT(![regexp isKindOfClass:[NSString class]]))
754 {
755 // Invalid type -- match fails.
756 return NO;
757 }
758
759 if (![string oo_matchesRegularExpression:regexp]) return NO;
760 }
761 return YES;
762 }
763
764 // Invalid type -- match fails.
765 return NO;
766}
767
768
769NSComparisonResult CompareGPUSettingsByPriority(id a, id b, void *context)
770{
771 NSString *keyA = a;
772 NSString *keyB = b;
773 NSDictionary *configurations = context;
774 NSDictionary *dictA = [configurations oo_dictionaryForKey:keyA];
775 NSDictionary *dictB = [configurations oo_dictionaryForKey:keyB];
776 double precedenceA = [dictA oo_doubleForKey:@"precedence" defaultValue:1];
777 double precedenceB = [dictB oo_doubleForKey:@"precedence" defaultValue:1];
778
779 if (precedenceA > precedenceB) return NSOrderedAscending;
780 if (precedenceA < precedenceB) return NSOrderedDescending;
781
782 return [keyA caseInsensitiveCompare:keyB];
783}
784
785
786- (NSDictionary *) lookUpPerGPUSettingsWithVersionString:(NSString *)versionStr extensionsString:(NSString *)extensionsStr
787{
788 NSDictionary *configurations = [ResourceManager dictionaryFromFilesNamed:@"gpu-settings.plist"
789 inFolder:@"Config"
790 andMerge:YES];
791
792 NSArray *keys = [[configurations allKeys] sortedArrayUsingFunction:CompareGPUSettingsByPriority context:configurations];
793
794 NSString *key = nil;
795 NSDictionary *config = nil;
796
797 foreach (key, keys)
798 {
799 config = [configurations oo_dictionaryForKey:key];
800 if (EXPECT_NOT(config == nil)) continue;
801
802 NSDictionary *match = [config oo_dictionaryForKey:@"match"];
803 NSString *expr = nil;
804
805 expr = [match objectForKey:@"vendor"];
806 if (!CheckRegExps(vendor, expr)) continue;
807
808 expr = [match oo_stringForKey:@"renderer"];
809 if (!CheckRegExps(renderer, expr)) continue;
810
811 expr = [match oo_stringForKey:@"version"];
812 if (!CheckRegExps(versionStr, expr)) continue;
813
814 expr = [match oo_stringForKey:@"extensions"];
815 if (!CheckRegExps(extensionsStr, expr)) continue;
816
817 OOLog(@"rendering.opengl.gpuSpecific", @"Matched GPU configuration \"%@\".", key);
818 return config;
819 }
820
821 return [NSDictionary dictionary];
822}
823
824@end
825
826
827@implementation OOOpenGLExtensionManager (Singleton)
828
829/* Canonical singleton boilerplate.
830 See Cocoa Fundamentals Guide: Creating a Singleton Instance.
831 See also +sharedManager above.
832
833 // NOTE: assumes single-threaded first access.
834*/
835
836+ (id)allocWithZone:(NSZone *)inZone
837{
838 if (sSingleton == nil)
839 {
840 sSingleton = [super allocWithZone:inZone];
841 return sSingleton;
842 }
843 return nil;
844}
845
846
847- (id)copyWithZone:(NSZone *)inZone
848{
849 return self;
850}
851
852
853- (id)retain
854{
855 return self;
856}
857
858
859- (NSUInteger)retainCount
860{
861 return UINT_MAX;
862}
863
864
865- (void)release
866{}
867
868
869- (id)autorelease
870{
871 return self;
872}
873
874@end
875
876
877#if OOLITE_WINDOWS
878
879static void OOBadOpenGLExtensionUsed(void)
880{
881 OOLog(@"rendering.opengl.badExtension", @"***** An uninitialized OpenGL extension function has been called, terminating. This is a serious error, please report it. *****");
882 exit(EXIT_FAILURE);
883}
884
885#endif
#define DESTROY(x)
Definition OOCocoa.h:75
OOShaderSetting OOShaderSettingFromString(NSString *string)
static OODebugMonitor * sSingleton
#define EXPECT_NOT(x)
#define GCC_ATTR(x)
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define MAX(A, B)
Definition OOMaths.h:114
static NSString *const kOOLogOpenGLShaderSupport
static OOOpenGLExtensionManager * sSingleton
static NSArray * ArrayOfExtensions(NSString *extensionString)
static unsigned IntegerFromString(const GLubyte **ioString)
@ SHADERS_FULL
Definition OOOpenGL.h:40
@ SHADERS_OFF
Definition OOOpenGL.h:38
@ SHADERS_NOT_SUPPORTED
Definition OOOpenGL.h:37
#define OOGL(statement)
Definition OOOpenGL.h:251
return self
unsigned count
return nil
OOGraphicsDetail
Definition OOTypes.h:243
@ DETAIL_LEVEL_MAXIMUM
Definition OOTypes.h:251
@ DETAIL_LEVEL_MINIMUM
Definition OOTypes.h:244
static BOOL CheckRegExps(NSString *string, id regexps)
NSComparisonResult CompareGPUSettingsByPriority(id a, id b, void *context)
NSDictionary * dictionaryFromFilesNamed:inFolder:andMerge:(NSString *fileName,[inFolder] NSString *folderName,[andMerge] BOOL mergeFiles)