/src/mozilla-central/gfx/gl/GLContext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* vim: set ts=8 sts=4 et sw=4 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "GLContext.h" |
8 | | |
9 | | #include <algorithm> |
10 | | #include <stdio.h> |
11 | | #include <string.h> |
12 | | #include <ctype.h> |
13 | | #include <regex> |
14 | | #include <string> |
15 | | #include <vector> |
16 | | #ifdef MOZ_WIDGET_ANDROID |
17 | | #include <sys/mman.h> |
18 | | #endif |
19 | | |
20 | | #include "GLBlitHelper.h" |
21 | | #include "GLReadTexImageHelper.h" |
22 | | #include "GLScreenBuffer.h" |
23 | | |
24 | | #include "gfxCrashReporterUtils.h" |
25 | | #include "gfxEnv.h" |
26 | | #include "gfxUtils.h" |
27 | | #include "GLContextProvider.h" |
28 | | #include "GLTextureImage.h" |
29 | | #include "nsPrintfCString.h" |
30 | | #include "nsThreadUtils.h" |
31 | | #include "prenv.h" |
32 | | #include "prlink.h" |
33 | | #include "ScopedGLHelpers.h" |
34 | | #include "SharedSurfaceGL.h" |
35 | | #include "GfxTexturesReporter.h" |
36 | | #include "gfx2DGlue.h" |
37 | | #include "gfxPrefs.h" |
38 | | #include "mozilla/IntegerPrintfMacros.h" |
39 | | #include "mozilla/gfx/Logging.h" |
40 | | |
41 | | #include "OGLShaderProgram.h" // for ShaderProgramType |
42 | | |
43 | | #include "mozilla/DebugOnly.h" |
44 | | |
45 | | #ifdef XP_MACOSX |
46 | | #include <CoreServices/CoreServices.h> |
47 | | #endif |
48 | | |
49 | | #if defined(MOZ_WIDGET_COCOA) |
50 | | #include "nsCocoaFeatures.h" |
51 | | #endif |
52 | | |
53 | | #ifdef MOZ_WIDGET_ANDROID |
54 | | #include "mozilla/jni/Utils.h" |
55 | | #endif |
56 | | |
57 | | namespace mozilla { |
58 | | namespace gl { |
59 | | |
60 | | using namespace mozilla::gfx; |
61 | | using namespace mozilla::layers; |
62 | | |
63 | | MOZ_THREAD_LOCAL(uintptr_t) GLContext::sCurrentContext; |
64 | | |
65 | | // If adding defines, don't forget to undefine symbols. See #undef block below. |
66 | 0 | #define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, { #x, nullptr } } |
67 | 0 | #define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x, #x #y, #x #z, nullptr } } |
68 | 0 | #define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, nullptr } } |
69 | 0 | #define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, #x #w, nullptr } } |
70 | 0 | #define END_SYMBOLS { nullptr, { nullptr } } |
71 | | |
72 | | // should match the order of GLExtensions, and be null-terminated. |
73 | | static const char* const sExtensionNames[] = { |
74 | | "NO_EXTENSION", |
75 | | "GL_AMD_compressed_ATC_texture", |
76 | | "GL_ANGLE_depth_texture", |
77 | | "GL_ANGLE_framebuffer_blit", |
78 | | "GL_ANGLE_framebuffer_multisample", |
79 | | "GL_ANGLE_instanced_arrays", |
80 | | "GL_ANGLE_texture_compression_dxt3", |
81 | | "GL_ANGLE_texture_compression_dxt5", |
82 | | "GL_ANGLE_timer_query", |
83 | | "GL_APPLE_client_storage", |
84 | | "GL_APPLE_fence", |
85 | | "GL_APPLE_framebuffer_multisample", |
86 | | "GL_APPLE_sync", |
87 | | "GL_APPLE_texture_range", |
88 | | "GL_APPLE_vertex_array_object", |
89 | | "GL_ARB_ES2_compatibility", |
90 | | "GL_ARB_ES3_compatibility", |
91 | | "GL_ARB_color_buffer_float", |
92 | | "GL_ARB_compatibility", |
93 | | "GL_ARB_copy_buffer", |
94 | | "GL_ARB_depth_texture", |
95 | | "GL_ARB_draw_buffers", |
96 | | "GL_ARB_draw_instanced", |
97 | | "GL_ARB_framebuffer_object", |
98 | | "GL_ARB_framebuffer_sRGB", |
99 | | "GL_ARB_geometry_shader4", |
100 | | "GL_ARB_half_float_pixel", |
101 | | "GL_ARB_instanced_arrays", |
102 | | "GL_ARB_internalformat_query", |
103 | | "GL_ARB_invalidate_subdata", |
104 | | "GL_ARB_map_buffer_range", |
105 | | "GL_ARB_occlusion_query2", |
106 | | "GL_ARB_pixel_buffer_object", |
107 | | "GL_ARB_robust_buffer_access_behavior", |
108 | | "GL_ARB_robustness", |
109 | | "GL_ARB_sampler_objects", |
110 | | "GL_ARB_seamless_cube_map", |
111 | | "GL_ARB_shader_texture_lod", |
112 | | "GL_ARB_sync", |
113 | | "GL_ARB_texture_compression", |
114 | | "GL_ARB_texture_float", |
115 | | "GL_ARB_texture_non_power_of_two", |
116 | | "GL_ARB_texture_rectangle", |
117 | | "GL_ARB_texture_rg", |
118 | | "GL_ARB_texture_storage", |
119 | | "GL_ARB_texture_swizzle", |
120 | | "GL_ARB_timer_query", |
121 | | "GL_ARB_transform_feedback2", |
122 | | "GL_ARB_uniform_buffer_object", |
123 | | "GL_ARB_vertex_array_object", |
124 | | "GL_EXT_bgra", |
125 | | "GL_EXT_blend_minmax", |
126 | | "GL_EXT_color_buffer_float", |
127 | | "GL_EXT_color_buffer_half_float", |
128 | | "GL_EXT_copy_texture", |
129 | | "GL_EXT_disjoint_timer_query", |
130 | | "GL_EXT_draw_buffers", |
131 | | "GL_EXT_draw_buffers2", |
132 | | "GL_EXT_draw_instanced", |
133 | | "GL_EXT_draw_range_elements", |
134 | | "GL_EXT_frag_depth", |
135 | | "GL_EXT_framebuffer_blit", |
136 | | "GL_EXT_framebuffer_multisample", |
137 | | "GL_EXT_framebuffer_object", |
138 | | "GL_EXT_framebuffer_sRGB", |
139 | | "GL_EXT_gpu_shader4", |
140 | | "GL_EXT_multisampled_render_to_texture", |
141 | | "GL_EXT_occlusion_query_boolean", |
142 | | "GL_EXT_packed_depth_stencil", |
143 | | "GL_EXT_read_format_bgra", |
144 | | "GL_EXT_robustness", |
145 | | "GL_EXT_sRGB", |
146 | | "GL_EXT_sRGB_write_control", |
147 | | "GL_EXT_shader_texture_lod", |
148 | | "GL_EXT_texture3D", |
149 | | "GL_EXT_texture_compression_dxt1", |
150 | | "GL_EXT_texture_compression_s3tc", |
151 | | "GL_EXT_texture_compression_s3tc_srgb", |
152 | | "GL_EXT_texture_filter_anisotropic", |
153 | | "GL_EXT_texture_format_BGRA8888", |
154 | | "GL_EXT_texture_sRGB", |
155 | | "GL_EXT_texture_storage", |
156 | | "GL_EXT_timer_query", |
157 | | "GL_EXT_transform_feedback", |
158 | | "GL_EXT_unpack_subimage", |
159 | | "GL_IMG_read_format", |
160 | | "GL_IMG_texture_compression_pvrtc", |
161 | | "GL_IMG_texture_npot", |
162 | | "GL_KHR_debug", |
163 | | "GL_KHR_robust_buffer_access_behavior", |
164 | | "GL_KHR_robustness", |
165 | | "GL_KHR_texture_compression_astc_hdr", |
166 | | "GL_KHR_texture_compression_astc_ldr", |
167 | | "GL_NV_draw_instanced", |
168 | | "GL_NV_fence", |
169 | | "GL_NV_framebuffer_blit", |
170 | | "GL_NV_geometry_program4", |
171 | | "GL_NV_half_float", |
172 | | "GL_NV_instanced_arrays", |
173 | | "GL_NV_primitive_restart", |
174 | | "GL_NV_texture_barrier", |
175 | | "GL_NV_transform_feedback", |
176 | | "GL_NV_transform_feedback2", |
177 | | "GL_OES_EGL_image", |
178 | | "GL_OES_EGL_image_external", |
179 | | "GL_OES_EGL_sync", |
180 | | "GL_OES_compressed_ETC1_RGB8_texture", |
181 | | "GL_OES_depth24", |
182 | | "GL_OES_depth32", |
183 | | "GL_OES_depth_texture", |
184 | | "GL_OES_element_index_uint", |
185 | | "GL_OES_framebuffer_object", |
186 | | "GL_OES_packed_depth_stencil", |
187 | | "GL_OES_rgb8_rgba8", |
188 | | "GL_OES_standard_derivatives", |
189 | | "GL_OES_stencil8", |
190 | | "GL_OES_texture_3D", |
191 | | "GL_OES_texture_float", |
192 | | "GL_OES_texture_float_linear", |
193 | | "GL_OES_texture_half_float", |
194 | | "GL_OES_texture_half_float_linear", |
195 | | "GL_OES_texture_npot", |
196 | | "GL_OES_vertex_array_object" |
197 | | }; |
198 | | |
199 | | static bool |
200 | | ShouldUseTLSIsCurrent(bool useTLSIsCurrent) |
201 | 0 | { |
202 | 0 | if (gfxPrefs::UseTLSIsCurrent() == 0) |
203 | 0 | return useTLSIsCurrent; |
204 | 0 | |
205 | 0 | return gfxPrefs::UseTLSIsCurrent() > 0; |
206 | 0 | } |
207 | | |
208 | | static bool |
209 | | ParseVersion(const std::string& versionStr, uint32_t* const out_major, |
210 | | uint32_t* const out_minor) |
211 | 0 | { |
212 | 0 | static const std::regex kVersionRegex("([0-9]+)\\.([0-9]+)"); |
213 | 0 | std::smatch match; |
214 | 0 | if (!std::regex_search(versionStr, match, kVersionRegex)) |
215 | 0 | return false; |
216 | 0 | |
217 | 0 | const auto& majorStr = match.str(1); |
218 | 0 | const auto& minorStr = match.str(2); |
219 | 0 | *out_major = atoi(majorStr.c_str()); |
220 | 0 | *out_minor = atoi(minorStr.c_str()); |
221 | 0 | return true; |
222 | 0 | } |
223 | | |
224 | | /*static*/ uint8_t |
225 | | GLContext::ChooseDebugFlags(const CreateContextFlags createFlags) |
226 | 0 | { |
227 | 0 | uint8_t debugFlags = 0; |
228 | 0 |
|
229 | | #ifdef MOZ_GL_DEBUG |
230 | | if (gfxEnv::GlDebug()) { |
231 | | debugFlags |= GLContext::DebugFlagEnabled; |
232 | | } |
233 | | |
234 | | // Enables extra verbose output, informing of the start and finish of every GL call. |
235 | | // Useful e.g. to record information to investigate graphics system crashes/lockups |
236 | | if (gfxEnv::GlDebugVerbose()) { |
237 | | debugFlags |= GLContext::DebugFlagTrace; |
238 | | } |
239 | | |
240 | | // Aborts on GL error. Can be useful to debug quicker code that is known not to |
241 | | // generate any GL error in principle. |
242 | | bool abortOnError = false; |
243 | | |
244 | | if (createFlags & CreateContextFlags::NO_VALIDATION) { |
245 | | abortOnError = true; |
246 | | |
247 | | const auto fnStringsMatch = [](const char* a, const char* b) { |
248 | | return strcmp(a, b) == 0; |
249 | | }; |
250 | | |
251 | | const char* envAbortOnError = PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR"); |
252 | | if (envAbortOnError && fnStringsMatch(envAbortOnError, "0")) { |
253 | | abortOnError = false; |
254 | | } |
255 | | } |
256 | | |
257 | | if (abortOnError) { |
258 | | debugFlags |= GLContext::DebugFlagAbortOnError; |
259 | | } |
260 | | #endif |
261 | |
|
262 | 0 | return debugFlags; |
263 | 0 | } |
264 | | |
265 | | GLContext::GLContext(CreateContextFlags flags, const SurfaceCaps& caps, |
266 | | GLContext* sharedContext, bool isOffscreen, bool useTLSIsCurrent) |
267 | | : mUseTLSIsCurrent(ShouldUseTLSIsCurrent(useTLSIsCurrent)), |
268 | | mIsOffscreen(isOffscreen), |
269 | | mDebugFlags(ChooseDebugFlags(flags)), |
270 | | mSharedContext(sharedContext), |
271 | | mCaps(caps) |
272 | 0 | { |
273 | 0 | mOwningThreadId = PlatformThread::CurrentId(); |
274 | 0 | MOZ_ALWAYS_TRUE( sCurrentContext.init() ); |
275 | 0 | sCurrentContext.set(0); |
276 | 0 | } |
277 | | |
278 | 0 | GLContext::~GLContext() { |
279 | 0 | NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!"); |
280 | | #ifdef MOZ_GL_DEBUG |
281 | | if (mSharedContext) { |
282 | | GLContext* tip = mSharedContext; |
283 | | while (tip->mSharedContext) |
284 | | tip = tip->mSharedContext; |
285 | | tip->SharedContextDestroyed(this); |
286 | | tip->ReportOutstandingNames(); |
287 | | } else { |
288 | | ReportOutstandingNames(); |
289 | | } |
290 | | #endif |
291 | | } |
292 | | |
293 | | /*static*/ void |
294 | | GLContext::StaticDebugCallback(GLenum source, |
295 | | GLenum type, |
296 | | GLuint id, |
297 | | GLenum severity, |
298 | | GLsizei length, |
299 | | const GLchar* message, |
300 | | const GLvoid* userParam) |
301 | 0 | { |
302 | 0 | GLContext* gl = (GLContext*)userParam; |
303 | 0 | gl->DebugCallback(source, type, id, severity, length, message); |
304 | 0 | } |
305 | | |
306 | | static void |
307 | | ClearSymbols(const GLLibraryLoader::SymLoadStruct* symbols) |
308 | 0 | { |
309 | 0 | while (symbols->symPointer) { |
310 | 0 | *symbols->symPointer = nullptr; |
311 | 0 | symbols++; |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | | bool |
316 | | GLContext::InitWithPrefix(const char* prefix, bool trygl) |
317 | 0 | { |
318 | 0 | MOZ_RELEASE_ASSERT(!mSymbols.fBindFramebuffer, |
319 | 0 | "GFX: InitWithPrefix should only be called once."); |
320 | 0 |
|
321 | 0 | ScopedGfxFeatureReporter reporter("GL Context"); |
322 | 0 |
|
323 | 0 | if (!InitWithPrefixImpl(prefix, trygl)) { |
324 | 0 | // If initialization fails, zero the symbols to avoid hard-to-understand bugs. |
325 | 0 | mSymbols = {}; |
326 | 0 | NS_WARNING("GLContext::InitWithPrefix failed!"); |
327 | 0 | return false; |
328 | 0 | } |
329 | 0 |
|
330 | 0 | reporter.SetSuccessful(); |
331 | 0 | return true; |
332 | 0 | } |
333 | | |
334 | | static bool |
335 | | LoadGLSymbols(GLContext* gl, const char* prefix, bool trygl, |
336 | | const GLLibraryLoader::SymLoadStruct* list, const char* desc) |
337 | 0 | { |
338 | 0 | if (gl->LoadSymbols(list, trygl, prefix)) |
339 | 0 | return true; |
340 | 0 | |
341 | 0 | ClearSymbols(list); |
342 | 0 |
|
343 | 0 | if (desc) { |
344 | 0 | const nsPrintfCString err("Failed to load symbols for %s.", desc); |
345 | 0 | NS_ERROR(err.BeginReading()); |
346 | 0 | } |
347 | 0 | return false; |
348 | 0 | } |
349 | | |
350 | | bool |
351 | | GLContext::LoadExtSymbols(const char* prefix, bool trygl, const SymLoadStruct* list, |
352 | | GLExtensions ext) |
353 | 0 | { |
354 | 0 | const char* extName = sExtensionNames[size_t(ext)]; |
355 | 0 | if (!LoadGLSymbols(this, prefix, trygl, list, extName)) { |
356 | 0 | MarkExtensionUnsupported(ext); |
357 | 0 | return false; |
358 | 0 | } |
359 | 0 | return true; |
360 | 0 | }; |
361 | | |
362 | | bool |
363 | | GLContext::LoadFeatureSymbols(const char* prefix, bool trygl, const SymLoadStruct* list, |
364 | | GLFeature feature) |
365 | 0 | { |
366 | 0 | const char* featureName = GetFeatureName(feature); |
367 | 0 | if (!LoadGLSymbols(this, prefix, trygl, list, featureName)) { |
368 | 0 | MarkUnsupported(feature); |
369 | 0 | return false; |
370 | 0 | } |
371 | 0 | return true; |
372 | 0 | }; |
373 | | |
374 | | bool |
375 | | GLContext::InitWithPrefixImpl(const char* prefix, bool trygl) |
376 | 0 | { |
377 | 0 | mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs(); |
378 | 0 |
|
379 | 0 | const SymLoadStruct coreSymbols[] = { |
380 | 0 | { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } }, |
381 | 0 | { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } }, |
382 | 0 | { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } }, |
383 | 0 | { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } }, |
384 | 0 | { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } }, |
385 | 0 | { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } }, |
386 | 0 | { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", nullptr } }, |
387 | 0 | { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, { "BlendEquationSeparate", "BlendEquationSeparateEXT", nullptr } }, |
388 | 0 | { (PRFuncPtr*) &mSymbols.fBlendFunc, { "BlendFunc", nullptr } }, |
389 | 0 | { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, { "BlendFuncSeparate", "BlendFuncSeparateEXT", nullptr } }, |
390 | 0 | { (PRFuncPtr*) &mSymbols.fBufferData, { "BufferData", nullptr } }, |
391 | 0 | { (PRFuncPtr*) &mSymbols.fBufferSubData, { "BufferSubData", nullptr } }, |
392 | 0 | { (PRFuncPtr*) &mSymbols.fClear, { "Clear", nullptr } }, |
393 | 0 | { (PRFuncPtr*) &mSymbols.fClearColor, { "ClearColor", nullptr } }, |
394 | 0 | { (PRFuncPtr*) &mSymbols.fClearStencil, { "ClearStencil", nullptr } }, |
395 | 0 | { (PRFuncPtr*) &mSymbols.fColorMask, { "ColorMask", nullptr } }, |
396 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexImage2D, {"CompressedTexImage2D", nullptr} }, |
397 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage2D, {"CompressedTexSubImage2D", nullptr} }, |
398 | 0 | { (PRFuncPtr*) &mSymbols.fCullFace, { "CullFace", nullptr } }, |
399 | 0 | { (PRFuncPtr*) &mSymbols.fDetachShader, { "DetachShader", "DetachShaderARB", nullptr } }, |
400 | 0 | { (PRFuncPtr*) &mSymbols.fDepthFunc, { "DepthFunc", nullptr } }, |
401 | 0 | { (PRFuncPtr*) &mSymbols.fDepthMask, { "DepthMask", nullptr } }, |
402 | 0 | { (PRFuncPtr*) &mSymbols.fDisable, { "Disable", nullptr } }, |
403 | 0 | { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, { "DisableVertexAttribArray", "DisableVertexAttribArrayARB", nullptr } }, |
404 | 0 | { (PRFuncPtr*) &mSymbols.fDrawArrays, { "DrawArrays", nullptr } }, |
405 | 0 | { (PRFuncPtr*) &mSymbols.fDrawElements, { "DrawElements", nullptr } }, |
406 | 0 | { (PRFuncPtr*) &mSymbols.fEnable, { "Enable", nullptr } }, |
407 | 0 | { (PRFuncPtr*) &mSymbols.fEnableVertexAttribArray, { "EnableVertexAttribArray", "EnableVertexAttribArrayARB", nullptr } }, |
408 | 0 | { (PRFuncPtr*) &mSymbols.fFinish, { "Finish", nullptr } }, |
409 | 0 | { (PRFuncPtr*) &mSymbols.fFlush, { "Flush", nullptr } }, |
410 | 0 | { (PRFuncPtr*) &mSymbols.fFrontFace, { "FrontFace", nullptr } }, |
411 | 0 | { (PRFuncPtr*) &mSymbols.fGetActiveAttrib, { "GetActiveAttrib", "GetActiveAttribARB", nullptr } }, |
412 | 0 | { (PRFuncPtr*) &mSymbols.fGetActiveUniform, { "GetActiveUniform", "GetActiveUniformARB", nullptr } }, |
413 | 0 | { (PRFuncPtr*) &mSymbols.fGetAttachedShaders, { "GetAttachedShaders", "GetAttachedShadersARB", nullptr } }, |
414 | 0 | { (PRFuncPtr*) &mSymbols.fGetAttribLocation, { "GetAttribLocation", "GetAttribLocationARB", nullptr } }, |
415 | 0 | { (PRFuncPtr*) &mSymbols.fGetIntegerv, { "GetIntegerv", nullptr } }, |
416 | 0 | { (PRFuncPtr*) &mSymbols.fGetFloatv, { "GetFloatv", nullptr } }, |
417 | 0 | { (PRFuncPtr*) &mSymbols.fGetBooleanv, { "GetBooleanv", nullptr } }, |
418 | 0 | { (PRFuncPtr*) &mSymbols.fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", nullptr } }, |
419 | 0 | { (PRFuncPtr*) &mSymbols.fGetError, { "GetError", nullptr } }, |
420 | 0 | { (PRFuncPtr*) &mSymbols.fGetProgramiv, { "GetProgramiv", "GetProgramivARB", nullptr } }, |
421 | 0 | { (PRFuncPtr*) &mSymbols.fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", nullptr } }, |
422 | 0 | { (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", nullptr } }, |
423 | 0 | { (PRFuncPtr*) &mSymbols.fTexParameteriv, { "TexParameteriv", nullptr } }, |
424 | 0 | { (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", nullptr } }, |
425 | 0 | { (PRFuncPtr*) &mSymbols.fGetString, { "GetString", nullptr } }, |
426 | 0 | { (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", nullptr } }, |
427 | 0 | { (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", nullptr } }, |
428 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", nullptr } }, |
429 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformiv, { "GetUniformiv", "GetUniformivARB", nullptr } }, |
430 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformLocation, { "GetUniformLocation", "GetUniformLocationARB", nullptr } }, |
431 | 0 | { (PRFuncPtr*) &mSymbols.fGetVertexAttribfv, { "GetVertexAttribfv", "GetVertexAttribfvARB", nullptr } }, |
432 | 0 | { (PRFuncPtr*) &mSymbols.fGetVertexAttribiv, { "GetVertexAttribiv", "GetVertexAttribivARB", nullptr } }, |
433 | 0 | { (PRFuncPtr*) &mSymbols.fGetVertexAttribPointerv, { "GetVertexAttribPointerv", nullptr } }, |
434 | 0 | { (PRFuncPtr*) &mSymbols.fHint, { "Hint", nullptr } }, |
435 | 0 | { (PRFuncPtr*) &mSymbols.fIsBuffer, { "IsBuffer", "IsBufferARB", nullptr } }, |
436 | 0 | { (PRFuncPtr*) &mSymbols.fIsEnabled, { "IsEnabled", nullptr } }, |
437 | 0 | { (PRFuncPtr*) &mSymbols.fIsProgram, { "IsProgram", "IsProgramARB", nullptr } }, |
438 | 0 | { (PRFuncPtr*) &mSymbols.fIsShader, { "IsShader", "IsShaderARB", nullptr } }, |
439 | 0 | { (PRFuncPtr*) &mSymbols.fIsTexture, { "IsTexture", "IsTextureARB", nullptr } }, |
440 | 0 | { (PRFuncPtr*) &mSymbols.fLineWidth, { "LineWidth", nullptr } }, |
441 | 0 | { (PRFuncPtr*) &mSymbols.fLinkProgram, { "LinkProgram", "LinkProgramARB", nullptr } }, |
442 | 0 | { (PRFuncPtr*) &mSymbols.fPixelStorei, { "PixelStorei", nullptr } }, |
443 | 0 | { (PRFuncPtr*) &mSymbols.fPolygonOffset, { "PolygonOffset", nullptr } }, |
444 | 0 | { (PRFuncPtr*) &mSymbols.fReadPixels, { "ReadPixels", nullptr } }, |
445 | 0 | { (PRFuncPtr*) &mSymbols.fSampleCoverage, { "SampleCoverage", nullptr } }, |
446 | 0 | { (PRFuncPtr*) &mSymbols.fScissor, { "Scissor", nullptr } }, |
447 | 0 | { (PRFuncPtr*) &mSymbols.fStencilFunc, { "StencilFunc", nullptr } }, |
448 | 0 | { (PRFuncPtr*) &mSymbols.fStencilFuncSeparate, { "StencilFuncSeparate", "StencilFuncSeparateEXT", nullptr } }, |
449 | 0 | { (PRFuncPtr*) &mSymbols.fStencilMask, { "StencilMask", nullptr } }, |
450 | 0 | { (PRFuncPtr*) &mSymbols.fStencilMaskSeparate, { "StencilMaskSeparate", "StencilMaskSeparateEXT", nullptr } }, |
451 | 0 | { (PRFuncPtr*) &mSymbols.fStencilOp, { "StencilOp", nullptr } }, |
452 | 0 | { (PRFuncPtr*) &mSymbols.fStencilOpSeparate, { "StencilOpSeparate", "StencilOpSeparateEXT", nullptr } }, |
453 | 0 | { (PRFuncPtr*) &mSymbols.fTexImage2D, { "TexImage2D", nullptr } }, |
454 | 0 | { (PRFuncPtr*) &mSymbols.fTexSubImage2D, { "TexSubImage2D", nullptr } }, |
455 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1f, { "Uniform1f", nullptr } }, |
456 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1fv, { "Uniform1fv", nullptr } }, |
457 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1i, { "Uniform1i", nullptr } }, |
458 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1iv, { "Uniform1iv", nullptr } }, |
459 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2f, { "Uniform2f", nullptr } }, |
460 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2fv, { "Uniform2fv", nullptr } }, |
461 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2i, { "Uniform2i", nullptr } }, |
462 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2iv, { "Uniform2iv", nullptr } }, |
463 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3f, { "Uniform3f", nullptr } }, |
464 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3fv, { "Uniform3fv", nullptr } }, |
465 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3i, { "Uniform3i", nullptr } }, |
466 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3iv, { "Uniform3iv", nullptr } }, |
467 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4f, { "Uniform4f", nullptr } }, |
468 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4fv, { "Uniform4fv", nullptr } }, |
469 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4i, { "Uniform4i", nullptr } }, |
470 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4iv, { "Uniform4iv", nullptr } }, |
471 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix2fv, { "UniformMatrix2fv", nullptr } }, |
472 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix3fv, { "UniformMatrix3fv", nullptr } }, |
473 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix4fv, { "UniformMatrix4fv", nullptr } }, |
474 | 0 | { (PRFuncPtr*) &mSymbols.fUseProgram, { "UseProgram", nullptr } }, |
475 | 0 | { (PRFuncPtr*) &mSymbols.fValidateProgram, { "ValidateProgram", nullptr } }, |
476 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } }, |
477 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib1f, { "VertexAttrib1f", nullptr } }, |
478 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib2f, { "VertexAttrib2f", nullptr } }, |
479 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib3f, { "VertexAttrib3f", nullptr } }, |
480 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib4f, { "VertexAttrib4f", nullptr } }, |
481 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib1fv, { "VertexAttrib1fv", nullptr } }, |
482 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib2fv, { "VertexAttrib2fv", nullptr } }, |
483 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib3fv, { "VertexAttrib3fv", nullptr } }, |
484 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttrib4fv, { "VertexAttrib4fv", nullptr } }, |
485 | 0 | { (PRFuncPtr*) &mSymbols.fViewport, { "Viewport", nullptr } }, |
486 | 0 | { (PRFuncPtr*) &mSymbols.fCompileShader, { "CompileShader", nullptr } }, |
487 | 0 | { (PRFuncPtr*) &mSymbols.fCopyTexImage2D, { "CopyTexImage2D", nullptr } }, |
488 | 0 | { (PRFuncPtr*) &mSymbols.fCopyTexSubImage2D, { "CopyTexSubImage2D", nullptr } }, |
489 | 0 | { (PRFuncPtr*) &mSymbols.fGetShaderiv, { "GetShaderiv", nullptr } }, |
490 | 0 | { (PRFuncPtr*) &mSymbols.fGetShaderInfoLog, { "GetShaderInfoLog", nullptr } }, |
491 | 0 | { (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", nullptr } }, |
492 | 0 | { (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", nullptr } }, |
493 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } }, |
494 | 0 |
|
495 | 0 | { (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", nullptr } }, |
496 | 0 | { (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", nullptr } }, |
497 | 0 | { (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", nullptr } }, |
498 | 0 | { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", nullptr } }, |
499 | 0 |
|
500 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", nullptr } }, |
501 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", nullptr } }, |
502 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", nullptr } }, |
503 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", nullptr } }, |
504 | 0 |
|
505 | 0 | END_SYMBOLS |
506 | 0 | }; |
507 | 0 |
|
508 | 0 | if (!LoadGLSymbols(this, prefix, trygl, coreSymbols, "GL")) |
509 | 0 | return false; |
510 | 0 | |
511 | 0 | //////////////// |
512 | 0 | |
513 | 0 | if (!MakeCurrent()) { |
514 | 0 | return false; |
515 | 0 | } |
516 | 0 | |
517 | 0 | const std::string versionStr = (const char*)fGetString(LOCAL_GL_VERSION); |
518 | 0 | if (versionStr.find("OpenGL ES") == 0) { |
519 | 0 | mProfile = ContextProfile::OpenGLES; |
520 | 0 | } |
521 | 0 |
|
522 | 0 | uint32_t majorVer, minorVer; |
523 | 0 | if (!ParseVersion(versionStr, &majorVer, &minorVer)) { |
524 | 0 | MOZ_ASSERT(false, "Failed to parse GL_VERSION"); |
525 | 0 | return false; |
526 | 0 | } |
527 | 0 | MOZ_ASSERT(majorVer < 10); |
528 | 0 | MOZ_ASSERT(minorVer < 10); |
529 | 0 | mVersion = majorVer*100 + minorVer*10; |
530 | 0 | if (mVersion < 200) |
531 | 0 | return false; |
532 | 0 | |
533 | 0 | //// |
534 | 0 | |
535 | 0 | const auto glslVersionStr = (const char*)fGetString(LOCAL_GL_SHADING_LANGUAGE_VERSION); |
536 | 0 | if (!glslVersionStr) { |
537 | 0 | // This happens on the Android emulators. We'll just return 100 |
538 | 0 | mShadingLanguageVersion = 100; |
539 | 0 | } else if (ParseVersion(glslVersionStr, &majorVer, &minorVer)) { |
540 | 0 | MOZ_ASSERT(majorVer < 10); |
541 | 0 | MOZ_ASSERT(minorVer < 100); |
542 | 0 | mShadingLanguageVersion = majorVer*100 + minorVer; |
543 | 0 | } else { |
544 | 0 | MOZ_ASSERT(false, "Failed to parse GL_SHADING_LANGUAGE_VERSION"); |
545 | 0 | return false; |
546 | 0 | } |
547 | 0 |
|
548 | 0 | if (ShouldSpew()) { |
549 | 0 | printf_stderr("GL version detected: %u\n", mVersion); |
550 | 0 | printf_stderr("GLSL version detected: %u\n", mShadingLanguageVersion); |
551 | 0 | printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR)); |
552 | 0 | printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER)); |
553 | 0 | } |
554 | 0 |
|
555 | 0 | //////////////// |
556 | 0 |
|
557 | 0 | // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2. |
558 | 0 | if (mProfile == ContextProfile::OpenGLES) { |
559 | 0 | const SymLoadStruct symbols[] = { |
560 | 0 | { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } }, |
561 | 0 | { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } }, |
562 | 0 | { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", nullptr } }, |
563 | 0 | END_SYMBOLS |
564 | 0 | }; |
565 | 0 |
|
566 | 0 | if (!LoadGLSymbols(this, prefix, trygl, symbols, "OpenGL ES")) |
567 | 0 | return false; |
568 | 0 | } else { |
569 | 0 | const SymLoadStruct symbols[] = { |
570 | 0 | { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", nullptr } }, |
571 | 0 | { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", nullptr } }, |
572 | 0 | { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } }, |
573 | 0 | { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", nullptr } }, |
574 | 0 | { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } }, |
575 | 0 | { (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", nullptr } }, |
576 | 0 | { (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", nullptr } }, |
577 | 0 | // The following functions are only used by Skia/GL in desktop mode. |
578 | 0 | // Other parts of Gecko should avoid using these |
579 | 0 | { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } }, |
580 | 0 | { (PRFuncPtr*) &mSymbols.fClientActiveTexture, { "ClientActiveTexture", nullptr } }, |
581 | 0 | { (PRFuncPtr*) &mSymbols.fDisableClientState, { "DisableClientState", nullptr } }, |
582 | 0 | { (PRFuncPtr*) &mSymbols.fEnableClientState, { "EnableClientState", nullptr } }, |
583 | 0 | { (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } }, |
584 | 0 | { (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } }, |
585 | 0 | { (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } }, |
586 | 0 | { (PRFuncPtr*) &mSymbols.fPolygonMode, { "PolygonMode", nullptr } }, |
587 | 0 | { (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } }, |
588 | 0 | { (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } }, |
589 | 0 | { (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } }, |
590 | 0 | { (PRFuncPtr*) &mSymbols.fVertexPointer, { "VertexPointer", nullptr } }, |
591 | 0 | END_SYMBOLS |
592 | 0 | }; |
593 | 0 |
|
594 | 0 | if (!LoadGLSymbols(this, prefix, trygl, symbols, "Desktop OpenGL")) |
595 | 0 | return false; |
596 | 0 | } |
597 | 0 | |
598 | 0 | //////////////// |
599 | 0 | |
600 | 0 | const char* glVendorString = (const char*)fGetString(LOCAL_GL_VENDOR); |
601 | 0 | const char* glRendererString = (const char*)fGetString(LOCAL_GL_RENDERER); |
602 | 0 | if (!glVendorString || !glRendererString) |
603 | 0 | return false; |
604 | 0 | |
605 | 0 | // The order of these strings must match up with the order of the enum |
606 | 0 | // defined in GLContext.h for vendor IDs. |
607 | 0 | const char* vendorMatchStrings[size_t(GLVendor::Other) + 1] = { |
608 | 0 | "Intel", |
609 | 0 | "NVIDIA", |
610 | 0 | "ATI", |
611 | 0 | "Qualcomm", |
612 | 0 | "Imagination", |
613 | 0 | "nouveau", |
614 | 0 | "Vivante", |
615 | 0 | "VMware, Inc.", |
616 | 0 | "ARM", |
617 | 0 | "Unknown" |
618 | 0 | }; |
619 | 0 |
|
620 | 0 | mVendor = GLVendor::Other; |
621 | 0 | for (size_t i = 0; i < size_t(GLVendor::Other); ++i) { |
622 | 0 | if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) { |
623 | 0 | mVendor = GLVendor(i); |
624 | 0 | break; |
625 | 0 | } |
626 | 0 | } |
627 | 0 |
|
628 | 0 | // The order of these strings must match up with the order of the enum |
629 | 0 | // defined in GLContext.h for renderer IDs. |
630 | 0 | const char* rendererMatchStrings[size_t(GLRenderer::Other) + 1] = { |
631 | 0 | "Adreno 200", |
632 | 0 | "Adreno 205", |
633 | 0 | "Adreno (TM) 200", |
634 | 0 | "Adreno (TM) 205", |
635 | 0 | "Adreno (TM) 305", |
636 | 0 | "Adreno (TM) 320", |
637 | 0 | "Adreno (TM) 330", |
638 | 0 | "Adreno (TM) 420", |
639 | 0 | "Mali-400 MP", |
640 | 0 | "Mali-450 MP", |
641 | 0 | "PowerVR SGX 530", |
642 | 0 | "PowerVR SGX 540", |
643 | 0 | "PowerVR SGX 544MP", |
644 | 0 | "NVIDIA Tegra", |
645 | 0 | "Android Emulator", |
646 | 0 | "Gallium 0.4 on llvmpipe", |
647 | 0 | "Intel HD Graphics 3000 OpenGL Engine", |
648 | 0 | "Microsoft Basic Render Driver", |
649 | 0 | "Unknown" |
650 | 0 | }; |
651 | 0 |
|
652 | 0 | mRenderer = GLRenderer::Other; |
653 | 0 | for (size_t i = 0; i < size_t(GLRenderer::Other); ++i) { |
654 | 0 | if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) { |
655 | 0 | mRenderer = GLRenderer(i); |
656 | 0 | break; |
657 | 0 | } |
658 | 0 | } |
659 | 0 |
|
660 | 0 | if (ShouldSpew()) { |
661 | 0 | printf_stderr("GL_VENDOR: %s\n", glVendorString); |
662 | 0 | printf_stderr("mVendor: %s\n", vendorMatchStrings[size_t(mVendor)]); |
663 | 0 | printf_stderr("GL_RENDERER: %s\n", glRendererString); |
664 | 0 | printf_stderr("mRenderer: %s\n", rendererMatchStrings[size_t(mRenderer)]); |
665 | 0 | } |
666 | 0 |
|
667 | 0 | //////////////// |
668 | 0 |
|
669 | 0 | if (mVersion >= 300) { // Both GL3 and ES3. |
670 | 0 | const SymLoadStruct symbols[] = { |
671 | 0 | { (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } }, |
672 | 0 | END_SYMBOLS |
673 | 0 | }; |
674 | 0 |
|
675 | 0 | if (!LoadGLSymbols(this, prefix, trygl, symbols, "GetStringi")) { |
676 | 0 | MOZ_RELEASE_ASSERT(false, "GFX: GetStringi is required!"); |
677 | 0 | return false; |
678 | 0 | } |
679 | 0 | } |
680 | 0 | |
681 | 0 | InitExtensions(); |
682 | 0 | if (mProfile != ContextProfile::OpenGLES) { |
683 | 0 | if (mVersion >= 310 && !IsExtensionSupported(ARB_compatibility)) { |
684 | 0 | mProfile = ContextProfile::OpenGLCore; |
685 | 0 | } else { |
686 | 0 | mProfile = ContextProfile::OpenGLCompatibility; |
687 | 0 | } |
688 | 0 | } |
689 | 0 | MOZ_ASSERT(mProfile != ContextProfile::Unknown); |
690 | 0 |
|
691 | 0 | if (ShouldSpew()) { |
692 | 0 | const char* profileStr = ""; |
693 | 0 | if (mProfile == ContextProfile::OpenGLES) { |
694 | 0 | profileStr = " es"; |
695 | 0 | } else if (mProfile == ContextProfile::OpenGLCore) { |
696 | 0 | profileStr = " core"; |
697 | 0 | } |
698 | 0 | printf_stderr("Detected profile: %u%s\n", mVersion, profileStr); |
699 | 0 | } |
700 | 0 |
|
701 | 0 | InitFeatures(); |
702 | 0 |
|
703 | 0 | //// |
704 | 0 |
|
705 | 0 | // Disable extensions with partial or incorrect support. |
706 | 0 | if (WorkAroundDriverBugs()) { |
707 | 0 | if (Renderer() == GLRenderer::AdrenoTM320) { |
708 | 0 | MarkUnsupported(GLFeature::standard_derivatives); |
709 | 0 | } |
710 | 0 |
|
711 | 0 | if (Vendor() == GLVendor::Vivante) { |
712 | 0 | // bug 958256 |
713 | 0 | MarkUnsupported(GLFeature::standard_derivatives); |
714 | 0 | } |
715 | 0 |
|
716 | 0 | if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) { |
717 | 0 | // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer) |
718 | 0 | // multisampling hardcodes blending with the default blendfunc, which breaks WebGL. |
719 | 0 | MarkUnsupported(GLFeature::framebuffer_multisample); |
720 | 0 | } |
721 | 0 |
|
722 | | #ifdef XP_MACOSX |
723 | | // The Mac Nvidia driver, for versions up to and including 10.8, |
724 | | // don't seem to properly support this. See 814839 |
725 | | // this has been fixed in Mac OS X 10.9. See 907946 |
726 | | // and it also works in 10.8.3 and higher. See 1094338. |
727 | | if (Vendor() == gl::GLVendor::NVIDIA && |
728 | | !nsCocoaFeatures::IsAtLeastVersion(10,8,3)) |
729 | | { |
730 | | MarkUnsupported(GLFeature::depth_texture); |
731 | | } |
732 | | #endif |
733 | |
|
734 | 0 | const auto versionStr = (const char*)fGetString(LOCAL_GL_VERSION); |
735 | 0 | if (strstr(versionStr, "Mesa")) { |
736 | 0 | // DrawElementsInstanced hangs the driver. |
737 | 0 | MarkUnsupported(GLFeature::robust_buffer_access_behavior); |
738 | 0 | } |
739 | 0 | } |
740 | 0 |
|
741 | 0 | if (IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) { |
742 | 0 | MOZ_ASSERT((mSymbols.fMapBuffer && mSymbols.fUnmapBuffer), |
743 | 0 | "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer" |
744 | 0 | " being available!"); |
745 | 0 | } |
746 | 0 |
|
747 | 0 | //////////////////////////////////////////////////////////////////////////// |
748 | 0 |
|
749 | 0 | const auto fnLoadForFeature = [this, prefix, trygl](const SymLoadStruct* list, |
750 | 0 | GLFeature feature) |
751 | 0 | { |
752 | 0 | return this->LoadFeatureSymbols(prefix, trygl, list, feature); |
753 | 0 | }; |
754 | 0 |
|
755 | 0 | // Check for ARB_framebuffer_objects |
756 | 0 | if (IsSupported(GLFeature::framebuffer_object)) { |
757 | 0 | // https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt |
758 | 0 | const SymLoadStruct symbols[] = { |
759 | 0 | CORE_SYMBOL(IsRenderbuffer), |
760 | 0 | CORE_SYMBOL(BindRenderbuffer), |
761 | 0 | CORE_SYMBOL(DeleteRenderbuffers), |
762 | 0 | CORE_SYMBOL(GenRenderbuffers), |
763 | 0 | CORE_SYMBOL(RenderbufferStorage), |
764 | 0 | CORE_SYMBOL(RenderbufferStorageMultisample), |
765 | 0 | CORE_SYMBOL(GetRenderbufferParameteriv), |
766 | 0 | CORE_SYMBOL(IsFramebuffer), |
767 | 0 | CORE_SYMBOL(BindFramebuffer), |
768 | 0 | CORE_SYMBOL(DeleteFramebuffers), |
769 | 0 | CORE_SYMBOL(GenFramebuffers), |
770 | 0 | CORE_SYMBOL(CheckFramebufferStatus), |
771 | 0 | CORE_SYMBOL(FramebufferTexture2D), |
772 | 0 | CORE_SYMBOL(FramebufferTextureLayer), |
773 | 0 | CORE_SYMBOL(FramebufferRenderbuffer), |
774 | 0 | CORE_SYMBOL(GetFramebufferAttachmentParameteriv), |
775 | 0 | CORE_SYMBOL(BlitFramebuffer), |
776 | 0 | CORE_SYMBOL(GenerateMipmap), |
777 | 0 | END_SYMBOLS |
778 | 0 | }; |
779 | 0 | fnLoadForFeature(symbols, GLFeature::framebuffer_object); |
780 | 0 | } |
781 | 0 |
|
782 | 0 | if (!IsSupported(GLFeature::framebuffer_object)) { |
783 | 0 | // Check for aux symbols based on extensions |
784 | 0 | if (IsSupported(GLFeature::framebuffer_object_EXT_OES)) { |
785 | 0 | const SymLoadStruct symbols[] = { |
786 | 0 | CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES), |
787 | 0 | CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES), |
788 | 0 | CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES), |
789 | 0 | CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES), |
790 | 0 | CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES), |
791 | 0 | CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES), |
792 | 0 | CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES), |
793 | 0 | CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES), |
794 | 0 | CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES), |
795 | 0 | CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES), |
796 | 0 | CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES), |
797 | 0 | CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES), |
798 | 0 | CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES), |
799 | 0 | CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES), |
800 | 0 | CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES), |
801 | 0 | END_SYMBOLS |
802 | 0 | }; |
803 | 0 | fnLoadForFeature(symbols, GLFeature::framebuffer_object_EXT_OES); |
804 | 0 | } |
805 | 0 |
|
806 | 0 | if (IsSupported(GLFeature::framebuffer_blit)) { |
807 | 0 | const SymLoadStruct symbols[] = { |
808 | 0 | EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV), |
809 | 0 | END_SYMBOLS |
810 | 0 | }; |
811 | 0 | fnLoadForFeature(symbols, GLFeature::framebuffer_blit); |
812 | 0 | } |
813 | 0 |
|
814 | 0 | if (IsSupported(GLFeature::framebuffer_multisample)) { |
815 | 0 | const SymLoadStruct symbols[] = { |
816 | 0 | EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT), |
817 | 0 | END_SYMBOLS |
818 | 0 | }; |
819 | 0 | fnLoadForFeature(symbols, GLFeature::framebuffer_multisample); |
820 | 0 | } |
821 | 0 |
|
822 | 0 | if (IsExtensionSupported(GLContext::ARB_geometry_shader4) || |
823 | 0 | IsExtensionSupported(GLContext::NV_geometry_program4)) |
824 | 0 | { |
825 | 0 | const SymLoadStruct symbols[] = { |
826 | 0 | EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT), |
827 | 0 | END_SYMBOLS |
828 | 0 | }; |
829 | 0 | if (!LoadGLSymbols(this, prefix, trygl, symbols, |
830 | 0 | "ARB_geometry_shader4/NV_geometry_program4")) |
831 | 0 | { |
832 | 0 | MarkExtensionUnsupported(GLContext::ARB_geometry_shader4); |
833 | 0 | MarkExtensionUnsupported(GLContext::NV_geometry_program4); |
834 | 0 | } |
835 | 0 | } |
836 | 0 | } |
837 | 0 |
|
838 | 0 | if (!IsSupported(GLFeature::framebuffer_object) && |
839 | 0 | !IsSupported(GLFeature::framebuffer_object_EXT_OES)) |
840 | 0 | { |
841 | 0 | NS_ERROR("GLContext requires support for framebuffer objects."); |
842 | 0 | return false; |
843 | 0 | } |
844 | 0 | MOZ_RELEASE_ASSERT(mSymbols.fBindFramebuffer, "GFX: mSymbols.fBindFramebuffer zero or not set."); |
845 | 0 |
|
846 | 0 | //////////////// |
847 | 0 |
|
848 | 0 | const auto err = mSymbols.fGetError(); |
849 | 0 | MOZ_RELEASE_ASSERT(!err); |
850 | 0 | if (err) |
851 | 0 | return false; |
852 | 0 | |
853 | 0 | LoadMoreSymbols(prefix, trygl); |
854 | 0 |
|
855 | 0 | //////////////////////////////////////////////////////////////////////////// |
856 | 0 |
|
857 | 0 | raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect); |
858 | 0 | raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect); |
859 | 0 | raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); |
860 | 0 | raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize); |
861 | 0 | raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); |
862 | 0 | raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); |
863 | 0 |
|
864 | | #ifdef XP_MACOSX |
865 | | if (mWorkAroundDriverBugs && |
866 | | nsCocoaFeatures::OSXVersionMajor() == 10 && |
867 | | nsCocoaFeatures::OSXVersionMinor() < 12) |
868 | | { |
869 | | if (mVendor == GLVendor::Intel) { |
870 | | // see bug 737182 for 2D textures, bug 684882 for cube map textures. |
871 | | mMaxTextureSize = std::min(mMaxTextureSize, 4096); |
872 | | mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512); |
873 | | // for good measure, we align renderbuffers on what we do for 2D textures |
874 | | mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096); |
875 | | mNeedsTextureSizeChecks = true; |
876 | | } else if (mVendor == GLVendor::NVIDIA) { |
877 | | // See bug 879656. 8192 fails, 8191 works. |
878 | | mMaxTextureSize = std::min(mMaxTextureSize, 8191); |
879 | | mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191); |
880 | | |
881 | | // Part of the bug 879656, but it also doesn't hurt the 877949 |
882 | | mNeedsTextureSizeChecks = true; |
883 | | } |
884 | | } |
885 | | #endif |
886 | | #ifdef MOZ_X11 |
887 | 0 | if (mWorkAroundDriverBugs) { |
888 | 0 | if (mVendor == GLVendor::Nouveau) { |
889 | 0 | // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau. |
890 | 0 | mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048); |
891 | 0 | mNeedsTextureSizeChecks = true; |
892 | 0 | } else if (mVendor == GLVendor::Intel) { |
893 | 0 | // Bug 1199923. Driver seems to report a larger max size than |
894 | 0 | // actually supported. |
895 | 0 | mMaxTextureSize /= 2; |
896 | 0 | mMaxRenderbufferSize /= 2; |
897 | 0 | mNeedsTextureSizeChecks = true; |
898 | 0 | } |
899 | 0 | // Bug 1367570. Explicitly set vertex attributes [1,3] to opaque |
900 | 0 | // black because Nvidia doesn't do it for us. |
901 | 0 | if (mVendor == GLVendor::NVIDIA) { |
902 | 0 | for (size_t i = 1; i <= 3; ++i) { |
903 | 0 | mSymbols.fVertexAttrib4f(i, 0, 0, 0, 1); |
904 | 0 | } |
905 | 0 | } |
906 | 0 | } |
907 | 0 | #endif |
908 | 0 | if (mWorkAroundDriverBugs && |
909 | 0 | Renderer() == GLRenderer::AdrenoTM420) { |
910 | 0 | // see bug 1194923. Calling glFlush before glDeleteFramebuffers |
911 | 0 | // prevents occasional driver crash. |
912 | 0 | mNeedsFlushBeforeDeleteFB = true; |
913 | 0 | } |
914 | | #ifdef MOZ_WIDGET_ANDROID |
915 | | if (mWorkAroundDriverBugs && |
916 | | (Renderer() == GLRenderer::AdrenoTM305 || |
917 | | Renderer() == GLRenderer::AdrenoTM320 || |
918 | | Renderer() == GLRenderer::AdrenoTM330) && |
919 | | jni::GetAPIVersion() < 21) { |
920 | | // Bug 1164027. Driver crashes when functions such as |
921 | | // glTexImage2D fail due to virtual memory exhaustion. |
922 | | mTextureAllocCrashesOnMapFailure = true; |
923 | | } |
924 | | #endif |
925 | | #if MOZ_WIDGET_ANDROID |
926 | | if (mWorkAroundDriverBugs && |
927 | | Renderer() == GLRenderer::SGX540 && |
928 | | jni::GetAPIVersion() <= 15) { |
929 | | // Bug 1288446. Driver sometimes crashes when uploading data to a |
930 | | // texture if the render target has changed since the texture was |
931 | | // rendered from. Calling glCheckFramebufferStatus after |
932 | | // glFramebufferTexture2D prevents the crash. |
933 | | mNeedsCheckAfterAttachTextureToFb = true; |
934 | | } |
935 | | #endif |
936 | |
|
937 | 0 | mMaxTextureImageSize = mMaxTextureSize; |
938 | 0 |
|
939 | 0 | if (IsSupported(GLFeature::framebuffer_multisample)) { |
940 | 0 | fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples); |
941 | 0 | } |
942 | 0 |
|
943 | 0 | mMaxTexOrRbSize = std::min(mMaxTextureSize, mMaxRenderbufferSize); |
944 | 0 |
|
945 | 0 | //////////////////////////////////////////////////////////////////////////// |
946 | 0 |
|
947 | 0 | // We're ready for final setup. |
948 | 0 | fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
949 | 0 |
|
950 | 0 | // TODO: Remove SurfaceCaps::any. |
951 | 0 | if (mCaps.any) { |
952 | 0 | mCaps.any = false; |
953 | 0 | mCaps.color = true; |
954 | 0 | mCaps.alpha = false; |
955 | 0 | } |
956 | 0 |
|
957 | 0 | MOZ_ASSERT(IsCurrent()); |
958 | 0 |
|
959 | 0 | if (ShouldSpew() && IsExtensionSupported(KHR_debug)) { |
960 | 0 | fEnable(LOCAL_GL_DEBUG_OUTPUT); |
961 | 0 | fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS); |
962 | 0 | fDebugMessageCallback(&StaticDebugCallback, (void*)this); |
963 | 0 | fDebugMessageControl(LOCAL_GL_DONT_CARE, |
964 | 0 | LOCAL_GL_DONT_CARE, |
965 | 0 | LOCAL_GL_DONT_CARE, |
966 | 0 | 0, nullptr, |
967 | 0 | true); |
968 | 0 | } |
969 | 0 |
|
970 | 0 | return true; |
971 | 0 | } |
972 | | |
973 | | void |
974 | | GLContext::LoadMoreSymbols(const char* prefix, bool trygl) |
975 | 0 | { |
976 | 0 | const auto fnLoadForExt = [this, prefix, trygl](const SymLoadStruct* list, |
977 | 0 | GLExtensions ext) |
978 | 0 | { |
979 | 0 | return this->LoadExtSymbols(prefix, trygl, list, ext); |
980 | 0 | }; |
981 | 0 |
|
982 | 0 | const auto fnLoadForFeature = [this, prefix, trygl](const SymLoadStruct* list, |
983 | 0 | GLFeature feature) |
984 | 0 | { |
985 | 0 | return this->LoadFeatureSymbols(prefix, trygl, list, feature); |
986 | 0 | }; |
987 | 0 |
|
988 | 0 | const auto fnLoadFeatureByCore = [this, fnLoadForFeature](const SymLoadStruct* coreList, |
989 | 0 | const SymLoadStruct* extList, |
990 | 0 | GLFeature feature) |
991 | 0 | { |
992 | 0 | const bool useCore = this->IsFeatureProvidedByCoreSymbols(feature); |
993 | 0 | const auto list = useCore ? coreList : extList; |
994 | 0 | return fnLoadForFeature(list, feature); |
995 | 0 | }; |
996 | 0 |
|
997 | 0 | if (IsSupported(GLFeature::robustness)) { |
998 | 0 | const auto resetStrategy = GetIntAs<GLuint>(LOCAL_GL_RESET_NOTIFICATION_STRATEGY); |
999 | 0 | if (resetStrategy != LOCAL_GL_LOSE_CONTEXT_ON_RESET) { |
1000 | 0 | NS_WARNING("Robustness supported, strategy is not LOSE_CONTEXT_ON_RESET!"); |
1001 | 0 | if (ShouldSpew()) { |
1002 | 0 | const bool isDisabled = (resetStrategy == LOCAL_GL_NO_RESET_NOTIFICATION); |
1003 | 0 | printf_stderr("Strategy: %s (0x%04x)", |
1004 | 0 | (isDisabled ? "disabled" : "unrecognized"), |
1005 | 0 | resetStrategy); |
1006 | 0 | } |
1007 | 0 | MarkUnsupported(GLFeature::robustness); |
1008 | 0 | } |
1009 | 0 | } |
1010 | 0 | if (IsSupported(GLFeature::robustness)) { |
1011 | 0 | const SymLoadStruct symbols[] = { |
1012 | 0 | { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatus", |
1013 | 0 | "GetGraphicsResetStatusARB", |
1014 | 0 | "GetGraphicsResetStatusKHR", |
1015 | 0 | "GetGraphicsResetStatusEXT", |
1016 | 0 | nullptr } }, |
1017 | 0 | END_SYMBOLS |
1018 | 0 | }; |
1019 | 0 | if (fnLoadForFeature(symbols, GLFeature::robustness)) { |
1020 | 0 | const auto status = mSymbols.fGetGraphicsResetStatus(); |
1021 | 0 | MOZ_ALWAYS_TRUE(!status); |
1022 | 0 |
|
1023 | 0 | const auto err = mSymbols.fGetError(); |
1024 | 0 | MOZ_ALWAYS_TRUE(!err); |
1025 | 0 | } |
1026 | 0 | } |
1027 | 0 |
|
1028 | 0 | if (IsSupported(GLFeature::sync)) { |
1029 | 0 | const SymLoadStruct symbols[] = { |
1030 | 0 | { (PRFuncPtr*) &mSymbols.fFenceSync, { "FenceSync", nullptr } }, |
1031 | 0 | { (PRFuncPtr*) &mSymbols.fIsSync, { "IsSync", nullptr } }, |
1032 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteSync, { "DeleteSync", nullptr } }, |
1033 | 0 | { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "ClientWaitSync", nullptr } }, |
1034 | 0 | { (PRFuncPtr*) &mSymbols.fWaitSync, { "WaitSync", nullptr } }, |
1035 | 0 | { (PRFuncPtr*) &mSymbols.fGetInteger64v, { "GetInteger64v", nullptr } }, |
1036 | 0 | { (PRFuncPtr*) &mSymbols.fGetSynciv, { "GetSynciv", nullptr } }, |
1037 | 0 | END_SYMBOLS |
1038 | 0 | }; |
1039 | 0 | fnLoadForFeature(symbols, GLFeature::sync); |
1040 | 0 | } |
1041 | 0 |
|
1042 | 0 | if (IsExtensionSupported(OES_EGL_image)) { |
1043 | 0 | const SymLoadStruct symbols[] = { |
1044 | 0 | { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } }, |
1045 | 0 | { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } }, |
1046 | 0 | END_SYMBOLS |
1047 | 0 | }; |
1048 | 0 | fnLoadForExt(symbols, OES_EGL_image); |
1049 | 0 | } |
1050 | 0 |
|
1051 | 0 | if (IsExtensionSupported(APPLE_texture_range)) { |
1052 | 0 | const SymLoadStruct symbols[] = { |
1053 | 0 | { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } }, |
1054 | 0 | END_SYMBOLS |
1055 | 0 | }; |
1056 | 0 | fnLoadForExt(symbols, APPLE_texture_range); |
1057 | 0 | } |
1058 | 0 |
|
1059 | 0 | if (IsExtensionSupported(APPLE_fence)) { |
1060 | 0 | const SymLoadStruct symbols[] = { |
1061 | 0 | { (PRFuncPtr*) &mSymbols.fFinishObjectAPPLE, { "FinishObjectAPPLE", nullptr } }, |
1062 | 0 | { (PRFuncPtr*) &mSymbols.fTestObjectAPPLE, { "TestObjectAPPLE", nullptr } }, |
1063 | 0 | END_SYMBOLS |
1064 | 0 | }; |
1065 | 0 | fnLoadForExt(symbols, APPLE_fence); |
1066 | 0 | } |
1067 | 0 |
|
1068 | 0 | if (IsSupported(GLFeature::vertex_array_object)) { |
1069 | 0 | const SymLoadStruct coreSymbols[] = { |
1070 | 0 | { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArray", nullptr } }, |
1071 | 0 | { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArrays", nullptr } }, |
1072 | 0 | { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", nullptr } }, |
1073 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", nullptr } }, |
1074 | 0 | END_SYMBOLS |
1075 | 0 | }; |
1076 | 0 | const SymLoadStruct extSymbols[] = { |
1077 | 0 | { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArrayARB", "IsVertexArrayOES", "IsVertexArrayAPPLE", nullptr } }, |
1078 | 0 | { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArraysARB", "GenVertexArraysOES", "GenVertexArraysAPPLE", nullptr } }, |
1079 | 0 | { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArrayARB", "BindVertexArrayOES", "BindVertexArrayAPPLE", nullptr } }, |
1080 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArraysARB", "DeleteVertexArraysOES", "DeleteVertexArraysAPPLE", nullptr } }, |
1081 | 0 | END_SYMBOLS |
1082 | 0 | }; |
1083 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::vertex_array_object); |
1084 | 0 | } |
1085 | 0 |
|
1086 | 0 | if (IsSupported(GLFeature::draw_instanced)) { |
1087 | 0 | const SymLoadStruct coreSymbols[] = { |
1088 | 0 | { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstanced", nullptr } }, |
1089 | 0 | { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstanced", nullptr } }, |
1090 | 0 | END_SYMBOLS |
1091 | 0 | }; |
1092 | 0 | const SymLoadStruct extSymbols[] = { |
1093 | 0 | { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstancedARB", "DrawArraysInstancedEXT", "DrawArraysInstancedNV", "DrawArraysInstancedANGLE", nullptr } }, |
1094 | 0 | { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstancedARB", "DrawElementsInstancedEXT", "DrawElementsInstancedNV", "DrawElementsInstancedANGLE", nullptr } |
1095 | 0 | }, |
1096 | 0 | END_SYMBOLS |
1097 | 0 | }; |
1098 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_instanced); |
1099 | 0 | } |
1100 | 0 |
|
1101 | 0 | if (IsSupported(GLFeature::instanced_arrays)) { |
1102 | 0 | const SymLoadStruct coreSymbols[] = { |
1103 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisor", nullptr } }, |
1104 | 0 | END_SYMBOLS |
1105 | 0 | }; |
1106 | 0 | const SymLoadStruct extSymbols[] = { |
1107 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisorARB", "VertexAttribDivisorNV", "VertexAttribDivisorANGLE", nullptr } }, |
1108 | 0 | END_SYMBOLS |
1109 | 0 | }; |
1110 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::instanced_arrays); |
1111 | 0 | } |
1112 | 0 |
|
1113 | 0 | if (IsSupported(GLFeature::texture_storage)) { |
1114 | 0 | const SymLoadStruct coreSymbols[] = { |
1115 | 0 | { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2D", nullptr } }, |
1116 | 0 | { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3D", nullptr } }, |
1117 | 0 | END_SYMBOLS |
1118 | 0 | }; |
1119 | 0 | const SymLoadStruct extSymbols[] = { |
1120 | 0 | { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2DEXT", nullptr } }, |
1121 | 0 | { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3DEXT", nullptr } }, |
1122 | 0 | END_SYMBOLS |
1123 | 0 | }; |
1124 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_storage); |
1125 | 0 | } |
1126 | 0 |
|
1127 | 0 | if (IsSupported(GLFeature::sampler_objects)) { |
1128 | 0 | const SymLoadStruct symbols[] = { |
1129 | 0 | { (PRFuncPtr*) &mSymbols.fGenSamplers, { "GenSamplers", nullptr } }, |
1130 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteSamplers, { "DeleteSamplers", nullptr } }, |
1131 | 0 | { (PRFuncPtr*) &mSymbols.fIsSampler, { "IsSampler", nullptr } }, |
1132 | 0 | { (PRFuncPtr*) &mSymbols.fBindSampler, { "BindSampler", nullptr } }, |
1133 | 0 | { (PRFuncPtr*) &mSymbols.fSamplerParameteri, { "SamplerParameteri", nullptr } }, |
1134 | 0 | { (PRFuncPtr*) &mSymbols.fSamplerParameteriv, { "SamplerParameteriv", nullptr } }, |
1135 | 0 | { (PRFuncPtr*) &mSymbols.fSamplerParameterf, { "SamplerParameterf", nullptr } }, |
1136 | 0 | { (PRFuncPtr*) &mSymbols.fSamplerParameterfv, { "SamplerParameterfv", nullptr } }, |
1137 | 0 | { (PRFuncPtr*) &mSymbols.fGetSamplerParameteriv, { "GetSamplerParameteriv", nullptr } }, |
1138 | 0 | { (PRFuncPtr*) &mSymbols.fGetSamplerParameterfv, { "GetSamplerParameterfv", nullptr } }, |
1139 | 0 | END_SYMBOLS |
1140 | 0 | }; |
1141 | 0 | fnLoadForFeature(symbols, GLFeature::sampler_objects); |
1142 | 0 | } |
1143 | 0 |
|
1144 | 0 | // ARB_transform_feedback2/NV_transform_feedback2 is a |
1145 | 0 | // superset of EXT_transform_feedback/NV_transform_feedback |
1146 | 0 | // and adds glPauseTransformFeedback & |
1147 | 0 | // glResumeTransformFeedback, which are required for WebGL2. |
1148 | 0 | if (IsSupported(GLFeature::transform_feedback2)) { |
1149 | 0 | const SymLoadStruct coreSymbols[] = { |
1150 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBase", nullptr } }, |
1151 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRange", nullptr } }, |
1152 | 0 | { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacks", nullptr } }, |
1153 | 0 | { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedback", nullptr } }, |
1154 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacks", nullptr } }, |
1155 | 0 | { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedback", nullptr } }, |
1156 | 0 | { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedback", nullptr } }, |
1157 | 0 | { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedback", nullptr } }, |
1158 | 0 | { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryings", nullptr } }, |
1159 | 0 | { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVarying", nullptr } }, |
1160 | 0 | { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedback", nullptr } }, |
1161 | 0 | { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedback", nullptr } }, |
1162 | 0 | END_SYMBOLS |
1163 | 0 | }; |
1164 | 0 | const SymLoadStruct extSymbols[] = { |
1165 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBaseEXT", "BindBufferBaseNV", nullptr } }, |
1166 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRangeEXT", "BindBufferRangeNV", nullptr } }, |
1167 | 0 | { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacksNV", nullptr } }, |
1168 | 0 | { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedbackNV", nullptr } }, |
1169 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacksNV", nullptr } }, |
1170 | 0 | { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedbackNV", nullptr } }, |
1171 | 0 | { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedbackEXT", "BeginTransformFeedbackNV", nullptr } }, |
1172 | 0 | { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedbackEXT", "EndTransformFeedbackNV", nullptr } }, |
1173 | 0 | { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryingsEXT", "TransformFeedbackVaryingsNV", nullptr } }, |
1174 | 0 | { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVaryingEXT", "GetTransformFeedbackVaryingNV", nullptr } }, |
1175 | 0 | { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedbackNV", nullptr } }, |
1176 | 0 | { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedbackNV", nullptr } }, |
1177 | 0 | END_SYMBOLS |
1178 | 0 | }; |
1179 | 0 | if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_storage)) { |
1180 | 0 | // Also mark bind_buffer_offset as unsupported. |
1181 | 0 | MarkUnsupported(GLFeature::bind_buffer_offset); |
1182 | 0 | } |
1183 | 0 | } |
1184 | 0 |
|
1185 | 0 | if (IsSupported(GLFeature::bind_buffer_offset)) { |
1186 | 0 | const SymLoadStruct coreSymbols[] = { |
1187 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferOffset, { "BindBufferOffset", nullptr } }, |
1188 | 0 | END_SYMBOLS |
1189 | 0 | }; |
1190 | 0 | const SymLoadStruct extSymbols[] = { |
1191 | 0 | { (PRFuncPtr*) &mSymbols.fBindBufferOffset, |
1192 | 0 | { "BindBufferOffsetEXT", "BindBufferOffsetNV", nullptr } |
1193 | 0 | }, |
1194 | 0 | END_SYMBOLS |
1195 | 0 | }; |
1196 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::bind_buffer_offset); |
1197 | 0 | } |
1198 | 0 |
|
1199 | 0 | if (IsSupported(GLFeature::query_counter)) { |
1200 | 0 | const SymLoadStruct coreSymbols[] = { |
1201 | 0 | { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounter", nullptr } }, |
1202 | 0 | END_SYMBOLS |
1203 | 0 | }; |
1204 | 0 | const SymLoadStruct extSymbols[] = { |
1205 | 0 | { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounterEXT", "QueryCounterANGLE", nullptr } }, |
1206 | 0 | END_SYMBOLS |
1207 | 0 | }; |
1208 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_counter); |
1209 | 0 | } |
1210 | 0 |
|
1211 | 0 | if (IsSupported(GLFeature::query_objects)) { |
1212 | 0 | const SymLoadStruct coreSymbols[] = { |
1213 | 0 | { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", nullptr } }, |
1214 | 0 | { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueries", nullptr } }, |
1215 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueries", nullptr } }, |
1216 | 0 | { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQuery", nullptr } }, |
1217 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryiv", nullptr } }, |
1218 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuiv", nullptr } }, |
1219 | 0 | { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQuery", nullptr } }, |
1220 | 0 | END_SYMBOLS |
1221 | 0 | }; |
1222 | 0 | const SymLoadStruct extSymbols[] = { |
1223 | 0 | { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQueryEXT", "BeginQueryANGLE", nullptr } }, |
1224 | 0 | { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueriesEXT", "GenQueriesANGLE", nullptr } }, |
1225 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueriesEXT", "DeleteQueriesANGLE", nullptr } }, |
1226 | 0 | { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQueryEXT", "EndQueryANGLE", nullptr } }, |
1227 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryivEXT", "GetQueryivANGLE", nullptr } }, |
1228 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuivEXT", "GetQueryObjectuivANGLE", nullptr } }, |
1229 | 0 | { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQueryEXT", "IsQueryANGLE", nullptr } }, |
1230 | 0 | END_SYMBOLS |
1231 | 0 | }; |
1232 | 0 | if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_objects)) { |
1233 | 0 | MarkUnsupported(GLFeature::get_query_object_i64v); |
1234 | 0 | MarkUnsupported(GLFeature::get_query_object_iv); |
1235 | 0 | MarkUnsupported(GLFeature::occlusion_query); |
1236 | 0 | MarkUnsupported(GLFeature::occlusion_query_boolean); |
1237 | 0 | MarkUnsupported(GLFeature::occlusion_query2); |
1238 | 0 | } |
1239 | 0 | } |
1240 | 0 |
|
1241 | 0 | if (IsSupported(GLFeature::get_query_object_i64v)) { |
1242 | 0 | const SymLoadStruct coreSymbols[] = { |
1243 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64v", nullptr } }, |
1244 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64v", nullptr } }, |
1245 | 0 | END_SYMBOLS |
1246 | 0 | }; |
1247 | 0 | const SymLoadStruct extSymbols[] = { |
1248 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64vEXT", "GetQueryObjecti64vANGLE", nullptr } }, |
1249 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64vEXT", "GetQueryObjectui64vANGLE", nullptr } }, |
1250 | 0 | END_SYMBOLS |
1251 | 0 | }; |
1252 | 0 | if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_i64v)) { |
1253 | 0 | MarkUnsupported(GLFeature::query_counter); |
1254 | 0 | } |
1255 | 0 | } |
1256 | 0 |
|
1257 | 0 | if (IsSupported(GLFeature::get_query_object_iv)) { |
1258 | 0 | const SymLoadStruct coreSymbols[] = { |
1259 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", nullptr } }, |
1260 | 0 | END_SYMBOLS |
1261 | 0 | }; |
1262 | 0 | const SymLoadStruct extSymbols[] = { |
1263 | 0 | { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectivEXT", "GetQueryObjectivANGLE", nullptr } }, |
1264 | 0 | END_SYMBOLS |
1265 | 0 | }; |
1266 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_iv); |
1267 | 0 | } |
1268 | 0 |
|
1269 | 0 | if (IsSupported(GLFeature::clear_buffers)) { |
1270 | 0 | const SymLoadStruct symbols[] = { |
1271 | 0 | { (PRFuncPtr*) &mSymbols.fClearBufferfi, { "ClearBufferfi", nullptr } }, |
1272 | 0 | { (PRFuncPtr*) &mSymbols.fClearBufferfv, { "ClearBufferfv", nullptr } }, |
1273 | 0 | { (PRFuncPtr*) &mSymbols.fClearBufferiv, { "ClearBufferiv", nullptr } }, |
1274 | 0 | { (PRFuncPtr*) &mSymbols.fClearBufferuiv, { "ClearBufferuiv", nullptr } }, |
1275 | 0 | END_SYMBOLS |
1276 | 0 | }; |
1277 | 0 | fnLoadForFeature(symbols, GLFeature::clear_buffers); |
1278 | 0 | } |
1279 | 0 |
|
1280 | 0 | if (IsSupported(GLFeature::copy_buffer)) { |
1281 | 0 | const SymLoadStruct symbols[] = { |
1282 | 0 | { (PRFuncPtr*) &mSymbols.fCopyBufferSubData, { "CopyBufferSubData", nullptr } }, |
1283 | 0 | END_SYMBOLS |
1284 | 0 | }; |
1285 | 0 | fnLoadForFeature(symbols, GLFeature::copy_buffer); |
1286 | 0 | } |
1287 | 0 |
|
1288 | 0 | if (IsSupported(GLFeature::draw_buffers)) { |
1289 | 0 | const SymLoadStruct coreSymbols[] = { |
1290 | 0 | { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } }, |
1291 | 0 | END_SYMBOLS |
1292 | 0 | }; |
1293 | 0 | const SymLoadStruct extSymbols[] = { |
1294 | 0 | { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffersARB", "DrawBuffersEXT", nullptr } }, |
1295 | 0 | END_SYMBOLS |
1296 | 0 | }; |
1297 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_buffers); |
1298 | 0 | } |
1299 | 0 |
|
1300 | 0 | if (IsSupported(GLFeature::draw_range_elements)) { |
1301 | 0 | const SymLoadStruct coreSymbols[] = { |
1302 | 0 | { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElements", nullptr } }, |
1303 | 0 | END_SYMBOLS |
1304 | 0 | }; |
1305 | 0 | const SymLoadStruct extSymbols[] = { |
1306 | 0 | { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElementsEXT", nullptr } }, |
1307 | 0 | END_SYMBOLS |
1308 | 0 | }; |
1309 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_range_elements); |
1310 | 0 | } |
1311 | 0 |
|
1312 | 0 | if (IsSupported(GLFeature::get_integer_indexed)) { |
1313 | 0 | const SymLoadStruct coreSymbols[] = { |
1314 | 0 | { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegeri_v", nullptr } }, |
1315 | 0 | END_SYMBOLS |
1316 | 0 | }; |
1317 | 0 | const SymLoadStruct extSymbols[] ={ |
1318 | 0 | { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegerIndexedvEXT", nullptr } }, |
1319 | 0 | END_SYMBOLS |
1320 | 0 | }; |
1321 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_integer_indexed); |
1322 | 0 | } |
1323 | 0 |
|
1324 | 0 | if (IsSupported(GLFeature::get_integer64_indexed)) { |
1325 | 0 | const SymLoadStruct symbols[] = { |
1326 | 0 | { (PRFuncPtr*) &mSymbols.fGetInteger64i_v, { "GetInteger64i_v", nullptr } }, |
1327 | 0 | END_SYMBOLS |
1328 | 0 | }; |
1329 | 0 | fnLoadForFeature(symbols, GLFeature::get_integer64_indexed); |
1330 | 0 | } |
1331 | 0 |
|
1332 | 0 | if (IsSupported(GLFeature::gpu_shader4)) { |
1333 | 0 | const SymLoadStruct symbols[] = { |
1334 | 0 | { (PRFuncPtr*) &mSymbols.fGetVertexAttribIiv, { "GetVertexAttribIiv", "GetVertexAttribIivEXT", nullptr } }, |
1335 | 0 | { (PRFuncPtr*) &mSymbols.fGetVertexAttribIuiv, { "GetVertexAttribIuiv", "GetVertexAttribIuivEXT", nullptr } }, |
1336 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribI4i, { "VertexAttribI4i", "VertexAttribI4iEXT", nullptr } }, |
1337 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribI4iv, { "VertexAttribI4iv","VertexAttribI4ivEXT", nullptr } }, |
1338 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribI4ui, { "VertexAttribI4ui", "VertexAttribI4uiEXT", nullptr } }, |
1339 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribI4uiv, { "VertexAttribI4uiv", "VertexAttribI4uivEXT", nullptr } }, |
1340 | 0 | { (PRFuncPtr*) &mSymbols.fVertexAttribIPointer, { "VertexAttribIPointer", "VertexAttribIPointerEXT", nullptr } }, |
1341 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1ui, { "Uniform1ui", "Uniform1uiEXT", nullptr } }, |
1342 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2ui, { "Uniform2ui", "Uniform2uiEXT", nullptr } }, |
1343 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3ui, { "Uniform3ui", "Uniform3uiEXT", nullptr } }, |
1344 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4ui, { "Uniform4ui", "Uniform4uiEXT", nullptr } }, |
1345 | 0 | { (PRFuncPtr*) &mSymbols.fUniform1uiv, { "Uniform1uiv", "Uniform1uivEXT", nullptr } }, |
1346 | 0 | { (PRFuncPtr*) &mSymbols.fUniform2uiv, { "Uniform2uiv", "Uniform2uivEXT", nullptr } }, |
1347 | 0 | { (PRFuncPtr*) &mSymbols.fUniform3uiv, { "Uniform3uiv", "Uniform3uivEXT", nullptr } }, |
1348 | 0 | { (PRFuncPtr*) &mSymbols.fUniform4uiv, { "Uniform4uiv", "Uniform4uivEXT", nullptr } }, |
1349 | 0 | { (PRFuncPtr*) &mSymbols.fGetFragDataLocation, { "GetFragDataLocation", "GetFragDataLocationEXT", nullptr } }, |
1350 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformuiv, { "GetUniformuiv", "GetUniformuivEXT", nullptr } }, |
1351 | 0 | END_SYMBOLS |
1352 | 0 | }; |
1353 | 0 | fnLoadForFeature(symbols, GLFeature::gpu_shader4); |
1354 | 0 | } |
1355 | 0 |
|
1356 | 0 | if (IsSupported(GLFeature::map_buffer_range)) { |
1357 | 0 | const SymLoadStruct symbols[] = { |
1358 | 0 | { (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } }, |
1359 | 0 | { (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } }, |
1360 | 0 | { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } }, |
1361 | 0 | END_SYMBOLS |
1362 | 0 | }; |
1363 | 0 | fnLoadForFeature(symbols, GLFeature::map_buffer_range); |
1364 | 0 | } |
1365 | 0 |
|
1366 | 0 | if (IsSupported(GLFeature::texture_3D)) { |
1367 | 0 | const SymLoadStruct coreSymbols[] = { |
1368 | 0 | { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } }, |
1369 | 0 | { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } }, |
1370 | 0 | END_SYMBOLS |
1371 | 0 | }; |
1372 | 0 | const SymLoadStruct extSymbols[] = { |
1373 | 0 | { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3DEXT", "TexSubImage3DOES", nullptr } }, |
1374 | 0 | END_SYMBOLS |
1375 | 0 | }; |
1376 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D); |
1377 | 0 | } |
1378 | 0 |
|
1379 | 0 | if (IsSupported(GLFeature::texture_3D_compressed)) { |
1380 | 0 | const SymLoadStruct coreSymbols[] = { |
1381 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3D", nullptr } }, |
1382 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3D", nullptr } }, |
1383 | 0 | END_SYMBOLS |
1384 | 0 | }; |
1385 | 0 | const SymLoadStruct extSymbols[] = { |
1386 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3DARB", "CompressedTexImage3DOES", nullptr } }, |
1387 | 0 | { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3DARB", "CompressedTexSubImage3DOES", nullptr } }, |
1388 | 0 | END_SYMBOLS |
1389 | 0 | }; |
1390 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_compressed); |
1391 | 0 | } |
1392 | 0 |
|
1393 | 0 | if (IsSupported(GLFeature::texture_3D_copy)) { |
1394 | 0 | const SymLoadStruct coreSymbols[] = { |
1395 | 0 | { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3D", nullptr } }, |
1396 | 0 | END_SYMBOLS |
1397 | 0 | }; |
1398 | 0 | const SymLoadStruct extSymbols[] = { |
1399 | 0 | { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3DEXT", "CopyTexSubImage3DOES", nullptr } }, |
1400 | 0 | END_SYMBOLS |
1401 | 0 | }; |
1402 | 0 | fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_copy); |
1403 | 0 | } |
1404 | 0 |
|
1405 | 0 | if (IsSupported(GLFeature::uniform_buffer_object)) { |
1406 | 0 | // Note: Don't query for glGetActiveUniformName because it is not |
1407 | 0 | // supported by GL ES 3. |
1408 | 0 | const SymLoadStruct symbols[] = { |
1409 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformIndices, { "GetUniformIndices", nullptr } }, |
1410 | 0 | { (PRFuncPtr*) &mSymbols.fGetActiveUniformsiv, { "GetActiveUniformsiv", nullptr } }, |
1411 | 0 | { (PRFuncPtr*) &mSymbols.fGetUniformBlockIndex, { "GetUniformBlockIndex", nullptr } }, |
1412 | 0 | { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockiv, { "GetActiveUniformBlockiv", nullptr } }, |
1413 | 0 | { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockName, { "GetActiveUniformBlockName", nullptr } }, |
1414 | 0 | { (PRFuncPtr*) &mSymbols.fUniformBlockBinding, { "UniformBlockBinding", nullptr } }, |
1415 | 0 | END_SYMBOLS |
1416 | 0 | }; |
1417 | 0 | fnLoadForFeature(symbols, GLFeature::uniform_buffer_object); |
1418 | 0 | } |
1419 | 0 |
|
1420 | 0 | if (IsSupported(GLFeature::uniform_matrix_nonsquare)) { |
1421 | 0 | const SymLoadStruct symbols[] = { |
1422 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix2x3fv, { "UniformMatrix2x3fv", nullptr } }, |
1423 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix2x4fv, { "UniformMatrix2x4fv", nullptr } }, |
1424 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix3x2fv, { "UniformMatrix3x2fv", nullptr } }, |
1425 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix3x4fv, { "UniformMatrix3x4fv", nullptr } }, |
1426 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix4x2fv, { "UniformMatrix4x2fv", nullptr } }, |
1427 | 0 | { (PRFuncPtr*) &mSymbols.fUniformMatrix4x3fv, { "UniformMatrix4x3fv", nullptr } }, |
1428 | 0 | END_SYMBOLS |
1429 | 0 | }; |
1430 | 0 | fnLoadForFeature(symbols, GLFeature::uniform_matrix_nonsquare); |
1431 | 0 | } |
1432 | 0 |
|
1433 | 0 | if (IsSupported(GLFeature::internalformat_query)) { |
1434 | 0 | const SymLoadStruct symbols[] = { |
1435 | 0 | CORE_SYMBOL(GetInternalformativ), |
1436 | 0 | END_SYMBOLS |
1437 | 0 | }; |
1438 | 0 | fnLoadForFeature(symbols, GLFeature::internalformat_query); |
1439 | 0 | } |
1440 | 0 |
|
1441 | 0 | if (IsSupported(GLFeature::invalidate_framebuffer)) { |
1442 | 0 | const SymLoadStruct symbols[] = { |
1443 | 0 | { (PRFuncPtr*) &mSymbols.fInvalidateFramebuffer, { "InvalidateFramebuffer", nullptr } }, |
1444 | 0 | { (PRFuncPtr*) &mSymbols.fInvalidateSubFramebuffer, { "InvalidateSubFramebuffer", nullptr } }, |
1445 | 0 | END_SYMBOLS |
1446 | 0 | }; |
1447 | 0 | fnLoadForFeature(symbols, GLFeature::invalidate_framebuffer); |
1448 | 0 | } |
1449 | 0 |
|
1450 | 0 | if (IsSupported(GLFeature::prim_restart)) { |
1451 | 0 | const SymLoadStruct symbols[] = { |
1452 | 0 | { (PRFuncPtr*) &mSymbols.fPrimitiveRestartIndex, { "PrimitiveRestartIndex", "PrimitiveRestartIndexNV", nullptr } }, |
1453 | 0 | END_SYMBOLS |
1454 | 0 | }; |
1455 | 0 | fnLoadForFeature(symbols, GLFeature::prim_restart); |
1456 | 0 | } |
1457 | 0 |
|
1458 | 0 | if (IsExtensionSupported(KHR_debug)) { |
1459 | 0 | const SymLoadStruct symbols[] = { |
1460 | 0 | { (PRFuncPtr*) &mSymbols.fDebugMessageControl, { "DebugMessageControl", "DebugMessageControlKHR", nullptr } }, |
1461 | 0 | { (PRFuncPtr*) &mSymbols.fDebugMessageInsert, { "DebugMessageInsert", "DebugMessageInsertKHR", nullptr } }, |
1462 | 0 | { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } }, |
1463 | 0 | { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog, { "GetDebugMessageLog", "GetDebugMessageLogKHR", nullptr } }, |
1464 | 0 | { (PRFuncPtr*) &mSymbols.fGetPointerv, { "GetPointerv", "GetPointervKHR", nullptr } }, |
1465 | 0 | { (PRFuncPtr*) &mSymbols.fPushDebugGroup, { "PushDebugGroup", "PushDebugGroupKHR", nullptr } }, |
1466 | 0 | { (PRFuncPtr*) &mSymbols.fPopDebugGroup, { "PopDebugGroup", "PopDebugGroupKHR", nullptr } }, |
1467 | 0 | { (PRFuncPtr*) &mSymbols.fObjectLabel, { "ObjectLabel", "ObjectLabelKHR", nullptr } }, |
1468 | 0 | { (PRFuncPtr*) &mSymbols.fGetObjectLabel, { "GetObjectLabel", "GetObjectLabelKHR", nullptr } }, |
1469 | 0 | { (PRFuncPtr*) &mSymbols.fObjectPtrLabel, { "ObjectPtrLabel", "ObjectPtrLabelKHR", nullptr } }, |
1470 | 0 | { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel, { "GetObjectPtrLabel", "GetObjectPtrLabelKHR", nullptr } }, |
1471 | 0 | END_SYMBOLS |
1472 | 0 | }; |
1473 | 0 | fnLoadForExt(symbols, KHR_debug); |
1474 | 0 | } |
1475 | 0 |
|
1476 | 0 | if (IsExtensionSupported(NV_fence)) { |
1477 | 0 | const SymLoadStruct symbols[] = { |
1478 | 0 | { (PRFuncPtr*) &mSymbols.fGenFences, { "GenFencesNV", nullptr } }, |
1479 | 0 | { (PRFuncPtr*) &mSymbols.fDeleteFences, { "DeleteFencesNV", nullptr } }, |
1480 | 0 | { (PRFuncPtr*) &mSymbols.fSetFence, { "SetFenceNV", nullptr } }, |
1481 | 0 | { (PRFuncPtr*) &mSymbols.fTestFence, { "TestFenceNV", nullptr } }, |
1482 | 0 | { (PRFuncPtr*) &mSymbols.fFinishFence, { "FinishFenceNV", nullptr } }, |
1483 | 0 | { (PRFuncPtr*) &mSymbols.fIsFence, { "IsFenceNV", nullptr } }, |
1484 | 0 | { (PRFuncPtr*) &mSymbols.fGetFenceiv, { "GetFenceivNV", nullptr } }, |
1485 | 0 | END_SYMBOLS |
1486 | 0 | }; |
1487 | 0 | fnLoadForExt(symbols, NV_fence); |
1488 | 0 | } |
1489 | 0 |
|
1490 | 0 | if (IsExtensionSupported(NV_texture_barrier)) { |
1491 | 0 | const SymLoadStruct symbols[] = { |
1492 | 0 | { (PRFuncPtr*) &mSymbols.fTextureBarrier, { "TextureBarrierNV", nullptr } }, |
1493 | 0 | END_SYMBOLS |
1494 | 0 | }; |
1495 | 0 | fnLoadForExt(symbols, NV_texture_barrier); |
1496 | 0 | } |
1497 | 0 |
|
1498 | 0 | if (IsSupported(GLFeature::read_buffer)) { |
1499 | 0 | const SymLoadStruct symbols[] = { |
1500 | 0 | { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } }, |
1501 | 0 | END_SYMBOLS |
1502 | 0 | }; |
1503 | 0 | fnLoadForFeature(symbols, GLFeature::read_buffer); |
1504 | 0 | } |
1505 | 0 |
|
1506 | 0 | if (IsExtensionSupported(APPLE_framebuffer_multisample)) { |
1507 | 0 | const SymLoadStruct symbols[] = { |
1508 | 0 | { (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } }, |
1509 | 0 | END_SYMBOLS |
1510 | 0 | }; |
1511 | 0 | fnLoadForExt(symbols, APPLE_framebuffer_multisample); |
1512 | 0 | } |
1513 | 0 |
|
1514 | 0 | // Load developer symbols, don't fail if we can't find them. |
1515 | 0 | const SymLoadStruct devSymbols[] = { |
1516 | 0 | { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } }, |
1517 | 0 | { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } }, |
1518 | 0 | END_SYMBOLS |
1519 | 0 | }; |
1520 | 0 | const bool warnOnFailures = ShouldSpew(); |
1521 | 0 | LoadSymbols(devSymbols, trygl, prefix, warnOnFailures); |
1522 | 0 | } |
1523 | | |
1524 | | #undef CORE_SYMBOL |
1525 | | #undef CORE_EXT_SYMBOL2 |
1526 | | #undef EXT_SYMBOL2 |
1527 | | #undef EXT_SYMBOL3 |
1528 | | #undef END_SYMBOLS |
1529 | | |
1530 | | void |
1531 | | GLContext::DebugCallback(GLenum source, |
1532 | | GLenum type, |
1533 | | GLuint id, |
1534 | | GLenum severity, |
1535 | | GLsizei length, |
1536 | | const GLchar* message) |
1537 | 0 | { |
1538 | 0 | nsAutoCString sourceStr; |
1539 | 0 | switch (source) { |
1540 | 0 | case LOCAL_GL_DEBUG_SOURCE_API: |
1541 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_API"); |
1542 | 0 | break; |
1543 | 0 | case LOCAL_GL_DEBUG_SOURCE_WINDOW_SYSTEM: |
1544 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_WINDOW_SYSTEM"); |
1545 | 0 | break; |
1546 | 0 | case LOCAL_GL_DEBUG_SOURCE_SHADER_COMPILER: |
1547 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_SHADER_COMPILER"); |
1548 | 0 | break; |
1549 | 0 | case LOCAL_GL_DEBUG_SOURCE_THIRD_PARTY: |
1550 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_THIRD_PARTY"); |
1551 | 0 | break; |
1552 | 0 | case LOCAL_GL_DEBUG_SOURCE_APPLICATION: |
1553 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_APPLICATION"); |
1554 | 0 | break; |
1555 | 0 | case LOCAL_GL_DEBUG_SOURCE_OTHER: |
1556 | 0 | sourceStr = NS_LITERAL_CSTRING("SOURCE_OTHER"); |
1557 | 0 | break; |
1558 | 0 | default: |
1559 | 0 | sourceStr = nsPrintfCString("<source 0x%04x>", source); |
1560 | 0 | break; |
1561 | 0 | } |
1562 | 0 | |
1563 | 0 | nsAutoCString typeStr; |
1564 | 0 | switch (type) { |
1565 | 0 | case LOCAL_GL_DEBUG_TYPE_ERROR: |
1566 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_ERROR"); |
1567 | 0 | break; |
1568 | 0 | case LOCAL_GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: |
1569 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_DEPRECATED_BEHAVIOR"); |
1570 | 0 | break; |
1571 | 0 | case LOCAL_GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: |
1572 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_UNDEFINED_BEHAVIOR"); |
1573 | 0 | break; |
1574 | 0 | case LOCAL_GL_DEBUG_TYPE_PORTABILITY: |
1575 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_PORTABILITY"); |
1576 | 0 | break; |
1577 | 0 | case LOCAL_GL_DEBUG_TYPE_PERFORMANCE: |
1578 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_PERFORMANCE"); |
1579 | 0 | break; |
1580 | 0 | case LOCAL_GL_DEBUG_TYPE_OTHER: |
1581 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_OTHER"); |
1582 | 0 | break; |
1583 | 0 | case LOCAL_GL_DEBUG_TYPE_MARKER: |
1584 | 0 | typeStr = NS_LITERAL_CSTRING("TYPE_MARKER"); |
1585 | 0 | break; |
1586 | 0 | default: |
1587 | 0 | typeStr = nsPrintfCString("<type 0x%04x>", type); |
1588 | 0 | break; |
1589 | 0 | } |
1590 | 0 | |
1591 | 0 | nsAutoCString sevStr; |
1592 | 0 | switch (severity) { |
1593 | 0 | case LOCAL_GL_DEBUG_SEVERITY_HIGH: |
1594 | 0 | sevStr = NS_LITERAL_CSTRING("SEVERITY_HIGH"); |
1595 | 0 | break; |
1596 | 0 | case LOCAL_GL_DEBUG_SEVERITY_MEDIUM: |
1597 | 0 | sevStr = NS_LITERAL_CSTRING("SEVERITY_MEDIUM"); |
1598 | 0 | break; |
1599 | 0 | case LOCAL_GL_DEBUG_SEVERITY_LOW: |
1600 | 0 | sevStr = NS_LITERAL_CSTRING("SEVERITY_LOW"); |
1601 | 0 | break; |
1602 | 0 | case LOCAL_GL_DEBUG_SEVERITY_NOTIFICATION: |
1603 | 0 | sevStr = NS_LITERAL_CSTRING("SEVERITY_NOTIFICATION"); |
1604 | 0 | break; |
1605 | 0 | default: |
1606 | 0 | sevStr = nsPrintfCString("<severity 0x%04x>", severity); |
1607 | 0 | break; |
1608 | 0 | } |
1609 | 0 | |
1610 | 0 | printf_stderr("[KHR_debug: 0x%" PRIxPTR "] ID %u: %s, %s, %s:\n %s\n", |
1611 | 0 | (uintptr_t)this, |
1612 | 0 | id, |
1613 | 0 | sourceStr.BeginReading(), |
1614 | 0 | typeStr.BeginReading(), |
1615 | 0 | sevStr.BeginReading(), |
1616 | 0 | message); |
1617 | 0 | } |
1618 | | |
1619 | | void |
1620 | | GLContext::InitExtensions() |
1621 | 0 | { |
1622 | 0 | MOZ_ASSERT(IsCurrent()); |
1623 | 0 |
|
1624 | 0 | std::vector<nsCString> driverExtensionList; |
1625 | 0 |
|
1626 | 0 | [&]() { |
1627 | 0 | if (mSymbols.fGetStringi) { |
1628 | 0 | GLuint count = 0; |
1629 | 0 | if (GetPotentialInteger(LOCAL_GL_NUM_EXTENSIONS, (GLint*)&count)) { |
1630 | 0 | for (GLuint i = 0; i < count; i++) { |
1631 | 0 | // This is UTF-8. |
1632 | 0 | const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i); |
1633 | 0 |
|
1634 | 0 | // We CANNOT use nsDependentCString here, because the spec doesn't guarantee |
1635 | 0 | // that the pointers returned are different, only that their contents are. |
1636 | 0 | // On Flame, each of these index string queries returns the same address. |
1637 | 0 | driverExtensionList.push_back(nsCString(rawExt)); |
1638 | 0 | } |
1639 | 0 | return; |
1640 | 0 | } |
1641 | 0 | } |
1642 | 0 |
|
1643 | 0 | const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS); |
1644 | 0 | if (rawExts) { |
1645 | 0 | nsDependentCString exts(rawExts); |
1646 | 0 | SplitByChar(exts, ' ', &driverExtensionList); |
1647 | 0 | } |
1648 | 0 | }(); |
1649 | 0 | const auto err = fGetError(); |
1650 | 0 | MOZ_ALWAYS_TRUE(!err); |
1651 | 0 |
|
1652 | 0 | const bool shouldDumpExts = ShouldDumpExts(); |
1653 | 0 | if (shouldDumpExts) { |
1654 | 0 | printf_stderr("%i GL driver extensions: (*: recognized)\n", |
1655 | 0 | (uint32_t)driverExtensionList.size()); |
1656 | 0 | } |
1657 | 0 |
|
1658 | 0 | MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sExtensionNames, |
1659 | 0 | &mAvailableExtensions); |
1660 | 0 |
|
1661 | 0 | if (WorkAroundDriverBugs()) { |
1662 | 0 | if (Vendor() == GLVendor::Qualcomm) { |
1663 | 0 | // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. |
1664 | 0 | MarkExtensionSupported(OES_EGL_sync); |
1665 | 0 | } |
1666 | 0 |
|
1667 | 0 | if (Vendor() == GLVendor::ATI) { |
1668 | 0 | // ATI drivers say this extension exists, but we can't |
1669 | 0 | // actually find the EGLImageTargetRenderbufferStorageOES |
1670 | 0 | // extension function pointer in the drivers. |
1671 | 0 | MarkExtensionUnsupported(OES_EGL_image); |
1672 | 0 | } |
1673 | 0 |
|
1674 | 0 | if (Vendor() == GLVendor::Imagination && |
1675 | 0 | Renderer() == GLRenderer::SGX540) |
1676 | 0 | { |
1677 | 0 | // Bug 980048 |
1678 | 0 | MarkExtensionUnsupported(OES_EGL_sync); |
1679 | 0 | } |
1680 | 0 |
|
1681 | | #ifdef MOZ_WIDGET_ANDROID |
1682 | | if (Vendor() == GLVendor::Imagination && |
1683 | | Renderer() == GLRenderer::SGX544MP && |
1684 | | jni::GetAPIVersion() < 21) |
1685 | | { |
1686 | | // Bug 1026404 |
1687 | | MarkExtensionUnsupported(OES_EGL_image); |
1688 | | MarkExtensionUnsupported(OES_EGL_image_external); |
1689 | | } |
1690 | | #endif |
1691 | |
|
1692 | 0 | if (Vendor() == GLVendor::ARM && |
1693 | 0 | (Renderer() == GLRenderer::Mali400MP || |
1694 | 0 | Renderer() == GLRenderer::Mali450MP)) |
1695 | 0 | { |
1696 | 0 | // Bug 1264505 |
1697 | 0 | MarkExtensionUnsupported(OES_EGL_image_external); |
1698 | 0 | } |
1699 | 0 |
|
1700 | 0 | if (Renderer() == GLRenderer::AndroidEmulator) { |
1701 | 0 | // the Android emulator, which we use to run B2G reftests on, |
1702 | 0 | // doesn't expose the OES_rgb8_rgba8 extension, but it seems to |
1703 | 0 | // support it (tautologically, as it only runs on desktop GL). |
1704 | 0 | MarkExtensionSupported(OES_rgb8_rgba8); |
1705 | 0 | } |
1706 | 0 |
|
1707 | 0 | if (Vendor() == GLVendor::VMware && |
1708 | 0 | Renderer() == GLRenderer::GalliumLlvmpipe) |
1709 | 0 | { |
1710 | 0 | // The llvmpipe driver that is used on linux try servers appears to have |
1711 | 0 | // buggy support for s3tc/dxt1 compressed textures. |
1712 | 0 | // See Bug 975824. |
1713 | 0 | MarkExtensionUnsupported(EXT_texture_compression_s3tc); |
1714 | 0 | MarkExtensionUnsupported(EXT_texture_compression_dxt1); |
1715 | 0 | MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); |
1716 | 0 | MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); |
1717 | 0 | } |
1718 | 0 |
|
1719 | | #ifdef XP_MACOSX |
1720 | | // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD |
1721 | | // 3000 appears to be buggy WRT updating sub-images of S3TC |
1722 | | // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 |
1723 | | // and Intel HD 5000/Iris that I tested. |
1724 | | // Bug 1124996: Appears to be the same on OSX Yosemite (10.10) |
1725 | | if (nsCocoaFeatures::OSXVersionMajor() == 10 && |
1726 | | nsCocoaFeatures::OSXVersionMinor() >= 9 && |
1727 | | Renderer() == GLRenderer::IntelHD3000) |
1728 | | { |
1729 | | MarkExtensionUnsupported(EXT_texture_compression_s3tc); |
1730 | | } |
1731 | | |
1732 | | // OSX supports EXT_texture_sRGB in Legacy contexts, but not in Core contexts. |
1733 | | // Though EXT_texture_sRGB was included into GL2.1, it *excludes* the interactions |
1734 | | // with s3tc. Strictly speaking, you must advertize support for EXT_texture_sRGB |
1735 | | // in order to allow for srgb+s3tc on desktop GL. The omission of EXT_texture_sRGB |
1736 | | // in OSX Core contexts appears to be a bug. |
1737 | | MarkExtensionSupported(EXT_texture_sRGB); |
1738 | | #endif |
1739 | | } |
1740 | 0 |
|
1741 | 0 | if (shouldDumpExts) { |
1742 | 0 | printf_stderr("\nActivated extensions:\n"); |
1743 | 0 |
|
1744 | 0 | for (size_t i = 0; i < mAvailableExtensions.size(); i++) { |
1745 | 0 | if (!mAvailableExtensions[i]) |
1746 | 0 | continue; |
1747 | 0 | |
1748 | 0 | const char* ext = sExtensionNames[i]; |
1749 | 0 | printf_stderr("[%i] %s\n", (uint32_t)i, ext); |
1750 | 0 | } |
1751 | 0 | } |
1752 | 0 | } |
1753 | | |
1754 | | void |
1755 | | GLContext::PlatformStartup() |
1756 | 0 | { |
1757 | 0 | RegisterStrongMemoryReporter(new GfxTexturesReporter()); |
1758 | 0 | } |
1759 | | |
1760 | | // Common code for checking for both GL extensions and GLX extensions. |
1761 | | bool |
1762 | | GLContext::ListHasExtension(const GLubyte* extensions, const char* extension) |
1763 | 0 | { |
1764 | 0 | // fix bug 612572 - we were crashing as we were calling this function with extensions==null |
1765 | 0 | if (extensions == nullptr || extension == nullptr) |
1766 | 0 | return false; |
1767 | 0 | |
1768 | 0 | const GLubyte* start; |
1769 | 0 | GLubyte* where; |
1770 | 0 | GLubyte* terminator; |
1771 | 0 |
|
1772 | 0 | /* Extension names should not have spaces. */ |
1773 | 0 | where = (GLubyte*) strchr(extension, ' '); |
1774 | 0 | if (where || *extension == '\0') |
1775 | 0 | return false; |
1776 | 0 | |
1777 | 0 | /* |
1778 | 0 | * It takes a bit of care to be fool-proof about parsing the |
1779 | 0 | * OpenGL extensions string. Don't be fooled by sub-strings, |
1780 | 0 | * etc. |
1781 | 0 | */ |
1782 | 0 | start = extensions; |
1783 | 0 | for (;;) { |
1784 | 0 | where = (GLubyte*) strstr((const char*) start, extension); |
1785 | 0 | if (!where) { |
1786 | 0 | break; |
1787 | 0 | } |
1788 | 0 | terminator = where + strlen(extension); |
1789 | 0 | if (where == start || *(where - 1) == ' ') { |
1790 | 0 | if (*terminator == ' ' || *terminator == '\0') { |
1791 | 0 | return true; |
1792 | 0 | } |
1793 | 0 | } |
1794 | 0 | start = terminator; |
1795 | 0 | } |
1796 | 0 | return false; |
1797 | 0 | } |
1798 | | |
1799 | | GLFormats |
1800 | | GLContext::ChooseGLFormats(const SurfaceCaps& caps) const |
1801 | 0 | { |
1802 | 0 | GLFormats formats; |
1803 | 0 |
|
1804 | 0 | // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less |
1805 | 0 | // OR we don't support full 8-bit color, return a 4444 or 565 format. |
1806 | 0 | bool bpp16 = caps.bpp16; |
1807 | 0 | if (IsGLES()) { |
1808 | 0 | if (!IsExtensionSupported(OES_rgb8_rgba8)) |
1809 | 0 | bpp16 = true; |
1810 | 0 | } else { |
1811 | 0 | // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility. |
1812 | 0 | // Since it's also vanishingly useless there, let's not support it. |
1813 | 0 | bpp16 = false; |
1814 | 0 | } |
1815 | 0 |
|
1816 | 0 | if (bpp16) { |
1817 | 0 | MOZ_ASSERT(IsGLES()); |
1818 | 0 | if (caps.alpha) { |
1819 | 0 | formats.color_texInternalFormat = LOCAL_GL_RGBA; |
1820 | 0 | formats.color_texFormat = LOCAL_GL_RGBA; |
1821 | 0 | formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4; |
1822 | 0 | formats.color_rbFormat = LOCAL_GL_RGBA4; |
1823 | 0 | } else { |
1824 | 0 | formats.color_texInternalFormat = LOCAL_GL_RGB; |
1825 | 0 | formats.color_texFormat = LOCAL_GL_RGB; |
1826 | 0 | formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_5_6_5; |
1827 | 0 | formats.color_rbFormat = LOCAL_GL_RGB565; |
1828 | 0 | } |
1829 | 0 | } else { |
1830 | 0 | formats.color_texType = LOCAL_GL_UNSIGNED_BYTE; |
1831 | 0 |
|
1832 | 0 | if (caps.alpha) { |
1833 | 0 | formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8; |
1834 | 0 | formats.color_texFormat = LOCAL_GL_RGBA; |
1835 | 0 | formats.color_rbFormat = LOCAL_GL_RGBA8; |
1836 | 0 | } else { |
1837 | 0 | formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8; |
1838 | 0 | formats.color_texFormat = LOCAL_GL_RGB; |
1839 | 0 | formats.color_rbFormat = LOCAL_GL_RGB8; |
1840 | 0 | } |
1841 | 0 | } |
1842 | 0 |
|
1843 | 0 | uint32_t msaaLevel = gfxPrefs::MSAALevel(); |
1844 | 0 | GLsizei samples = msaaLevel * msaaLevel; |
1845 | 0 | samples = std::min(samples, mMaxSamples); |
1846 | 0 |
|
1847 | 0 | // Bug 778765. |
1848 | 0 | if (WorkAroundDriverBugs() && samples == 1) { |
1849 | 0 | samples = 0; |
1850 | 0 | } |
1851 | 0 | formats.samples = samples; |
1852 | 0 |
|
1853 | 0 |
|
1854 | 0 | // Be clear that these are 0 if unavailable. |
1855 | 0 | formats.depthStencil = 0; |
1856 | 0 | if (IsSupported(GLFeature::packed_depth_stencil)) { |
1857 | 0 | formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8; |
1858 | 0 | } |
1859 | 0 |
|
1860 | 0 | formats.depth = 0; |
1861 | 0 | if (IsGLES()) { |
1862 | 0 | if (IsExtensionSupported(OES_depth24)) { |
1863 | 0 | formats.depth = LOCAL_GL_DEPTH_COMPONENT24; |
1864 | 0 | } else { |
1865 | 0 | formats.depth = LOCAL_GL_DEPTH_COMPONENT16; |
1866 | 0 | } |
1867 | 0 | } else { |
1868 | 0 | formats.depth = LOCAL_GL_DEPTH_COMPONENT24; |
1869 | 0 | } |
1870 | 0 |
|
1871 | 0 | formats.stencil = LOCAL_GL_STENCIL_INDEX8; |
1872 | 0 |
|
1873 | 0 | return formats; |
1874 | 0 | } |
1875 | | |
1876 | | bool |
1877 | | GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) |
1878 | 0 | { |
1879 | 0 | MOZ_ASSERT(fb); |
1880 | 0 |
|
1881 | 0 | ScopedBindFramebuffer autoFB(this, fb); |
1882 | 0 | MOZ_ASSERT(fIsFramebuffer(fb)); |
1883 | 0 |
|
1884 | 0 | GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); |
1885 | 0 | if (pStatus) |
1886 | 0 | *pStatus = status; |
1887 | 0 |
|
1888 | 0 | return status == LOCAL_GL_FRAMEBUFFER_COMPLETE; |
1889 | 0 | } |
1890 | | |
1891 | | void |
1892 | | GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB, |
1893 | | GLuint depthRB, GLuint stencilRB, |
1894 | | GLuint fb, GLenum target) |
1895 | 0 | { |
1896 | 0 | MOZ_ASSERT(fb); |
1897 | 0 | MOZ_ASSERT( !(colorTex && colorRB) ); |
1898 | 0 |
|
1899 | 0 | ScopedBindFramebuffer autoFB(this, fb); |
1900 | 0 | MOZ_ASSERT(fIsFramebuffer(fb)); // It only counts after being bound. |
1901 | 0 |
|
1902 | 0 | if (colorTex) { |
1903 | 0 | MOZ_ASSERT(fIsTexture(colorTex)); |
1904 | 0 | MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || |
1905 | 0 | target == LOCAL_GL_TEXTURE_RECTANGLE_ARB); |
1906 | 0 | fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, |
1907 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
1908 | 0 | target, |
1909 | 0 | colorTex, |
1910 | 0 | 0); |
1911 | 0 | } else if (colorRB) { |
1912 | 0 | // On the Android 4.3 emulator, IsRenderbuffer may return false incorrectly. |
1913 | 0 | MOZ_ASSERT_IF(Renderer() != GLRenderer::AndroidEmulator, fIsRenderbuffer(colorRB)); |
1914 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1915 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
1916 | 0 | LOCAL_GL_RENDERBUFFER, |
1917 | 0 | colorRB); |
1918 | 0 | } |
1919 | 0 |
|
1920 | 0 | if (depthRB) { |
1921 | 0 | MOZ_ASSERT_IF(Renderer() != GLRenderer::AndroidEmulator, fIsRenderbuffer(depthRB)); |
1922 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1923 | 0 | LOCAL_GL_DEPTH_ATTACHMENT, |
1924 | 0 | LOCAL_GL_RENDERBUFFER, |
1925 | 0 | depthRB); |
1926 | 0 | } |
1927 | 0 |
|
1928 | 0 | if (stencilRB) { |
1929 | 0 | MOZ_ASSERT_IF(Renderer() != GLRenderer::AndroidEmulator, fIsRenderbuffer(stencilRB)); |
1930 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1931 | 0 | LOCAL_GL_STENCIL_ATTACHMENT, |
1932 | 0 | LOCAL_GL_RENDERBUFFER, |
1933 | 0 | stencilRB); |
1934 | 0 | } |
1935 | 0 | } |
1936 | | |
1937 | | bool |
1938 | | GLContext::AssembleOffscreenFBs(const GLuint colorMSRB, |
1939 | | const GLuint depthRB, |
1940 | | const GLuint stencilRB, |
1941 | | const GLuint texture, |
1942 | | GLuint* drawFB_out, |
1943 | | GLuint* readFB_out) |
1944 | 0 | { |
1945 | 0 | if (!colorMSRB && !texture) { |
1946 | 0 | MOZ_ASSERT(!depthRB && !stencilRB); |
1947 | 0 |
|
1948 | 0 | if (drawFB_out) |
1949 | 0 | *drawFB_out = 0; |
1950 | 0 | if (readFB_out) |
1951 | 0 | *readFB_out = 0; |
1952 | 0 |
|
1953 | 0 | return true; |
1954 | 0 | } |
1955 | 0 |
|
1956 | 0 | ScopedBindFramebuffer autoFB(this); |
1957 | 0 |
|
1958 | 0 | GLuint drawFB = 0; |
1959 | 0 | GLuint readFB = 0; |
1960 | 0 |
|
1961 | 0 | if (texture) { |
1962 | 0 | readFB = 0; |
1963 | 0 | fGenFramebuffers(1, &readFB); |
1964 | 0 | BindFB(readFB); |
1965 | 0 | fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, |
1966 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
1967 | 0 | LOCAL_GL_TEXTURE_2D, |
1968 | 0 | texture, |
1969 | 0 | 0); |
1970 | 0 | } |
1971 | 0 |
|
1972 | 0 | if (colorMSRB) { |
1973 | 0 | drawFB = 0; |
1974 | 0 | fGenFramebuffers(1, &drawFB); |
1975 | 0 | BindFB(drawFB); |
1976 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1977 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
1978 | 0 | LOCAL_GL_RENDERBUFFER, |
1979 | 0 | colorMSRB); |
1980 | 0 | } else { |
1981 | 0 | drawFB = readFB; |
1982 | 0 | } |
1983 | 0 | MOZ_ASSERT(GetFB() == drawFB); |
1984 | 0 |
|
1985 | 0 | if (depthRB) { |
1986 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1987 | 0 | LOCAL_GL_DEPTH_ATTACHMENT, |
1988 | 0 | LOCAL_GL_RENDERBUFFER, |
1989 | 0 | depthRB); |
1990 | 0 | } |
1991 | 0 |
|
1992 | 0 | if (stencilRB) { |
1993 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, |
1994 | 0 | LOCAL_GL_STENCIL_ATTACHMENT, |
1995 | 0 | LOCAL_GL_RENDERBUFFER, |
1996 | 0 | stencilRB); |
1997 | 0 | } |
1998 | 0 |
|
1999 | 0 | // We should be all resized. Check for framebuffer completeness. |
2000 | 0 | GLenum status; |
2001 | 0 | bool isComplete = true; |
2002 | 0 |
|
2003 | 0 | if (!IsFramebufferComplete(drawFB, &status)) { |
2004 | 0 | NS_WARNING("DrawFBO: Incomplete"); |
2005 | | #ifdef MOZ_GL_DEBUG |
2006 | | if (ShouldSpew()) { |
2007 | | printf_stderr("Framebuffer status: %X\n", status); |
2008 | | } |
2009 | | #endif |
2010 | | isComplete = false; |
2011 | 0 | } |
2012 | 0 |
|
2013 | 0 | if (!IsFramebufferComplete(readFB, &status)) { |
2014 | 0 | NS_WARNING("ReadFBO: Incomplete"); |
2015 | | #ifdef MOZ_GL_DEBUG |
2016 | | if (ShouldSpew()) { |
2017 | | printf_stderr("Framebuffer status: %X\n", status); |
2018 | | } |
2019 | | #endif |
2020 | | isComplete = false; |
2021 | 0 | } |
2022 | 0 |
|
2023 | 0 | if (drawFB_out) { |
2024 | 0 | *drawFB_out = drawFB; |
2025 | 0 | } else if (drawFB) { |
2026 | 0 | MOZ_CRASH("drawFB created when not requested!"); |
2027 | 0 | } |
2028 | 0 |
|
2029 | 0 | if (readFB_out) { |
2030 | 0 | *readFB_out = readFB; |
2031 | 0 | } else if (readFB) { |
2032 | 0 | MOZ_CRASH("readFB created when not requested!"); |
2033 | 0 | } |
2034 | 0 |
|
2035 | 0 | return isComplete; |
2036 | 0 | } |
2037 | | |
2038 | | void |
2039 | | GLContext::MarkDestroyed() |
2040 | 0 | { |
2041 | 0 | if (IsDestroyed()) |
2042 | 0 | return; |
2043 | 0 | |
2044 | 0 | // Null these before they're naturally nulled after dtor, as we want GLContext to |
2045 | 0 | // still be alive in *their* dtors. |
2046 | 0 | mScreen = nullptr; |
2047 | 0 | mBlitHelper = nullptr; |
2048 | 0 | mReadTexImageHelper = nullptr; |
2049 | 0 |
|
2050 | 0 | if (!MakeCurrent()) { |
2051 | 0 | NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown."); |
2052 | 0 | } |
2053 | 0 |
|
2054 | 0 | mSymbols = {}; |
2055 | 0 | } |
2056 | | |
2057 | | #ifdef MOZ_GL_DEBUG |
2058 | | /* static */ void |
2059 | | GLContext::AssertNotPassingStackBufferToTheGL(const void* ptr) |
2060 | | { |
2061 | | int somethingOnTheStack; |
2062 | | const void* someStackPtr = &somethingOnTheStack; |
2063 | | const int page_bits = 12; |
2064 | | intptr_t page = reinterpret_cast<uintptr_t>(ptr) >> page_bits; |
2065 | | intptr_t someStackPage = reinterpret_cast<uintptr_t>(someStackPtr) >> page_bits; |
2066 | | uintptr_t pageDistance = std::abs(page - someStackPage); |
2067 | | |
2068 | | // Explanation for the "distance <= 1" check here as opposed to just |
2069 | | // an equality check. |
2070 | | // |
2071 | | // Here we assume that pages immediately adjacent to the someStackAddress page, |
2072 | | // are also stack pages. That allows to catch the case where the calling frame put |
2073 | | // a buffer on the stack, and we just crossed the page boundary. That is likely |
2074 | | // to happen, precisely, when using stack arrays. I hit that specifically |
2075 | | // with CompositorOGL::Initialize. |
2076 | | // |
2077 | | // In theory we could be unlucky and wrongly assert here. If that happens, |
2078 | | // it will only affect debug builds, and looking at stacks we'll be able to |
2079 | | // see that this assert is wrong and revert to the conservative and safe |
2080 | | // approach of only asserting when address and someStackAddress are |
2081 | | // on the same page. |
2082 | | bool isStackAddress = pageDistance <= 1; |
2083 | | MOZ_ASSERT(!isStackAddress, |
2084 | | "Please don't pass stack arrays to the GL. " |
2085 | | "Consider using HeapCopyOfStackArray. " |
2086 | | "See bug 1005658."); |
2087 | | } |
2088 | | |
2089 | | void |
2090 | | GLContext::CreatedProgram(GLContext* aOrigin, GLuint aName) |
2091 | | { |
2092 | | mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName)); |
2093 | | } |
2094 | | |
2095 | | void |
2096 | | GLContext::CreatedShader(GLContext* aOrigin, GLuint aName) |
2097 | | { |
2098 | | mTrackedShaders.AppendElement(NamedResource(aOrigin, aName)); |
2099 | | } |
2100 | | |
2101 | | void |
2102 | | GLContext::CreatedBuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames) |
2103 | | { |
2104 | | for (GLsizei i = 0; i < aCount; ++i) { |
2105 | | mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i])); |
2106 | | } |
2107 | | } |
2108 | | |
2109 | | void |
2110 | | GLContext::CreatedQueries(GLContext* aOrigin, GLsizei aCount, GLuint* aNames) |
2111 | | { |
2112 | | for (GLsizei i = 0; i < aCount; ++i) { |
2113 | | mTrackedQueries.AppendElement(NamedResource(aOrigin, aNames[i])); |
2114 | | } |
2115 | | } |
2116 | | |
2117 | | void |
2118 | | GLContext::CreatedTextures(GLContext* aOrigin, GLsizei aCount, GLuint* aNames) |
2119 | | { |
2120 | | for (GLsizei i = 0; i < aCount; ++i) { |
2121 | | mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i])); |
2122 | | } |
2123 | | } |
2124 | | |
2125 | | void |
2126 | | GLContext::CreatedFramebuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames) |
2127 | | { |
2128 | | for (GLsizei i = 0; i < aCount; ++i) { |
2129 | | mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i])); |
2130 | | } |
2131 | | } |
2132 | | |
2133 | | void |
2134 | | GLContext::CreatedRenderbuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames) |
2135 | | { |
2136 | | for (GLsizei i = 0; i < aCount; ++i) { |
2137 | | mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i])); |
2138 | | } |
2139 | | } |
2140 | | |
2141 | | static void |
2142 | | RemoveNamesFromArray(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames, nsTArray<GLContext::NamedResource>& aArray) |
2143 | | { |
2144 | | for (GLsizei j = 0; j < aCount; ++j) { |
2145 | | GLuint name = aNames[j]; |
2146 | | // name 0 can be ignored |
2147 | | if (name == 0) |
2148 | | continue; |
2149 | | |
2150 | | for (uint32_t i = 0; i < aArray.Length(); ++i) { |
2151 | | if (aArray[i].name == name) { |
2152 | | aArray.RemoveElementAt(i); |
2153 | | break; |
2154 | | } |
2155 | | } |
2156 | | } |
2157 | | } |
2158 | | |
2159 | | void |
2160 | | GLContext::DeletedProgram(GLContext* aOrigin, GLuint aName) |
2161 | | { |
2162 | | RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms); |
2163 | | } |
2164 | | |
2165 | | void |
2166 | | GLContext::DeletedShader(GLContext* aOrigin, GLuint aName) |
2167 | | { |
2168 | | RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders); |
2169 | | } |
2170 | | |
2171 | | void |
2172 | | GLContext::DeletedBuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames) |
2173 | | { |
2174 | | RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers); |
2175 | | } |
2176 | | |
2177 | | void |
2178 | | GLContext::DeletedQueries(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames) |
2179 | | { |
2180 | | RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedQueries); |
2181 | | } |
2182 | | |
2183 | | void |
2184 | | GLContext::DeletedTextures(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames) |
2185 | | { |
2186 | | RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures); |
2187 | | } |
2188 | | |
2189 | | void |
2190 | | GLContext::DeletedFramebuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames) |
2191 | | { |
2192 | | RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers); |
2193 | | } |
2194 | | |
2195 | | void |
2196 | | GLContext::DeletedRenderbuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames) |
2197 | | { |
2198 | | RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers); |
2199 | | } |
2200 | | |
2201 | | static void |
2202 | | MarkContextDestroyedInArray(GLContext* aContext, nsTArray<GLContext::NamedResource>& aArray) |
2203 | | { |
2204 | | for (uint32_t i = 0; i < aArray.Length(); ++i) { |
2205 | | if (aArray[i].origin == aContext) |
2206 | | aArray[i].originDeleted = true; |
2207 | | } |
2208 | | } |
2209 | | |
2210 | | void |
2211 | | GLContext::SharedContextDestroyed(GLContext* aChild) |
2212 | | { |
2213 | | MarkContextDestroyedInArray(aChild, mTrackedPrograms); |
2214 | | MarkContextDestroyedInArray(aChild, mTrackedShaders); |
2215 | | MarkContextDestroyedInArray(aChild, mTrackedTextures); |
2216 | | MarkContextDestroyedInArray(aChild, mTrackedFramebuffers); |
2217 | | MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers); |
2218 | | MarkContextDestroyedInArray(aChild, mTrackedBuffers); |
2219 | | MarkContextDestroyedInArray(aChild, mTrackedQueries); |
2220 | | } |
2221 | | |
2222 | | static void |
2223 | | ReportArrayContents(const char* title, const nsTArray<GLContext::NamedResource>& aArray) |
2224 | | { |
2225 | | if (aArray.Length() == 0) |
2226 | | return; |
2227 | | |
2228 | | printf_stderr("%s:\n", title); |
2229 | | |
2230 | | nsTArray<GLContext::NamedResource> copy(aArray); |
2231 | | copy.Sort(); |
2232 | | |
2233 | | GLContext* lastContext = nullptr; |
2234 | | for (uint32_t i = 0; i < copy.Length(); ++i) { |
2235 | | if (lastContext != copy[i].origin) { |
2236 | | if (lastContext) |
2237 | | printf_stderr("\n"); |
2238 | | printf_stderr(" [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live"); |
2239 | | lastContext = copy[i].origin; |
2240 | | } |
2241 | | printf_stderr("%d ", copy[i].name); |
2242 | | } |
2243 | | printf_stderr("\n"); |
2244 | | } |
2245 | | |
2246 | | void |
2247 | | GLContext::ReportOutstandingNames() |
2248 | | { |
2249 | | if (!ShouldSpew()) |
2250 | | return; |
2251 | | |
2252 | | printf_stderr("== GLContext %p Outstanding ==\n", this); |
2253 | | |
2254 | | ReportArrayContents("Outstanding Textures", mTrackedTextures); |
2255 | | ReportArrayContents("Outstanding Buffers", mTrackedBuffers); |
2256 | | ReportArrayContents("Outstanding Queries", mTrackedQueries); |
2257 | | ReportArrayContents("Outstanding Programs", mTrackedPrograms); |
2258 | | ReportArrayContents("Outstanding Shaders", mTrackedShaders); |
2259 | | ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers); |
2260 | | ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers); |
2261 | | } |
2262 | | |
2263 | | #endif /* DEBUG */ |
2264 | | |
2265 | | void |
2266 | | GLContext::GuaranteeResolve() |
2267 | 0 | { |
2268 | 0 | if (mScreen) { |
2269 | 0 | mScreen->AssureBlitted(); |
2270 | 0 | } |
2271 | 0 | fFinish(); |
2272 | 0 | } |
2273 | | |
2274 | | const gfx::IntSize& |
2275 | | GLContext::OffscreenSize() const |
2276 | 0 | { |
2277 | 0 | MOZ_ASSERT(IsOffscreen()); |
2278 | 0 | return mScreen->Size(); |
2279 | 0 | } |
2280 | | |
2281 | | bool |
2282 | | GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps) |
2283 | 0 | { |
2284 | 0 | UniquePtr<GLScreenBuffer> newScreen = GLScreenBuffer::Create(this, size, caps); |
2285 | 0 | if (!newScreen) |
2286 | 0 | return false; |
2287 | 0 | |
2288 | 0 | if (!newScreen->Resize(size)) { |
2289 | 0 | return false; |
2290 | 0 | } |
2291 | 0 | |
2292 | 0 | // This will rebind to 0 (Screen) if needed when |
2293 | 0 | // it falls out of scope. |
2294 | 0 | ScopedBindFramebuffer autoFB(this); |
2295 | 0 |
|
2296 | 0 | mScreen = std::move(newScreen); |
2297 | 0 |
|
2298 | 0 | return true; |
2299 | 0 | } |
2300 | | |
2301 | | bool |
2302 | | GLContext::ResizeScreenBuffer(const IntSize& size) |
2303 | 0 | { |
2304 | 0 | if (!IsOffscreenSizeAllowed(size)) |
2305 | 0 | return false; |
2306 | 0 | |
2307 | 0 | return mScreen->Resize(size); |
2308 | 0 | } |
2309 | | |
2310 | | void |
2311 | | GLContext::ForceDirtyScreen() |
2312 | 0 | { |
2313 | 0 | ScopedBindFramebuffer autoFB(0); |
2314 | 0 |
|
2315 | 0 | BeforeGLDrawCall(); |
2316 | 0 | // no-op; just pretend we did something |
2317 | 0 | AfterGLDrawCall(); |
2318 | 0 | } |
2319 | | |
2320 | | void |
2321 | | GLContext::CleanDirtyScreen() |
2322 | 0 | { |
2323 | 0 | ScopedBindFramebuffer autoFB(0); |
2324 | 0 |
|
2325 | 0 | BeforeGLReadCall(); |
2326 | 0 | // no-op; we just want to make sure the Read FBO is updated if it needs to be |
2327 | 0 | AfterGLReadCall(); |
2328 | 0 | } |
2329 | | |
2330 | | bool |
2331 | | GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const |
2332 | 0 | { |
2333 | 0 | int32_t biggerDimension = std::max(aSize.width, aSize.height); |
2334 | 0 | int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize); |
2335 | 0 | return biggerDimension <= maxAllowed; |
2336 | 0 | } |
2337 | | |
2338 | | bool |
2339 | | GLContext::IsOwningThreadCurrent() |
2340 | 0 | { |
2341 | 0 | return PlatformThread::CurrentId() == mOwningThreadId; |
2342 | 0 | } |
2343 | | |
2344 | | GLBlitHelper* |
2345 | | GLContext::BlitHelper() |
2346 | 0 | { |
2347 | 0 | if (!mBlitHelper) { |
2348 | 0 | mBlitHelper.reset(new GLBlitHelper(this)); |
2349 | 0 | } |
2350 | 0 |
|
2351 | 0 | return mBlitHelper.get(); |
2352 | 0 | } |
2353 | | |
2354 | | GLReadTexImageHelper* |
2355 | | GLContext::ReadTexImageHelper() |
2356 | 0 | { |
2357 | 0 | if (!mReadTexImageHelper) { |
2358 | 0 | mReadTexImageHelper = MakeUnique<GLReadTexImageHelper>(this); |
2359 | 0 | } |
2360 | 0 |
|
2361 | 0 | return mReadTexImageHelper.get(); |
2362 | 0 | } |
2363 | | |
2364 | | void |
2365 | | GLContext::FlushIfHeavyGLCallsSinceLastFlush() |
2366 | 0 | { |
2367 | 0 | if (!mHeavyGLCallsSinceLastFlush) { |
2368 | 0 | return; |
2369 | 0 | } |
2370 | 0 | if (MakeCurrent()) { |
2371 | 0 | fFlush(); |
2372 | 0 | } |
2373 | 0 | } |
2374 | | |
2375 | | /*static*/ bool |
2376 | | GLContext::ShouldDumpExts() |
2377 | 0 | { |
2378 | 0 | return gfxEnv::GlDumpExtensions(); |
2379 | 0 | } |
2380 | | |
2381 | | bool |
2382 | | DoesStringMatch(const char* aString, const char* aWantedString) |
2383 | 0 | { |
2384 | 0 | if (!aString || !aWantedString) |
2385 | 0 | return false; |
2386 | 0 | |
2387 | 0 | const char* occurrence = strstr(aString, aWantedString); |
2388 | 0 |
|
2389 | 0 | // aWanted not found |
2390 | 0 | if (!occurrence) |
2391 | 0 | return false; |
2392 | 0 | |
2393 | 0 | // aWantedString preceded by alpha character |
2394 | 0 | if (occurrence != aString && isalpha(*(occurrence-1))) |
2395 | 0 | return false; |
2396 | 0 | |
2397 | 0 | // aWantedVendor followed by alpha character |
2398 | 0 | const char* afterOccurrence = occurrence + strlen(aWantedString); |
2399 | 0 | if (isalpha(*afterOccurrence)) |
2400 | 0 | return false; |
2401 | 0 | |
2402 | 0 | return true; |
2403 | 0 | } |
2404 | | |
2405 | | /*static*/ bool |
2406 | | GLContext::ShouldSpew() |
2407 | 0 | { |
2408 | 0 | return gfxEnv::GlSpew(); |
2409 | 0 | } |
2410 | | |
2411 | | void |
2412 | | SplitByChar(const nsACString& str, const char delim, std::vector<nsCString>* const out) |
2413 | 0 | { |
2414 | 0 | uint32_t start = 0; |
2415 | 0 | while (true) { |
2416 | 0 | int32_t end = str.FindChar(' ', start); |
2417 | 0 | if (end == -1) |
2418 | 0 | break; |
2419 | 0 | |
2420 | 0 | uint32_t len = (uint32_t)end - start; |
2421 | 0 | nsDependentCSubstring substr(str, start, len); |
2422 | 0 | out->push_back(nsCString(substr)); |
2423 | 0 |
|
2424 | 0 | start = end + 1; |
2425 | 0 | } |
2426 | 0 |
|
2427 | 0 | nsDependentCSubstring substr(str, start); |
2428 | 0 | out->push_back(nsCString(substr)); |
2429 | 0 | } |
2430 | | |
2431 | | bool |
2432 | | GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) |
2433 | 0 | { |
2434 | 0 | MOZ_ASSERT(src && dest); |
2435 | 0 | MOZ_ASSERT(dest->GetSize() == src->mSize); |
2436 | 0 |
|
2437 | 0 | if (!MakeCurrent()) { |
2438 | 0 | return false; |
2439 | 0 | } |
2440 | 0 | |
2441 | 0 | SharedSurface* prev = GetLockedSurface(); |
2442 | 0 |
|
2443 | 0 | const bool needsSwap = src != prev; |
2444 | 0 | if (needsSwap) { |
2445 | 0 | if (prev) |
2446 | 0 | prev->UnlockProd(); |
2447 | 0 | src->LockProd(); |
2448 | 0 | } |
2449 | 0 |
|
2450 | 0 | GLuint tempFB = 0; |
2451 | 0 | GLuint tempTex = 0; |
2452 | 0 |
|
2453 | 0 | { |
2454 | 0 | ScopedBindFramebuffer autoFB(this); |
2455 | 0 |
|
2456 | 0 | // We're consuming from the producer side, so which do we use? |
2457 | 0 | // Really, we just want a read-only lock, so ConsumerAcquire is the best match. |
2458 | 0 | src->ProducerReadAcquire(); |
2459 | 0 |
|
2460 | 0 | if (src->mAttachType == AttachmentType::Screen) { |
2461 | 0 | fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
2462 | 0 | } else { |
2463 | 0 | fGenFramebuffers(1, &tempFB); |
2464 | 0 | fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, tempFB); |
2465 | 0 |
|
2466 | 0 | switch (src->mAttachType) { |
2467 | 0 | case AttachmentType::GLTexture: |
2468 | 0 | fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, |
2469 | 0 | src->ProdTextureTarget(), src->ProdTexture(), 0); |
2470 | 0 | break; |
2471 | 0 | case AttachmentType::GLRenderbuffer: |
2472 | 0 | fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, |
2473 | 0 | LOCAL_GL_RENDERBUFFER, src->ProdRenderbuffer()); |
2474 | 0 | break; |
2475 | 0 | default: |
2476 | 0 | MOZ_CRASH("GFX: bad `src->mAttachType`."); |
2477 | 0 | } |
2478 | 0 |
|
2479 | 0 | DebugOnly<GLenum> status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); |
2480 | 0 | MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE); |
2481 | 0 | } |
2482 | 0 |
|
2483 | 0 | if (src->NeedsIndirectReads()) { |
2484 | 0 | fGenTextures(1, &tempTex); |
2485 | 0 | { |
2486 | 0 | ScopedBindTexture autoTex(this, tempTex); |
2487 | 0 |
|
2488 | 0 | GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA |
2489 | 0 | : LOCAL_GL_RGB; |
2490 | 0 | auto width = src->mSize.width; |
2491 | 0 | auto height = src->mSize.height; |
2492 | 0 | fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, |
2493 | 0 | height, 0); |
2494 | 0 | } |
2495 | 0 |
|
2496 | 0 | fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, |
2497 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
2498 | 0 | LOCAL_GL_TEXTURE_2D, tempTex, 0); |
2499 | 0 | } |
2500 | 0 |
|
2501 | 0 | ReadPixelsIntoDataSurface(this, dest); |
2502 | 0 |
|
2503 | 0 | src->ProducerReadRelease(); |
2504 | 0 | } |
2505 | 0 |
|
2506 | 0 | if (tempFB) |
2507 | 0 | fDeleteFramebuffers(1, &tempFB); |
2508 | 0 |
|
2509 | 0 | if (tempTex) { |
2510 | 0 | fDeleteTextures(1, &tempTex); |
2511 | 0 | } |
2512 | 0 |
|
2513 | 0 | if (needsSwap) { |
2514 | 0 | src->UnlockProd(); |
2515 | 0 | if (prev) |
2516 | 0 | prev->LockProd(); |
2517 | 0 | } |
2518 | 0 |
|
2519 | 0 | return true; |
2520 | 0 | } |
2521 | | |
2522 | | // Do whatever tear-down is necessary after drawing to our offscreen FBO, |
2523 | | // if it's bound. |
2524 | | void |
2525 | | GLContext::AfterGLDrawCall() |
2526 | 0 | { |
2527 | 0 | if (mScreen) { |
2528 | 0 | mScreen->AfterDrawCall(); |
2529 | 0 | } |
2530 | 0 | mHeavyGLCallsSinceLastFlush = true; |
2531 | 0 | } |
2532 | | |
2533 | | // Do whatever setup is necessary to read from our offscreen FBO, if it's |
2534 | | // bound. |
2535 | | void |
2536 | | GLContext::BeforeGLReadCall() |
2537 | 0 | { |
2538 | 0 | if (mScreen) |
2539 | 0 | mScreen->BeforeReadCall(); |
2540 | 0 | } |
2541 | | |
2542 | | void |
2543 | | GLContext::fBindFramebuffer(GLenum target, GLuint framebuffer) |
2544 | 0 | { |
2545 | 0 | if (!mScreen) { |
2546 | 0 | raw_fBindFramebuffer(target, framebuffer); |
2547 | 0 | return; |
2548 | 0 | } |
2549 | 0 | |
2550 | 0 | switch (target) { |
2551 | 0 | case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: |
2552 | 0 | mScreen->BindDrawFB(framebuffer); |
2553 | 0 | return; |
2554 | 0 |
|
2555 | 0 | case LOCAL_GL_READ_FRAMEBUFFER_EXT: |
2556 | 0 | mScreen->BindReadFB(framebuffer); |
2557 | 0 | return; |
2558 | 0 |
|
2559 | 0 | case LOCAL_GL_FRAMEBUFFER: |
2560 | 0 | mScreen->BindFB(framebuffer); |
2561 | 0 | return; |
2562 | 0 |
|
2563 | 0 | default: |
2564 | 0 | // Nothing we care about, likely an error. |
2565 | 0 | break; |
2566 | 0 | } |
2567 | 0 | |
2568 | 0 | raw_fBindFramebuffer(target, framebuffer); |
2569 | 0 | } |
2570 | | |
2571 | | void |
2572 | | GLContext::fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, |
2573 | | GLint y, GLsizei width, GLsizei height, GLint border) |
2574 | 0 | { |
2575 | 0 | if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { |
2576 | 0 | // pass wrong values to cause the GL to generate GL_INVALID_VALUE. |
2577 | 0 | // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. |
2578 | 0 | level = -1; |
2579 | 0 | width = -1; |
2580 | 0 | height = -1; |
2581 | 0 | border = -1; |
2582 | 0 | } |
2583 | 0 |
|
2584 | 0 | BeforeGLReadCall(); |
2585 | 0 | bool didCopyTexImage2D = false; |
2586 | 0 | if (mScreen) { |
2587 | 0 | didCopyTexImage2D = mScreen->CopyTexImage2D(target, level, internalformat, x, |
2588 | 0 | y, width, height, border); |
2589 | 0 | } |
2590 | 0 |
|
2591 | 0 | if (!didCopyTexImage2D) { |
2592 | 0 | raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, |
2593 | 0 | border); |
2594 | 0 | } |
2595 | 0 | AfterGLReadCall(); |
2596 | 0 | } |
2597 | | |
2598 | | void |
2599 | | GLContext::fGetIntegerv(GLenum pname, GLint* params) |
2600 | 0 | { |
2601 | 0 | switch (pname) { |
2602 | 0 | // LOCAL_GL_FRAMEBUFFER_BINDING is equal to |
2603 | 0 | // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, |
2604 | 0 | // so we don't need two cases. |
2605 | 0 | case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT: |
2606 | 0 | if (mScreen) { |
2607 | 0 | *params = mScreen->GetDrawFB(); |
2608 | 0 | } else { |
2609 | 0 | raw_fGetIntegerv(pname, params); |
2610 | 0 | } |
2611 | 0 | break; |
2612 | 0 |
|
2613 | 0 | case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT: |
2614 | 0 | if (mScreen) { |
2615 | 0 | *params = mScreen->GetReadFB(); |
2616 | 0 | } else { |
2617 | 0 | raw_fGetIntegerv(pname, params); |
2618 | 0 | } |
2619 | 0 | break; |
2620 | 0 |
|
2621 | 0 | case LOCAL_GL_MAX_TEXTURE_SIZE: |
2622 | 0 | MOZ_ASSERT(mMaxTextureSize>0); |
2623 | 0 | *params = mMaxTextureSize; |
2624 | 0 | break; |
2625 | 0 |
|
2626 | 0 | case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: |
2627 | 0 | MOZ_ASSERT(mMaxCubeMapTextureSize>0); |
2628 | 0 | *params = mMaxCubeMapTextureSize; |
2629 | 0 | break; |
2630 | 0 |
|
2631 | 0 | case LOCAL_GL_MAX_RENDERBUFFER_SIZE: |
2632 | 0 | MOZ_ASSERT(mMaxRenderbufferSize>0); |
2633 | 0 | *params = mMaxRenderbufferSize; |
2634 | 0 | break; |
2635 | 0 |
|
2636 | 0 | case LOCAL_GL_VIEWPORT: |
2637 | 0 | for (size_t i = 0; i < 4; i++) { |
2638 | 0 | params[i] = mViewportRect[i]; |
2639 | 0 | } |
2640 | 0 | break; |
2641 | 0 |
|
2642 | 0 | case LOCAL_GL_SCISSOR_BOX: |
2643 | 0 | for (size_t i = 0; i < 4; i++) { |
2644 | 0 | params[i] = mScissorRect[i]; |
2645 | 0 | } |
2646 | 0 | break; |
2647 | 0 |
|
2648 | 0 | default: |
2649 | 0 | raw_fGetIntegerv(pname, params); |
2650 | 0 | break; |
2651 | 0 | } |
2652 | 0 | } |
2653 | | |
2654 | | void |
2655 | | GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, |
2656 | | GLenum type, GLvoid* pixels) |
2657 | 0 | { |
2658 | 0 | BeforeGLReadCall(); |
2659 | 0 |
|
2660 | 0 | bool didReadPixels = false; |
2661 | 0 | if (mScreen) { |
2662 | 0 | didReadPixels = mScreen->ReadPixels(x, y, width, height, format, type, pixels); |
2663 | 0 | } |
2664 | 0 |
|
2665 | 0 | if (!didReadPixels) { |
2666 | 0 | raw_fReadPixels(x, y, width, height, format, type, pixels); |
2667 | 0 | } |
2668 | 0 |
|
2669 | 0 | AfterGLReadCall(); |
2670 | 0 |
|
2671 | 0 | // Check if GL is giving back 1.0 alpha for |
2672 | 0 | // RGBA reads to RGBA images from no-alpha buffers. |
2673 | | #ifdef XP_MACOSX |
2674 | | if (WorkAroundDriverBugs() && |
2675 | | Vendor() == gl::GLVendor::NVIDIA && |
2676 | | format == LOCAL_GL_RGBA && |
2677 | | type == LOCAL_GL_UNSIGNED_BYTE && |
2678 | | !IsCoreProfile() && |
2679 | | width && height) |
2680 | | { |
2681 | | GLint alphaBits = 0; |
2682 | | fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits); |
2683 | | if (!alphaBits) { |
2684 | | const uint32_t alphaMask = 0xff000000; |
2685 | | |
2686 | | uint32_t* itr = (uint32_t*)pixels; |
2687 | | uint32_t testPixel = *itr; |
2688 | | if ((testPixel & alphaMask) != alphaMask) { |
2689 | | // We need to set the alpha channel to 1.0 manually. |
2690 | | uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4. |
2691 | | |
2692 | | for (; itr != itrEnd; itr++) { |
2693 | | *itr |= alphaMask; |
2694 | | } |
2695 | | } |
2696 | | } |
2697 | | } |
2698 | | #endif |
2699 | | } |
2700 | | |
2701 | | void |
2702 | | GLContext::fDeleteFramebuffers(GLsizei n, const GLuint* names) |
2703 | 0 | { |
2704 | 0 | if (mScreen) { |
2705 | 0 | // Notify mScreen which framebuffers we're deleting. |
2706 | 0 | // Otherwise, we will get framebuffer binding mispredictions. |
2707 | 0 | for (int i = 0; i < n; i++) { |
2708 | 0 | mScreen->DeletingFB(names[i]); |
2709 | 0 | } |
2710 | 0 | } |
2711 | 0 |
|
2712 | 0 | // Avoid crash by flushing before glDeleteFramebuffers. See bug 1194923. |
2713 | 0 | if (mNeedsFlushBeforeDeleteFB) { |
2714 | 0 | fFlush(); |
2715 | 0 | } |
2716 | 0 |
|
2717 | 0 | if (n == 1 && *names == 0) { |
2718 | 0 | // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228. |
2719 | 0 | } else { |
2720 | 0 | raw_fDeleteFramebuffers(n, names); |
2721 | 0 | } |
2722 | 0 | TRACKING_CONTEXT(DeletedFramebuffers(this, n, names)); |
2723 | 0 | } |
2724 | | |
2725 | | #ifdef MOZ_WIDGET_ANDROID |
2726 | | /** |
2727 | | * Conservatively estimate whether there is enough available |
2728 | | * contiguous virtual address space to map a newly allocated texture. |
2729 | | */ |
2730 | | static bool |
2731 | | WillTextureMapSucceed(GLsizei width, GLsizei height, GLenum format, GLenum type) |
2732 | | { |
2733 | | bool willSucceed = false; |
2734 | | // Some drivers leave large gaps between textures, so require |
2735 | | // there to be double the actual size of the texture available. |
2736 | | size_t size = width * height * GetBytesPerTexel(format, type) * 2; |
2737 | | |
2738 | | void *p = mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
2739 | | if (p != MAP_FAILED) { |
2740 | | willSucceed = true; |
2741 | | munmap(p, size); |
2742 | | } |
2743 | | |
2744 | | return willSucceed; |
2745 | | } |
2746 | | #endif // MOZ_WIDGET_ANDROID |
2747 | | |
2748 | | void |
2749 | | GLContext::fTexImage2D(GLenum target, GLint level, GLint internalformat, |
2750 | | GLsizei width, GLsizei height, GLint border, |
2751 | 0 | GLenum format, GLenum type, const GLvoid* pixels) { |
2752 | 0 | if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { |
2753 | 0 | // pass wrong values to cause the GL to generate GL_INVALID_VALUE. |
2754 | 0 | // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. |
2755 | 0 | level = -1; |
2756 | 0 | width = -1; |
2757 | 0 | height = -1; |
2758 | 0 | border = -1; |
2759 | 0 | } |
2760 | | #if MOZ_WIDGET_ANDROID |
2761 | | if (mTextureAllocCrashesOnMapFailure) { |
2762 | | // We have no way of knowing whether this texture already has |
2763 | | // storage allocated for it, and therefore whether this check |
2764 | | // is necessary. We must therefore assume it does not and |
2765 | | // always perform the check. |
2766 | | if (!WillTextureMapSucceed(width, height, internalformat, type)) { |
2767 | | return; |
2768 | | } |
2769 | | } |
2770 | | #endif |
2771 | | raw_fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); |
2772 | 0 | } |
2773 | | |
2774 | | GLuint |
2775 | | GLContext::GetDrawFB() |
2776 | 0 | { |
2777 | 0 | if (mScreen) |
2778 | 0 | return mScreen->GetDrawFB(); |
2779 | 0 | |
2780 | 0 | GLuint ret = 0; |
2781 | 0 | GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret); |
2782 | 0 | return ret; |
2783 | 0 | } |
2784 | | |
2785 | | GLuint |
2786 | | GLContext::GetReadFB() |
2787 | 0 | { |
2788 | 0 | if (mScreen) |
2789 | 0 | return mScreen->GetReadFB(); |
2790 | 0 | |
2791 | 0 | GLenum bindEnum = IsSupported(GLFeature::split_framebuffer) |
2792 | 0 | ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT |
2793 | 0 | : LOCAL_GL_FRAMEBUFFER_BINDING; |
2794 | 0 |
|
2795 | 0 | GLuint ret = 0; |
2796 | 0 | GetUIntegerv(bindEnum, &ret); |
2797 | 0 | return ret; |
2798 | 0 | } |
2799 | | |
2800 | | GLuint |
2801 | | GLContext::GetFB() |
2802 | 0 | { |
2803 | 0 | if (mScreen) { |
2804 | 0 | // This has a very important extra assert that checks that we're |
2805 | 0 | // not accidentally ignoring a situation where the draw and read |
2806 | 0 | // FBs differ. |
2807 | 0 | return mScreen->GetFB(); |
2808 | 0 | } |
2809 | 0 | |
2810 | 0 | GLuint ret = 0; |
2811 | 0 | GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); |
2812 | 0 | return ret; |
2813 | 0 | } |
2814 | | |
2815 | | bool |
2816 | | GLContext::InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps) |
2817 | 0 | { |
2818 | 0 | if (!CreateScreenBuffer(size, caps)) |
2819 | 0 | return false; |
2820 | 0 | |
2821 | 0 | if (!MakeCurrent()) { |
2822 | 0 | return false; |
2823 | 0 | } |
2824 | 0 | fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
2825 | 0 | fScissor(0, 0, size.width, size.height); |
2826 | 0 | fViewport(0, 0, size.width, size.height); |
2827 | 0 |
|
2828 | 0 | mCaps = mScreen->mCaps; |
2829 | 0 | MOZ_ASSERT(!mCaps.any); |
2830 | 0 |
|
2831 | 0 | return true; |
2832 | 0 | } |
2833 | | |
2834 | | bool |
2835 | | GLContext::IsDrawingToDefaultFramebuffer() |
2836 | 0 | { |
2837 | 0 | return Screen()->IsDrawFramebufferDefault(); |
2838 | 0 | } |
2839 | | |
2840 | | GLuint |
2841 | | CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, |
2842 | | GLenum aType, const gfx::IntSize& aSize, bool linear) |
2843 | 0 | { |
2844 | 0 | GLuint tex = 0; |
2845 | 0 | aGL->fGenTextures(1, &tex); |
2846 | 0 | ScopedBindTexture autoTex(aGL, tex); |
2847 | 0 |
|
2848 | 0 | aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, |
2849 | 0 | LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR |
2850 | 0 | : LOCAL_GL_NEAREST); |
2851 | 0 | aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, |
2852 | 0 | LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR |
2853 | 0 | : LOCAL_GL_NEAREST); |
2854 | 0 | aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, |
2855 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
2856 | 0 | aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, |
2857 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
2858 | 0 |
|
2859 | 0 | aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, |
2860 | 0 | 0, |
2861 | 0 | aInternalFormat, |
2862 | 0 | aSize.width, aSize.height, |
2863 | 0 | 0, |
2864 | 0 | aFormat, |
2865 | 0 | aType, |
2866 | 0 | nullptr); |
2867 | 0 |
|
2868 | 0 | return tex; |
2869 | 0 | } |
2870 | | |
2871 | | GLuint |
2872 | | CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, |
2873 | | const gfx::IntSize& aSize) |
2874 | 0 | { |
2875 | 0 | MOZ_ASSERT(aFormats.color_texInternalFormat); |
2876 | 0 | MOZ_ASSERT(aFormats.color_texFormat); |
2877 | 0 | MOZ_ASSERT(aFormats.color_texType); |
2878 | 0 |
|
2879 | 0 | GLenum internalFormat = aFormats.color_texInternalFormat; |
2880 | 0 | GLenum unpackFormat = aFormats.color_texFormat; |
2881 | 0 | GLenum unpackType = aFormats.color_texType; |
2882 | 0 | if (aGL->IsANGLE()) { |
2883 | 0 | MOZ_ASSERT(internalFormat == LOCAL_GL_RGBA); |
2884 | 0 | MOZ_ASSERT(unpackFormat == LOCAL_GL_RGBA); |
2885 | 0 | MOZ_ASSERT(unpackType == LOCAL_GL_UNSIGNED_BYTE); |
2886 | 0 | internalFormat = LOCAL_GL_BGRA_EXT; |
2887 | 0 | unpackFormat = LOCAL_GL_BGRA_EXT; |
2888 | 0 | } |
2889 | 0 |
|
2890 | 0 | return CreateTexture(aGL, internalFormat, unpackFormat, unpackType, aSize); |
2891 | 0 | } |
2892 | | |
2893 | | uint32_t |
2894 | | GetBytesPerTexel(GLenum format, GLenum type) |
2895 | 0 | { |
2896 | 0 | // If there is no defined format or type, we're not taking up any memory |
2897 | 0 | if (!format || !type) { |
2898 | 0 | return 0; |
2899 | 0 | } |
2900 | 0 | |
2901 | 0 | if (format == LOCAL_GL_DEPTH_COMPONENT) { |
2902 | 0 | if (type == LOCAL_GL_UNSIGNED_SHORT) |
2903 | 0 | return 2; |
2904 | 0 | else if (type == LOCAL_GL_UNSIGNED_INT) |
2905 | 0 | return 4; |
2906 | 0 | } else if (format == LOCAL_GL_DEPTH_STENCIL) { |
2907 | 0 | if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT) |
2908 | 0 | return 4; |
2909 | 0 | } |
2910 | 0 | |
2911 | 0 | if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT || type == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) { |
2912 | 0 | uint32_t multiplier = type == LOCAL_GL_UNSIGNED_BYTE ? 1 : 4; |
2913 | 0 | switch (format) { |
2914 | 0 | case LOCAL_GL_ALPHA: |
2915 | 0 | case LOCAL_GL_LUMINANCE: |
2916 | 0 | return 1 * multiplier; |
2917 | 0 | case LOCAL_GL_LUMINANCE_ALPHA: |
2918 | 0 | return 2 * multiplier; |
2919 | 0 | case LOCAL_GL_RGB: |
2920 | 0 | return 3 * multiplier; |
2921 | 0 | case LOCAL_GL_RGBA: |
2922 | 0 | case LOCAL_GL_BGRA_EXT: |
2923 | 0 | return 4 * multiplier; |
2924 | 0 | default: |
2925 | 0 | break; |
2926 | 0 | } |
2927 | 0 | } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 || |
2928 | 0 | type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 || |
2929 | 0 | type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 || |
2930 | 0 | type == LOCAL_GL_UNSIGNED_SHORT) |
2931 | 0 | { |
2932 | 0 | return 2; |
2933 | 0 | } |
2934 | 0 | |
2935 | 0 | gfxCriticalError() << "Unknown texture type " << type << " or format " << format; |
2936 | 0 | return 0; |
2937 | 0 | } |
2938 | | |
2939 | | bool |
2940 | | GLContext::MakeCurrent(bool aForce) const |
2941 | 0 | { |
2942 | 0 | if (MOZ_UNLIKELY( IsDestroyed() )) |
2943 | 0 | return false; |
2944 | 0 | |
2945 | 0 | if (MOZ_LIKELY( !aForce )) { |
2946 | 0 | bool isCurrent; |
2947 | 0 | if (mUseTLSIsCurrent) { |
2948 | 0 | isCurrent = (sCurrentContext.get() == reinterpret_cast<uintptr_t>(this)); |
2949 | 0 | } else { |
2950 | 0 | isCurrent = IsCurrentImpl(); |
2951 | 0 | } |
2952 | 0 | if (MOZ_LIKELY( isCurrent )) { |
2953 | 0 | MOZ_ASSERT(IsCurrentImpl()); |
2954 | 0 | return true; |
2955 | 0 | } |
2956 | 0 | } |
2957 | 0 |
|
2958 | 0 | if (!MakeCurrentImpl()) |
2959 | 0 | return false; |
2960 | 0 | |
2961 | 0 | sCurrentContext.set(reinterpret_cast<uintptr_t>(this)); |
2962 | 0 | return true; |
2963 | 0 | } |
2964 | | |
2965 | | void |
2966 | | GLContext::ResetSyncCallCount(const char* resetReason) const |
2967 | 0 | { |
2968 | 0 | if (ShouldSpew()) { |
2969 | 0 | printf_stderr("On %s, mSyncGLCallCount = %" PRIu64 "\n", |
2970 | 0 | resetReason, mSyncGLCallCount); |
2971 | 0 | } |
2972 | 0 |
|
2973 | 0 | mSyncGLCallCount = 0; |
2974 | 0 | } |
2975 | | |
2976 | | // -- |
2977 | | |
2978 | | void |
2979 | | GLContext::BeforeGLCall_Debug(const char* const funcName) const |
2980 | 0 | { |
2981 | 0 | MOZ_ASSERT(mDebugFlags); |
2982 | 0 |
|
2983 | 0 | FlushErrors(); |
2984 | 0 |
|
2985 | 0 | if (mDebugFlags & DebugFlagTrace) { |
2986 | 0 | printf_stderr("[gl:%p] > %s\n", this, funcName); |
2987 | 0 | } |
2988 | 0 | } |
2989 | | |
2990 | | void |
2991 | | GLContext::AfterGLCall_Debug(const char* const funcName) const |
2992 | 0 | { |
2993 | 0 | MOZ_ASSERT(mDebugFlags); |
2994 | 0 |
|
2995 | 0 | // calling fFinish() immediately after every GL call makes sure that if this GL command crashes, |
2996 | 0 | // the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces |
2997 | 0 | // tend to be meaningless |
2998 | 0 | mSymbols.fFinish(); |
2999 | 0 | GLenum err = FlushErrors(); |
3000 | 0 |
|
3001 | 0 | if (mDebugFlags & DebugFlagTrace) { |
3002 | 0 | printf_stderr("[gl:%p] < %s [%s (0x%04x)]\n", this, funcName, |
3003 | 0 | GLErrorToString(err), err); |
3004 | 0 | } |
3005 | 0 |
|
3006 | 0 | if (err != LOCAL_GL_NO_ERROR && |
3007 | 0 | !mLocalErrorScopeStack.size()) |
3008 | 0 | { |
3009 | 0 | printf_stderr("[gl:%p] %s: Generated unexpected %s error." |
3010 | 0 | " (0x%04x)\n", this, funcName, |
3011 | 0 | GLErrorToString(err), err); |
3012 | 0 |
|
3013 | 0 | if (mDebugFlags & DebugFlagAbortOnError) { |
3014 | 0 | MOZ_CRASH("Unexpected error with MOZ_GL_DEBUG_ABORT_ON_ERROR. (Run" |
3015 | 0 | " with MOZ_GL_DEBUG_ABORT_ON_ERROR=0 to disable)"); |
3016 | 0 | } |
3017 | 0 | } |
3018 | 0 | } |
3019 | | |
3020 | | /*static*/ void |
3021 | | GLContext::OnImplicitMakeCurrentFailure(const char* const funcName) |
3022 | 0 | { |
3023 | 0 | gfxCriticalError() << "Ignoring call to " << funcName << " with failed" |
3024 | 0 | << " mImplicitMakeCurrent."; |
3025 | 0 | } |
3026 | | |
3027 | | } /* namespace gl */ |
3028 | | } /* namespace mozilla */ |