Oolite 1.91.0.7644-241112-7f5034b
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 NSEnumerator *extEnum = nil;
186 NSString *extStr = nil;
187 for (extEnum = [components objectEnumerator]; (extStr = [extEnum nextObject]); )
188 {
189 if ([extStr length] > 0) [result addObject:extStr];
190 }
191 return result;
192}
193
194
195@implementation OOOpenGLExtensionManager
196
197- (id)init
198{
199 self = [super init];
200 if (self != nil)
201 {
202#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
203 lock = [[NSLock alloc] init];
204 [lock setName:@"OOOpenGLExtensionManager extension set lock"];
205#endif
206
207 [self reset];
208 }
209
210 return self;
211}
212
213
214- (void) reset
215{
216 const GLubyte *versionString = NULL, *curr = NULL;
217
218 DESTROY(extensions);
219 DESTROY(vendor);
220 DESTROY(renderer);
221
222 NSString *extensionsStr = [NSString stringWithUTF8String:(char *)glGetString(GL_EXTENSIONS)];
223 extensions = [[NSSet alloc] initWithArray:ArrayOfExtensions(extensionsStr)];
224
225 vendor = [[NSString alloc] initWithUTF8String:(const char *)glGetString(GL_VENDOR)];
226 renderer = [[NSString alloc] initWithUTF8String:(const char *)glGetString(GL_RENDERER)];
227
228 versionString = glGetString(GL_VERSION);
229 if (versionString != NULL)
230 {
231 /* String is supposed to be "major.minorFOO" or
232 "major.minor.releaseFOO" where FOO is an empty string or
233 a string beginning with space.
234 */
235 curr = versionString;
236 major = IntegerFromString(&curr);
237 if (*curr == '.')
238 {
239 curr++;
240 minor = IntegerFromString(&curr);
241 }
242 if (*curr == '.')
243 {
244 curr++;
245 release = IntegerFromString(&curr);
246 }
247 }
248
249 /* For aesthetic reasons, cause the ResourceManager to initialize its
250 search paths here. If we don't, the search path dump ends up in
251 the middle of the OpenGL stuff.
252 */
254
255 OOLog(@"rendering.opengl.version", @"OpenGL renderer version: %u.%u.%u (\"%s\"). Vendor: \"%@\". Renderer: \"%@\".", major, minor, release, versionString, vendor, renderer);
256 OOLog(@"rendering.opengl.extensions", @"OpenGL extensions (%lu):\n%@", [extensions count], [[extensions allObjects] componentsJoinedByString:@", "]);
257
258 if (![self versionIsAtLeastMajor:kMinMajorVersion minor:kMinMinorVersion])
259 {
260 OOLog(@"rendering.opengl.version.insufficient", @"***** Oolite requires OpenGL version %u.%u or later.", kMinMajorVersion, kMinMinorVersion);
261 [NSException raise:@"OoliteOpenGLTooOldException"
262 format:@"Oolite requires at least OpenGL %u.%u. You have %u.%u (\"%s\").", kMinMajorVersion, kMinMinorVersion, major, minor, versionString];
263 }
264
265 NSString *versionStr = [[[NSString alloc] initWithUTF8String:(const char *)versionString] autorelease];
266 NSDictionary *gpuConfig = [self lookUpPerGPUSettingsWithVersionString:versionStr extensionsString:extensionsStr];
267
268#if OO_SHADERS
269 [self checkShadersSupported];
270
271 if (shadersAvailable)
272 {
273 defaultShaderSetting = OOShaderSettingFromString([gpuConfig oo_stringForKey:@"default_shader_level"
274 defaultValue:@"SHADERS_FULL"]);
275 maximumShaderSetting = OOShaderSettingFromString([gpuConfig oo_stringForKey:@"maximum_shader_level"
276 defaultValue:@"SHADERS_FULL"]);
277 if (maximumShaderSetting <= SHADERS_OFF)
278 {
279 shadersAvailable = NO;
280 maximumShaderSetting = SHADERS_NOT_SUPPORTED;
281 OOLog(kOOLogOpenGLShaderSupport, @"Shaders will not be used (disallowed for GPU type \"%@\").", [gpuConfig oo_stringForKey:@"name" defaultValue:renderer]);
282 }
283 if (maximumShaderSetting < defaultShaderSetting)
284 {
285 defaultShaderSetting = maximumShaderSetting;
286 }
287
288 if (shadersAvailable)
289 {
290 OOLog(kOOLogOpenGLShaderSupport, @"%@", @"Shaders are supported.");
291 }
292 }
293 else
294 {
295 defaultShaderSetting = SHADERS_NOT_SUPPORTED;
296 maximumShaderSetting = SHADERS_NOT_SUPPORTED;
297 }
298
299 GLint texImageUnitOverride = [gpuConfig oo_intForKey:@"texture_image_units" defaultValue:textureImageUnitCount];
300 if (texImageUnitOverride < textureImageUnitCount) textureImageUnitCount = MAX(texImageUnitOverride, 0);
301#endif
302
303#if OO_USE_VBO
304 [self checkVBOSupported];
305#endif
306#if OO_USE_FBO
307 [self checkFBOSupported];
308#endif
309#if OO_MULTITEXTURE
310 [self checkTextureCombinersSupported];
311 GLint texUnitOverride = [gpuConfig oo_intForKey:@"texture_units" defaultValue:textureUnitCount];
312 if (texUnitOverride < textureUnitCount) textureUnitCount = MAX(texUnitOverride, 0);
313#endif
314
315 usePointSmoothing = [gpuConfig oo_boolForKey:@"smooth_points" defaultValue:YES];
316 useLineSmoothing = [gpuConfig oo_boolForKey:@"smooth_lines" defaultValue:YES];
317 useDustShader = [gpuConfig oo_boolForKey:@"use_dust_shader" defaultValue:YES];
318}
319
320
321- (void)dealloc
322{
323 if (sSingleton == self) sSingleton = nil;
324
325#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
326 [lock release];
327#endif
328 DESTROY(extensions);
329 DESTROY(vendor);
330 DESTROY(renderer);
331
332 [super dealloc];
333}
334
335
336+ (OOOpenGLExtensionManager *)sharedManager
337{
338 // NOTE: assumes single-threaded first access. See header.
339 if (sSingleton == nil) sSingleton = [[self alloc] init];
340 return sSingleton;
341}
342
343
344- (BOOL)haveExtension:(NSString *)extension
345{
346// NSSet is documented as thread-safe under OS X, but I'm not sure about GNUstep. -- Ahruman
347#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
348 [lock lock];
349#endif
350
351 BOOL result = [extensions containsObject:extension];
352
353#if OOOPENGLEXTMGR_LOCK_SET_ACCESS
354 [lock unlock];
355#endif
356
357 return result;
358}
359
360
361- (BOOL)shadersSupported
362{
363#if OO_SHADERS
364 return shadersAvailable;
365#else
366 return NO;
367#endif
368}
369
370
371- (BOOL)shadersForceDisabled
372{
373#if OO_SHADERS
374 return shadersForceDisabled;
375#else
376 return YES;
377#endif
378}
379
380
381- (OOGraphicsDetail)defaultDetailLevel
382{
383#if OO_SHADERS
384 if (defaultShaderSetting < SHADERS_FULL)
385 {
387 }
388 else
389 {
391 }
392#else
394#endif
395}
396
397
398- (OOGraphicsDetail)maximumDetailLevel
399{
400#if OO_SHADERS
401 if (maximumShaderSetting < SHADERS_FULL)
402 {
404 }
405 else
406 {
408 }
409#else
411#endif
412}
413
414
415- (GLint)textureImageUnitCount
416{
417#if OO_SHADERS
418 return textureImageUnitCount;
419#else
420 return 0;
421#endif
422}
423
424
425- (BOOL)vboSupported
426{
427#if OO_USE_VBO
428 return vboSupported;
429#else
430 return NO;
431#endif
432}
433
434
435- (BOOL)fboSupported
436{
437#if OO_USE_FBO
438 return fboSupported;
439#else
440 return NO;
441#endif
442}
443
444
445- (BOOL)textureCombinersSupported
446{
447#if OO_MULTITEXTURE
448 return textureCombinersSupported;
449#else
450 return NO;
451#endif
452}
453
454
455- (GLint)textureUnitCount
456{
457#if OO_MULTITEXTURE
458 return textureUnitCount;
459#else
460 return 0;
461#endif
462}
463
464
465- (NSUInteger)majorVersionNumber
466{
467 return major;
468}
469
470
471- (NSUInteger)minorVersionNumber
472{
473 return minor;
474}
475
476
477- (NSUInteger)releaseVersionNumber
478{
479 return release;
480}
481
482
483- (void)getVersionMajor:(unsigned *)outMajor minor:(unsigned *)outMinor release:(unsigned *)outRelease
484{
485 if (outMajor != NULL) *outMajor = major;
486 if (outMinor != NULL) *outMinor = minor;
487 if (outRelease != NULL) *outRelease = release;
488}
489
490
491- (BOOL) versionIsAtLeastMajor:(unsigned)maj minor:(unsigned)min
492{
493 return major > maj || (major == maj && minor >= min);
494}
495
496
497- (NSString *) vendorString
498{
499 return vendor;
500}
501
502
503- (NSString *) rendererString
504{
505 return renderer;
506}
507
508
509- (BOOL) usePointSmoothing
510{
511 return usePointSmoothing;
512}
513
514
515- (BOOL) useLineSmoothing
516{
517 return useLineSmoothing;
518}
519
520
521- (BOOL) useDustShader
522{
523 return useDustShader;
524}
525
526@end
527
528
529static unsigned IntegerFromString(const GLubyte **ioString)
530{
531 if (EXPECT_NOT(ioString == NULL)) return 0;
532
533 unsigned result = 0;
534 const GLubyte *curr = *ioString;
535
536 while ('0' <= *curr && *curr <= '9')
537 {
538 result = result * 10 + *curr++ - '0';
539 }
540
541 *ioString = curr;
542 return result;
543}
544
545
546@implementation OOOpenGLExtensionManager (OOPrivate)
547
548
549#if OO_SHADERS
550
556{
557 shadersAvailable = NO;
558 shadersForceDisabled = NO;
559
560 /* Some cards claim to support shaders but do so extremely
561 * badly. These are listed in gpu-settings.plist where we know
562 * about them; for those we don't being able to run with
563 * -noshaders may help get the game up and running at a frame rate
564 * where thegraphics settings can be changed. - CIM */
565 NSArray *arguments = [[NSProcessInfo processInfo] arguments];
566 NSEnumerator *argEnum = nil;
567 NSString *arg = nil;
568 // scan for shader overrides: -noshaders || --noshaders
569 for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); )
570 {
571 if ([arg isEqual:@"-noshaders"] || [arg isEqual:@"--noshaders"])
572 {
573 shadersForceDisabled = YES;
574 OOLog(kOOLogOpenGLShaderSupport, @"%@", @"Shaders will not be used (disabled on command line).");
575 return;
576 }
577 }
578
579 NSString * const requiredExtension[] =
580 {
581 @"GL_ARB_shading_language_100",
582 @"GL_ARB_fragment_shader",
583 @"GL_ARB_vertex_shader",
584 @"GL_ARB_multitexture",
585 @"GL_ARB_shader_objects",
586 nil // sentinel - don't remove!
587 };
588 NSString * const *required = NULL;
589
590 for (required = requiredExtension; *required != nil; ++required)
591 {
592 if (![self haveExtension:*required])
593 {
594 OOLog(kOOLogOpenGLShaderSupport, @"Shaders will not be used (OpenGL extension %@ is not available).", *required);
595 return;
596 }
597 }
598
599#if OOLITE_WINDOWS
600 glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
601 glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
602 glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
603 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
604 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
605 glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
606 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");
607 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
608 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
609 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
610 glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
611 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB");
612 glUniform1iARB = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB");
613 glUniform1fARB = (PFNGLUNIFORM1FARBPROC)wglGetProcAddress("glUniform1fARB");
614 glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)wglGetProcAddress("glUniformMatrix3fvARB");
615 glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)wglGetProcAddress("glUniformMatrix4fvARB");
616 glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)wglGetProcAddress("glUniform4fvARB");
617 glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)wglGetProcAddress("glUniform2fvARB");
618 glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)wglGetProcAddress("glBindAttribLocationARB");
619 glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glEnableVertexAttribArrayARB");
620 glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)wglGetProcAddress("glVertexAttribPointerARB");
621 glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glDisableVertexAttribArrayARB");
622 glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)wglGetProcAddress("glValidateProgramARB");
623#endif
624
625 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &textureImageUnitCount);
626
627 shadersAvailable = YES;
628}
629#endif
630
631
632#if OO_USE_VBO
633- (void)checkVBOSupported
634{
635 vboSupported = NO;
636
637 if ([self versionIsAtLeastMajor:1 minor:5] || [self haveExtension:@"GL_ARB_vertex_buffer_object"])
638 {
639 vboSupported = YES;
640 }
641
642#if OOLITE_WINDOWS
643 if (vboSupported)
644 {
645 glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
646 glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
647 glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
648 glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
649 }
650#endif
651}
652#endif
653
654
655#if OO_USE_FBO
656- (void)checkFBOSupported
657{
658 fboSupported = NO;
659
660 if ([self haveExtension:@"GL_EXT_framebuffer_object"])
661 {
662 fboSupported = YES;
663 }
664
665#if OOLITE_WINDOWS
666 if (fboSupported)
667 {
668 glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");
669 glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
670 glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");
671 glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
672 glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress("glRenderbufferStorageEXT");
673 glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");
674 glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
675 glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
676 glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)wglGetProcAddress("glDeleteFramebuffersEXT");
677 glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");
678 glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress("glGenRenderbuffers");
679 glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress ("glBindRenderbuffer" );
680 glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress ("glRenderbufferStorage" );
681 glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress ("glGenFramebuffers" );
682 glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress ("glBindFramebuffer" );
683 glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress ("glFramebufferRenderbuffer" );
684 glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress ("glFramebufferTexture2D" );
685 glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress ("glGenVertexArrays" );
686 glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress ("glGenBuffers" );
687 glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress ("glBindVertexArray" );
688 glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress ("glBindBuffer" );
689 glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress ("glBufferData" );
690 glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress ("glVertexAttribPointer" );
691 glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress ("glEnableVertexAttribArray" );
692 glUseProgram = (PFNGLUSEPROGRAMPROC) wglGetProcAddress ("glUseProgram" );
693 glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress ("glGetUniformLocation" );
694 glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress ("glUniform1i" );
695 glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress ("glActiveTexture" );
696 glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)wglGetProcAddress ("glBlendFuncSeparate" );
697 glUniform1f = (PFNGLUNIFORM1FPROC)wglGetProcAddress ("glUniform1f" );
698 glUniform2fv = (PFNGLUNIFORM2FVPROC)wglGetProcAddress ("glUniform2fv" );
699 glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wglGetProcAddress ("glDeleteRenderbuffer" );
700 glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress ("glDeleteFramebuffers" );
701 glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)wglGetProcAddress ("glDeleteVertexArrays" );
702 glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress ("glDeleteBuffers" );
703 glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress ("glDrawBuffers" );
704 glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress ("glCheckFramebufferStatus" );
705 glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)wglGetProcAddress ("glTexImage2DMultisample" );
706 glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)wglGetProcAddress ("glRenderbufferStorageMultisample" );
707 glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)wglGetProcAddress ("glBlitFramebuffer" );
708 glClampColor = (PFNGLCLAMPCOLORPROC)wglGetProcAddress ("glClampColor" );
709 }
710#endif
711}
712#endif
713
714
715#if OO_MULTITEXTURE
716- (void)checkTextureCombinersSupported
717{
718 textureCombinersSupported = [self haveExtension:@"GL_ARB_texture_env_combine"];
719
720 if (textureCombinersSupported)
721 {
722 OOGL(glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &textureUnitCount));
723
724#if OOLITE_WINDOWS
725 // Duplicated in checkShadersSupported. but that's not really a problem.
726 glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
727
728 glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
729#endif
730 }
731 else
732 {
733 textureUnitCount = 1;
734 }
735
736}
737#endif
738
739
740// regexps may be a single string or an array of strings (in which case results are ANDed).
741static BOOL CheckRegExps(NSString *string, id regexps)
742{
743 if (regexps == nil) return YES; // No restriction == match.
744 if ([regexps isKindOfClass:[NSString class]])
745 {
746 return [string oo_matchesRegularExpression:regexps];
747 }
748 if ([regexps isKindOfClass:[NSArray class]])
749 {
750 NSEnumerator *regexpEnum = nil;
751 NSString *regexp = nil;
752
753 for (regexpEnum = [regexps objectEnumerator]; (regexp = [regexpEnum nextObject]); )
754 {
755 if (EXPECT_NOT(![regexp isKindOfClass:[NSString class]]))
756 {
757 // Invalid type -- match fails.
758 return NO;
759 }
760
761 if (![string oo_matchesRegularExpression:regexp]) return NO;
762 }
763 return YES;
764 }
765
766 // Invalid type -- match fails.
767 return NO;
768}
769
770
771NSComparisonResult CompareGPUSettingsByPriority(id a, id b, void *context)
772{
773 NSString *keyA = a;
774 NSString *keyB = b;
775 NSDictionary *configurations = context;
776 NSDictionary *dictA = [configurations oo_dictionaryForKey:keyA];
777 NSDictionary *dictB = [configurations oo_dictionaryForKey:keyB];
778 double precedenceA = [dictA oo_doubleForKey:@"precedence" defaultValue:1];
779 double precedenceB = [dictB oo_doubleForKey:@"precedence" defaultValue:1];
780
781 if (precedenceA > precedenceB) return NSOrderedAscending;
782 if (precedenceA < precedenceB) return NSOrderedDescending;
783
784 return [keyA caseInsensitiveCompare:keyB];
785}
786
787
788- (NSDictionary *) lookUpPerGPUSettingsWithVersionString:(NSString *)versionStr extensionsString:(NSString *)extensionsStr
789{
790 NSDictionary *configurations = [ResourceManager dictionaryFromFilesNamed:@"gpu-settings.plist"
791 inFolder:@"Config"
792 andMerge:YES];
793
794 NSArray *keys = [[configurations allKeys] sortedArrayUsingFunction:CompareGPUSettingsByPriority context:configurations];
795
796 NSEnumerator *keyEnum = nil;
797 NSString *key = nil;
798 NSDictionary *config = nil;
799
800 for (keyEnum = [keys objectEnumerator]; (key = [keyEnum nextObject]); )
801 {
802 config = [configurations oo_dictionaryForKey:key];
803 if (EXPECT_NOT(config == nil)) continue;
804
805 NSDictionary *match = [config oo_dictionaryForKey:@"match"];
806 NSString *expr = nil;
807
808 expr = [match objectForKey:@"vendor"];
809 if (!CheckRegExps(vendor, expr)) continue;
810
811 expr = [match oo_stringForKey:@"renderer"];
812 if (!CheckRegExps(renderer, expr)) continue;
813
814 expr = [match oo_stringForKey:@"version"];
815 if (!CheckRegExps(versionStr, expr)) continue;
816
817 expr = [match oo_stringForKey:@"extensions"];
818 if (!CheckRegExps(extensionsStr, expr)) continue;
819
820 OOLog(@"rendering.opengl.gpuSpecific", @"Matched GPU configuration \"%@\".", key);
821 return config;
822 }
823
824 return [NSDictionary dictionary];
825}
826
827@end
828
829
830@implementation OOOpenGLExtensionManager (Singleton)
831
832/* Canonical singleton boilerplate.
833 See Cocoa Fundamentals Guide: Creating a Singleton Instance.
834 See also +sharedManager above.
835
836 // NOTE: assumes single-threaded first access.
837*/
838
839+ (id)allocWithZone:(NSZone *)inZone
840{
841 if (sSingleton == nil)
842 {
843 sSingleton = [super allocWithZone:inZone];
844 return sSingleton;
845 }
846 return nil;
847}
848
849
850- (id)copyWithZone:(NSZone *)inZone
851{
852 return self;
853}
854
855
856- (id)retain
857{
858 return self;
859}
860
861
862- (NSUInteger)retainCount
863{
864 return UINT_MAX;
865}
866
867
868- (void)release
869{}
870
871
872- (id)autorelease
873{
874 return self;
875}
876
877@end
878
879
880#if OOLITE_WINDOWS
881
882static void OOBadOpenGLExtensionUsed(void)
883{
884 OOLog(@"rendering.opengl.badExtension", @"***** An uninitialized OpenGL extension function has been called, terminating. This is a serious error, please report it. *****");
885 exit(EXIT_FAILURE);
886}
887
888#endif
#define DESTROY(x)
Definition OOCocoa.h:77
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
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)