Line data Source code
1 0 : /*
2 :
3 : OOOpenGLExtensionManager.m
4 :
5 :
6 : Copyright (C) 2007-2013 Jens Ayton and contributors
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : #import "OOOpenGLExtensionManager.h"
29 : #import "OOLogging.h"
30 : #import "OOFunctionAttributes.h"
31 : #include <stdlib.h>
32 : #import "NSThreadOOExtensions.h"
33 :
34 : #import "ResourceManager.h"
35 : #import "OOCollectionExtractors.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 : */
48 0 : enum
49 : {
50 : kMinMajorVersion = 3,
51 : kMinMinorVersion = 3
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 : */
59 : static void OOBadOpenGLExtensionUsed(void) GCC_ATTR((noreturn, used));
60 :
61 : #if OO_SHADERS
62 :
63 : PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
64 : PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)&OOBadOpenGLExtensionUsed;
65 : PFNGLUNIFORM1IARBPROC glUniform1iARB = (PFNGLUNIFORM1IARBPROC)&OOBadOpenGLExtensionUsed;
66 : PFNGLUNIFORM1FARBPROC glUniform1fARB = (PFNGLUNIFORM1FARBPROC)&OOBadOpenGLExtensionUsed;
67 : PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)&OOBadOpenGLExtensionUsed;
68 : PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)&OOBadOpenGLExtensionUsed;
69 : PFNGLUNIFORM4FVARBPROC glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)&OOBadOpenGLExtensionUsed;
70 : PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)&OOBadOpenGLExtensionUsed;
71 : PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)&OOBadOpenGLExtensionUsed;
72 : PFNGLGETINFOLOGARBPROC glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)&OOBadOpenGLExtensionUsed;
73 : PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
74 : PFNGLATTACHOBJECTARBPROC glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
75 : PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)&OOBadOpenGLExtensionUsed;
76 : PFNGLLINKPROGRAMARBPROC glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)&OOBadOpenGLExtensionUsed;
77 : PFNGLCOMPILESHADERARBPROC glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)&OOBadOpenGLExtensionUsed;
78 : PFNGLSHADERSOURCEARBPROC glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)&OOBadOpenGLExtensionUsed;
79 : PFNGLUNIFORM2FVARBPROC glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)&OOBadOpenGLExtensionUsed;
80 : PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)&OOBadOpenGLExtensionUsed;
81 : PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)&OOBadOpenGLExtensionUsed;
82 : PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)&OOBadOpenGLExtensionUsed;
83 : PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)&OOBadOpenGLExtensionUsed;
84 : PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)&OOBadOpenGLExtensionUsed;
85 : #endif
86 :
87 : #if OO_SHADERS || OO_MULTITEXTURE
88 : PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)&OOBadOpenGLExtensionUsed;
89 : #endif
90 :
91 : #if OO_MULTITEXTURE
92 : PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)&OOBadOpenGLExtensionUsed;
93 : #endif
94 :
95 : #if OO_USE_VBO
96 : PFNGLGENBUFFERSARBPROC glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)&OOBadOpenGLExtensionUsed;
97 : PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)&OOBadOpenGLExtensionUsed;
98 : PFNGLBINDBUFFERARBPROC glBindBufferARB = (PFNGLBINDBUFFERARBPROC)&OOBadOpenGLExtensionUsed;
99 : PFNGLBUFFERDATAARBPROC glBufferDataARB = (PFNGLBUFFERDATAARBPROC)&OOBadOpenGLExtensionUsed;
100 : #endif
101 :
102 : #if OO_USE_FBO
103 : PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
104 : PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
105 : PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
106 : PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
107 : PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)&OOBadOpenGLExtensionUsed;
108 : PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)&OOBadOpenGLExtensionUsed;
109 : PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)&OOBadOpenGLExtensionUsed;
110 : PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)&OOBadOpenGLExtensionUsed;
111 : PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
112 : PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)&OOBadOpenGLExtensionUsed;
113 : PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)&OOBadOpenGLExtensionUsed;
114 : PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)&OOBadOpenGLExtensionUsed;
115 : PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)&OOBadOpenGLExtensionUsed;
116 : PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
117 : PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)&OOBadOpenGLExtensionUsed;
118 : PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)&OOBadOpenGLExtensionUsed;
119 : PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)&OOBadOpenGLExtensionUsed;
120 : PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)&OOBadOpenGLExtensionUsed;
121 : PFNGLGENBUFFERSPROC glGenBuffers = (PFNGLGENBUFFERSPROC)&OOBadOpenGLExtensionUsed;
122 : PFNGLBINDVERTEXARRAYPROC glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)&OOBadOpenGLExtensionUsed;
123 : PFNGLBINDBUFFERPROC glBindBuffer = (PFNGLBINDBUFFERPROC)&OOBadOpenGLExtensionUsed;
124 : PFNGLBUFFERDATAPROC glBufferData = (PFNGLBUFFERDATAPROC)&OOBadOpenGLExtensionUsed;
125 : PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)&OOBadOpenGLExtensionUsed;
126 : PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)&OOBadOpenGLExtensionUsed;
127 : PFNGLUSEPROGRAMPROC glUseProgram = (PFNGLUSEPROGRAMPROC)&OOBadOpenGLExtensionUsed;
128 : PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)&OOBadOpenGLExtensionUsed;
129 : PFNGLUNIFORM1IPROC glUniform1i = (PFNGLUNIFORM1IPROC)&OOBadOpenGLExtensionUsed;
130 : PFNGLACTIVETEXTUREPROC glActiveTexture = (PFNGLACTIVETEXTUREPROC)&OOBadOpenGLExtensionUsed;
131 : PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)&OOBadOpenGLExtensionUsed;
132 : PFNGLUNIFORM1FPROC glUniform1f = (PFNGLUNIFORM1FPROC)&OOBadOpenGLExtensionUsed;
133 : PFNGLUNIFORM2FVPROC glUniform2fv = (PFNGLUNIFORM2FVPROC)&OOBadOpenGLExtensionUsed;
134 : PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)&OOBadOpenGLExtensionUsed;
135 : PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
136 : PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)&OOBadOpenGLExtensionUsed;
137 : PFNGLDELETEBUFFERSPROC glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)&OOBadOpenGLExtensionUsed;
138 : PFNGLDRAWBUFFERSPROC glDrawBuffers = (PFNGLDRAWBUFFERSPROC)&OOBadOpenGLExtensionUsed;
139 : PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)&OOBadOpenGLExtensionUsed;
140 : PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)&OOBadOpenGLExtensionUsed;
141 : PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)&OOBadOpenGLExtensionUsed;
142 : PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)&OOBadOpenGLExtensionUsed;
143 : PFNGLCLAMPCOLORPROC glClampColor = (PFNGLCLAMPCOLORPROC)&OOBadOpenGLExtensionUsed;
144 : #endif
145 : #endif
146 :
147 :
148 0 : static NSString * const kOOLogOpenGLShaderSupport = @"rendering.opengl.shader.support";
149 :
150 :
151 0 : static OOOpenGLExtensionManager *sSingleton = nil;
152 :
153 :
154 : // Read integer from string, advancing string to end of read data.
155 : static unsigned IntegerFromString(const GLubyte **ioString);
156 :
157 :
158 : @interface OOOpenGLExtensionManager (OOPrivate)
159 :
160 : #if OO_SHADERS
161 1 : - (void)checkShadersSupported;
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 0 : - (NSDictionary *) lookUpPerGPUSettingsWithVersionString:(NSString *)version extensionsString:(NSString *)extensionsStr;
177 :
178 : @end
179 :
180 :
181 0 : static 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 0 : - (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 : */
253 : [ResourceManager paths];
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 0 : - (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 : {
386 : return DETAIL_LEVEL_MINIMUM;
387 : }
388 : else
389 : {
390 : return DETAIL_LEVEL_MAXIMUM;
391 : }
392 : #else
393 : return SHADERS_NOT_SUPPORTED;
394 : #endif
395 : }
396 :
397 :
398 : - (OOGraphicsDetail)maximumDetailLevel
399 : {
400 : #if OO_SHADERS
401 : if (maximumShaderSetting < SHADERS_FULL)
402 : {
403 : return DETAIL_LEVEL_MINIMUM;
404 : }
405 : else
406 : {
407 : return DETAIL_LEVEL_MAXIMUM;
408 : }
409 : #else
410 : return DETAIL_LEVEL_MINIMUM;
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 :
529 0 : static 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 :
551 : /**
552 : * \ingroup cli
553 : * Scans the command line for -noshaders or --noshaders arguments.
554 : */
555 : - (void)checkShadersSupported
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).
741 0 : static 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 :
771 0 : NSComparisonResult 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 0 : + (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 0 : - (id)copyWithZone:(NSZone *)inZone
851 : {
852 : return self;
853 : }
854 :
855 :
856 0 : - (id)retain
857 : {
858 : return self;
859 : }
860 :
861 :
862 0 : - (NSUInteger)retainCount
863 : {
864 : return UINT_MAX;
865 : }
866 :
867 :
868 0 : - (void)release
869 : {}
870 :
871 :
872 0 : - (id)autorelease
873 : {
874 : return self;
875 : }
876 :
877 : @end
878 :
879 :
880 : #if OOLITE_WINDOWS
881 :
882 : static 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
|