Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
7 #include <algorithm>
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
12 #include "GLContext.h"
13 #include "GLBlitHelper.h"
14 #include "GLBlitTextureImageHelper.h"
15 #include "GLReadTexImageHelper.h"
17 #include "gfxCrashReporterUtils.h"
18 #include "gfxUtils.h"
19 #include "GLContextProvider.h"
20 #include "GLTextureImage.h"
21 #include "nsPrintfCString.h"
22 #include "nsThreadUtils.h"
23 #include "prenv.h"
24 #include "prlink.h"
25 #include "ScopedGLHelpers.h"
26 #include "SharedSurfaceGL.h"
27 #include "SurfaceStream.h"
28 #include "GfxTexturesReporter.h"
29 #include "TextureGarbageBin.h"
30 #include "gfx2DGlue.h"
31 #include "gfxPrefs.h"
33 #include "OGLShaderProgram.h" // for ShaderProgramType
35 #include "mozilla/DebugOnly.h"
37 #ifdef XP_MACOSX
38 #include <CoreServices/CoreServices.h>
39 #include "gfxColor.h"
40 #endif
42 #if defined(MOZ_WIDGET_COCOA)
43 #include "nsCocoaFeatures.h"
44 #endif
46 using namespace mozilla::gfx;
47 using namespace mozilla::layers;
49 namespace mozilla {
50 namespace gl {
52 #ifdef DEBUG
53 unsigned GLContext::sCurrentGLContextTLS = -1;
54 #endif
56 uint32_t GLContext::sDebugMode = 0;
59 #define MAX_SYMBOL_LENGTH 128
60 #define MAX_SYMBOL_NAMES 5
62 // should match the order of GLExtensions, and be null-terminated.
63 static const char *sExtensionNames[] = {
64 "GL_EXT_framebuffer_object",
65 "GL_ARB_framebuffer_object",
66 "GL_ARB_texture_rectangle",
67 "GL_EXT_bgra",
68 "GL_EXT_texture_format_BGRA8888",
69 "GL_OES_depth24",
70 "GL_OES_depth32",
71 "GL_OES_stencil8",
72 "GL_OES_texture_npot",
73 "GL_ARB_depth_texture",
74 "GL_OES_depth_texture",
75 "GL_OES_packed_depth_stencil",
76 "GL_IMG_read_format",
77 "GL_EXT_read_format_bgra",
78 "GL_APPLE_client_storage",
79 "GL_APPLE_texture_range",
80 "GL_ARB_texture_non_power_of_two",
81 "GL_ARB_pixel_buffer_object",
82 "GL_ARB_ES2_compatibility",
83 "GL_ARB_ES3_compatibility",
84 "GL_OES_texture_float",
85 "GL_OES_texture_float_linear",
86 "GL_ARB_texture_float",
87 "GL_OES_texture_half_float",
88 "GL_OES_texture_half_float_linear",
89 "GL_NV_half_float",
90 "GL_EXT_color_buffer_float",
91 "GL_EXT_color_buffer_half_float",
92 "GL_ARB_color_buffer_float",
93 "GL_EXT_unpack_subimage",
94 "GL_OES_standard_derivatives",
95 "GL_EXT_texture_filter_anisotropic",
96 "GL_EXT_texture_compression_s3tc",
97 "GL_EXT_texture_compression_dxt1",
98 "GL_ANGLE_texture_compression_dxt3",
99 "GL_ANGLE_texture_compression_dxt5",
100 "GL_AMD_compressed_ATC_texture",
101 "GL_IMG_texture_compression_pvrtc",
102 "GL_EXT_framebuffer_blit",
103 "GL_ANGLE_framebuffer_blit",
104 "GL_EXT_framebuffer_multisample",
105 "GL_ANGLE_framebuffer_multisample",
106 "GL_OES_rgb8_rgba8",
107 "GL_ARB_robustness",
108 "GL_EXT_robustness",
109 "GL_ARB_sync",
110 "GL_OES_EGL_image",
111 "GL_OES_EGL_sync",
112 "GL_OES_EGL_image_external",
113 "GL_EXT_packed_depth_stencil",
114 "GL_OES_element_index_uint",
115 "GL_OES_vertex_array_object",
116 "GL_ARB_vertex_array_object",
117 "GL_APPLE_vertex_array_object",
118 "GL_ARB_draw_buffers",
119 "GL_EXT_draw_buffers",
120 "GL_EXT_gpu_shader4",
121 "GL_EXT_blend_minmax",
122 "GL_ARB_draw_instanced",
123 "GL_EXT_draw_instanced",
124 "GL_NV_draw_instanced",
125 "GL_ARB_instanced_arrays",
126 "GL_NV_instanced_arrays",
127 "GL_ANGLE_instanced_arrays",
128 "GL_EXT_occlusion_query_boolean",
129 "GL_ARB_occlusion_query2",
130 "GL_EXT_transform_feedback",
131 "GL_NV_transform_feedback",
132 "GL_ANGLE_depth_texture",
133 "GL_EXT_sRGB",
134 "GL_EXT_texture_sRGB",
135 "GL_ARB_framebuffer_sRGB",
136 "GL_EXT_framebuffer_sRGB",
137 "GL_KHR_debug",
138 "GL_ARB_half_float_pixel",
139 "GL_EXT_frag_depth",
140 "GL_OES_compressed_ETC1_RGB8_texture",
141 "GL_EXT_draw_range_elements",
142 nullptr
143 };
145 static bool
146 ParseGLVersion(GLContext* gl, unsigned int* version)
147 {
148 GLenum error = gl->fGetError();
149 if (error != LOCAL_GL_NO_ERROR) {
150 MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
151 return false;
152 }
154 /**
155 * B2G emulator bug work around: The emulator implements OpenGL ES 2.0 on
156 * OpenGL 3.2. The bug is that GetIntegerv(LOCAL_GL_{MAJOR,MINOR}_VERSION)
157 * returns OpenGL 3.2 instead of generating an error.
158 */
159 if (!gl->IsGLES())
160 {
161 /**
162 * OpenGL 3.1 and OpenGL ES 3.0 both introduce GL_{MAJOR,MINOR}_VERSION
163 * with GetIntegerv. So we first try those constants even though we
164 * might not have an OpenGL context supporting them, has this is a
165 * better way than parsing GL_VERSION.
166 */
167 GLint majorVersion = 0;
168 GLint minorVersion = 0;
170 gl->fGetIntegerv(LOCAL_GL_MAJOR_VERSION, &majorVersion);
171 gl->fGetIntegerv(LOCAL_GL_MINOR_VERSION, &minorVersion);
173 // If it's not an OpenGL (ES) 3.0 context, we will have an error
174 error = gl->fGetError();
175 if (error == LOCAL_GL_NO_ERROR &&
176 majorVersion > 0 &&
177 minorVersion >= 0)
178 {
179 *version = majorVersion * 100 + minorVersion * 10;
180 return true;
181 }
182 }
184 /**
185 * We were not able to use GL_{MAJOR,MINOR}_VERSION, so we parse
186 * GL_VERSION.
187 *
188 *
189 * OpenGL 2.x, 3.x, 4.x specifications:
190 * The VERSION and SHADING_LANGUAGE_VERSION strings are laid out as follows:
191 *
192 * <version number><space><vendor-specific information>
193 *
194 * The version number is either of the form major_number.minor_number or
195 * major_number.minor_number.release_number, where the numbers all have
196 * one or more digits.
197 *
198 *
199 * OpenGL ES 2.0, 3.0 specifications:
200 * The VERSION string is laid out as follows:
201 *
202 * "OpenGL ES N.M vendor-specific information"
203 *
204 * The version number is either of the form major_number.minor_number or
205 * major_number.minor_number.release_number, where the numbers all have
206 * one or more digits.
207 *
208 *
209 * Note:
210 * We don't care about release_number.
211 */
212 const char* versionString = (const char*)gl->fGetString(LOCAL_GL_VERSION);
214 error = gl->fGetError();
215 if (error != LOCAL_GL_NO_ERROR) {
216 MOZ_ASSERT(false, "glGetString(GL_VERSION) has generated an error");
217 return false;
218 } else if (!versionString) {
219 MOZ_ASSERT(false, "glGetString(GL_VERSION) has returned 0");
220 return false;
221 }
223 const char kGLESVersionPrefix[] = "OpenGL ES ";
224 if (strncmp(versionString, kGLESVersionPrefix, strlen(kGLESVersionPrefix)) == 0) {
225 versionString += strlen(kGLESVersionPrefix);
226 }
228 const char* itr = versionString;
229 char* end = nullptr;
230 int majorVersion = (int)strtol(itr, &end, 10);
232 if (!end) {
233 MOZ_ASSERT(false, "Failed to parse the GL major version number.");
234 return false;
235 } else if (*end != '.') {
236 MOZ_ASSERT(false, "Failed to parse GL's major-minor version number separator.");
237 return false;
238 }
240 // we skip the '.' between the major and the minor version
241 itr = end + 1;
243 end = nullptr;
245 int minorVersion = (int)strtol(itr, &end, 10);
246 if (!end) {
247 MOZ_ASSERT(false, "Failed to parse GL's minor version number.");
248 return false;
249 }
251 if (majorVersion <= 0 || majorVersion >= 100) {
252 MOZ_ASSERT(false, "Invalid major version.");
253 return false;
254 } else if (minorVersion < 0 || minorVersion >= 10) {
255 MOZ_ASSERT(false, "Invalid minor version.");
256 return false;
257 }
259 *version = (unsigned int)(majorVersion * 100 + minorVersion * 10);
260 return true;
261 }
263 GLContext::GLContext(const SurfaceCaps& caps,
264 GLContext* sharedContext,
265 bool isOffscreen)
266 : mInitialized(false),
267 mIsOffscreen(isOffscreen),
268 mContextLost(false),
269 mVersion(0),
270 mProfile(ContextProfile::Unknown),
271 mVendor(GLVendor::Other),
272 mRenderer(GLRenderer::Other),
273 mHasRobustness(false),
274 #ifdef DEBUG
275 mGLError(LOCAL_GL_NO_ERROR),
276 #endif
277 mSharedContext(sharedContext),
278 mCaps(caps),
279 mScreen(nullptr),
280 mLockedSurface(nullptr),
281 mMaxTextureSize(0),
282 mMaxCubeMapTextureSize(0),
283 mMaxTextureImageSize(0),
284 mMaxRenderbufferSize(0),
285 mNeedsTextureSizeChecks(false),
286 mWorkAroundDriverBugs(true)
287 {
288 mOwningThread = NS_GetCurrentThread();
289 }
291 GLContext::~GLContext() {
292 NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!");
293 #ifdef DEBUG
294 if (mSharedContext) {
295 GLContext *tip = mSharedContext;
296 while (tip->mSharedContext)
297 tip = tip->mSharedContext;
298 tip->SharedContextDestroyed(this);
299 tip->ReportOutstandingNames();
300 } else {
301 ReportOutstandingNames();
302 }
303 #endif
304 }
306 bool
307 GLContext::InitWithPrefix(const char *prefix, bool trygl)
308 {
309 ScopedGfxFeatureReporter reporter("GL Context");
311 if (mInitialized) {
312 reporter.SetSuccessful();
313 return true;
314 }
316 mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
318 SymLoadStruct symbols[] = {
319 { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
320 { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
321 { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
322 { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
323 { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
324 { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } },
325 { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", nullptr } },
326 { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, { "BlendEquationSeparate", "BlendEquationSeparateEXT", nullptr } },
327 { (PRFuncPtr*) &mSymbols.fBlendFunc, { "BlendFunc", nullptr } },
328 { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, { "BlendFuncSeparate", "BlendFuncSeparateEXT", nullptr } },
329 { (PRFuncPtr*) &mSymbols.fBufferData, { "BufferData", nullptr } },
330 { (PRFuncPtr*) &mSymbols.fBufferSubData, { "BufferSubData", nullptr } },
331 { (PRFuncPtr*) &mSymbols.fClear, { "Clear", nullptr } },
332 { (PRFuncPtr*) &mSymbols.fClearColor, { "ClearColor", nullptr } },
333 { (PRFuncPtr*) &mSymbols.fClearStencil, { "ClearStencil", nullptr } },
334 { (PRFuncPtr*) &mSymbols.fColorMask, { "ColorMask", nullptr } },
335 { (PRFuncPtr*) &mSymbols.fCompressedTexImage2D, {"CompressedTexImage2D", nullptr} },
336 { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage2D, {"CompressedTexSubImage2D", nullptr} },
337 { (PRFuncPtr*) &mSymbols.fCullFace, { "CullFace", nullptr } },
338 { (PRFuncPtr*) &mSymbols.fDetachShader, { "DetachShader", "DetachShaderARB", nullptr } },
339 { (PRFuncPtr*) &mSymbols.fDepthFunc, { "DepthFunc", nullptr } },
340 { (PRFuncPtr*) &mSymbols.fDepthMask, { "DepthMask", nullptr } },
341 { (PRFuncPtr*) &mSymbols.fDisable, { "Disable", nullptr } },
342 { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, { "DisableVertexAttribArray", "DisableVertexAttribArrayARB", nullptr } },
343 { (PRFuncPtr*) &mSymbols.fDrawArrays, { "DrawArrays", nullptr } },
344 { (PRFuncPtr*) &mSymbols.fDrawElements, { "DrawElements", nullptr } },
345 { (PRFuncPtr*) &mSymbols.fEnable, { "Enable", nullptr } },
346 { (PRFuncPtr*) &mSymbols.fEnableVertexAttribArray, { "EnableVertexAttribArray", "EnableVertexAttribArrayARB", nullptr } },
347 { (PRFuncPtr*) &mSymbols.fFinish, { "Finish", nullptr } },
348 { (PRFuncPtr*) &mSymbols.fFlush, { "Flush", nullptr } },
349 { (PRFuncPtr*) &mSymbols.fFrontFace, { "FrontFace", nullptr } },
350 { (PRFuncPtr*) &mSymbols.fGetActiveAttrib, { "GetActiveAttrib", "GetActiveAttribARB", nullptr } },
351 { (PRFuncPtr*) &mSymbols.fGetActiveUniform, { "GetActiveUniform", "GetActiveUniformARB", nullptr } },
352 { (PRFuncPtr*) &mSymbols.fGetAttachedShaders, { "GetAttachedShaders", "GetAttachedShadersARB", nullptr } },
353 { (PRFuncPtr*) &mSymbols.fGetAttribLocation, { "GetAttribLocation", "GetAttribLocationARB", nullptr } },
354 { (PRFuncPtr*) &mSymbols.fGetIntegerv, { "GetIntegerv", nullptr } },
355 { (PRFuncPtr*) &mSymbols.fGetFloatv, { "GetFloatv", nullptr } },
356 { (PRFuncPtr*) &mSymbols.fGetBooleanv, { "GetBooleanv", nullptr } },
357 { (PRFuncPtr*) &mSymbols.fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", nullptr } },
358 { (PRFuncPtr*) &mSymbols.fGetError, { "GetError", nullptr } },
359 { (PRFuncPtr*) &mSymbols.fGetProgramiv, { "GetProgramiv", "GetProgramivARB", nullptr } },
360 { (PRFuncPtr*) &mSymbols.fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", nullptr } },
361 { (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", nullptr } },
362 { (PRFuncPtr*) &mSymbols.fTexParameteriv, { "TexParameteriv", nullptr } },
363 { (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", nullptr } },
364 { (PRFuncPtr*) &mSymbols.fGetString, { "GetString", nullptr } },
365 { (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", nullptr } },
366 { (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", nullptr } },
367 { (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", nullptr } },
368 { (PRFuncPtr*) &mSymbols.fGetUniformiv, { "GetUniformiv", "GetUniformivARB", nullptr } },
369 { (PRFuncPtr*) &mSymbols.fGetUniformLocation, { "GetUniformLocation", "GetUniformLocationARB", nullptr } },
370 { (PRFuncPtr*) &mSymbols.fGetVertexAttribfv, { "GetVertexAttribfv", "GetVertexAttribfvARB", nullptr } },
371 { (PRFuncPtr*) &mSymbols.fGetVertexAttribiv, { "GetVertexAttribiv", "GetVertexAttribivARB", nullptr } },
372 { (PRFuncPtr*) &mSymbols.fGetVertexAttribPointerv, { "GetVertexAttribPointerv", nullptr } },
373 { (PRFuncPtr*) &mSymbols.fHint, { "Hint", nullptr } },
374 { (PRFuncPtr*) &mSymbols.fIsBuffer, { "IsBuffer", "IsBufferARB", nullptr } },
375 { (PRFuncPtr*) &mSymbols.fIsEnabled, { "IsEnabled", nullptr } },
376 { (PRFuncPtr*) &mSymbols.fIsProgram, { "IsProgram", "IsProgramARB", nullptr } },
377 { (PRFuncPtr*) &mSymbols.fIsShader, { "IsShader", "IsShaderARB", nullptr } },
378 { (PRFuncPtr*) &mSymbols.fIsTexture, { "IsTexture", "IsTextureARB", nullptr } },
379 { (PRFuncPtr*) &mSymbols.fLineWidth, { "LineWidth", nullptr } },
380 { (PRFuncPtr*) &mSymbols.fLinkProgram, { "LinkProgram", "LinkProgramARB", nullptr } },
381 { (PRFuncPtr*) &mSymbols.fPixelStorei, { "PixelStorei", nullptr } },
382 { (PRFuncPtr*) &mSymbols.fPolygonOffset, { "PolygonOffset", nullptr } },
383 { (PRFuncPtr*) &mSymbols.fReadPixels, { "ReadPixels", nullptr } },
384 { (PRFuncPtr*) &mSymbols.fSampleCoverage, { "SampleCoverage", nullptr } },
385 { (PRFuncPtr*) &mSymbols.fScissor, { "Scissor", nullptr } },
386 { (PRFuncPtr*) &mSymbols.fStencilFunc, { "StencilFunc", nullptr } },
387 { (PRFuncPtr*) &mSymbols.fStencilFuncSeparate, { "StencilFuncSeparate", "StencilFuncSeparateEXT", nullptr } },
388 { (PRFuncPtr*) &mSymbols.fStencilMask, { "StencilMask", nullptr } },
389 { (PRFuncPtr*) &mSymbols.fStencilMaskSeparate, { "StencilMaskSeparate", "StencilMaskSeparateEXT", nullptr } },
390 { (PRFuncPtr*) &mSymbols.fStencilOp, { "StencilOp", nullptr } },
391 { (PRFuncPtr*) &mSymbols.fStencilOpSeparate, { "StencilOpSeparate", "StencilOpSeparateEXT", nullptr } },
392 { (PRFuncPtr*) &mSymbols.fTexImage2D, { "TexImage2D", nullptr } },
393 { (PRFuncPtr*) &mSymbols.fTexSubImage2D, { "TexSubImage2D", nullptr } },
394 { (PRFuncPtr*) &mSymbols.fUniform1f, { "Uniform1f", nullptr } },
395 { (PRFuncPtr*) &mSymbols.fUniform1fv, { "Uniform1fv", nullptr } },
396 { (PRFuncPtr*) &mSymbols.fUniform1i, { "Uniform1i", nullptr } },
397 { (PRFuncPtr*) &mSymbols.fUniform1iv, { "Uniform1iv", nullptr } },
398 { (PRFuncPtr*) &mSymbols.fUniform2f, { "Uniform2f", nullptr } },
399 { (PRFuncPtr*) &mSymbols.fUniform2fv, { "Uniform2fv", nullptr } },
400 { (PRFuncPtr*) &mSymbols.fUniform2i, { "Uniform2i", nullptr } },
401 { (PRFuncPtr*) &mSymbols.fUniform2iv, { "Uniform2iv", nullptr } },
402 { (PRFuncPtr*) &mSymbols.fUniform3f, { "Uniform3f", nullptr } },
403 { (PRFuncPtr*) &mSymbols.fUniform3fv, { "Uniform3fv", nullptr } },
404 { (PRFuncPtr*) &mSymbols.fUniform3i, { "Uniform3i", nullptr } },
405 { (PRFuncPtr*) &mSymbols.fUniform3iv, { "Uniform3iv", nullptr } },
406 { (PRFuncPtr*) &mSymbols.fUniform4f, { "Uniform4f", nullptr } },
407 { (PRFuncPtr*) &mSymbols.fUniform4fv, { "Uniform4fv", nullptr } },
408 { (PRFuncPtr*) &mSymbols.fUniform4i, { "Uniform4i", nullptr } },
409 { (PRFuncPtr*) &mSymbols.fUniform4iv, { "Uniform4iv", nullptr } },
410 { (PRFuncPtr*) &mSymbols.fUniformMatrix2fv, { "UniformMatrix2fv", nullptr } },
411 { (PRFuncPtr*) &mSymbols.fUniformMatrix3fv, { "UniformMatrix3fv", nullptr } },
412 { (PRFuncPtr*) &mSymbols.fUniformMatrix4fv, { "UniformMatrix4fv", nullptr } },
413 { (PRFuncPtr*) &mSymbols.fUseProgram, { "UseProgram", nullptr } },
414 { (PRFuncPtr*) &mSymbols.fValidateProgram, { "ValidateProgram", nullptr } },
415 { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } },
416 { (PRFuncPtr*) &mSymbols.fVertexAttrib1f, { "VertexAttrib1f", nullptr } },
417 { (PRFuncPtr*) &mSymbols.fVertexAttrib2f, { "VertexAttrib2f", nullptr } },
418 { (PRFuncPtr*) &mSymbols.fVertexAttrib3f, { "VertexAttrib3f", nullptr } },
419 { (PRFuncPtr*) &mSymbols.fVertexAttrib4f, { "VertexAttrib4f", nullptr } },
420 { (PRFuncPtr*) &mSymbols.fVertexAttrib1fv, { "VertexAttrib1fv", nullptr } },
421 { (PRFuncPtr*) &mSymbols.fVertexAttrib2fv, { "VertexAttrib2fv", nullptr } },
422 { (PRFuncPtr*) &mSymbols.fVertexAttrib3fv, { "VertexAttrib3fv", nullptr } },
423 { (PRFuncPtr*) &mSymbols.fVertexAttrib4fv, { "VertexAttrib4fv", nullptr } },
424 { (PRFuncPtr*) &mSymbols.fViewport, { "Viewport", nullptr } },
425 { (PRFuncPtr*) &mSymbols.fCompileShader, { "CompileShader", nullptr } },
426 { (PRFuncPtr*) &mSymbols.fCopyTexImage2D, { "CopyTexImage2D", nullptr } },
427 { (PRFuncPtr*) &mSymbols.fCopyTexSubImage2D, { "CopyTexSubImage2D", nullptr } },
428 { (PRFuncPtr*) &mSymbols.fGetShaderiv, { "GetShaderiv", nullptr } },
429 { (PRFuncPtr*) &mSymbols.fGetShaderInfoLog, { "GetShaderInfoLog", nullptr } },
430 { (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", nullptr } },
431 { (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", nullptr } },
432 { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } },
433 { (PRFuncPtr*) &mSymbols.fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", nullptr } },
434 { (PRFuncPtr*) &mSymbols.fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", nullptr } },
435 { (PRFuncPtr*) &mSymbols.fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", nullptr } },
436 { (PRFuncPtr*) &mSymbols.fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", nullptr } },
437 { (PRFuncPtr*) &mSymbols.fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", nullptr } },
438 { (PRFuncPtr*) &mSymbols.fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", nullptr } },
439 { (PRFuncPtr*) &mSymbols.fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", nullptr } },
440 { (PRFuncPtr*) &mSymbols.fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", nullptr } },
441 { (PRFuncPtr*) &mSymbols.fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", nullptr } },
442 { (PRFuncPtr*) &mSymbols.fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", nullptr } },
443 { (PRFuncPtr*) &mSymbols.fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", nullptr } },
445 { (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", nullptr } },
446 { (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", nullptr } },
447 { (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", nullptr } },
448 { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", nullptr } },
449 { (PRFuncPtr*) &mSymbols.fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", nullptr } },
450 { (PRFuncPtr*) &mSymbols.fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", nullptr } },
452 { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", nullptr } },
453 { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", nullptr } },
454 { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", nullptr } },
455 { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", nullptr } },
456 { (PRFuncPtr*) &mSymbols.fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", nullptr } },
457 { (PRFuncPtr*) &mSymbols.fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", nullptr } },
459 { nullptr, { nullptr } },
461 };
463 mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
464 MakeCurrent();
465 if (mInitialized) {
466 unsigned int version = 0;
468 ParseGLVersion(this, &version);
470 #ifdef DEBUG
471 printf_stderr("OpenGL version detected: %u\n", version);
472 printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR));
473 printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER));
474 #endif
476 if (version >= mVersion) {
477 mVersion = version;
478 }
479 // Don't fail if version < mVersion, see bug 999445,
480 // Mac OSX 10.6/10.7 machines with Intel GPUs claim only OpenGL 1.4 but
481 // have all the GL2+ extensions that we need.
482 }
484 // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
485 if (mInitialized) {
486 if (IsGLES()) {
487 SymLoadStruct symbols_ES2[] = {
488 { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
489 { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
490 { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", nullptr } },
491 { nullptr, { nullptr } },
492 };
494 if (!LoadSymbols(&symbols_ES2[0], trygl, prefix)) {
495 NS_ERROR("OpenGL ES 2.0 supported, but symbols could not be loaded.");
496 mInitialized = false;
497 }
498 } else {
499 SymLoadStruct symbols_desktop[] = {
500 { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", nullptr } },
501 { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", nullptr } },
502 { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
503 { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", nullptr } },
504 { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
505 { (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", nullptr } },
506 { (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", nullptr } },
507 // These functions are only used by Skia/GL in desktop mode.
508 // Other parts of Gecko should avoid using these
509 { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
510 { (PRFuncPtr*) &mSymbols.fClientActiveTexture, { "ClientActiveTexture", nullptr } },
511 { (PRFuncPtr*) &mSymbols.fDisableClientState, { "DisableClientState", nullptr } },
512 { (PRFuncPtr*) &mSymbols.fEnableClientState, { "EnableClientState", nullptr } },
513 { (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } },
514 { (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } },
515 { (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } },
516 { (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } },
517 { (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } },
518 { (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } },
519 { (PRFuncPtr*) &mSymbols.fVertexPointer, { "VertexPointer", nullptr } },
520 { nullptr, { nullptr } },
521 };
523 if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) {
524 NS_ERROR("Desktop symbols failed to load.");
525 mInitialized = false;
526 }
527 }
528 }
530 const char *glVendorString = nullptr;
531 const char *glRendererString = nullptr;
533 if (mInitialized) {
534 // The order of these strings must match up with the order of the enum
535 // defined in GLContext.h for vendor IDs
536 glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR);
537 if (!glVendorString)
538 mInitialized = false;
540 const char *vendorMatchStrings[size_t(GLVendor::Other)] = {
541 "Intel",
542 "NVIDIA",
543 "ATI",
544 "Qualcomm",
545 "Imagination",
546 "nouveau",
547 "Vivante",
548 "VMware, Inc."
549 };
551 mVendor = GLVendor::Other;
552 for (size_t i = 0; i < size_t(GLVendor::Other); ++i) {
553 if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
554 mVendor = GLVendor(i);
555 break;
556 }
557 }
559 // The order of these strings must match up with the order of the enum
560 // defined in GLContext.h for renderer IDs
561 glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
562 if (!glRendererString)
563 mInitialized = false;
565 const char *rendererMatchStrings[size_t(GLRenderer::Other)] = {
566 "Adreno 200",
567 "Adreno 205",
568 "Adreno (TM) 205",
569 "Adreno (TM) 320",
570 "PowerVR SGX 530",
571 "PowerVR SGX 540",
572 "NVIDIA Tegra",
573 "Android Emulator",
574 "Gallium 0.4 on llvmpipe"
575 };
577 mRenderer = GLRenderer::Other;
578 for (size_t i = 0; i < size_t(GLRenderer::Other); ++i) {
579 if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
580 mRenderer = GLRenderer(i);
581 break;
582 }
583 }
584 }
587 #ifdef DEBUG
588 if (PR_GetEnv("MOZ_GL_DEBUG"))
589 sDebugMode |= DebugEnabled;
591 // enables extra verbose output, informing of the start and finish of every GL call.
592 // useful e.g. to record information to investigate graphics system crashes/lockups
593 if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE"))
594 sDebugMode |= DebugTrace;
596 // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
597 if (PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR"))
598 sDebugMode |= DebugAbortOnError;
599 #endif
601 if (mInitialized) {
602 #ifdef DEBUG
603 static bool firstRun = true;
604 if (firstRun && DebugMode()) {
605 const char *vendors[size_t(GLVendor::Other)] = {
606 "Intel",
607 "NVIDIA",
608 "ATI",
609 "Qualcomm"
610 };
612 MOZ_ASSERT(glVendorString);
613 if (mVendor < GLVendor::Other) {
614 printf_stderr("OpenGL vendor ('%s') recognized as: %s\n",
615 glVendorString, vendors[size_t(mVendor)]);
616 } else {
617 printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString);
618 }
619 }
620 firstRun = false;
621 #endif
623 InitExtensions();
624 InitFeatures();
626 // Disable extensions with partial or incorrect support.
627 if (WorkAroundDriverBugs()) {
628 if (Renderer() == GLRenderer::AdrenoTM320) {
629 MarkUnsupported(GLFeature::standard_derivatives);
630 }
632 if (Vendor() == GLVendor::Vivante) {
633 // bug 958256
634 MarkUnsupported(GLFeature::standard_derivatives);
635 }
637 if (Vendor() == GLVendor::Imagination &&
638 Renderer() == GLRenderer::SGX540) {
639 // Bug 980048
640 MarkExtensionUnsupported(OES_EGL_sync);
641 }
643 #ifdef XP_MACOSX
644 // The Mac Nvidia driver, for versions up to and including 10.8, don't seem
645 // to properly support this. See 814839
646 // this has been fixed in Mac OS X 10.9. See 907946
647 if (Vendor() == gl::GLVendor::NVIDIA &&
648 !nsCocoaFeatures::OnMavericksOrLater())
649 {
650 MarkUnsupported(GLFeature::depth_texture);
651 }
652 #endif
653 // ANGLE's divisor support is busted. (see bug 916816)
654 if (IsANGLE()) {
655 MarkUnsupported(GLFeature::instanced_arrays);
656 }
657 }
659 NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) ||
660 (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
661 "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!");
663 if (SupportsRobustness()) {
664 mHasRobustness = false;
666 if (IsExtensionSupported(ARB_robustness)) {
667 SymLoadStruct robustnessSymbols[] = {
668 { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", nullptr } },
669 { nullptr, { nullptr } },
670 };
672 if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
673 NS_ERROR("GL supports ARB_robustness without supplying GetGraphicsResetStatusARB.");
675 mSymbols.fGetGraphicsResetStatus = nullptr;
676 } else {
677 mHasRobustness = true;
678 }
679 }
680 if (!IsExtensionSupported(ARB_robustness) &&
681 IsExtensionSupported(EXT_robustness)) {
682 SymLoadStruct robustnessSymbols[] = {
683 { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", nullptr } },
684 { nullptr, { nullptr } },
685 };
687 if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
688 NS_ERROR("GL supports EXT_robustness without supplying GetGraphicsResetStatusEXT.");
690 mSymbols.fGetGraphicsResetStatus = nullptr;
691 } else {
692 mHasRobustness = true;
693 }
694 }
696 if (!mHasRobustness) {
697 MarkUnsupported(GLFeature::robustness);
698 }
699 }
701 // Check for aux symbols based on extensions
702 if (IsSupported(GLFeature::framebuffer_blit))
703 {
704 SymLoadStruct auxSymbols[] = {
705 {
706 (PRFuncPtr*) &mSymbols.fBlitFramebuffer,
707 {
708 "BlitFramebuffer",
709 "BlitFramebufferEXT",
710 "BlitFramebufferANGLE",
711 nullptr
712 }
713 },
714 { nullptr, { nullptr } },
715 };
716 if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
717 NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer");
719 MarkUnsupported(GLFeature::framebuffer_blit);
720 mSymbols.fBlitFramebuffer = nullptr;
721 }
722 }
724 if (IsSupported(GLFeature::framebuffer_multisample))
725 {
726 SymLoadStruct auxSymbols[] = {
727 {
728 (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample,
729 {
730 "RenderbufferStorageMultisample",
731 "RenderbufferStorageMultisampleEXT",
732 "RenderbufferStorageMultisampleANGLE",
733 nullptr
734 }
735 },
736 { nullptr, { nullptr } },
737 };
738 if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
739 NS_ERROR("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample");
741 MarkUnsupported(GLFeature::framebuffer_multisample);
742 mSymbols.fRenderbufferStorageMultisample = nullptr;
743 }
744 }
746 if (IsExtensionSupported(ARB_sync)) {
747 SymLoadStruct syncSymbols[] = {
748 { (PRFuncPtr*) &mSymbols.fFenceSync, { "FenceSync", nullptr } },
749 { (PRFuncPtr*) &mSymbols.fIsSync, { "IsSync", nullptr } },
750 { (PRFuncPtr*) &mSymbols.fDeleteSync, { "DeleteSync", nullptr } },
751 { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "ClientWaitSync", nullptr } },
752 { (PRFuncPtr*) &mSymbols.fWaitSync, { "WaitSync", nullptr } },
753 { (PRFuncPtr*) &mSymbols.fGetInteger64v, { "GetInteger64v", nullptr } },
754 { (PRFuncPtr*) &mSymbols.fGetSynciv, { "GetSynciv", nullptr } },
755 { nullptr, { nullptr } },
756 };
758 if (!LoadSymbols(&syncSymbols[0], trygl, prefix)) {
759 NS_ERROR("GL supports ARB_sync without supplying its functions.");
761 MarkExtensionUnsupported(ARB_sync);
762 mSymbols.fFenceSync = nullptr;
763 mSymbols.fIsSync = nullptr;
764 mSymbols.fDeleteSync = nullptr;
765 mSymbols.fClientWaitSync = nullptr;
766 mSymbols.fWaitSync = nullptr;
767 mSymbols.fGetInteger64v = nullptr;
768 mSymbols.fGetSynciv = nullptr;
769 }
770 }
772 if (IsExtensionSupported(OES_EGL_image)) {
773 SymLoadStruct imageSymbols[] = {
774 { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } },
775 { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } },
776 { nullptr, { nullptr } },
777 };
779 if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) {
780 NS_ERROR("GL supports OES_EGL_image without supplying its functions.");
782 MarkExtensionUnsupported(OES_EGL_image);
783 mSymbols.fEGLImageTargetTexture2D = nullptr;
784 mSymbols.fEGLImageTargetRenderbufferStorage = nullptr;
785 }
786 }
788 if (IsExtensionSupported(APPLE_texture_range)) {
789 SymLoadStruct vaoSymbols[] = {
790 { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } },
791 { nullptr, { nullptr } },
792 };
794 if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) {
795 mSymbols.fTextureRangeAPPLE = nullptr;
796 }
797 }
799 if (IsExtensionSupported(ARB_vertex_array_object) ||
800 IsExtensionSupported(OES_vertex_array_object)) {
801 SymLoadStruct vaoSymbols[] = {
802 { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArray", "IsVertexArrayOES", nullptr } },
803 { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArrays", "GenVertexArraysOES", nullptr } },
804 { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", "BindVertexArrayOES", nullptr } },
805 { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", "DeleteVertexArraysOES", nullptr } },
806 { nullptr, { nullptr } },
807 };
809 if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) {
810 NS_ERROR("GL supports Vertex Array Object without supplying its functions.");
812 MarkUnsupported(GLFeature::vertex_array_object);
813 mSymbols.fIsVertexArray = nullptr;
814 mSymbols.fGenVertexArrays = nullptr;
815 mSymbols.fBindVertexArray = nullptr;
816 mSymbols.fDeleteVertexArrays = nullptr;
817 }
818 }
819 else if (IsExtensionSupported(APPLE_vertex_array_object)) {
820 /*
821 * separate call to LoadSymbols with APPLE_vertex_array_object to work around
822 * a driver bug : the IsVertexArray symbol (without suffix) can be present but unusable.
823 */
824 SymLoadStruct vaoSymbols[] = {
825 { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArrayAPPLE", nullptr } },
826 { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArraysAPPLE", nullptr } },
827 { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArrayAPPLE", nullptr } },
828 { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArraysAPPLE", nullptr } },
829 { nullptr, { nullptr } },
830 };
832 if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) {
833 NS_ERROR("GL supports Vertex Array Object without supplying its functions.");
835 MarkUnsupported(GLFeature::vertex_array_object);
836 mSymbols.fIsVertexArray = nullptr;
837 mSymbols.fGenVertexArrays = nullptr;
838 mSymbols.fBindVertexArray = nullptr;
839 mSymbols.fDeleteVertexArrays = nullptr;
840 }
841 }
843 if (IsSupported(GLFeature::draw_instanced)) {
844 SymLoadStruct drawInstancedSymbols[] = {
845 { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced,
846 { "DrawArraysInstanced",
847 "DrawArraysInstancedARB",
848 "DrawArraysInstancedEXT",
849 "DrawArraysInstancedNV",
850 "DrawArraysInstancedANGLE",
851 nullptr
852 }
853 },
854 { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced,
855 { "DrawElementsInstanced",
856 "DrawElementsInstancedARB",
857 "DrawElementsInstancedEXT",
858 "DrawElementsInstancedNV",
859 "DrawElementsInstancedANGLE",
860 nullptr
861 }
862 },
863 { nullptr, { nullptr } },
864 };
866 if (!LoadSymbols(drawInstancedSymbols, trygl, prefix)) {
867 NS_ERROR("GL supports instanced draws without supplying its functions.");
869 MarkUnsupported(GLFeature::draw_instanced);
870 mSymbols.fDrawArraysInstanced = nullptr;
871 mSymbols.fDrawElementsInstanced = nullptr;
872 }
873 }
875 if (IsSupported(GLFeature::instanced_arrays)) {
876 SymLoadStruct instancedArraySymbols[] = {
877 { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor,
878 { "VertexAttribDivisor",
879 "VertexAttribDivisorARB",
880 "VertexAttribDivisorNV",
881 "VertexAttribDivisorANGLE",
882 nullptr
883 }
884 },
885 { nullptr, { nullptr } },
886 };
888 if (!LoadSymbols(instancedArraySymbols, trygl, prefix)) {
889 NS_ERROR("GL supports array instanced without supplying it function.");
891 MarkUnsupported(GLFeature::instanced_arrays);
892 mSymbols.fVertexAttribDivisor = nullptr;
893 }
894 }
896 if (IsSupported(GLFeature::transform_feedback)) {
897 SymLoadStruct transformFeedbackSymbols[] = {
898 { (PRFuncPtr*) &mSymbols.fBindBufferBase,
899 { "BindBufferBase",
900 "BindBufferBaseEXT",
901 "BindBufferBaseNV",
902 nullptr
903 }
904 },
905 { (PRFuncPtr*) &mSymbols.fBindBufferRange,
906 { "BindBufferRange",
907 "BindBufferRangeEXT",
908 "BindBufferRangeNV",
909 nullptr
910 }
911 },
912 { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback,
913 { "BeginTransformFeedback",
914 "BeginTransformFeedbackEXT",
915 "BeginTransformFeedbackNV",
916 nullptr
917 }
918 },
919 { (PRFuncPtr*) &mSymbols.fEndTransformFeedback,
920 { "EndTransformFeedback",
921 "EndTransformFeedbackEXT",
922 "EndTransformFeedbackNV",
923 nullptr
924 }
925 },
926 { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings,
927 { "TransformFeedbackVaryings",
928 "TransformFeedbackVaryingsEXT",
929 "TransformFeedbackVaryingsNV",
930 nullptr
931 }
932 },
933 { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying,
934 { "GetTransformFeedbackVarying",
935 "GetTransformFeedbackVaryingEXT",
936 "GetTransformFeedbackVaryingNV",
937 nullptr
938 }
939 },
940 { (PRFuncPtr*) &mSymbols.fGetIntegeri_v,
941 { "GetIntegeri_v",
942 "GetIntegerIndexedvEXT",
943 "GetIntegerIndexedvNV",
944 nullptr
945 }
946 },
947 { nullptr, { nullptr } },
948 };
950 if (!LoadSymbols(transformFeedbackSymbols, trygl, prefix)) {
951 NS_ERROR("GL supports transform feedback without supplying its functions.");
953 MarkUnsupported(GLFeature::transform_feedback);
954 MarkUnsupported(GLFeature::bind_buffer_offset);
955 mSymbols.fBindBufferBase = nullptr;
956 mSymbols.fBindBufferRange = nullptr;
957 mSymbols.fBeginTransformFeedback = nullptr;
958 mSymbols.fEndTransformFeedback = nullptr;
959 mSymbols.fTransformFeedbackVaryings = nullptr;
960 mSymbols.fGetTransformFeedbackVarying = nullptr;
961 mSymbols.fGetIntegeri_v = nullptr;
962 }
963 }
965 if (IsSupported(GLFeature::bind_buffer_offset)) {
966 SymLoadStruct bindBufferOffsetSymbols[] = {
967 { (PRFuncPtr*) &mSymbols.fBindBufferOffset,
968 { "BindBufferOffset",
969 "BindBufferOffsetEXT",
970 "BindBufferOffsetNV",
971 nullptr
972 }
973 },
974 { nullptr, { nullptr } },
975 };
977 if (!LoadSymbols(bindBufferOffsetSymbols, trygl, prefix)) {
978 NS_ERROR("GL supports BindBufferOffset without supplying its function.");
980 MarkUnsupported(GLFeature::bind_buffer_offset);
981 mSymbols.fBindBufferOffset = nullptr;
982 }
983 }
985 if (IsSupported(GLFeature::query_objects)) {
986 SymLoadStruct queryObjectsSymbols[] = {
987 { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", "BeginQueryEXT", nullptr } },
988 { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueries", "GenQueriesEXT", nullptr } },
989 { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueries", "DeleteQueriesEXT", nullptr } },
990 { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQuery", "EndQueryEXT", nullptr } },
991 { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryiv", "GetQueryivEXT", nullptr } },
992 { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuiv", "GetQueryObjectuivEXT", nullptr } },
993 { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQuery", "IsQueryEXT", nullptr } },
994 { nullptr, { nullptr } },
995 };
997 if (!LoadSymbols(queryObjectsSymbols, trygl, prefix)) {
998 NS_ERROR("GL supports query objects without supplying its functions.");
1000 MarkUnsupported(GLFeature::query_objects);
1001 MarkUnsupported(GLFeature::get_query_object_iv);
1002 MarkUnsupported(GLFeature::occlusion_query);
1003 MarkUnsupported(GLFeature::occlusion_query_boolean);
1004 MarkUnsupported(GLFeature::occlusion_query2);
1005 mSymbols.fBeginQuery = nullptr;
1006 mSymbols.fGenQueries = nullptr;
1007 mSymbols.fDeleteQueries = nullptr;
1008 mSymbols.fEndQuery = nullptr;
1009 mSymbols.fGetQueryiv = nullptr;
1010 mSymbols.fGetQueryObjectuiv = nullptr;
1011 mSymbols.fIsQuery = nullptr;
1012 }
1013 }
1015 if (IsSupported(GLFeature::get_query_object_iv)) {
1016 SymLoadStruct queryObjectsSymbols[] = {
1017 { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", "GetQueryObjectivEXT", nullptr } },
1018 { nullptr, { nullptr } },
1019 };
1021 if (!LoadSymbols(queryObjectsSymbols, trygl, prefix)) {
1022 NS_ERROR("GL supports query objects iv getter without supplying its function.");
1024 MarkUnsupported(GLFeature::get_query_object_iv);
1025 mSymbols.fGetQueryObjectiv = nullptr;
1026 }
1027 }
1029 if (IsSupported(GLFeature::draw_buffers)) {
1030 SymLoadStruct drawBuffersSymbols[] = {
1031 { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
1032 { nullptr, { nullptr } },
1033 };
1035 if (!LoadSymbols(drawBuffersSymbols, trygl, prefix)) {
1036 NS_ERROR("GL supports draw_buffers without supplying its functions.");
1038 MarkUnsupported(GLFeature::draw_buffers);
1039 mSymbols.fDrawBuffers = nullptr;
1040 }
1041 }
1043 if (IsExtensionSupported(KHR_debug)) {
1044 SymLoadStruct extSymbols[] = {
1045 { (PRFuncPtr*) &mSymbols.fDebugMessageControl, { "DebugMessageControl", "DebugMessageControlKHR", nullptr } },
1046 { (PRFuncPtr*) &mSymbols.fDebugMessageInsert, { "DebugMessageInsert", "DebugMessageInsertKHR", nullptr } },
1047 { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
1048 { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog, { "GetDebugMessageLog", "GetDebugMessageLogKHR", nullptr } },
1049 { (PRFuncPtr*) &mSymbols.fGetPointerv, { "GetPointerv", "GetPointervKHR", nullptr } },
1050 { (PRFuncPtr*) &mSymbols.fPushDebugGroup, { "PushDebugGroup", "PushDebugGroupKHR", nullptr } },
1051 { (PRFuncPtr*) &mSymbols.fPopDebugGroup, { "PopDebugGroup", "PopDebugGroupKHR", nullptr } },
1052 { (PRFuncPtr*) &mSymbols.fObjectLabel, { "ObjectLabel", "ObjectLabelKHR", nullptr } },
1053 { (PRFuncPtr*) &mSymbols.fGetObjectLabel, { "GetObjectLabel", "GetObjectLabelKHR", nullptr } },
1054 { (PRFuncPtr*) &mSymbols.fObjectPtrLabel, { "ObjectPtrLabel", "ObjectPtrLabelKHR", nullptr } },
1055 { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel, { "GetObjectPtrLabel", "GetObjectPtrLabelKHR", nullptr } },
1056 { nullptr, { nullptr } },
1057 };
1059 if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
1060 NS_ERROR("GL supports KHR_debug without supplying its functions.");
1062 MarkExtensionUnsupported(KHR_debug);
1063 mSymbols.fDebugMessageControl = nullptr;
1064 mSymbols.fDebugMessageInsert = nullptr;
1065 mSymbols.fDebugMessageCallback = nullptr;
1066 mSymbols.fGetDebugMessageLog = nullptr;
1067 mSymbols.fGetPointerv = nullptr;
1068 mSymbols.fPushDebugGroup = nullptr;
1069 mSymbols.fPopDebugGroup = nullptr;
1070 mSymbols.fObjectLabel = nullptr;
1071 mSymbols.fGetObjectLabel = nullptr;
1072 mSymbols.fObjectPtrLabel = nullptr;
1073 mSymbols.fGetObjectPtrLabel = nullptr;
1074 }
1075 }
1077 if (IsSupported(GLFeature::draw_range_elements)) {
1078 SymLoadStruct imageSymbols[] = {
1079 { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElementsEXT", "DrawRangeElements", nullptr } },
1080 { nullptr, { nullptr } },
1081 };
1083 if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) {
1084 NS_ERROR("GL supports draw_range_elements without supplying its functions.");
1086 MarkUnsupported(GLFeature::draw_range_elements);
1087 mSymbols.fDrawRangeElements = nullptr;
1088 }
1089 }
1091 // Load developer symbols, don't fail if we can't find them.
1092 SymLoadStruct auxSymbols[] = {
1093 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
1094 { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
1095 { nullptr, { nullptr } },
1096 };
1097 bool warnOnFailures = DebugMode();
1098 LoadSymbols(&auxSymbols[0], trygl, prefix, warnOnFailures);
1099 }
1101 if (mInitialized) {
1102 raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect);
1103 raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect);
1104 raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
1105 raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
1106 raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
1108 #ifdef XP_MACOSX
1109 if (mWorkAroundDriverBugs) {
1110 if (mVendor == GLVendor::Intel) {
1111 // see bug 737182 for 2D textures, bug 684882 for cube map textures.
1112 mMaxTextureSize = std::min(mMaxTextureSize, 4096);
1113 mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
1114 // for good measure, we align renderbuffers on what we do for 2D textures
1115 mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
1116 mNeedsTextureSizeChecks = true;
1117 } else if (mVendor == GLVendor::NVIDIA) {
1118 if (nsCocoaFeatures::OnMountainLionOrLater()) {
1119 // See bug 879656. 8192 fails, 8191 works.
1120 mMaxTextureSize = std::min(mMaxTextureSize, 8191);
1121 mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
1122 }
1123 else {
1124 // See bug 877949.
1125 mMaxTextureSize = std::min(mMaxTextureSize, 4096);
1126 mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
1127 }
1129 // Part of the bug 879656, but it also doesn't hurt the 877949
1130 mNeedsTextureSizeChecks = true;
1131 }
1132 }
1133 #endif
1134 #ifdef MOZ_X11
1135 if (mWorkAroundDriverBugs &&
1136 mVendor == GLVendor::Nouveau) {
1137 // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau.
1138 mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048);
1139 mNeedsTextureSizeChecks = true;
1140 }
1141 #endif
1143 mMaxTextureImageSize = mMaxTextureSize;
1145 mMaxSamples = 0;
1146 if (IsSupported(GLFeature::framebuffer_multisample)) {
1147 fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
1148 }
1150 // We're ready for final setup.
1151 fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
1153 if (mCaps.any)
1154 DetermineCaps();
1156 UpdatePixelFormat();
1157 UpdateGLFormats(mCaps);
1159 mTexGarbageBin = new TextureGarbageBin(this);
1161 MOZ_ASSERT(IsCurrent());
1162 }
1164 if (mInitialized)
1165 reporter.SetSuccessful();
1166 else {
1167 // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs
1168 mSymbols.Zero();
1169 NS_WARNING("InitWithPrefix failed!");
1170 }
1172 mVersionString = nsPrintfCString("%u.%u.%u", mVersion / 100, (mVersion / 10) % 10, mVersion % 10);
1174 return mInitialized;
1175 }
1177 void
1178 GLContext::InitExtensions()
1179 {
1180 MakeCurrent();
1181 const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
1182 if (!extensions)
1183 return;
1185 #ifdef DEBUG
1186 static bool firstRun = true;
1187 #else
1188 // Non-DEBUG, so never spew.
1189 const bool firstRun = false;
1190 #endif
1192 InitializeExtensionsBitSet(mAvailableExtensions, extensions, sExtensionNames, firstRun && DebugMode());
1194 if (WorkAroundDriverBugs() &&
1195 Vendor() == GLVendor::Qualcomm) {
1197 // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
1198 MarkExtensionSupported(OES_EGL_sync);
1199 }
1201 if (WorkAroundDriverBugs() &&
1202 Renderer() == GLRenderer::AndroidEmulator) {
1203 // the Android emulator, which we use to run B2G reftests on,
1204 // doesn't expose the OES_rgb8_rgba8 extension, but it seems to
1205 // support it (tautologically, as it only runs on desktop GL).
1206 MarkExtensionSupported(OES_rgb8_rgba8);
1207 }
1209 if (WorkAroundDriverBugs() &&
1210 Vendor() == GLVendor::VMware &&
1211 Renderer() == GLRenderer::GalliumLlvmpipe)
1212 {
1213 // The llvmpipe driver that is used on linux try servers appears to have
1214 // buggy support for s3tc/dxt1 compressed textures.
1215 // See Bug 975824.
1216 MarkExtensionUnsupported(EXT_texture_compression_s3tc);
1217 MarkExtensionUnsupported(EXT_texture_compression_dxt1);
1218 MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
1219 MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
1220 }
1222 #ifdef DEBUG
1223 firstRun = false;
1224 #endif
1225 }
1227 void
1228 GLContext::PlatformStartup()
1229 {
1230 RegisterStrongMemoryReporter(new GfxTexturesReporter());
1231 }
1233 // Common code for checking for both GL extensions and GLX extensions.
1234 bool
1235 GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
1236 {
1237 // fix bug 612572 - we were crashing as we were calling this function with extensions==null
1238 if (extensions == nullptr || extension == nullptr)
1239 return false;
1241 const GLubyte *start;
1242 GLubyte *where, *terminator;
1244 /* Extension names should not have spaces. */
1245 where = (GLubyte *) strchr(extension, ' ');
1246 if (where || *extension == '\0')
1247 return false;
1249 /*
1250 * It takes a bit of care to be fool-proof about parsing the
1251 * OpenGL extensions string. Don't be fooled by sub-strings,
1252 * etc.
1253 */
1254 start = extensions;
1255 for (;;) {
1256 where = (GLubyte *) strstr((const char *) start, extension);
1257 if (!where) {
1258 break;
1259 }
1260 terminator = where + strlen(extension);
1261 if (where == start || *(where - 1) == ' ') {
1262 if (*terminator == ' ' || *terminator == '\0') {
1263 return true;
1264 }
1265 }
1266 start = terminator;
1267 }
1268 return false;
1269 }
1271 void
1272 GLContext::DetermineCaps()
1273 {
1274 PixelBufferFormat format = QueryPixelFormat();
1276 SurfaceCaps caps;
1277 caps.color = !!format.red && !!format.green && !!format.blue;
1278 caps.bpp16 = caps.color && format.ColorBits() == 16;
1279 caps.alpha = !!format.alpha;
1280 caps.depth = !!format.depth;
1281 caps.stencil = !!format.stencil;
1282 caps.antialias = format.samples > 1;
1283 caps.preserve = true;
1285 mCaps = caps;
1286 }
1288 PixelBufferFormat
1289 GLContext::QueryPixelFormat()
1290 {
1291 PixelBufferFormat format;
1293 ScopedBindFramebuffer autoFB(this, 0);
1295 fGetIntegerv(LOCAL_GL_RED_BITS , &format.red );
1296 fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green);
1297 fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue );
1298 fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha);
1300 fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth);
1301 fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil);
1303 fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples);
1305 return format;
1306 }
1308 void
1309 GLContext::UpdatePixelFormat()
1310 {
1311 PixelBufferFormat format = QueryPixelFormat();
1312 #ifdef DEBUG
1313 const SurfaceCaps& caps = Caps();
1314 MOZ_ASSERT(!caps.any, "Did you forget to DetermineCaps()?");
1316 MOZ_ASSERT(caps.color == !!format.red);
1317 MOZ_ASSERT(caps.color == !!format.green);
1318 MOZ_ASSERT(caps.color == !!format.blue);
1320 MOZ_ASSERT(caps.alpha == !!format.alpha);
1322 // These we either must have if they're requested, or
1323 // we can have if they're not.
1324 MOZ_ASSERT(caps.depth == !!format.depth || !caps.depth);
1325 MOZ_ASSERT(caps.stencil == !!format.stencil || !caps.stencil);
1327 MOZ_ASSERT(caps.antialias == (format.samples > 1));
1328 #endif
1329 mPixelFormat = new PixelBufferFormat(format);
1330 }
1332 GLFormats
1333 GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
1334 {
1335 GLFormats formats;
1337 // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
1338 // OR we don't support full 8-bit color, return a 4444 or 565 format.
1339 bool bpp16 = caps.bpp16;
1340 if (IsGLES()) {
1341 if (!IsExtensionSupported(OES_rgb8_rgba8))
1342 bpp16 = true;
1343 } else {
1344 // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility.
1345 // Since it's also vanishingly useless there, let's not support it.
1346 bpp16 = false;
1347 }
1349 if (bpp16) {
1350 MOZ_ASSERT(IsGLES());
1351 if (caps.alpha) {
1352 formats.color_texInternalFormat = LOCAL_GL_RGBA;
1353 formats.color_texFormat = LOCAL_GL_RGBA;
1354 formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4;
1355 formats.color_rbFormat = LOCAL_GL_RGBA4;
1356 } else {
1357 formats.color_texInternalFormat = LOCAL_GL_RGB;
1358 formats.color_texFormat = LOCAL_GL_RGB;
1359 formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
1360 formats.color_rbFormat = LOCAL_GL_RGB565;
1361 }
1362 } else {
1363 formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
1365 if (caps.alpha) {
1366 formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
1367 formats.color_texFormat = LOCAL_GL_RGBA;
1368 formats.color_rbFormat = LOCAL_GL_RGBA8;
1369 } else {
1370 formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
1371 formats.color_texFormat = LOCAL_GL_RGB;
1372 formats.color_rbFormat = LOCAL_GL_RGB8;
1373 }
1374 }
1376 uint32_t msaaLevel = gfxPrefs::MSAALevel();
1377 GLsizei samples = msaaLevel * msaaLevel;
1378 samples = std::min(samples, mMaxSamples);
1380 // Bug 778765.
1381 if (WorkAroundDriverBugs() && samples == 1) {
1382 samples = 0;
1383 }
1384 formats.samples = samples;
1387 // Be clear that these are 0 if unavailable.
1388 formats.depthStencil = 0;
1389 if (!IsGLES() || IsExtensionSupported(OES_packed_depth_stencil)) {
1390 formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
1391 }
1393 formats.depth = 0;
1394 if (IsGLES()) {
1395 if (IsExtensionSupported(OES_depth24)) {
1396 formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
1397 } else {
1398 formats.depth = LOCAL_GL_DEPTH_COMPONENT16;
1399 }
1400 } else {
1401 formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
1402 }
1404 formats.stencil = LOCAL_GL_STENCIL_INDEX8;
1406 return formats;
1407 }
1409 bool
1410 GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus)
1411 {
1412 MOZ_ASSERT(fb);
1414 ScopedBindFramebuffer autoFB(this, fb);
1415 MOZ_ASSERT(fIsFramebuffer(fb));
1417 GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
1418 if (pStatus)
1419 *pStatus = status;
1421 return status == LOCAL_GL_FRAMEBUFFER_COMPLETE;
1422 }
1424 void
1425 GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB,
1426 GLuint depthRB, GLuint stencilRB,
1427 GLuint fb, GLenum target)
1428 {
1429 MOZ_ASSERT(fb);
1430 MOZ_ASSERT( !(colorTex && colorRB) );
1432 ScopedBindFramebuffer autoFB(this, fb);
1433 MOZ_ASSERT(fIsFramebuffer(fb)); // It only counts after being bound.
1435 if (colorTex) {
1436 MOZ_ASSERT(fIsTexture(colorTex));
1437 MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
1438 target == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
1439 fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
1440 LOCAL_GL_COLOR_ATTACHMENT0,
1441 target,
1442 colorTex,
1443 0);
1444 } else if (colorRB) {
1445 MOZ_ASSERT(fIsRenderbuffer(colorRB));
1446 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1447 LOCAL_GL_COLOR_ATTACHMENT0,
1448 LOCAL_GL_RENDERBUFFER,
1449 colorRB);
1450 }
1452 if (depthRB) {
1453 MOZ_ASSERT(fIsRenderbuffer(depthRB));
1454 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1455 LOCAL_GL_DEPTH_ATTACHMENT,
1456 LOCAL_GL_RENDERBUFFER,
1457 depthRB);
1458 }
1460 if (stencilRB) {
1461 MOZ_ASSERT(fIsRenderbuffer(stencilRB));
1462 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1463 LOCAL_GL_STENCIL_ATTACHMENT,
1464 LOCAL_GL_RENDERBUFFER,
1465 stencilRB);
1466 }
1467 }
1469 bool
1470 GLContext::AssembleOffscreenFBs(const GLuint colorMSRB,
1471 const GLuint depthRB,
1472 const GLuint stencilRB,
1473 const GLuint texture,
1474 GLuint* drawFB_out,
1475 GLuint* readFB_out)
1476 {
1477 if (!colorMSRB && !texture) {
1478 MOZ_ASSERT(!depthRB && !stencilRB);
1480 if (drawFB_out)
1481 *drawFB_out = 0;
1482 if (readFB_out)
1483 *readFB_out = 0;
1485 return true;
1486 }
1488 ScopedBindFramebuffer autoFB(this);
1490 GLuint drawFB = 0;
1491 GLuint readFB = 0;
1493 if (texture) {
1494 readFB = 0;
1495 fGenFramebuffers(1, &readFB);
1496 BindFB(readFB);
1497 fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
1498 LOCAL_GL_COLOR_ATTACHMENT0,
1499 LOCAL_GL_TEXTURE_2D,
1500 texture,
1501 0);
1502 }
1504 if (colorMSRB) {
1505 drawFB = 0;
1506 fGenFramebuffers(1, &drawFB);
1507 BindFB(drawFB);
1508 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1509 LOCAL_GL_COLOR_ATTACHMENT0,
1510 LOCAL_GL_RENDERBUFFER,
1511 colorMSRB);
1512 } else {
1513 drawFB = readFB;
1514 }
1515 MOZ_ASSERT(GetFB() == drawFB);
1517 if (depthRB) {
1518 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1519 LOCAL_GL_DEPTH_ATTACHMENT,
1520 LOCAL_GL_RENDERBUFFER,
1521 depthRB);
1522 }
1524 if (stencilRB) {
1525 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1526 LOCAL_GL_STENCIL_ATTACHMENT,
1527 LOCAL_GL_RENDERBUFFER,
1528 stencilRB);
1529 }
1531 // We should be all resized. Check for framebuffer completeness.
1532 GLenum status;
1533 bool isComplete = true;
1535 if (!IsFramebufferComplete(drawFB, &status)) {
1536 NS_WARNING("DrawFBO: Incomplete");
1537 #ifdef DEBUG
1538 if (DebugMode()) {
1539 printf_stderr("Framebuffer status: %X\n", status);
1540 }
1541 #endif
1542 isComplete = false;
1543 }
1545 if (!IsFramebufferComplete(readFB, &status)) {
1546 NS_WARNING("ReadFBO: Incomplete");
1547 #ifdef DEBUG
1548 if (DebugMode()) {
1549 printf_stderr("Framebuffer status: %X\n", status);
1550 }
1551 #endif
1552 isComplete = false;
1553 }
1555 if (drawFB_out) {
1556 *drawFB_out = drawFB;
1557 } else if (drawFB) {
1558 NS_RUNTIMEABORT("drawFB created when not requested!");
1559 }
1561 if (readFB_out) {
1562 *readFB_out = readFB;
1563 } else if (readFB) {
1564 NS_RUNTIMEABORT("readFB created when not requested!");
1565 }
1567 return isComplete;
1568 }
1572 bool
1573 GLContext::PublishFrame()
1574 {
1575 MOZ_ASSERT(mScreen);
1577 if (!mScreen->PublishFrame(OffscreenSize()))
1578 return false;
1580 return true;
1581 }
1583 SharedSurface_GL*
1584 GLContext::RequestFrame()
1585 {
1586 MOZ_ASSERT(mScreen);
1588 SharedSurface* ret = mScreen->Stream()->SwapConsumer();
1589 if (!ret)
1590 return nullptr;
1592 return SharedSurface_GL::Cast(ret);
1593 }
1597 void
1598 GLContext::ClearSafely()
1599 {
1600 // bug 659349 --- we must be very careful here: clearing a GL framebuffer is nontrivial, relies on a lot of state,
1601 // and in the case of the backbuffer of a WebGL context, state is exposed to scripts.
1602 //
1603 // The code here is taken from WebGLContext::ForceClearFramebufferWithDefaultValues, but I didn't find a good way of
1604 // sharing code with it. WebGL's code is somewhat performance-critical as it is typically called on every frame, so
1605 // WebGL keeps track of GL state to avoid having to query it everytime, and also tries to only do work for actually
1606 // present buffers (e.g. stencil buffer). Doing that here seems like premature optimization,
1607 // as ClearSafely() is called only when e.g. a canvas is resized, not on every animation frame.
1609 realGLboolean scissorTestEnabled;
1610 realGLboolean ditherEnabled;
1611 realGLboolean colorWriteMask[4];
1612 realGLboolean depthWriteMask;
1613 GLint stencilWriteMaskFront, stencilWriteMaskBack;
1614 GLfloat colorClearValue[4];
1615 GLfloat depthClearValue;
1616 GLint stencilClearValue;
1618 // save current GL state
1619 fGetBooleanv(LOCAL_GL_SCISSOR_TEST, &scissorTestEnabled);
1620 fGetBooleanv(LOCAL_GL_DITHER, &ditherEnabled);
1621 fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
1622 fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
1623 fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &stencilWriteMaskFront);
1624 fGetIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
1625 fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
1626 fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
1627 fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue);
1629 // prepare GL state for clearing
1630 fDisable(LOCAL_GL_SCISSOR_TEST);
1631 fDisable(LOCAL_GL_DITHER);
1633 fColorMask(1, 1, 1, 1);
1634 fClearColor(0.f, 0.f, 0.f, 0.f);
1636 fDepthMask(1);
1637 fClearDepth(1.0f);
1639 fStencilMask(0xffffffff);
1640 fClearStencil(0);
1642 // do clear
1643 fClear(LOCAL_GL_COLOR_BUFFER_BIT |
1644 LOCAL_GL_DEPTH_BUFFER_BIT |
1645 LOCAL_GL_STENCIL_BUFFER_BIT);
1647 // restore GL state after clearing
1648 fColorMask(colorWriteMask[0],
1649 colorWriteMask[1],
1650 colorWriteMask[2],
1651 colorWriteMask[3]);
1652 fClearColor(colorClearValue[0],
1653 colorClearValue[1],
1654 colorClearValue[2],
1655 colorClearValue[3]);
1657 fDepthMask(depthWriteMask);
1658 fClearDepth(depthClearValue);
1660 fStencilMaskSeparate(LOCAL_GL_FRONT, stencilWriteMaskFront);
1661 fStencilMaskSeparate(LOCAL_GL_BACK, stencilWriteMaskBack);
1662 fClearStencil(stencilClearValue);
1664 if (ditherEnabled)
1665 fEnable(LOCAL_GL_DITHER);
1666 else
1667 fDisable(LOCAL_GL_DITHER);
1669 if (scissorTestEnabled)
1670 fEnable(LOCAL_GL_SCISSOR_TEST);
1671 else
1672 fDisable(LOCAL_GL_SCISSOR_TEST);
1674 }
1676 void
1677 GLContext::MarkDestroyed()
1678 {
1679 if (IsDestroyed())
1680 return;
1682 if (MakeCurrent()) {
1683 DestroyScreenBuffer();
1685 mBlitHelper = nullptr;
1686 mBlitTextureImageHelper = nullptr;
1687 mReadTexImageHelper = nullptr;
1689 mTexGarbageBin->GLContextTeardown();
1690 } else {
1691 NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown.");
1692 }
1694 mSymbols.Zero();
1695 }
1697 #ifdef MOZ_ENABLE_GL_TRACKING
1698 void
1699 GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
1700 {
1701 mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
1702 }
1704 void
1705 GLContext::CreatedShader(GLContext *aOrigin, GLuint aName)
1706 {
1707 mTrackedShaders.AppendElement(NamedResource(aOrigin, aName));
1708 }
1710 void
1711 GLContext::CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
1712 {
1713 for (GLsizei i = 0; i < aCount; ++i) {
1714 mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
1715 }
1716 }
1718 void
1719 GLContext::CreatedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
1720 {
1721 for (GLsizei i = 0; i < aCount; ++i) {
1722 mTrackedQueries.AppendElement(NamedResource(aOrigin, aNames[i]));
1723 }
1724 }
1726 void
1727 GLContext::CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
1728 {
1729 for (GLsizei i = 0; i < aCount; ++i) {
1730 mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i]));
1731 }
1732 }
1734 void
1735 GLContext::CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
1736 {
1737 for (GLsizei i = 0; i < aCount; ++i) {
1738 mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
1739 }
1740 }
1742 void
1743 GLContext::CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
1744 {
1745 for (GLsizei i = 0; i < aCount; ++i) {
1746 mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
1747 }
1748 }
1750 static void
1751 RemoveNamesFromArray(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames, nsTArray<GLContext::NamedResource>& aArray)
1752 {
1753 for (GLsizei j = 0; j < aCount; ++j) {
1754 GLuint name = aNames[j];
1755 // name 0 can be ignored
1756 if (name == 0)
1757 continue;
1759 for (uint32_t i = 0; i < aArray.Length(); ++i) {
1760 if (aArray[i].name == name) {
1761 aArray.RemoveElementAt(i);
1762 break;
1763 }
1764 }
1765 }
1766 }
1768 void
1769 GLContext::DeletedProgram(GLContext *aOrigin, GLuint aName)
1770 {
1771 RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms);
1772 }
1774 void
1775 GLContext::DeletedShader(GLContext *aOrigin, GLuint aName)
1776 {
1777 RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders);
1778 }
1780 void
1781 GLContext::DeletedBuffers(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames)
1782 {
1783 RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers);
1784 }
1786 void
1787 GLContext::DeletedQueries(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames)
1788 {
1789 RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedQueries);
1790 }
1792 void
1793 GLContext::DeletedTextures(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames)
1794 {
1795 RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures);
1796 }
1798 void
1799 GLContext::DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames)
1800 {
1801 RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers);
1802 }
1804 void
1805 GLContext::DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, const GLuint *aNames)
1806 {
1807 RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers);
1808 }
1810 static void
1811 MarkContextDestroyedInArray(GLContext *aContext, nsTArray<GLContext::NamedResource>& aArray)
1812 {
1813 for (uint32_t i = 0; i < aArray.Length(); ++i) {
1814 if (aArray[i].origin == aContext)
1815 aArray[i].originDeleted = true;
1816 }
1817 }
1819 void
1820 GLContext::SharedContextDestroyed(GLContext *aChild)
1821 {
1822 MarkContextDestroyedInArray(aChild, mTrackedPrograms);
1823 MarkContextDestroyedInArray(aChild, mTrackedShaders);
1824 MarkContextDestroyedInArray(aChild, mTrackedTextures);
1825 MarkContextDestroyedInArray(aChild, mTrackedFramebuffers);
1826 MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers);
1827 MarkContextDestroyedInArray(aChild, mTrackedBuffers);
1828 MarkContextDestroyedInArray(aChild, mTrackedQueries);
1829 }
1831 static void
1832 ReportArrayContents(const char *title, const nsTArray<GLContext::NamedResource>& aArray)
1833 {
1834 if (aArray.Length() == 0)
1835 return;
1837 printf_stderr("%s:\n", title);
1839 nsTArray<GLContext::NamedResource> copy(aArray);
1840 copy.Sort();
1842 GLContext *lastContext = nullptr;
1843 for (uint32_t i = 0; i < copy.Length(); ++i) {
1844 if (lastContext != copy[i].origin) {
1845 if (lastContext)
1846 printf_stderr("\n");
1847 printf_stderr(" [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live");
1848 lastContext = copy[i].origin;
1849 }
1850 printf_stderr("%d ", copy[i].name);
1851 }
1852 printf_stderr("\n");
1853 }
1855 void
1856 GLContext::ReportOutstandingNames()
1857 {
1858 if (!DebugMode())
1859 return;
1861 printf_stderr("== GLContext %p Outstanding ==\n", this);
1863 ReportArrayContents("Outstanding Textures", mTrackedTextures);
1864 ReportArrayContents("Outstanding Buffers", mTrackedBuffers);
1865 ReportArrayContents("Outstanding Queries", mTrackedQueries);
1866 ReportArrayContents("Outstanding Programs", mTrackedPrograms);
1867 ReportArrayContents("Outstanding Shaders", mTrackedShaders);
1868 ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers);
1869 ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers);
1870 }
1872 #endif /* DEBUG */
1875 void
1876 GLContext::GuaranteeResolve()
1877 {
1878 if (mScreen) {
1879 mScreen->AssureBlitted();
1880 }
1881 fFinish();
1882 }
1884 const gfx::IntSize&
1885 GLContext::OffscreenSize() const
1886 {
1887 MOZ_ASSERT(IsOffscreen());
1888 return mScreen->Size();
1889 }
1891 bool
1892 GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps)
1893 {
1894 GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps);
1895 if (!newScreen)
1896 return false;
1898 if (!newScreen->Resize(size)) {
1899 delete newScreen;
1900 return false;
1901 }
1903 DestroyScreenBuffer();
1905 // This will rebind to 0 (Screen) if needed when
1906 // it falls out of scope.
1907 ScopedBindFramebuffer autoFB(this);
1909 mScreen = newScreen;
1911 return true;
1912 }
1914 bool
1915 GLContext::ResizeScreenBuffer(const IntSize& size)
1916 {
1917 if (!IsOffscreenSizeAllowed(size))
1918 return false;
1920 return mScreen->Resize(size);
1921 }
1924 void
1925 GLContext::DestroyScreenBuffer()
1926 {
1927 delete mScreen;
1928 mScreen = nullptr;
1929 }
1931 void
1932 GLContext::ForceDirtyScreen()
1933 {
1934 ScopedBindFramebuffer autoFB(0);
1936 BeforeGLDrawCall();
1937 // no-op; just pretend we did something
1938 AfterGLDrawCall();
1939 }
1941 void
1942 GLContext::CleanDirtyScreen()
1943 {
1944 ScopedBindFramebuffer autoFB(0);
1946 BeforeGLReadCall();
1947 // no-op; we just want to make sure the Read FBO is updated if it needs to be
1948 AfterGLReadCall();
1949 }
1951 void
1952 GLContext::EmptyTexGarbageBin()
1953 {
1954 TexGarbageBin()->EmptyGarbage();
1955 }
1957 bool
1958 GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const {
1959 int32_t biggerDimension = std::max(aSize.width, aSize.height);
1960 int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize);
1961 return biggerDimension <= maxAllowed;
1962 }
1964 bool
1965 GLContext::IsOwningThreadCurrent()
1966 {
1967 return NS_GetCurrentThread() == mOwningThread;
1968 }
1970 void
1971 GLContext::DispatchToOwningThread(nsIRunnable *event)
1972 {
1973 // Before dispatching, we need to ensure we're not in the middle of
1974 // shutting down. Dispatching runnables in the middle of shutdown
1975 // (that is, when the main thread is no longer get-able) can cause them
1976 // to leak. See Bug 741319, and Bug 744115.
1977 nsCOMPtr<nsIThread> mainThread;
1978 if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
1979 mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL);
1980 }
1981 }
1983 GLBlitHelper*
1984 GLContext::BlitHelper()
1985 {
1986 if (!mBlitHelper) {
1987 mBlitHelper = new GLBlitHelper(this);
1988 }
1990 return mBlitHelper;
1991 }
1993 GLBlitTextureImageHelper*
1994 GLContext::BlitTextureImageHelper()
1995 {
1996 if (!mBlitTextureImageHelper) {
1997 mBlitTextureImageHelper = new GLBlitTextureImageHelper(this);
1998 }
2000 return mBlitTextureImageHelper;
2001 }
2003 GLReadTexImageHelper*
2004 GLContext::ReadTexImageHelper()
2005 {
2006 if (!mReadTexImageHelper) {
2007 mReadTexImageHelper = new GLReadTexImageHelper(this);
2008 }
2010 return mReadTexImageHelper;
2011 }
2013 bool
2014 DoesStringMatch(const char* aString, const char *aWantedString)
2015 {
2016 if (!aString || !aWantedString)
2017 return false;
2019 const char *occurrence = strstr(aString, aWantedString);
2021 // aWanted not found
2022 if (!occurrence)
2023 return false;
2025 // aWantedString preceded by alpha character
2026 if (occurrence != aString && isalpha(*(occurrence-1)))
2027 return false;
2029 // aWantedVendor followed by alpha character
2030 const char *afterOccurrence = occurrence + strlen(aWantedString);
2031 if (isalpha(*afterOccurrence))
2032 return false;
2034 return true;
2035 }
2037 } /* namespace gl */
2038 } /* namespace mozilla */