gfx/gl/GLContext.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial