|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 |
|
7 #include "GLContext.h" |
|
8 #include "nsPrintfCString.h" |
|
9 |
|
10 #ifdef XP_MACOSX |
|
11 #include "nsCocoaFeatures.h" |
|
12 #endif |
|
13 |
|
14 namespace mozilla { |
|
15 namespace gl { |
|
16 |
|
17 const size_t kMAX_EXTENSION_GROUP_SIZE = 5; |
|
18 |
|
19 // ARB_ES2_compatibility is natively supported in OpenGL 4.1. |
|
20 static const unsigned int kGLCoreVersionForES2Compat = 410; |
|
21 |
|
22 // ARB_ES3_compatibility is natively supported in OpenGL 4.3. |
|
23 static const unsigned int kGLCoreVersionForES3Compat = 430; |
|
24 |
|
25 struct FeatureInfo |
|
26 { |
|
27 const char* mName; |
|
28 unsigned int mOpenGLVersion; |
|
29 unsigned int mOpenGLESVersion; |
|
30 GLContext::GLExtensions mExtensions[kMAX_EXTENSION_GROUP_SIZE]; |
|
31 }; |
|
32 |
|
33 static const FeatureInfo sFeatureInfoArr[] = { |
|
34 { |
|
35 "bind_buffer_offset", |
|
36 0, // OpenGL version |
|
37 0, // OpenGL ES version |
|
38 { |
|
39 GLContext::EXT_transform_feedback, |
|
40 GLContext::NV_transform_feedback, |
|
41 GLContext::Extensions_End |
|
42 } |
|
43 }, |
|
44 { |
|
45 "blend_minmax", |
|
46 200, // OpenGL version |
|
47 300, // OpenGL ES version |
|
48 { |
|
49 GLContext::EXT_blend_minmax, |
|
50 GLContext::Extensions_End |
|
51 } |
|
52 }, |
|
53 { |
|
54 "depth_texture", |
|
55 200, // OpenGL version |
|
56 300, // OpenGL ES version |
|
57 { |
|
58 GLContext::ARB_depth_texture, |
|
59 GLContext::OES_depth_texture, |
|
60 // Intentionally avoid putting ANGLE_depth_texture here, |
|
61 // it does not offer quite the same functionality. |
|
62 GLContext::Extensions_End |
|
63 } |
|
64 }, |
|
65 { |
|
66 "draw_buffers", |
|
67 200, // OpenGL version |
|
68 300, // OpenGL ES version |
|
69 { |
|
70 GLContext::ARB_draw_buffers, |
|
71 GLContext::EXT_draw_buffers, |
|
72 GLContext::Extensions_End |
|
73 } |
|
74 }, |
|
75 { |
|
76 "draw_instanced", |
|
77 310, // OpenGL version |
|
78 300, // OpenGL ES version |
|
79 { |
|
80 GLContext::ARB_draw_instanced, |
|
81 GLContext::EXT_draw_instanced, |
|
82 GLContext::NV_draw_instanced, |
|
83 GLContext::ANGLE_instanced_arrays, |
|
84 GLContext::Extensions_End |
|
85 } |
|
86 }, |
|
87 { |
|
88 "draw_range_elements", |
|
89 120, // OpenGL version |
|
90 300, // OpenGL ES version |
|
91 { |
|
92 GLContext::EXT_draw_range_elements, |
|
93 GLContext::Extensions_End |
|
94 } |
|
95 }, |
|
96 { |
|
97 "element_index_uint", |
|
98 200, // OpenGL version |
|
99 300, // OpenGL ES version |
|
100 { |
|
101 GLContext::OES_element_index_uint, |
|
102 GLContext::Extensions_End |
|
103 } |
|
104 }, |
|
105 { |
|
106 "ES2_compatibility", |
|
107 kGLCoreVersionForES2Compat, |
|
108 200, // OpenGL ES version |
|
109 { |
|
110 GLContext::ARB_ES2_compatibility, |
|
111 GLContext::Extensions_End |
|
112 } |
|
113 }, |
|
114 { |
|
115 "ES3_compatibility", |
|
116 kGLCoreVersionForES3Compat, |
|
117 300, // OpenGL ES version |
|
118 { |
|
119 GLContext::ARB_ES3_compatibility, |
|
120 GLContext::Extensions_End |
|
121 } |
|
122 }, |
|
123 { |
|
124 // Removes clamping for float color outputs from frag shaders. |
|
125 "frag_color_float", |
|
126 300, // OpenGL version |
|
127 300, // OpenGL ES version |
|
128 { |
|
129 GLContext::ARB_color_buffer_float, |
|
130 GLContext::EXT_color_buffer_float, |
|
131 GLContext::EXT_color_buffer_half_float, |
|
132 GLContext::Extensions_End |
|
133 } |
|
134 }, |
|
135 { |
|
136 "frag_depth", |
|
137 200, // OpenGL version |
|
138 300, // OpenGL ES version |
|
139 { |
|
140 GLContext::EXT_frag_depth, |
|
141 GLContext::Extensions_End |
|
142 } |
|
143 }, |
|
144 { |
|
145 "framebuffer_blit", |
|
146 300, // OpenGL version |
|
147 300, // OpenGL ES version |
|
148 { |
|
149 GLContext::EXT_framebuffer_blit, |
|
150 GLContext::ANGLE_framebuffer_blit, |
|
151 GLContext::Extensions_End |
|
152 } |
|
153 }, |
|
154 { |
|
155 "framebuffer_multisample", |
|
156 300, // OpenGL version |
|
157 300, // OpenGL ES version |
|
158 { |
|
159 GLContext::EXT_framebuffer_multisample, |
|
160 GLContext::ANGLE_framebuffer_multisample, |
|
161 GLContext::Extensions_End |
|
162 } |
|
163 }, |
|
164 { |
|
165 "framebuffer_object", |
|
166 300, // OpenGL version |
|
167 200, // OpenGL ES version |
|
168 { |
|
169 GLContext::ARB_framebuffer_object, |
|
170 GLContext::EXT_framebuffer_object, |
|
171 GLContext::Extensions_End |
|
172 } |
|
173 }, |
|
174 { |
|
175 "get_query_object_iv", |
|
176 200, // OpenGL version |
|
177 0, // OpenGL ES version |
|
178 { |
|
179 GLContext::Extensions_End |
|
180 } |
|
181 /* |
|
182 * XXX_get_query_object_iv only provide GetQueryObjectiv provided by |
|
183 * ARB_occlusion_query (added by OpenGL 2.0). |
|
184 */ |
|
185 }, |
|
186 { |
|
187 "instanced_arrays", |
|
188 330, // OpenGL version |
|
189 300, // OpenGL ES version |
|
190 { |
|
191 GLContext::ARB_instanced_arrays, |
|
192 GLContext::NV_instanced_arrays, |
|
193 GLContext::ANGLE_instanced_arrays, |
|
194 GLContext::Extensions_End |
|
195 } |
|
196 }, |
|
197 { |
|
198 "instanced_non_arrays", |
|
199 330, // OpenGL version |
|
200 300, // OpenGL ES version |
|
201 { |
|
202 GLContext::ARB_instanced_arrays, |
|
203 GLContext::Extensions_End |
|
204 } |
|
205 /* This is an expanded version of `instanced_arrays` that allows for all |
|
206 * enabled active attrib arrays to have non-zero divisors. |
|
207 * ANGLE_instanced_arrays and NV_instanced_arrays forbid this, but GLES3 |
|
208 * has no such restriction. |
|
209 */ |
|
210 }, |
|
211 { |
|
212 "occlusion_query", |
|
213 200, // OpenGL version |
|
214 0, // OpenGL ES version |
|
215 { |
|
216 GLContext::Extensions_End |
|
217 } |
|
218 // XXX_occlusion_query depend on ARB_occlusion_query (added in OpenGL 2.0) |
|
219 }, |
|
220 { |
|
221 "occlusion_query_boolean", |
|
222 kGLCoreVersionForES3Compat, |
|
223 300, // OpenGL ES version |
|
224 { |
|
225 GLContext::ARB_ES3_compatibility, |
|
226 GLContext::EXT_occlusion_query_boolean, |
|
227 GLContext::Extensions_End |
|
228 } |
|
229 /* |
|
230 * XXX_occlusion_query_boolean provide ANY_SAMPLES_PASSED_CONSERVATIVE, |
|
231 * but EXT_occlusion_query_boolean is only a OpenGL ES extension. But |
|
232 * it is supported on desktop if ARB_ES3_compatibility because |
|
233 * EXT_occlusion_query_boolean (added in OpenGL ES 3.0). |
|
234 */ |
|
235 }, |
|
236 { |
|
237 "occlusion_query2", |
|
238 330, // = min(330, kGLCoreVersionForES3Compat), |
|
239 300, // OpenGL ES version |
|
240 { |
|
241 GLContext::ARB_occlusion_query2, |
|
242 GLContext::ARB_ES3_compatibility, |
|
243 GLContext::EXT_occlusion_query_boolean, |
|
244 GLContext::Extensions_End |
|
245 } |
|
246 /* |
|
247 * XXX_occlusion_query2 (add in OpenGL 3.3) provide ANY_SAMPLES_PASSED, |
|
248 * which is provided by ARB_occlusion_query2, EXT_occlusion_query_boolean |
|
249 * (added in OpenGL ES 3.0) and ARB_ES3_compatibility |
|
250 */ |
|
251 }, |
|
252 { |
|
253 "packed_depth_stencil", |
|
254 300, // OpenGL version |
|
255 300, // OpenGL ES version |
|
256 { |
|
257 GLContext::EXT_packed_depth_stencil, |
|
258 GLContext::OES_packed_depth_stencil, |
|
259 GLContext::Extensions_End |
|
260 } |
|
261 }, |
|
262 { |
|
263 "query_objects", |
|
264 200, // OpenGL version |
|
265 300, // OpenGL ES version |
|
266 { |
|
267 GLContext::EXT_occlusion_query_boolean, |
|
268 GLContext::Extensions_End |
|
269 } |
|
270 /* |
|
271 * XXX_query_objects only provide entry points commonly supported by |
|
272 * ARB_occlusion_query (added in OpenGL 2.0) and EXT_occlusion_query_boolean |
|
273 * (added in OpenGL ES 3.0) |
|
274 */ |
|
275 }, |
|
276 { |
|
277 "renderbuffer_float", |
|
278 300, // OpenGL version |
|
279 300, // OpenGL ES version |
|
280 { |
|
281 GLContext::ARB_texture_float, |
|
282 GLContext::EXT_color_buffer_float, |
|
283 GLContext::Extensions_End |
|
284 } |
|
285 }, |
|
286 { |
|
287 "renderbuffer_half_float", |
|
288 300, // OpenGL version |
|
289 300, // OpenGL ES version |
|
290 { |
|
291 GLContext::ARB_texture_float, |
|
292 GLContext::EXT_color_buffer_half_float, |
|
293 GLContext::Extensions_End |
|
294 } |
|
295 }, |
|
296 { |
|
297 "robustness", |
|
298 0, // OpenGL version |
|
299 0, // OpenGL ES version |
|
300 { |
|
301 GLContext::ARB_robustness, |
|
302 GLContext::EXT_robustness, |
|
303 GLContext::Extensions_End |
|
304 } |
|
305 }, |
|
306 { |
|
307 "sRGB", |
|
308 300, // OpenGL version |
|
309 300, // OpenGL ES version |
|
310 { |
|
311 GLContext::EXT_sRGB, |
|
312 GLContext::Extensions_End |
|
313 } |
|
314 }, |
|
315 { |
|
316 "standard_derivatives", |
|
317 200, // OpenGL version |
|
318 300, // OpenGL ES version |
|
319 { |
|
320 GLContext::OES_standard_derivatives, |
|
321 GLContext::Extensions_End |
|
322 } |
|
323 }, |
|
324 { |
|
325 "texture_float", |
|
326 300, // OpenGL version |
|
327 300, // OpenGL ES version |
|
328 { |
|
329 GLContext::ARB_texture_float, |
|
330 GLContext::OES_texture_float, |
|
331 GLContext::Extensions_End |
|
332 } |
|
333 }, |
|
334 { |
|
335 "texture_float_linear", |
|
336 310, // OpenGL version |
|
337 300, // OpenGL ES version |
|
338 { |
|
339 GLContext::ARB_texture_float, |
|
340 GLContext::OES_texture_float_linear, |
|
341 GLContext::Extensions_End |
|
342 } |
|
343 }, |
|
344 { |
|
345 "texture_half_float", |
|
346 300, // OpenGL version |
|
347 300, // OpenGL ES version |
|
348 { |
|
349 GLContext::ARB_half_float_pixel, |
|
350 GLContext::ARB_texture_float, |
|
351 GLContext::NV_half_float, |
|
352 GLContext::Extensions_End |
|
353 } |
|
354 /** |
|
355 * We are not including OES_texture_half_float in this feature, because: |
|
356 * GL_HALF_FLOAT = 0x140B |
|
357 * GL_HALF_FLOAT_ARB = 0x140B == GL_HALF_FLOAT |
|
358 * GL_HALF_FLOAT_NV = 0x140B == GL_HALF_FLOAT |
|
359 * GL_HALF_FLOAT_OES = 0x8D61 != GL_HALF_FLOAT |
|
360 * WebGL handles this specifically with an OES_texture_half_float check. |
|
361 */ |
|
362 }, |
|
363 { |
|
364 "texture_half_float_linear", |
|
365 310, // OpenGL version |
|
366 300, // OpenGL ES version |
|
367 { |
|
368 GLContext::ARB_half_float_pixel, |
|
369 GLContext::ARB_texture_float, |
|
370 GLContext::NV_half_float, |
|
371 GLContext::OES_texture_half_float_linear, |
|
372 GLContext::Extensions_End |
|
373 } |
|
374 }, |
|
375 { |
|
376 "texture_non_power_of_two", |
|
377 200, // OpenGL version |
|
378 300, // OpenGL ES version |
|
379 { |
|
380 GLContext::ARB_texture_non_power_of_two, |
|
381 GLContext::OES_texture_npot, |
|
382 GLContext::Extensions_End |
|
383 } |
|
384 }, |
|
385 { |
|
386 "transform_feedback", |
|
387 300, // OpenGL version |
|
388 300, // OpenGL ES version |
|
389 { |
|
390 GLContext::EXT_transform_feedback, |
|
391 GLContext::NV_transform_feedback, |
|
392 GLContext::Extensions_End |
|
393 } |
|
394 }, |
|
395 { |
|
396 "vertex_array_object", |
|
397 300, // OpenGL version |
|
398 300, // OpenGL ES version |
|
399 { |
|
400 GLContext::ARB_vertex_array_object, |
|
401 GLContext::OES_vertex_array_object, |
|
402 GLContext::APPLE_vertex_array_object, |
|
403 GLContext::Extensions_End |
|
404 } |
|
405 } |
|
406 }; |
|
407 |
|
408 static inline const FeatureInfo& |
|
409 GetFeatureInfo(GLFeature feature) |
|
410 { |
|
411 static_assert(MOZ_ARRAY_LENGTH(sFeatureInfoArr) == size_t(GLFeature::EnumMax), |
|
412 "Mismatched lengths for sFeatureInfoInfos and GLFeature enums"); |
|
413 |
|
414 MOZ_ASSERT(feature < GLFeature::EnumMax, |
|
415 "GLContext::GetFeatureInfoInfo : unknown <feature>"); |
|
416 |
|
417 return sFeatureInfoArr[size_t(feature)]; |
|
418 } |
|
419 |
|
420 static inline uint32_t |
|
421 ProfileVersionForFeature(GLFeature feature, ContextProfile profile) |
|
422 { |
|
423 MOZ_ASSERT(profile != ContextProfile::Unknown, |
|
424 "GLContext::ProfileVersionForFeature : unknown <profile>"); |
|
425 |
|
426 const FeatureInfo& featureInfo = GetFeatureInfo(feature); |
|
427 |
|
428 if (profile == ContextProfile::OpenGLES) { |
|
429 return featureInfo.mOpenGLESVersion; |
|
430 } |
|
431 |
|
432 return featureInfo.mOpenGLVersion; |
|
433 } |
|
434 |
|
435 static inline bool |
|
436 IsFeatureIsPartOfProfileVersion(GLFeature feature, |
|
437 ContextProfile profile, unsigned int version) |
|
438 { |
|
439 unsigned int profileVersion = ProfileVersionForFeature(feature, profile); |
|
440 |
|
441 /** |
|
442 * if `profileVersion` is zero, it means that no version of the profile |
|
443 * added support for the feature. |
|
444 */ |
|
445 return profileVersion && version >= profileVersion; |
|
446 } |
|
447 |
|
448 const char* |
|
449 GLContext::GetFeatureName(GLFeature feature) |
|
450 { |
|
451 return GetFeatureInfo(feature).mName; |
|
452 } |
|
453 |
|
454 static bool |
|
455 CanReadSRGBFromFBOTexture(GLContext* gl) |
|
456 { |
|
457 if (!gl->WorkAroundDriverBugs()) |
|
458 return true; |
|
459 |
|
460 #ifdef XP_MACOSX |
|
461 // Bug 843668: |
|
462 // MacOSX 10.6 reports to support EXT_framebuffer_sRGB and |
|
463 // EXT_texture_sRGB but fails to convert from sRGB to linear |
|
464 // when writing to an sRGB texture attached to an FBO. |
|
465 if (!nsCocoaFeatures::OnLionOrLater()) { |
|
466 return false; |
|
467 } |
|
468 #endif // XP_MACOSX |
|
469 return true; |
|
470 } |
|
471 |
|
472 void |
|
473 GLContext::InitFeatures() |
|
474 { |
|
475 for (size_t feature_index = 0; feature_index < size_t(GLFeature::EnumMax); feature_index++) |
|
476 { |
|
477 GLFeature feature = GLFeature(feature_index); |
|
478 |
|
479 if (IsFeatureIsPartOfProfileVersion(feature, mProfile, mVersion)) { |
|
480 mAvailableFeatures[feature_index] = true; |
|
481 continue; |
|
482 } |
|
483 |
|
484 mAvailableFeatures[feature_index] = false; |
|
485 |
|
486 const FeatureInfo& featureInfo = GetFeatureInfo(feature); |
|
487 |
|
488 for (size_t j = 0; true; j++) |
|
489 { |
|
490 MOZ_ASSERT(j < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small"); |
|
491 |
|
492 if (featureInfo.mExtensions[j] == GLContext::Extensions_End) { |
|
493 break; |
|
494 } |
|
495 |
|
496 if (IsExtensionSupported(featureInfo.mExtensions[j])) { |
|
497 mAvailableFeatures[feature_index] = true; |
|
498 break; |
|
499 } |
|
500 } |
|
501 } |
|
502 |
|
503 // Bug 843668: Work around limitation of the feature system. |
|
504 // For sRGB support under OpenGL to match OpenGL ES spec, check for both |
|
505 // EXT_texture_sRGB and EXT_framebuffer_sRGB is required. |
|
506 const bool aresRGBExtensionsAvailable = |
|
507 IsExtensionSupported(EXT_texture_sRGB) && |
|
508 (IsExtensionSupported(ARB_framebuffer_sRGB) || |
|
509 IsExtensionSupported(EXT_framebuffer_sRGB)); |
|
510 |
|
511 mAvailableFeatures[size_t(GLFeature::sRGB)] = |
|
512 aresRGBExtensionsAvailable && |
|
513 CanReadSRGBFromFBOTexture(this); |
|
514 } |
|
515 |
|
516 void |
|
517 GLContext::MarkUnsupported(GLFeature feature) |
|
518 { |
|
519 mAvailableFeatures[size_t(feature)] = false; |
|
520 |
|
521 const FeatureInfo& featureInfo = GetFeatureInfo(feature); |
|
522 |
|
523 for (size_t i = 0; true; i++) |
|
524 { |
|
525 MOZ_ASSERT(i < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small"); |
|
526 |
|
527 if (featureInfo.mExtensions[i] == GLContext::Extensions_End) { |
|
528 break; |
|
529 } |
|
530 |
|
531 MarkExtensionUnsupported(featureInfo.mExtensions[i]); |
|
532 } |
|
533 |
|
534 MOZ_ASSERT(!IsSupported(feature), "GLContext::MarkUnsupported has failed!"); |
|
535 |
|
536 NS_WARNING(nsPrintfCString("%s marked as unsupported", GetFeatureName(feature)).get()); |
|
537 } |
|
538 |
|
539 } /* namespace gl */ |
|
540 } /* namespace mozilla */ |