diff options
Diffstat (limited to 'gfx/gl')
76 files changed, 33110 insertions, 0 deletions
diff --git a/gfx/gl/AndroidNativeWindow.h b/gfx/gl/AndroidNativeWindow.h new file mode 100644 index 0000000000..a45fccc099 --- /dev/null +++ b/gfx/gl/AndroidNativeWindow.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AndroidNativeWindow_h__ +#define AndroidNativeWindow_h__ + +#include <jni.h> +#include <android/native_window.h> +#include <android/native_window_jni.h> +#include "mozilla/java/GeckoSurfaceWrappers.h" +#include "SurfaceTexture.h" + +namespace mozilla { +namespace gl { + +class AndroidNativeWindow final { + public: + AndroidNativeWindow() : mNativeWindow(nullptr) {} + + explicit AndroidNativeWindow(java::sdk::Surface::Param aSurface) { + mNativeWindow = + ANativeWindow_fromSurface(jni::GetEnvForThread(), aSurface.Get()); + } + + explicit AndroidNativeWindow(java::GeckoSurface::Param aSurface) { + java::sdk::Surface::LocalRef surf = aSurface->GetSurface(); + mNativeWindow = + ANativeWindow_fromSurface(jni::GetEnvForThread(), surf.Get()); + } + + ~AndroidNativeWindow() { + if (mNativeWindow) { + ANativeWindow_release(mNativeWindow); + mNativeWindow = nullptr; + } + } + + ANativeWindow* NativeWindow() const { return mNativeWindow; } + + private: + ANativeWindow* mNativeWindow; +}; + +} // namespace gl +} // namespace mozilla + +#endif // AndroidNativeWindow_h__ diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp new file mode 100644 index 0000000000..30260efe32 --- /dev/null +++ b/gfx/gl/AndroidSurfaceTexture.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AndroidSurfaceTexture.h" + +#include "GLContextEGL.h" +#include "GLBlitHelper.h" +#include "GLImages.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/LayersSurfaces.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/java/GeckoSurfaceTextureNatives.h" +# include "AndroidNativeWindow.h" +#endif // MOZ_WIDGET_ANDROID + +namespace mozilla { +namespace gl { + +class AndroidSharedBlitGL final { + public: + explicit AndroidSharedBlitGL(const EGLNativeWindowType window) { + StaticMutexAutoLock lock(sMutex); + + if (!sContext) { + MOZ_ASSERT(sInstanceCount == 0); + sContext = CreateContext(); + if (!sContext) { + return; + } + } + + const auto& egl = *(sContext->mEgl); + mTargetSurface = + egl.fCreateWindowSurface(sContext->mSurfaceConfig, window, nullptr); + + ++sInstanceCount; + } + + ~AndroidSharedBlitGL() { + StaticMutexAutoLock lock(sMutex); + + if (mTargetSurface != EGL_NO_SURFACE) { + const auto& egl = *(sContext->mEgl); + egl.fDestroySurface(mTargetSurface); + } + + // Destroy shared GL context when no one uses it. + if (--sInstanceCount == 0) { + sContext = nullptr; + } + } + +#ifdef MOZ_WIDGET_ANDROID + void Blit(const java::GeckoSurfaceTexture::Ref& surfaceTexture, + const gfx::IntSize& imageSize) { + StaticMutexAutoLock lock(sMutex); + MOZ_ASSERT(sContext); + + // Setting overide also makes conext and surface current. + sContext->SetEGLSurfaceOverride(mTargetSurface); + DebugOnly<bool> rv = sContext->BlitHelper()->Blit(surfaceTexture, imageSize, + OriginPos::TopLeft); + MOZ_ASSERT(rv); + sContext->SwapBuffers(); + // This method is called through binder IPC and could run on any thread in + // the pool. Release the context and surface from this thread after use so + // they can be bound to another thread later. + UnmakeCurrent(sContext); + } +#endif + + private: + static already_AddRefed<GLContextEGL> CreateContextImpl(bool aUseGles) { + sMutex.AssertCurrentThreadOwns(); + MOZ_ASSERT(!sContext); + + nsCString ignored; + const auto egl = gl::DefaultEglDisplay(&ignored); + EGLConfig eglConfig; + CreateConfig(*egl, &eglConfig, /* bpp */ 24, /* depth buffer? */ false, + aUseGles); + auto gl = GLContextEGL::CreateGLContext(egl, {}, eglConfig, EGL_NO_SURFACE, + true, eglConfig, &ignored); + if (!gl) { + NS_WARNING("Fail to create GL context for native blitter."); + return nullptr; + } + gl->mOwningThreadId = Nothing(); + + // Yield the current state made in constructor. + UnmakeCurrent(gl); + return gl.forget(); + } + + static already_AddRefed<GLContextEGL> CreateContext() { + RefPtr<GLContextEGL> gl; +#if !defined(MOZ_WIDGET_ANDROID) + gl = CreateContextImpl(/* aUseGles */ false); +#endif // !defined(MOZ_WIDGET_ANDROID) + + if (!gl) { + gl = CreateContextImpl(/* aUseGles */ true); + } + return gl.forget(); + } + + static bool UnmakeCurrent(GLContextEGL* const gl) { + sMutex.AssertCurrentThreadOwns(); + MOZ_ASSERT(gl); + + if (!gl->IsCurrent()) { + return true; + } + const auto& egl = *(gl->mEgl); + return egl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + static StaticMutex sMutex MOZ_UNANNOTATED; + static StaticRefPtr<GLContextEGL> sContext; + static size_t sInstanceCount; + + EGLSurface mTargetSurface; +}; + +StaticMutex AndroidSharedBlitGL::sMutex; +StaticRefPtr<GLContextEGL> AndroidSharedBlitGL::sContext; +size_t AndroidSharedBlitGL::sInstanceCount = 0; + +// - +#ifdef MOZ_WIDGET_ANDROID + +void AndroidSurfaceTexture::GetTransformMatrix( + java::sdk::SurfaceTexture::Param surfaceTexture, + gfx::Matrix4x4* outMatrix) { + JNIEnv* const env = jni::GetEnvForThread(); + + auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16)); + surfaceTexture->GetTransformMatrix(jarray); + + jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr); + + memcpy(&(outMatrix->_11), array, sizeof(float) * 16); + + env->ReleaseFloatArrayElements(jarray.Get(), array, 0); +} + +class GLBlitterSupport final + : public java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives< + GLBlitterSupport> { + public: + using Base = + java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives<GLBlitterSupport>; + using Base::AttachNative; + using Base::DisposeNative; + using Base::GetNative; + + static java::GeckoSurfaceTexture::NativeGLBlitHelper::LocalRef NativeCreate( + jlong sourceTextureHandle, jni::Object::Param targetSurface, jint width, + jint height) { + AndroidNativeWindow win(java::GeckoSurface::Ref::From(targetSurface)); + auto helper = java::GeckoSurfaceTexture::NativeGLBlitHelper::New(); + const auto& eglWindow = win.NativeWindow(); + GLBlitterSupport::AttachNative( + helper, + MakeUnique<GLBlitterSupport>(MakeUnique<AndroidSharedBlitGL>(eglWindow), + sourceTextureHandle, width, height)); + return helper; + } + + GLBlitterSupport(UniquePtr<AndroidSharedBlitGL>&& gl, + jlong sourceTextureHandle, jint width, jint height) + : mGl(std::move(gl)), + mSourceTextureHandle(sourceTextureHandle), + mSize(width, height) {} + + void Blit() { + auto surfaceTexture = + java::GeckoSurfaceTexture::Lookup(mSourceTextureHandle); + mGl->Blit(surfaceTexture, mSize); + } + + private: + const UniquePtr<AndroidSharedBlitGL> mGl; + const AndroidSurfaceTextureHandle mSourceTextureHandle; + const gfx::IntSize mSize; +}; + +void AndroidSurfaceTexture::Init() { GLBlitterSupport::Init(); } + +#endif // MOZ_WIDGET_ANDROID + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/AndroidSurfaceTexture.h b/gfx/gl/AndroidSurfaceTexture.h new file mode 100644 index 0000000000..bf9a5ed6ae --- /dev/null +++ b/gfx/gl/AndroidSurfaceTexture.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AndroidSurfaceTexture_h__ +#define AndroidSurfaceTexture_h__ + +#include "mozilla/gfx/Matrix.h" + +typedef uint64_t AndroidSurfaceTextureHandle; + +#ifdef MOZ_WIDGET_ANDROID + +# include "SurfaceTexture.h" + +namespace mozilla { +namespace gl { + +class AndroidSurfaceTexture { + public: + static void Init(); + static void GetTransformMatrix( + java::sdk::SurfaceTexture::Param surfaceTexture, + mozilla::gfx::Matrix4x4* outMatrix); +}; + +} // namespace gl +} // namespace mozilla + +#endif // MOZ_WIDGET_ANDROID + +#endif // AndroidSurfaceTexture_h__ diff --git a/gfx/gl/AutoMappable.h b/gfx/gl/AutoMappable.h new file mode 100644 index 0000000000..f93b2ccb57 --- /dev/null +++ b/gfx/gl/AutoMappable.h @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_AUTO_MAPPABLE_H +#define MOZILLA_AUTO_MAPPABLE_H + +// Here be dragons. + +#include <functional> + +namespace mozilla::gfx { + +template <class T> +size_t Hash(const T&); + +template <class T> +struct StaticStdHasher { + static auto HashImpl(const T& v) { return std::hash<T>()(v); } +}; + +template <class T> +struct StaticHasher { + static auto HashImpl(const T& v) { return v.hash(); } +}; +template <class T> +struct StaticHasher<std::optional<T>> { + static size_t HashImpl(const std::optional<T>& v) { + if (!v) return 0; + return Hash(*v); + } +}; +template <> +struct StaticHasher<int> : public StaticStdHasher<int> {}; +template <> +struct StaticHasher<bool> : public StaticStdHasher<bool> {}; +template <> +struct StaticHasher<float> : public StaticStdHasher<float> {}; + +template <class T> +size_t Hash(const T& v) { + return StaticHasher<T>::HashImpl(v); +} + +//- +// From Boost: +// https://www.boost.org/doc/libs/1_37_0/doc/html/hash/reference.html#boost.hash_combine + +inline size_t HashCombine(size_t seed, const size_t hash) { + seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; +} + +// - +// See +// https://codereview.stackexchange.com/questions/136770/hashing-a-tuple-in-c17 + +template <class... Args, size_t... Ids> +size_t HashTupleN(const std::tuple<Args...>& tup, + const std::index_sequence<Ids...>&) { + size_t seed = 0; + for (const auto& hash : {Hash(std::get<Ids>(tup))...}) { + seed = HashCombine(seed, hash); + } + return seed; +} + +template <class... Args> +size_t HashTuple(const std::tuple<Args...>& tup) { + return HashTupleN(tup, std::make_index_sequence<sizeof...(Args)>()); +} + +// - + +template <class T> +auto MembersEq(const T& a, const T& b) { + const auto atup = a.Members(); + const auto btup = b.Members(); + return atup == btup; +} + +template <class T> +auto MembersLt(const T& a, const T& b) { + const auto atup = a.Members(); + const auto btup = b.Members(); + return atup == btup; +} + +template <class T> +auto MembersHash(const T& a) { + const auto atup = a.Members(); + return HashTuple(atup); +} + +template <class T> +struct MembersHasher final { + auto operator()(const T& v) const { return v.hash(); } +}; + +/** E.g.: +struct Foo { + int i; + bool b; + + auto Members() const { return std::tie(i, b); } + INLINE_AUTO_MAPPABLE(Foo) +}; +std::unordered_set<T, T::Hasher> easy; +**/ +#define INLINE_DERIVE_MEMBERS_EQ(T) \ + friend bool operator==(const T& a, const T& b) { \ + return mozilla::gfx::MembersEq(a, b); \ + } \ + friend bool operator!=(const T& a, const T& b) { return !operator==(a, b); } +#define INLINE_AUTO_MAPPABLE(T) \ + friend bool operator<(const T& a, const T& b) { \ + return mozilla::gfx::MembersLt(a, b); \ + } \ + INLINE_DERIVE_MEMBERS_EQ(T) \ + size_t hash() const { \ + return mozilla::gfx::MembersHash(*reinterpret_cast<const T*>(this)); \ + } \ + using Hasher = mozilla::gfx::MembersHasher<T>; + +// - + +/** E.g.: +``` +struct Foo : public AutoMappable<Foo> { + int i; + bool b; + + auto Members() const { return std::tie(i, b); } +}; +std::unordered_set<T, T::Hasher> easy; +``` +`easy.insert({{}, 2, true});` +The initial {} is needed for aggregate initialization of AutoMappable<Foo>. +Use INLINE_AUTO_MAPPABLE if this is too annoying. +**/ +template <class T> +struct AutoMappable { + INLINE_AUTO_MAPPABLE(T) +}; + +} // namespace mozilla::gfx + +#endif // MOZILLA_AUTO_MAPPABLE_H diff --git a/gfx/gl/Colorspaces.cpp b/gfx/gl/Colorspaces.cpp new file mode 100644 index 0000000000..29ddf37cd9 --- /dev/null +++ b/gfx/gl/Colorspaces.cpp @@ -0,0 +1,435 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// We are going to be doing so, so many transforms, so descriptive labels are +// critical. + +#include "Colorspaces.h" + +#include "nsDebug.h" +#include "qcms.h" + +namespace mozilla::color { + +// tf = { k * linear | linear < b +// { a * pow(linear, 1/g) - (1-a) | linear >= b +float TfFromLinear(const PiecewiseGammaDesc& desc, const float linear) { + if (linear < desc.b) { + return linear * desc.k; + } + float ret = linear; + ret = powf(ret, 1.0f / desc.g); + ret *= desc.a; + ret -= (desc.a - 1); + return ret; +} + +float LinearFromTf(const PiecewiseGammaDesc& desc, const float tf) { + const auto linear_if_low = tf / desc.k; + if (linear_if_low < desc.b) { + return linear_if_low; + } + float ret = tf; + ret += (desc.a - 1); + ret /= desc.a; + ret = powf(ret, 1.0f * desc.g); + return ret; +} + +// - + +mat3 YuvFromRgb(const YuvLumaCoeffs& yc) { + // Y is always [0,1] + // U and V are signed, and could be either [-1,+1] or [-0.5,+0.5]. + // Specs generally use [-0.5,+0.5], so we use that too. + // E.g. + // y = 0.2126*r + 0.7152*g + 0.0722*b + // u = (b - y) / (u_range = u_max - u_min) // u_min = -u_max + // = (b - y) / (u(0,0,1) - u(1,1,0)) + // = (b - y) / (2 * u(0,0,1)) + // = (b - y) / (2 * u.b)) + // = (b - y) / (2 * (1 - 0.0722)) + // = (-0.2126*r + -0.7152*g + (1-0.0722)*b) / 1.8556 + // v = (r - y) / 1.5748; + // = ((1-0.2126)*r + -0.7152*g + -0.0722*b) / 1.5748 + const auto y = vec3({yc.r, yc.g, yc.b}); + const auto u = vec3({0, 0, 1}) - y; + const auto v = vec3({1, 0, 0}) - y; + + // From rows: + return mat3({y, u / (2 * u.z()), v / (2 * v.x())}); +} + +mat4 YuvFromYcbcr(const YcbcrDesc& d) { + // E.g. + // y = (yy - 16) / (235 - 16); // 16->0, 235->1 + // u = (cb - 128) / (240 - 16); // 16->-0.5, 128->0, 240->+0.5 + // v = (cr - 128) / (240 - 16); + + const auto yRange = d.y1 - d.y0; + const auto uHalfRange = d.uPlusHalf - d.u0; + const auto uRange = 2 * uHalfRange; + + const auto ycbcrFromYuv = mat4{{vec4{{yRange, 0, 0, d.y0}}, + {{0, uRange, 0, d.u0}}, + {{0, 0, uRange, d.u0}}, + {{0, 0, 0, 1}}}}; + const auto yuvFromYcbcr = inverse(ycbcrFromYuv); + return yuvFromYcbcr; +} + +inline vec3 CIEXYZ_from_CIExyY(const vec2 xy, const float Y = 1) { + const auto xyz = vec3(xy, 1 - xy.x() - xy.y()); + const auto XYZ = xyz * (Y / xy.y()); + return XYZ; +} + +mat3 XyzFromLinearRgb(const Chromaticities& c) { + // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + + // Given red (xr, yr), green (xg, yg), blue (xb, yb), + // and whitepoint (XW, YW, ZW) + + // [ X ] [ R ] + // [ Y ] = M x [ G ] + // [ Z ] [ B ] + + // [ Sr*Xr Sg*Xg Sb*Xb ] + // M = [ Sr*Yr Sg*Yg Sb*Yb ] + // [ Sr*Zr Sg*Zg Sb*Zb ] + + // Xr = xr / yr + // Yr = 1 + // Zr = (1 - xr - yr) / yr + + // Xg = xg / yg + // Yg = 1 + // Zg = (1 - xg - yg) / yg + + // Xb = xb / yb + // Yb = 1 + // Zb = (1 - xb - yb) / yb + + // [ Sr ] [ Xr Xg Xb ]^-1 [ XW ] + // [ Sg ] = [ Yr Yg Yb ] x [ YW ] + // [ Sb ] [ Zr Zg Zb ] [ ZW ] + + const auto xrgb = vec3({c.rx, c.gx, c.bx}); + const auto yrgb = vec3({c.ry, c.gy, c.by}); + + const auto Xrgb = xrgb / yrgb; + const auto Yrgb = vec3(1); + const auto Zrgb = (vec3(1) - xrgb - yrgb) / yrgb; + + const auto XYZrgb = mat3({Xrgb, Yrgb, Zrgb}); + const auto XYZrgb_inv = inverse(XYZrgb); + const auto XYZwhitepoint = vec3({c.wx, c.wy, 1 - c.wx - c.wy}) / c.wy; + const auto Srgb = XYZrgb_inv * XYZwhitepoint; + + const auto M = mat3({Srgb * Xrgb, Srgb * Yrgb, Srgb * Zrgb}); + return M; +} + +// - +ColorspaceTransform ColorspaceTransform::Create(const ColorspaceDesc& src, + const ColorspaceDesc& dst) { + auto ct = ColorspaceTransform{src, dst}; + ct.srcTf = src.tf; + ct.dstTf = dst.tf; + + const auto RgbTfFrom = [&](const ColorspaceDesc& cs) { + auto rgbFrom = mat4::Identity(); + if (cs.yuv) { + const auto yuvFromYcbcr = YuvFromYcbcr(cs.yuv->ycbcr); + const auto yuvFromRgb = YuvFromRgb(cs.yuv->yCoeffs); + const auto rgbFromYuv = inverse(yuvFromRgb); + const auto rgbFromYuv4 = mat4(rgbFromYuv); + + const auto rgbFromYcbcr = rgbFromYuv4 * yuvFromYcbcr; + rgbFrom = rgbFromYcbcr; + } + return rgbFrom; + }; + + ct.srcRgbTfFromSrc = RgbTfFrom(src); + const auto dstRgbTfFromDst = RgbTfFrom(dst); + ct.dstFromDstRgbTf = inverse(dstRgbTfFromDst); + + // - + + ct.dstRgbLinFromSrcRgbLin = mat3::Identity(); + if (!(src.chrom == dst.chrom)) { + const auto xyzFromSrcRgbLin = XyzFromLinearRgb(src.chrom); + const auto xyzFromDstRgbLin = XyzFromLinearRgb(dst.chrom); + const auto dstRgbLinFromXyz = inverse(xyzFromDstRgbLin); + ct.dstRgbLinFromSrcRgbLin = dstRgbLinFromXyz * xyzFromSrcRgbLin; + } + + return ct; +} + +vec3 ColorspaceTransform::DstFromSrc(const vec3 src) const { + const auto srcRgbTf = srcRgbTfFromSrc * vec4(src, 1); + auto srcRgbLin = srcRgbTf; + if (srcTf) { + srcRgbLin.x(LinearFromTf(*srcTf, srcRgbTf.x())); + srcRgbLin.y(LinearFromTf(*srcTf, srcRgbTf.y())); + srcRgbLin.z(LinearFromTf(*srcTf, srcRgbTf.z())); + } + + const auto dstRgbLin = dstRgbLinFromSrcRgbLin * vec3(srcRgbLin); + auto dstRgbTf = dstRgbLin; + if (dstTf) { + dstRgbTf.x(TfFromLinear(*dstTf, dstRgbLin.x())); + dstRgbTf.y(TfFromLinear(*dstTf, dstRgbLin.y())); + dstRgbTf.z(TfFromLinear(*dstTf, dstRgbLin.z())); + } + + const auto dst4 = dstFromDstRgbTf * vec4(dstRgbTf, 1); + return vec3(dst4); +} + +// - + +mat3 XyzAFromXyzB_BradfordLinear(const vec2 xyA, const vec2 xyB) { + // This is what ICC profiles use to do whitepoint transforms, + // because ICC also requires D50 for the Profile Connection Space. + + // From https://www.color.org/specification/ICC.1-2022-05.pdf + // E.3 "Linearized Bradford transformation": + + const auto M_BFD = mat3{{ + vec3{{0.8951, 0.2664f, -0.1614f}}, + vec3{{-0.7502f, 1.7135f, 0.0367f}}, + vec3{{0.0389f, -0.0685f, 1.0296f}}, + }}; + // NB: They use rho/gamma/beta, but we'll use R/G/B here. + const auto XYZDst = CIEXYZ_from_CIExyY(xyA); // "XYZ_W", WP of PCS + const auto XYZSrc = CIEXYZ_from_CIExyY(xyB); // "XYZ_NAW", WP of src + const auto rgbSrc = M_BFD * XYZSrc; // "RGB_SRC" + const auto rgbDst = M_BFD * XYZDst; // "RGB_PCS" + const auto rgbDstOverSrc = rgbDst / rgbSrc; + const auto M_dstOverSrc = mat3::Scale(rgbDstOverSrc); + const auto M_adapt = inverse(M_BFD) * M_dstOverSrc * M_BFD; + return M_adapt; +} + +std::optional<mat4> ColorspaceTransform::ToMat4() const { + mat4 fromSrc = srcRgbTfFromSrc; + if (srcTf) return {}; + fromSrc = mat4(dstRgbLinFromSrcRgbLin) * fromSrc; + if (dstTf) return {}; + fromSrc = dstFromDstRgbTf * fromSrc; + return fromSrc; +} + +Lut3 ColorspaceTransform::ToLut3(const ivec3 size) const { + auto lut = Lut3::Create(size); + lut.SetMap([&](const vec3& srcVal) { return DstFromSrc(srcVal); }); + return lut; +} + +vec3 Lut3::Sample(const vec3 in01) const { + const auto coord = vec3(size - 1) * in01; + const auto p0 = floor(coord); + const auto dp = coord - p0; + const auto ip0 = ivec3(p0); + + // Trilinear + const auto f000 = Fetch(ip0 + ivec3({0, 0, 0})); + const auto f100 = Fetch(ip0 + ivec3({1, 0, 0})); + const auto f010 = Fetch(ip0 + ivec3({0, 1, 0})); + const auto f110 = Fetch(ip0 + ivec3({1, 1, 0})); + const auto f001 = Fetch(ip0 + ivec3({0, 0, 1})); + const auto f101 = Fetch(ip0 + ivec3({1, 0, 1})); + const auto f011 = Fetch(ip0 + ivec3({0, 1, 1})); + const auto f111 = Fetch(ip0 + ivec3({1, 1, 1})); + + const auto fx00 = mix(f000, f100, dp.x()); + const auto fx10 = mix(f010, f110, dp.x()); + const auto fx01 = mix(f001, f101, dp.x()); + const auto fx11 = mix(f011, f111, dp.x()); + + const auto fxy0 = mix(fx00, fx10, dp.y()); + const auto fxy1 = mix(fx01, fx11, dp.y()); + + const auto fxyz = mix(fxy0, fxy1, dp.z()); + return fxyz; +} + +// - + +ColorProfileDesc ColorProfileDesc::From(const ColorspaceDesc& cspace) { + auto ret = ColorProfileDesc{}; + + if (cspace.yuv) { + const auto yuvFromYcbcr = YuvFromYcbcr(cspace.yuv->ycbcr); + const auto yuvFromRgb = YuvFromRgb(cspace.yuv->yCoeffs); + const auto rgbFromYuv = inverse(yuvFromRgb); + ret.rgbFromYcbcr = mat4(rgbFromYuv) * yuvFromYcbcr; + } + + if (cspace.tf) { + const size_t tableSize = 256; + auto& tableR = ret.linearFromTf.r; + tableR.resize(tableSize); + for (size_t i = 0; i < tableR.size(); i++) { + const float tfVal = i / float(tableR.size() - 1); + const float linearVal = LinearFromTf(*cspace.tf, tfVal); + tableR[i] = linearVal; + } + ret.linearFromTf.g = tableR; + ret.linearFromTf.b = tableR; + } + + ret.xyzd65FromLinearRgb = XyzFromLinearRgb(cspace.chrom); + + return ret; +} + +// - + +template <class T> +constexpr inline T NewtonEstimateX(const T x1, const T y1, const T dydx, + const T y2 = 0) { + // Estimate x s.t. y=0 + // y = y0 + x*dydx; + // y0 = y - x*dydx; + // y1 - x1*dydx = y2 - x2*dydx + // x2*dydx = y2 - y1 + x1*dydx + // x2 = (y2 - y1)/dydx + x1 + return (y2 - y1) / dydx + x1; +} + +float GuessGamma(const std::vector<float>& vals, float exp_guess) { + // Approximate (signed) error = 0.0. + constexpr float d_exp = 0.001; + constexpr float error_tolerance = 0.001; + struct Samples { + float y1, y2; + }; + const auto Sample = [&](const float exp) { + int i = -1; + auto samples = Samples{}; + for (const auto& expected : vals) { + i += 1; + const auto in = i / float(vals.size() - 1); + samples.y1 += powf(in, exp) - expected; + samples.y2 += powf(in, exp + d_exp) - expected; + } + samples.y1 /= vals.size(); // Normalize by val count. + samples.y2 /= vals.size(); + return samples; + }; + constexpr int MAX_ITERS = 10; + for (int i = 1;; i++) { + const auto err = Sample(exp_guess); + const auto derr = err.y2 - err.y1; + exp_guess = NewtonEstimateX(exp_guess, err.y1, derr / d_exp); + // Check if we were close before, because then this last round of estimation + // should get us pretty much right on it. + if (std::abs(err.y1) < error_tolerance) { + return exp_guess; + } + if (i >= MAX_ITERS) { + printf_stderr("GuessGamma() -> %f after %i iterations (avg err %f)\n", + exp_guess, i, err.y1); + MOZ_ASSERT(false, "GuessGamma failed."); + return exp_guess; + } + } +} + +// - + +ColorProfileDesc ColorProfileDesc::From(const qcms_profile& qcmsProfile) { + ColorProfileDesc ret; + + qcms_profile_data data = {}; + qcms_profile_get_data(&qcmsProfile, &data); + + auto xyzd50FromLinearRgb = mat3{}; + // X contributions from [R,G,B] + xyzd50FromLinearRgb.at(0, 0) = data.red_colorant_xyzd50[0]; + xyzd50FromLinearRgb.at(1, 0) = data.green_colorant_xyzd50[0]; + xyzd50FromLinearRgb.at(2, 0) = data.blue_colorant_xyzd50[0]; + // Y contributions from [R,G,B] + xyzd50FromLinearRgb.at(0, 1) = data.red_colorant_xyzd50[1]; + xyzd50FromLinearRgb.at(1, 1) = data.green_colorant_xyzd50[1]; + xyzd50FromLinearRgb.at(2, 1) = data.blue_colorant_xyzd50[1]; + // Z contributions from [R,G,B] + xyzd50FromLinearRgb.at(0, 2) = data.red_colorant_xyzd50[2]; + xyzd50FromLinearRgb.at(1, 2) = data.green_colorant_xyzd50[2]; + xyzd50FromLinearRgb.at(2, 2) = data.blue_colorant_xyzd50[2]; + + const auto d65FromD50 = XyzAFromXyzB_BradfordLinear(D65, D50); + ret.xyzd65FromLinearRgb = d65FromD50 * xyzd50FromLinearRgb; + + // - + + const auto Fn = [&](std::vector<float>* const linearFromTf, + int32_t claimed_samples, + const qcms_color_channel channel) { + if (claimed_samples == 0) return; // No tf. + + if (claimed_samples == -1) { + claimed_samples = 4096; // Ask it to generate a bunch. + claimed_samples = 256; // Ask it to generate a bunch. + } + + linearFromTf->resize(AssertedCast<size_t>(claimed_samples)); + + const auto begin = linearFromTf->data(); + qcms_profile_get_lut(&qcmsProfile, channel, begin, + begin + linearFromTf->size()); + }; + + Fn(&ret.linearFromTf.r, data.linear_from_trc_red_samples, + qcms_color_channel::Red); + Fn(&ret.linearFromTf.b, data.linear_from_trc_blue_samples, + qcms_color_channel::Blue); + Fn(&ret.linearFromTf.g, data.linear_from_trc_green_samples, + qcms_color_channel::Green); + + // - + + return ret; +} + +// - + +ColorProfileConversionDesc ColorProfileConversionDesc::From( + const FromDesc& desc) { + const auto dstLinearRgbFromXyzd65 = inverse(desc.dst.xyzd65FromLinearRgb); + auto ret = ColorProfileConversionDesc{ + .srcRgbFromSrcYuv = desc.src.rgbFromYcbcr, + .srcLinearFromSrcTf = desc.src.linearFromTf, + .dstLinearFromSrcLinear = + dstLinearRgbFromXyzd65 * desc.src.xyzd65FromLinearRgb, + .dstTfFromDstLinear = {}, + }; + bool sameTF = true; + sameTF &= desc.src.linearFromTf.r == desc.dst.linearFromTf.r; + sameTF &= desc.src.linearFromTf.g == desc.dst.linearFromTf.g; + sameTF &= desc.src.linearFromTf.b == desc.dst.linearFromTf.b; + if (sameTF) { + ret.srcLinearFromSrcTf = {}; + ret.dstTfFromDstLinear = {}; + } else { + const auto Invert = [](const std::vector<float>& linearFromTf, + std::vector<float>* const tfFromLinear) { + const auto size = linearFromTf.size(); + MOZ_ASSERT(size != 1); // Less than two is uninvertable. + if (size < 2) return; + (*tfFromLinear).resize(size); + InvertLut(linearFromTf, &*tfFromLinear); + }; + Invert(desc.dst.linearFromTf.r, &ret.dstTfFromDstLinear.r); + Invert(desc.dst.linearFromTf.g, &ret.dstTfFromDstLinear.g); + Invert(desc.dst.linearFromTf.b, &ret.dstTfFromDstLinear.b); + } + return ret; +} + +} // namespace mozilla::color diff --git a/gfx/gl/Colorspaces.h b/gfx/gl/Colorspaces.h new file mode 100644 index 0000000000..8f36854d2d --- /dev/null +++ b/gfx/gl/Colorspaces.h @@ -0,0 +1,987 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_GL_COLORSPACES_H_ +#define MOZILLA_GFX_GL_COLORSPACES_H_ + +// Reference: https://hackmd.io/0wkiLmP7RWOFjcD13M870A + +// We are going to be doing so, so many transforms, so descriptive labels are +// critical. + +// Colorspace background info: https://hackmd.io/0wkiLmP7RWOFjcD13M870A + +#include <algorithm> +#include <array> +#include <cmath> +#include <cstdint> +#include <cstdlib> +#include <functional> +#include <optional> +#include <vector> + +#include "AutoMappable.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Span.h" + +#ifdef DEBUG +# define ASSERT(EXPR) \ + do { \ + if (!(EXPR)) { \ + __builtin_trap(); \ + } \ + } while (false) +#else +# define ASSERT(EXPR) (void)(EXPR) +#endif + +struct _qcms_profile; +typedef struct _qcms_profile qcms_profile; + +namespace mozilla::color { + +struct YuvLumaCoeffs final { + float r = 0.2126; + float g = 0.7152; + float b = 0.0722; + + auto Members() const { return std::tie(r, g, b); } + INLINE_AUTO_MAPPABLE(YuvLumaCoeffs) + + static constexpr auto Rec709() { return YuvLumaCoeffs(); } + + static constexpr auto Rec2020() { + return YuvLumaCoeffs{0.2627, 0.6780, 0.0593}; + } +}; + +struct PiecewiseGammaDesc final { + // tf = { k * linear | linear < b + // { a * pow(linear, 1/g) - (1-a) | linear >= b + + // Default to Srgb + float a = 1.055; + float b = 0.04045 / 12.92; + float g = 2.4; + float k = 12.92; + + auto Members() const { return std::tie(a, b, g, k); } + INLINE_AUTO_MAPPABLE(PiecewiseGammaDesc) + + static constexpr auto Srgb() { return PiecewiseGammaDesc(); } + static constexpr auto DisplayP3() { return Srgb(); } + + static constexpr auto Rec709() { + return PiecewiseGammaDesc{ + 1.099, + 0.018, + 1.0 / 0.45, // ~2.222 + 4.5, + }; + } + // FYI: static constexpr auto Rec2020_10bit() { return Rec709(); } + static constexpr auto Rec2020_12bit() { + return PiecewiseGammaDesc{ + 1.0993, + 0.0181, + 1.0 / 0.45, // ~2.222 + 4.5, + }; + } +}; + +struct YcbcrDesc final { + float y0 = 16 / 255.0; + float y1 = 235 / 255.0; + float u0 = 128 / 255.0; + float uPlusHalf = 240 / 255.0; + + auto Members() const { return std::tie(y0, y1, u0, uPlusHalf); } + INLINE_AUTO_MAPPABLE(YcbcrDesc) + + static constexpr auto Narrow8() { // AKA limited/studio/tv + return YcbcrDesc(); + } + static constexpr auto Full8() { // AKA pc + return YcbcrDesc{ + 0 / 255.0, + 255 / 255.0, + 128 / 255.0, + 254 / 255.0, + }; + } + static constexpr auto Float() { // Best for a LUT + return YcbcrDesc{0.0, 1.0, 0.5, 1.0}; + } +}; + +struct Chromaticities final { + float rx = 0.640; + float ry = 0.330; + float gx = 0.300; + float gy = 0.600; + float bx = 0.150; + float by = 0.060; + // D65: + static constexpr float wx = 0.3127; + static constexpr float wy = 0.3290; + + auto Members() const { return std::tie(rx, ry, gx, gy, bx, by); } + INLINE_AUTO_MAPPABLE(Chromaticities) + + // - + + static constexpr auto Rec709() { // AKA limited/studio/tv + return Chromaticities(); + } + static constexpr auto Srgb() { return Rec709(); } + + static constexpr auto Rec601_625_Pal() { + auto ret = Rec709(); + ret.gx = 0.290; + return ret; + } + static constexpr auto Rec601_525_Ntsc() { + return Chromaticities{ + 0.630, 0.340, // r + 0.310, 0.595, // g + 0.155, 0.070, // b + }; + } + static constexpr auto Rec2020() { + return Chromaticities{ + 0.708, 0.292, // r + 0.170, 0.797, // g + 0.131, 0.046, // b + }; + } + static constexpr auto DisplayP3() { + return Chromaticities{ + 0.680, 0.320, // r + 0.265, 0.690, // g + 0.150, 0.060, // b + }; + } +}; + +// - + +struct YuvDesc final { + YuvLumaCoeffs yCoeffs; + YcbcrDesc ycbcr; + + auto Members() const { return std::tie(yCoeffs, ycbcr); } + INLINE_AUTO_MAPPABLE(YuvDesc); +}; + +struct ColorspaceDesc final { + Chromaticities chrom; + std::optional<PiecewiseGammaDesc> tf; + std::optional<YuvDesc> yuv; + + auto Members() const { return std::tie(chrom, tf, yuv); } + INLINE_AUTO_MAPPABLE(ColorspaceDesc); +}; + +// - + +template <class TT, int NN> +struct avec final { + using T = TT; + static constexpr auto N = NN; + + std::array<T, N> data = {}; + + // - + + constexpr avec() = default; + constexpr avec(const avec&) = default; + + constexpr avec(const avec<T, N - 1>& v, T a) { + for (int i = 0; i < N - 1; i++) { + data[i] = v[i]; + } + data[N - 1] = a; + } + constexpr avec(const avec<T, N - 2>& v, T a, T b) { + for (int i = 0; i < N - 2; i++) { + data[i] = v[i]; + } + data[N - 2] = a; + data[N - 1] = b; + } + + MOZ_IMPLICIT constexpr avec(const std::array<T, N>& data) { + this->data = data; + } + + explicit constexpr avec(const T v) { + for (int i = 0; i < N; i++) { + data[i] = v; + } + } + + template <class T2, int N2> + explicit constexpr avec(const avec<T2, N2>& v) { + const auto n = std::min(N, N2); + for (int i = 0; i < n; i++) { + data[i] = static_cast<T>(v[i]); + } + } + + // - + + const auto& operator[](const size_t n) const { return data[n]; } + auto& operator[](const size_t n) { return data[n]; } + + template <int i> + constexpr auto get() const { + return (i < N) ? data[i] : 0; + } + constexpr auto x() const { return get<0>(); } + constexpr auto y() const { return get<1>(); } + constexpr auto z() const { return get<2>(); } + constexpr auto w() const { return get<3>(); } + + constexpr auto xyz() const { return vec3({x(), y(), z()}); } + + template <int i> + void set(const T v) { + if (i < N) { + data[i] = v; + } + } + void x(const T v) { set<0>(v); } + void y(const T v) { set<1>(v); } + void z(const T v) { set<2>(v); } + void w(const T v) { set<3>(v); } + + // - + +#define _(OP) \ + friend avec operator OP(const avec a, const avec b) { \ + avec c; \ + for (int i = 0; i < N; i++) { \ + c[i] = a[i] OP b[i]; \ + } \ + return c; \ + } \ + friend avec operator OP(const avec a, const T b) { \ + avec c; \ + for (int i = 0; i < N; i++) { \ + c[i] = a[i] OP b; \ + } \ + return c; \ + } \ + friend avec operator OP(const T a, const avec b) { \ + avec c; \ + for (int i = 0; i < N; i++) { \ + c[i] = a OP b[i]; \ + } \ + return c; \ + } + _(+) + _(-) + _(*) + _(/) +#undef _ + + friend bool operator==(const avec a, const avec b) { + bool eq = true; + for (int i = 0; i < N; i++) { + eq &= (a[i] == b[i]); + } + return eq; + } +}; +using vec2 = avec<float, 2>; +using vec3 = avec<float, 3>; +using vec4 = avec<float, 4>; +using ivec3 = avec<int32_t, 3>; +using ivec4 = avec<int32_t, 4>; + +template <class T, int N> +T dot(const avec<T, N>& a, const avec<T, N>& b) { + const auto c = a * b; + T ret = 0; + for (int i = 0; i < N; i++) { + ret += c[i]; + } + return ret; +} + +template <class V> +V mix(const V& zero, const V& one, const float val) { + return zero * (1 - val) + one * val; +} + +template <class T, int N> +auto min(const avec<T, N>& a, const avec<T, N>& b) { + auto ret = avec<T, N>{}; + for (int i = 0; i < ret.N; i++) { + ret[i] = std::min(a[i], b[i]); + } + return ret; +} + +template <class T, int N> +auto max(const avec<T, N>& a, const avec<T, N>& b) { + auto ret = avec<T, N>{}; + for (int i = 0; i < ret.N; i++) { + ret[i] = std::max(a[i], b[i]); + } + return ret; +} + +template <class T, int N> +auto floor(const avec<T, N>& a) { + auto ret = avec<T, N>{}; + for (int i = 0; i < ret.N; i++) { + ret[i] = floorf(a[i]); + } + return ret; +} + +template <class T, int N> +auto round(const avec<T, N>& a) { + auto ret = avec<T, N>{}; + for (int i = 0; i < ret.N; i++) { + ret[i] = roundf(a[i]); + } + return ret; +} + +template <class T, int N> +auto abs(const avec<T, N>& a) { + auto ret = avec<T, N>{}; + for (int i = 0; i < ret.N; i++) { + ret[i] = std::abs(a[i]); + } + return ret; +} + +// - + +template <int Y_Rows, int X_Cols> +struct mat final { + static constexpr int y_rows = Y_Rows; + static constexpr int x_cols = X_Cols; + + static constexpr auto Identity() { + auto ret = mat{}; + for (int i = 0; i < std::min(x_cols, y_rows); i++) { + ret.at(i, i) = 1; + } + return ret; + } + static constexpr auto Scale(const avec<float, std::min(x_cols, y_rows)>& v) { + auto ret = mat{}; + for (int i = 0; i < v.N; i++) { + ret.at(i, i) = v[i]; + } + return ret; + } + + std::array<avec<float, X_Cols>, Y_Rows> rows = {}; // row-major + + // - + + constexpr mat() = default; + + explicit constexpr mat(const std::array<avec<float, X_Cols>, Y_Rows>& rows) { + this->rows = rows; + } + + template <int Y_Rows2, int X_Cols2> + explicit constexpr mat(const mat<Y_Rows2, X_Cols2>& m) { + *this = Identity(); + for (int x = 0; x < std::min(X_Cols, X_Cols2); x++) { + for (int y = 0; y < std::min(Y_Rows, Y_Rows2); y++) { + at(x, y) = m.at(x, y); + } + } + } + + const auto& at(const int x, const int y) const { return rows.at(y)[x]; } + auto& at(const int x, const int y) { return rows.at(y)[x]; } + + friend auto operator*(const mat& a, const avec<float, X_Cols>& b_colvec) { + avec<float, Y_Rows> c_colvec; + for (int i = 0; i < y_rows; i++) { + c_colvec[i] = dot(a.rows.at(i), b_colvec); + } + return c_colvec; + } + + friend auto operator*(const mat& a, const float b) { + mat c; + for (int x = 0; x < x_cols; x++) { + for (int y = 0; y < y_rows; y++) { + c.at(x, y) = a.at(x, y) * b; + } + } + return c; + } + friend auto operator/(const mat& a, const float b) { return a * (1 / b); } + + template <int BCols, int BRows = X_Cols> + friend auto operator*(const mat& a, const mat<BRows, BCols>& b) { + const auto bt = transpose(b); + const auto& b_cols = bt.rows; + + mat<Y_Rows, BCols> c; + for (int x = 0; x < BCols; x++) { + for (int y = 0; y < Y_Rows; y++) { + c.at(x, y) = dot(a.rows.at(y), b_cols.at(x)); + } + } + return c; + } + + // For e.g. similarity evaluation + friend auto operator-(const mat& a, const mat& b) { + mat c; + for (int y = 0; y < y_rows; y++) { + c.rows[y] = a.rows[y] - b.rows[y]; + } + return c; + } +}; + +template <class M> +inline float dotDifference(const M& a, const M& b) { + const auto c = a - b; + const auto d = c * avec<float, M::x_cols>(1); + const auto d2 = dot(d, d); + return d2; +} +template <class M> +inline bool approx(const M& a, const M& b, const float eps = 0.0001) { + const auto errSquared = dotDifference(a, b); + return errSquared <= (eps * eps); +} + +using mat3 = mat<3, 3>; +using mat4 = mat<4, 4>; + +inline float determinant(const mat<1, 1>& m) { return m.at(0, 0); } +template <class T> +float determinant(const T& m) { + static_assert(T::x_cols == T::y_rows); + + float ret = 0; + for (int i = 0; i < T::x_cols; i++) { + const auto cofact = cofactor(m, i, 0); + ret += m.at(i, 0) * cofact; + } + return ret; +} + +// - + +template <class T> +float cofactor(const T& m, const int x_col, const int y_row) { + ASSERT(0 <= x_col && x_col < T::x_cols); + ASSERT(0 <= y_row && y_row < T::y_rows); + + auto cofactor = minor_val(m, x_col, y_row); + if ((x_col + y_row) % 2 == 1) { + cofactor *= -1; + } + return cofactor; +} + +// - + +// Unfortunately, can't call this `minor(...)` because there is +// `#define minor(dev) gnu_dev_minor (dev)` +// in /usr/include/x86_64-linux-gnu/sys/sysmacros.h:62 +template <class T> +float minor_val(const T& a, const int skip_x, const int skip_y) { + ASSERT(0 <= skip_x && skip_x < T::x_cols); + ASSERT(0 <= skip_y && skip_y < T::y_rows); + + // A minor matrix is a matrix without its x_col and y_row. + mat<T::y_rows - 1, T::x_cols - 1> b; + + int x_skips = 0; + for (int ax = 0; ax < T::x_cols; ax++) { + if (ax == skip_x) { + x_skips = 1; + continue; + } + + int y_skips = 0; + for (int ay = 0; ay < T::y_rows; ay++) { + if (ay == skip_y) { + y_skips = 1; + continue; + } + + b.at(ax - x_skips, ay - y_skips) = a.at(ax, ay); + } + } + + const auto minor = determinant(b); + return minor; +} + +// - + +/// The matrix of cofactors. +template <class T> +auto comatrix(const T& a) { + auto b = T{}; + for (int x = 0; x < T::x_cols; x++) { + for (int y = 0; y < T::y_rows; y++) { + b.at(x, y) = cofactor(a, x, y); + } + } + return b; +} + +// - + +template <class T> +auto transpose(const T& a) { + auto b = mat<T::x_cols, T::y_rows>{}; + for (int x = 0; x < T::x_cols; x++) { + for (int y = 0; y < T::y_rows; y++) { + b.at(y, x) = a.at(x, y); + } + } + return b; +} + +// - + +template <class T> +inline T inverse(const T& a) { + const auto det = determinant(a); + const auto comat = comatrix(a); + const auto adjugate = transpose(comat); + const auto inv = adjugate / det; + return inv; +} + +// - + +template <class F> +void ForEachIntWithin(const ivec3 size, const F& f) { + ivec3 p; + for (p.z(0); p.z() < size.z(); p.z(p.z() + 1)) { + for (p.y(0); p.y() < size.y(); p.y(p.y() + 1)) { + for (p.x(0); p.x() < size.x(); p.x(p.x() + 1)) { + f(p); + } + } + } +} +template <class F> +void ForEachSampleWithin(const ivec3 size, const F& f) { + const auto div = vec3(size - 1); + ForEachIntWithin(size, [&](const ivec3& isrc) { + const auto fsrc = vec3(isrc) / div; + f(fsrc); + }); +} + +// - + +struct Lut3 final { + ivec3 size; + std::vector<vec3> data; + + // - + + static Lut3 Create(const ivec3 size) { + Lut3 lut; + lut.size = size; + lut.data.resize(size.x() * size.y() * size.z()); + return lut; + } + + // - + + /// p: [0, N-1] (clamps) + size_t Index(ivec3 p) const { + const auto scales = ivec3({1, size.x(), size.x() * size.y()}); + p = max(ivec3(0), min(p, size - 1)); // clamp + return dot(p, scales); + } + + // - + + template <class F> + void SetMap(const F& dstFromSrc01) { + ForEachIntWithin(size, [&](const ivec3 p) { + const auto i = Index(p); + const auto src01 = vec3(p) / vec3(size - 1); + const auto dstVal = dstFromSrc01(src01); + data.at(i) = dstVal; + }); + } + + // - + + /// p: [0, N-1] (clamps) + vec3 Fetch(ivec3 p) const { + const auto i = Index(p); + return data.at(i); + } + + /// in01: [0.0, 1.0] (clamps) + vec3 Sample(vec3 in01) const; +}; + +// - + +/** +Naively, it would be ideal to map directly from ycbcr to rgb, +but headroom and footroom are problematic: For e.g. narrow-range-8-bit, +our naive LUT would start at absolute y=0/255. However, values only start +at y=16/255, and depending on where your first LUT sample is, you might get +very poor approximations for y=16/255. +Further, even for full-range-8-bit, y=-0.5 is encoded as 1/255. U and v +aren't *as* important as y, but we should try be accurate for the min and +max values. Additionally, it would be embarassing to get whites/greys wrong, +so preserving u=0.0 should also be a goal. +Finally, when using non-linear transfer functions, the linear approximation of a +point between two samples will be fairly inaccurate. +We preserve min and max by choosing our input range such that min and max are +the endpoints of their LUT axis. +We preserve accuracy (at and around) mid by choosing odd sizes for dimentions. + +But also, the LUT is surprisingly robust, so check if the simple version works +before adding complexity! +**/ + +struct ColorspaceTransform final { + ColorspaceDesc srcSpace; + ColorspaceDesc dstSpace; + mat4 srcRgbTfFromSrc; + std::optional<PiecewiseGammaDesc> srcTf; + mat3 dstRgbLinFromSrcRgbLin; + std::optional<PiecewiseGammaDesc> dstTf; + mat4 dstFromDstRgbTf; + + static ColorspaceTransform Create(const ColorspaceDesc& src, + const ColorspaceDesc& dst); + + // - + + vec3 DstFromSrc(vec3 src) const; + + std::optional<mat4> ToMat4() const; + + Lut3 ToLut3(const ivec3 size) const; + Lut3 ToLut3() const { + auto defaultSize = ivec3({31, 31, 15}); // Order of importance: G, R, B + if (srcSpace.yuv) { + defaultSize = ivec3({31, 15, 31}); // Y, Cb, Cr + } + return ToLut3(defaultSize); + } +}; + +// - + +struct RgbTransferTables { + std::vector<float> r; + std::vector<float> g; + std::vector<float> b; +}; +float GuessGamma(const std::vector<float>& vals, float exp_guess = 1.0); + +static constexpr auto D65 = vec2{{0.3127, 0.3290}}; +static constexpr auto D50 = vec2{{0.34567, 0.35850}}; +mat3 XyzAFromXyzB_BradfordLinear(const vec2 xyA, const vec2 xyB); + +// - + +struct ColorProfileDesc { + // ICC profiles are phrased as PCS-from-encoded (PCS is CIEXYZ-D50) + // However, all of our colorspaces are D65, so let's normalize to that, + // even though it's a reversible transform. + color::mat4 rgbFromYcbcr = color::mat4::Identity(); + RgbTransferTables linearFromTf; + color::mat3 xyzd65FromLinearRgb = color::mat3::Identity(); + + static ColorProfileDesc From(const ColorspaceDesc&); + static ColorProfileDesc From(const qcms_profile&); +}; + +template <class C> +inline float SampleOutByIn(const C& outByIn, const float in) { + switch (outByIn.size()) { + case 0: + return in; + case 1: + return outByIn.at(0); + } + MOZ_ASSERT(outByIn.size() >= 2); + const auto begin = outByIn.begin(); + + const auto in0i = size_t(floorf(in * (outByIn.size() - 1))); + const auto out0_itr = begin + std::min(in0i, outByIn.size() - 2); + + const auto in0 = float(out0_itr - begin) / (outByIn.size() - 1); + const auto out0 = *out0_itr; + const auto d_in = float(1) / (outByIn.size() - 1); + const auto d_out = *(out0_itr + 1) - *out0_itr; + + const auto out = out0 + (d_out / d_in) * (in - in0); + // printf("SampleOutByIn(%f)->%f\n", in, out); + return out; +} + +template <class C> +inline float SampleInByOut(const C& outByIn, const float out) { + MOZ_ASSERT(outByIn.size() >= 2); + const auto begin = outByIn.begin(); + + const auto out0_itr = std::lower_bound(begin + 1, outByIn.end() - 1, out) - 1; + + const auto in0 = float(out0_itr - begin) / (outByIn.size() - 1); + const auto out0 = *out0_itr; + const auto d_in = float(1) / (outByIn.size() - 1); + const auto d_out = *(out0_itr + 1) - *out0_itr; + + // printf("%f + (%f / %f) * (%f - %f)\n", in0, d_in, d_out, out, out0); + const auto in = in0 + (d_in / d_out) * (out - out0); + // printf("SampleInByOut(%f)->%f\n", out, in); + return in; +} + +template <class C, class FnLessEqualT = std::less_equal<typename C::value_type>> +inline bool IsMonotonic(const C& vals, const FnLessEqualT& LessEqual = {}) { + bool ok = true; + const auto begin = vals.begin(); + for (size_t i = 1; i < vals.size(); i++) { + const auto itr = begin + i; + ok &= LessEqual(*(itr - 1), *itr); + // Assert(true, [&]() { + // return prints("[%zu]->%f <= [%zu]->%f", i-1, *(itr-1), i, *itr); + // }); + } + return ok; +} + +template <class T, class I> +inline std::optional<I> SeekNeq(const T& ref, const I first, const I last) { + const auto inc = (last - first) > 0 ? 1 : -1; + auto itr = first; + while (true) { + if (*itr != ref) return itr; + if (itr == last) return {}; + itr += inc; + } +} + +template <class T> +struct TwoPoints { + struct { + T x; + T y; + } p0; + struct { + T x; + T y; + } p1; + + T y(const T x) const { + const auto dx = p1.x - p0.x; + const auto dy = p1.y - p0.y; + return p0.y + dy / dx * (x - p0.x); + } +}; + +/// Fills `vals` with `x:[0..vals.size()-1] => line.y(x)`. +template <class T> +static void LinearFill(T& vals, const TwoPoints<float>& line) { + float x = -1; + for (auto& val : vals) { + x += 1; + val = line.y(x); + } +} + +// - + +inline void DequantizeMonotonic(const Span<float> vals) { + MOZ_ASSERT(IsMonotonic(vals)); + + const auto first = vals.begin(); + const auto end = vals.end(); + if (first == end) return; + const auto last = end - 1; + if (first == last) return; + + // Three monotonic cases: + // 1. [0,0,0,0] + // 2. [0,0,1,1] + // 3. [0,1,1,2] + + const auto body_first = SeekNeq(*first, first, last); + if (!body_first) { + // E.g. [0,0,0,0] + return; + } + + const auto body_last = SeekNeq(*last, last, *body_first); + if (!body_last) { + // E.g. [0,0,1,1] + // This isn't the most accurate, but close enough. + // print("#2: %s", to_str(vals).c_str()); + LinearFill(vals, { + {0, *first}, + {float(vals.size() - 1), *last}, + }); + // print(" -> %s\n", to_str(vals).c_str()); + return; + } + + // E.g. [0,1,1,2] + // ^^^ body + // => f(0.5)->0.5, f(2.5)->1.5 + // => f(x) = f(x0) + (x-x0) * (f(x1) - f(x0)) / (x1-x0) + // => f(x) = f(x0) + (x-x0) * dfdx + + const auto head_end = *body_first; + const auto head = vals.subspan(0, head_end - vals.begin()); + const auto tail_begin = *body_last + 1; + const auto tail = vals.subspan(tail_begin - vals.begin()); + // print("head tail: %s %s\n", + // to_str(head).c_str(), + // to_str(tail).c_str()); + + // const auto body = vals->subspan(head.size(), vals->size()-tail.size()); + auto next_part_first = head_end; + while (next_part_first != tail_begin) { + const auto part_first = next_part_first; + // print("part_first: %f\n", *part_first); + next_part_first = *SeekNeq(*part_first, part_first, tail_begin); + // print("next_part_first: %f\n", *next_part_first); + const auto part = + Span<float>{part_first, size_t(next_part_first - part_first)}; + // print("part: %s\n", to_str(part).c_str()); + const auto prev_part_last = part_first - 1; + const auto part_last = next_part_first - 1; + const auto line = TwoPoints<float>{ + {-0.5, (*prev_part_last + *part_first) / 2}, + {part.size() - 0.5f, (*part_last + *next_part_first) / 2}, + }; + LinearFill(part, line); + } + + static constexpr bool INFER_HEAD_TAIL_FROM_BODY_EDGE = false; + // Basically ignore contents of head and tail, and infer from edges of body. + // print("3: %s\n", to_str(vals).c_str()); + if (!IsMonotonic(head, std::less<float>{})) { + if (!INFER_HEAD_TAIL_FROM_BODY_EDGE) { + LinearFill(head, + { + {0, *head.begin()}, + {head.size() - 0.5f, (*(head.end() - 1) + *head_end) / 2}, + }); + } else { + LinearFill(head, { + {head.size() + 0.0f, *head_end}, + {head.size() + 1.0f, *(head_end + 1)}, + }); + } + } + if (!IsMonotonic(tail, std::less<float>{})) { + if (!INFER_HEAD_TAIL_FROM_BODY_EDGE) { + LinearFill(tail, { + {-0.5, (*(tail_begin - 1) + *tail.begin()) / 2}, + {tail.size() - 1.0f, *(tail.end() - 1)}, + }); + } else { + LinearFill(tail, { + {-2.0f, *(tail_begin - 2)}, + {-1.0f, *(tail_begin - 1)}, + }); + } + } + // print("3: %s\n", to_str(vals).c_str()); + MOZ_ASSERT(IsMonotonic(vals, std::less<float>{})); + + // Rescale, because we tend to lose range. + static constexpr bool RESCALE = false; + if (RESCALE) { + const auto firstv = *first; + const auto lastv = *last; + for (auto& val : vals) { + val = (val - firstv) / (lastv - firstv); + } + } + // print("4: %s\n", to_str(vals).c_str()); +} + +template <class In, class Out> +static void InvertLut(const In& lut, Out* const out_invertedLut) { + MOZ_ASSERT(IsMonotonic(lut)); + auto plut = &lut; + auto vec = std::vector<float>{}; + if (!IsMonotonic(lut, std::less<float>{})) { + // print("Not strictly monotonic...\n"); + vec.assign(lut.begin(), lut.end()); + DequantizeMonotonic(vec); + plut = &vec; + // print(" Now strictly monotonic: %i: %s\n", + // int(IsMonotonic(*plut, std::less<float>{})), to_str(*plut).c_str()); + MOZ_ASSERT(IsMonotonic(*plut, std::less<float>{})); + } + MOZ_ASSERT(plut->size() >= 2); + + auto& ret = *out_invertedLut; + for (size_t i_out = 0; i_out < ret.size(); i_out++) { + const auto f_out = i_out / float(ret.size() - 1); + const auto f_in = SampleInByOut(*plut, f_out); + ret[i_out] = f_in; + } + + MOZ_ASSERT(IsMonotonic(ret)); + MOZ_ASSERT(IsMonotonic(ret, std::less<float>{})); +} + +// - + +struct ColorProfileConversionDesc { + // ICC profiles are phrased as PCS-from-encoded (PCS is CIEXYZ-D50) + color::mat4 srcRgbFromSrcYuv = color::mat4::Identity(); + RgbTransferTables srcLinearFromSrcTf; + color::mat3 dstLinearFromSrcLinear = color::mat3::Identity(); + RgbTransferTables dstTfFromDstLinear; + + struct FromDesc { + ColorProfileDesc src; + ColorProfileDesc dst; + }; + static ColorProfileConversionDesc From(const FromDesc&); + + vec3 Apply(const vec3 src) const { + const auto srcRgb = vec3(srcRgbFromSrcYuv * vec4(src, 1)); + const auto srcLinear = vec3{{ + SampleOutByIn(srcLinearFromSrcTf.r, srcRgb.x()), + SampleOutByIn(srcLinearFromSrcTf.g, srcRgb.y()), + SampleOutByIn(srcLinearFromSrcTf.b, srcRgb.z()), + }}; + const auto dstLinear = dstLinearFromSrcLinear * srcLinear; + const auto dstRgb = vec3{{ + SampleOutByIn(dstTfFromDstLinear.r, dstLinear.x()), + SampleOutByIn(dstTfFromDstLinear.g, dstLinear.y()), + SampleOutByIn(dstTfFromDstLinear.b, dstLinear.z()), + }}; + return dstRgb; + } +}; + +} // namespace mozilla::color + +#undef ASSERT + +#endif // MOZILLA_GFX_GL_COLORSPACES_H_ diff --git a/gfx/gl/ForceDiscreteGPUHelperCGL.h b/gfx/gl/ForceDiscreteGPUHelperCGL.h new file mode 100644 index 0000000000..523d76def3 --- /dev/null +++ b/gfx/gl/ForceDiscreteGPUHelperCGL.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ForceDiscreteGPUHelperCGL_h_ +#define ForceDiscreteGPUHelperCGL_h_ + +#include <OpenGL/OpenGL.h> + +/** This RAII helper guarantees that we're on the discrete GPU during its + * lifetime. + * + * As long as any ForceDiscreteGPUHelperCGL object is alive, we're on the + * discrete GPU. + */ +class ForceDiscreteGPUHelperCGL { + CGLPixelFormatObj mPixelFormatObj; + + public: + ForceDiscreteGPUHelperCGL() : mPixelFormatObj(nullptr) { + // the code in this function is taken from Chromium, + // src/ui/gfx/gl/gl_context_cgl.cc, r122013 + // BSD-style license, (c) The Chromium Authors + CGLPixelFormatAttribute attribs[1]; + attribs[0] = static_cast<CGLPixelFormatAttribute>(0); + GLint num_pixel_formats = 0; + CGLChoosePixelFormat(attribs, &mPixelFormatObj, &num_pixel_formats); + } + + ~ForceDiscreteGPUHelperCGL() { CGLReleasePixelFormat(mPixelFormatObj); } +}; + +#endif // ForceDiscreteGPUHelperCGL_h_ diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp new file mode 100644 index 0000000000..dd9fa00235 --- /dev/null +++ b/gfx/gl/GLBlitHelper.cpp @@ -0,0 +1,1684 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLBlitHelper.h" + +#include "gfxEnv.h" +#include "gfxUtils.h" +#include "GLContext.h" +#include "GLScreenBuffer.h" +#include "GPUVideoImage.h" +#include "HeapCopyOfStackArray.h" +#include "ImageContainer.h" +#include "ScopedGLHelpers.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Casting.h" +#include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/gfx/Matrix.h" +#include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/layers/LayersSurfaces.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "AndroidSurfaceTexture.h" +# include "GLImages.h" +# include "GLLibraryEGL.h" +#endif + +#ifdef XP_MACOSX +# include "GLContextCGL.h" +# include "MacIOSurfaceImage.h" +#endif + +#ifdef XP_WIN +# include "mozilla/layers/D3D11ShareHandleImage.h" +# include "mozilla/layers/D3D11TextureIMFSampleImage.h" +# include "mozilla/layers/D3D11YCbCrImage.h" +#endif + +#ifdef MOZ_WIDGET_GTK +# include "mozilla/layers/DMABUFSurfaceImage.h" +# include "mozilla/widget/DMABufSurface.h" +# include "mozilla/widget/DMABufLibWrapper.h" +#endif + +using mozilla::layers::PlanarYCbCrData; +using mozilla::layers::PlanarYCbCrImage; + +namespace mozilla { +namespace gl { + +// -- + +static const char kFragPreprocHeader[] = R"( + #ifdef GL_ES + #ifdef GL_FRAGMENT_PRECISION_HIGH + #define MAXP highp + #endif + #else + #define MAXP highp + #endif + #ifndef MAXP + #define MAXP mediump + #endif + + #if __VERSION__ >= 130 + #define VARYING in + #else + #define VARYING varying + #endif + #if __VERSION__ >= 120 + #define MAT4X3 mat4x3 + #else + #define MAT4X3 mat4 + #endif +)"; + +// - + +const char* const kFragHeader_Tex2D = R"( + #define SAMPLER sampler2D + #if __VERSION__ >= 130 + #define TEXTURE texture + #else + #define TEXTURE texture2D + #endif +)"; +const char* const kFragHeader_Tex2DRect = R"( + #define SAMPLER sampler2DRect + #if __VERSION__ >= 130 + #define TEXTURE texture + #else + #define TEXTURE texture2DRect + #endif +)"; +const char* const kFragHeader_TexExt = R"( + #extension GL_OES_EGL_image_external : enable + #extension GL_OES_EGL_image_external_essl3 : enable + #if __VERSION__ >= 130 + #define TEXTURE texture + #else + #define TEXTURE texture2D + #endif + #define SAMPLER samplerExternalOES +)"; + +// - + +static const char kFragDeclHeader[] = R"( + precision PRECISION float; + #if __VERSION__ >= 130 + #define FRAG_COLOR oFragColor + out vec4 FRAG_COLOR; + #else + #define FRAG_COLOR gl_FragColor + #endif +)"; + +// - + +const char* const kFragSample_OnePlane = R"( + VARYING mediump vec2 vTexCoord0; + uniform PRECISION SAMPLER uTex0; + + vec4 metaSample() { + vec4 src = TEXTURE(uTex0, vTexCoord0); + return src; + } +)"; +// Ideally this would just change the color-matrix it uses, but this is +// acceptable debt for now. +// `extern` so that we don't get ifdef-dependent const-var-unused Werrors. +extern const char* const kFragSample_OnePlane_YUV_via_GBR = R"( + VARYING mediump vec2 vTexCoord0; + uniform PRECISION SAMPLER uTex0; + + vec4 metaSample() { + vec4 yuva = TEXTURE(uTex0, vTexCoord0).gbra; + return yuva; + } +)"; +const char* const kFragSample_TwoPlane = R"( + VARYING mediump vec2 vTexCoord0; + VARYING mediump vec2 vTexCoord1; + uniform PRECISION SAMPLER uTex0; + uniform PRECISION SAMPLER uTex1; + + vec4 metaSample() { + vec4 src = TEXTURE(uTex0, vTexCoord0); // Keep r and a. + src.gb = TEXTURE(uTex1, vTexCoord1).rg; + return src; + } +)"; +const char* const kFragSample_ThreePlane = R"( + VARYING mediump vec2 vTexCoord0; + VARYING mediump vec2 vTexCoord1; + uniform PRECISION SAMPLER uTex0; + uniform PRECISION SAMPLER uTex1; + uniform PRECISION SAMPLER uTex2; + + vec4 metaSample() { + vec4 src = TEXTURE(uTex0, vTexCoord0); // Keep r and a. + src.g = TEXTURE(uTex1, vTexCoord1).r; + src.b = TEXTURE(uTex2, vTexCoord1).r; + return src; + } +)"; + +// - + +const char* const kFragConvert_None = R"( + vec3 metaConvert(vec3 src) { + return src; + } +)"; +const char* const kFragConvert_BGR = R"( + vec3 metaConvert(vec3 src) { + return src.bgr; + } +)"; +const char* const kFragConvert_ColorMatrix = R"( + uniform mediump MAT4X3 uColorMatrix; + + vec3 metaConvert(vec3 src) { + return (uColorMatrix * vec4(src, 1)).rgb; + } +)"; +const char* const kFragConvert_ColorLut = R"( + uniform PRECISION sampler3D uColorLut; + + vec3 metaConvert(vec3 src) { + // Half-texel filtering hazard! + // E.g. For texture size of 2, + // E.g. 0.5/2=0.25 is still sampling 100% of texel 0, 0% of texel 1. + // For the LUT, we need 0.5/2=0.25 to filter 25/75 texel 0 and 1. + // That is, we need to adjust our sampling point such that it's 0.25 of the + // way from texel 0's center to texel 1's center. + // We need, for N=2: + // v=0.0|N=2 => v'=0.5/2 + // v=1.0|N=2 => v'=1.5/2 + // For N=3: + // v=0.0|N=3 => v'=0.5/3 + // v=1.0|N=3 => v'=2.5/3 + // => v' = ( 0.5 + v * (3 - 1) )/3 + vec3 size = vec3(textureSize(uColorLut, 0)); + src = (0.5 + src * (size - 1.0)) / size; + return texture(uColorLut, src).rgb; + } +)"; + +// - + +const char* const kFragMixin_AlphaMultColors = R"( + #define MIXIN_ALPHA_MULT_COLORS +)"; +const char* const kFragMixin_AlphaClampColors = R"( + #define MIXIN_ALPHA_CLAMP_COLORS +)"; +const char* const kFragMixin_AlphaOne = R"( + #define MIXIN_ALPHA_ONE +)"; + +// - + +static const char kFragBody[] = R"( + void main(void) { + vec4 src = metaSample(); + vec4 dst = vec4(metaConvert(src.rgb), src.a); + + #ifdef MIXIN_ALPHA_MULT_COLORS + dst.rgb *= dst.a; + #endif + #ifdef MIXIN_ALPHA_CLAMP_COLORS + dst.rgb = min(dst.rgb, vec3(dst.a)); // Ensure valid premult-alpha colors. + #endif + #ifdef MIXIN_ALPHA_ONE + dst.a = 1.0; + #endif + + FRAG_COLOR = dst; + } +)"; + +// -- + +Mat3 SubRectMat3(const float x, const float y, const float w, const float h) { + auto ret = Mat3{}; + ret.at(0, 0) = w; + ret.at(1, 1) = h; + ret.at(2, 0) = x; + ret.at(2, 1) = y; + ret.at(2, 2) = 1.0f; + return ret; +} + +Mat3 SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size) { + return SubRectMat3(float(subrect.X()) / size.width, + float(subrect.Y()) / size.height, + float(subrect.Width()) / size.width, + float(subrect.Height()) / size.height); +} + +Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize, + const gfx::IntSize& divisors) { + const float x = float(bigSubrect.X()) / divisors.width; + const float y = float(bigSubrect.Y()) / divisors.height; + const float w = float(bigSubrect.Width()) / divisors.width; + const float h = float(bigSubrect.Height()) / divisors.height; + return SubRectMat3(x / smallSize.width, y / smallSize.height, + w / smallSize.width, h / smallSize.height); +} + +// -- + +ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, + const std::vector<uint8_t>& texUnits, + const GLenum texTarget) + : mGL(*gl), + mTexUnits(texUnits), + mTexTarget(texTarget), + mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE)) { + MOZ_RELEASE_ASSERT(texUnits.size() >= 1); + + GLenum texBinding; + switch (mTexTarget) { + case LOCAL_GL_TEXTURE_2D: + texBinding = LOCAL_GL_TEXTURE_BINDING_2D; + break; + case LOCAL_GL_TEXTURE_3D: + texBinding = LOCAL_GL_TEXTURE_BINDING_3D; + break; + case LOCAL_GL_TEXTURE_RECTANGLE: + texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE; + break; + case LOCAL_GL_TEXTURE_EXTERNAL: + texBinding = LOCAL_GL_TEXTURE_BINDING_EXTERNAL; + break; + default: + gfxCriticalError() << "Unhandled texTarget: " << texTarget; + MOZ_CRASH(); + } + + for (const auto i : IntegerRange(mTexUnits.size())) { + const auto& unit = mTexUnits[i]; + mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + unit); + if (mGL.IsSupported(GLFeature::sampler_objects)) { + mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING); + mGL.fBindSampler(unit, 0); + } + mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding); + } +} + +ScopedSaveMultiTex::~ScopedSaveMultiTex() { + // Unbind in reverse order, in case we have repeats. + // Order matters because we unbound samplers during ctor, so now we have to + // make sure we rebind them in the right order. + for (const auto i : Reversed(IntegerRange(mTexUnits.size()))) { + const auto& unit = mTexUnits[i]; + mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + unit); + if (mGL.IsSupported(GLFeature::sampler_objects)) { + mGL.fBindSampler(unit, mOldTexSampler[i]); + } + mGL.fBindTexture(mTexTarget, mOldTex[i]); + } + mGL.fActiveTexture(mOldTexUnit); +} + +// -- + +class ScopedBindArrayBuffer final { + public: + GLContext& mGL; + const GLuint mOldVBO; + + ScopedBindArrayBuffer(GLContext* const gl, const GLuint vbo) + : mGL(*gl), mOldVBO(mGL.GetIntAs<GLuint>(LOCAL_GL_ARRAY_BUFFER_BINDING)) { + mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo); + } + + ~ScopedBindArrayBuffer() { mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mOldVBO); } +}; + +// -- + +class ScopedShader final { + GLContext& mGL; + const GLuint mName; + + public: + ScopedShader(GLContext* const gl, const GLenum shaderType) + : mGL(*gl), mName(mGL.fCreateShader(shaderType)) {} + + ~ScopedShader() { mGL.fDeleteShader(mName); } + + operator GLuint() const { return mName; } +}; + +// -- + +class SaveRestoreCurrentProgram final { + GLContext& mGL; + const GLuint mOld; + + public: + explicit SaveRestoreCurrentProgram(GLContext* const gl) + : mGL(*gl), mOld(mGL.GetIntAs<GLuint>(LOCAL_GL_CURRENT_PROGRAM)) {} + + ~SaveRestoreCurrentProgram() { mGL.fUseProgram(mOld); } +}; + +// -- + +class ScopedDrawBlitState final { + GLContext& mGL; + + const bool blend; + const bool cullFace; + const bool depthTest; + const bool dither; + const bool polyOffsFill; + const bool sampleAToC; + const bool sampleCover; + const bool scissor; + const bool stencil; + Maybe<bool> rasterizerDiscard; + + realGLboolean colorMask[4]; + GLint viewport[4]; + + public: + ScopedDrawBlitState(GLContext* const gl, const gfx::IntSize& destSize) + : mGL(*gl), + blend(mGL.PushEnabled(LOCAL_GL_BLEND, false)), + cullFace(mGL.PushEnabled(LOCAL_GL_CULL_FACE, false)), + depthTest(mGL.PushEnabled(LOCAL_GL_DEPTH_TEST, false)), + dither(mGL.PushEnabled(LOCAL_GL_DITHER, true)), + polyOffsFill(mGL.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL, false)), + sampleAToC(mGL.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false)), + sampleCover(mGL.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE, false)), + scissor(mGL.PushEnabled(LOCAL_GL_SCISSOR_TEST, false)), + stencil(mGL.PushEnabled(LOCAL_GL_STENCIL_TEST, false)) { + if (mGL.IsSupported(GLFeature::transform_feedback2)) { + // Technically transform_feedback2 requires transform_feedback, which + // actually adds RASTERIZER_DISCARD. + rasterizerDiscard = + Some(mGL.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD, false)); + } + + mGL.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask); + if (mGL.IsSupported(GLFeature::draw_buffers_indexed)) { + mGL.fColorMaski(0, true, true, true, true); + } else { + mGL.fColorMask(true, true, true, true); + } + + mGL.fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); + MOZ_ASSERT(destSize.width && destSize.height); + mGL.fViewport(0, 0, destSize.width, destSize.height); + } + + ~ScopedDrawBlitState() { + mGL.SetEnabled(LOCAL_GL_BLEND, blend); + mGL.SetEnabled(LOCAL_GL_CULL_FACE, cullFace); + mGL.SetEnabled(LOCAL_GL_DEPTH_TEST, depthTest); + mGL.SetEnabled(LOCAL_GL_DITHER, dither); + mGL.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL, polyOffsFill); + mGL.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, sampleAToC); + mGL.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE, sampleCover); + mGL.SetEnabled(LOCAL_GL_SCISSOR_TEST, scissor); + mGL.SetEnabled(LOCAL_GL_STENCIL_TEST, stencil); + if (rasterizerDiscard) { + mGL.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD, rasterizerDiscard.value()); + } + + if (mGL.IsSupported(GLFeature::draw_buffers_indexed)) { + mGL.fColorMaski(0, colorMask[0], colorMask[1], colorMask[2], + colorMask[3]); + } else { + mGL.fColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); + } + mGL.fViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + } +}; + +// -- + +DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog) + : mParent(*parent), + mProg(prog), + mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix")), + mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0")), + mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1")), + mLoc_uColorLut(mParent.mGL->fGetUniformLocation(mProg, "uColorLut")), + mLoc_uColorMatrix( + mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix")) { + const auto& gl = mParent.mGL; + MOZ_GL_ASSERT(gl, mLoc_uDestMatrix != -1); // Required + MOZ_GL_ASSERT(gl, mLoc_uTexMatrix0 != -1); // Required + if (mLoc_uColorMatrix != -1) { + MOZ_GL_ASSERT(gl, mLoc_uTexMatrix1 != -1); + + int32_t numActiveUniforms = 0; + gl->fGetProgramiv(mProg, LOCAL_GL_ACTIVE_UNIFORMS, &numActiveUniforms); + + const size_t kMaxNameSize = 32; + char name[kMaxNameSize] = {0}; + GLint size = 0; + GLenum type = 0; + for (int32_t i = 0; i < numActiveUniforms; i++) { + gl->fGetActiveUniform(mProg, i, kMaxNameSize, nullptr, &size, &type, + name); + if (strcmp("uColorMatrix", name) == 0) { + mType_uColorMatrix = type; + break; + } + } + MOZ_GL_ASSERT(gl, mType_uColorMatrix); + } +} + +DrawBlitProg::~DrawBlitProg() { + const auto& gl = mParent.mGL; + if (!gl->MakeCurrent()) return; + + gl->fDeleteProgram(mProg); +} + +void DrawBlitProg::Draw(const BaseArgs& args, + const YUVArgs* const argsYUV) const { + const auto& gl = mParent.mGL; + + const SaveRestoreCurrentProgram oldProg(gl); + gl->fUseProgram(mProg); + + // -- + + Mat3 destMatrix; + if (args.destRect) { + const auto& destRect = args.destRect.value(); + destMatrix = SubRectMat3(destRect.X() / args.destSize.width, + destRect.Y() / args.destSize.height, + destRect.Width() / args.destSize.width, + destRect.Height() / args.destSize.height); + } else { + destMatrix = Mat3::I(); + } + + if (args.yFlip) { + // Apply the y-flip matrix before the destMatrix. + // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect. + destMatrix.at(2, 1) += destMatrix.at(1, 1); + destMatrix.at(1, 1) *= -1.0f; + } + + gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m); + gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m); + + if (args.texUnitForColorLut) { + gl->fUniform1i(mLoc_uColorLut, + AssertedCast<GLint>(*args.texUnitForColorLut)); + } + + MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1)); + if (argsYUV) { + gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m); + + if (mLoc_uColorMatrix != -1) { + const auto& colorMatrix = + gfxUtils::YuvToRgbMatrix4x4ColumnMajor(*argsYUV->colorSpaceForMatrix); + float mat4x3[4 * 3]; + switch (mType_uColorMatrix) { + case LOCAL_GL_FLOAT_MAT4: + gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix); + break; + case LOCAL_GL_FLOAT_MAT4x3: + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 3; y++) { + mat4x3[3 * x + y] = colorMatrix[4 * x + y]; + } + } + gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3); + break; + default: + gfxCriticalError() + << "Bad mType_uColorMatrix: " << gfx::hexa(mType_uColorMatrix); + } + } + } + + // -- + + const ScopedDrawBlitState drawState(gl, args.destSize); + + GLuint oldVAO; + GLint vaa0Enabled; + GLint vaa0Size; + GLenum vaa0Type; + GLint vaa0Normalized; + GLsizei vaa0Stride; + GLvoid* vaa0Pointer; + GLuint vaa0Buffer; + if (mParent.mQuadVAO) { + oldVAO = gl->GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING); + gl->fBindVertexArray(mParent.mQuadVAO); + } else { + // clang-format off + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*)&vaa0Buffer); + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vaa0Enabled); + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &vaa0Size); + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint*)&vaa0Type); + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vaa0Normalized); + gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, (GLint*)&vaa0Stride); + gl->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &vaa0Pointer); + // clang-format on + + gl->fEnableVertexAttribArray(0); + const ScopedBindArrayBuffer bindVBO(gl, mParent.mQuadVBO); + gl->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0); + } + + gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + + if (mParent.mQuadVAO) { + gl->fBindVertexArray(oldVAO); + } else { + if (vaa0Enabled) { + gl->fEnableVertexAttribArray(0); + } else { + gl->fDisableVertexAttribArray(0); + } + // The current VERTEX_ARRAY_BINDING is not necessarily the same as the + // buffer set for vaa0Buffer. + const ScopedBindArrayBuffer bindVBO(gl, vaa0Buffer); + gl->fVertexAttribPointer(0, vaa0Size, vaa0Type, bool(vaa0Normalized), + vaa0Stride, vaa0Pointer); + } +} + +// -- + +GLBlitHelper::GLBlitHelper(GLContext* const gl) + : mGL(gl), + mDrawBlitProg_VertShader(mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER)) +//, mYuvUploads_YSize(0, 0) +//, mYuvUploads_UVSize(0, 0) +{ + mGL->fGenBuffers(1, &mQuadVBO); + { + const ScopedBindArrayBuffer bindVBO(mGL, mQuadVBO); + + const float quadData[] = {0, 0, 1, 0, 0, 1, 1, 1}; + const HeapCopyOfStackArray<float> heapQuadData(quadData); + mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, heapQuadData.ByteLength(), + heapQuadData.Data(), LOCAL_GL_STATIC_DRAW); + + if (mGL->IsSupported(GLFeature::vertex_array_object)) { + const auto prev = mGL->GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING); + + mGL->fGenVertexArrays(1, &mQuadVAO); + mGL->fBindVertexArray(mQuadVAO); + mGL->fEnableVertexAttribArray(0); + mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0); + + mGL->fBindVertexArray(prev); + } + } + + // -- + + const auto glslVersion = mGL->ShadingLanguageVersion(); + + if (mGL->IsGLES()) { + // If you run into problems on old android devices, it might be because some + // devices have OES_EGL_image_external but not OES_EGL_image_external_essl3. + // We could just use 100 in that particular case, but then we lose out on + // e.g. sampler3D. Let's just try 300 for now, and if we get regressions + // we'll add an essl100 fallback. + if (glslVersion >= 300) { + mDrawBlitProg_VersionLine = nsCString("#version 300 es\n"); + } else { + mDrawBlitProg_VersionLine = nsCString("#version 100\n"); + } + } else if (glslVersion >= 130) { + mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion); + } + + const char kVertSource[] = + "\ + #if __VERSION__ >= 130 \n\ + #define ATTRIBUTE in \n\ + #define VARYING out \n\ + #else \n\ + #define ATTRIBUTE attribute \n\ + #define VARYING varying \n\ + #endif \n\ + \n\ + ATTRIBUTE vec2 aVert; // [0.0-1.0] \n\ + \n\ + uniform mat3 uDestMatrix; \n\ + uniform mat3 uTexMatrix0; \n\ + uniform mat3 uTexMatrix1; \n\ + \n\ + VARYING vec2 vTexCoord0; \n\ + VARYING vec2 vTexCoord1; \n\ + \n\ + void main(void) \n\ + { \n\ + vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy; \n\ + gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0); \n\ + \n\ + vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy; \n\ + vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy; \n\ + } \n\ + "; + const char* const parts[] = {mDrawBlitProg_VersionLine.get(), kVertSource}; + mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts, + nullptr); + mGL->fCompileShader(mDrawBlitProg_VertShader); +} + +GLBlitHelper::~GLBlitHelper() { + for (const auto& pair : mDrawBlitProgs) { + const auto& ptr = pair.second; + delete ptr; + } + mDrawBlitProgs.clear(); + + if (!mGL->MakeCurrent()) return; + + mGL->fDeleteShader(mDrawBlitProg_VertShader); + mGL->fDeleteBuffers(1, &mQuadVBO); + + if (mQuadVAO) { + mGL->fDeleteVertexArrays(1, &mQuadVAO); + } +} + +// -- + +const DrawBlitProg* GLBlitHelper::GetDrawBlitProg( + const DrawBlitProg::Key& key) const { + const auto& res = mDrawBlitProgs.insert({key, nullptr}); + auto& pair = *(res.first); + const auto& didInsert = res.second; + if (didInsert) { + pair.second = CreateDrawBlitProg(pair.first); + } + return pair.second; +} + +const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg( + const DrawBlitProg::Key& key) const { + const auto precisionPref = StaticPrefs::gfx_blithelper_precision(); + const char* precision; + switch (precisionPref) { + case 0: + precision = "lowp"; + break; + case 1: + precision = "mediump"; + break; + default: + if (precisionPref != 2) { + NS_WARNING("gfx.blithelper.precision clamped to 2."); + } + precision = "MAXP"; + break; + } + + nsPrintfCString precisionLine("\n#define PRECISION %s\n", precision); + + // - + + const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER); + + std::vector<const char*> parts; + { + parts.push_back(mDrawBlitProg_VersionLine.get()); + parts.push_back(kFragPreprocHeader); + if (key.fragHeader) { + parts.push_back(key.fragHeader); + } + parts.push_back(precisionLine.BeginReading()); + parts.push_back(kFragDeclHeader); + for (const auto& part : key.fragParts) { + if (part) { + parts.push_back(part); + } + } + parts.push_back(kFragBody); + } + + const auto PrintFragSource = [&]() { + printf_stderr("Frag source:\n"); + int i = 0; + for (const auto& part : parts) { + printf_stderr("// parts[%i]:\n%s\n", i, part); + i += 1; + } + }; + if (gfxEnv::MOZ_DUMP_GLBLITHELPER()) { + PrintFragSource(); + } + + mGL->fShaderSource(fs, AssertedCast<GLint>(parts.size()), parts.data(), + nullptr); + mGL->fCompileShader(fs); + + const auto prog = mGL->fCreateProgram(); + mGL->fAttachShader(prog, mDrawBlitProg_VertShader); + mGL->fAttachShader(prog, fs); + + mGL->fBindAttribLocation(prog, 0, "aVert"); + mGL->fLinkProgram(prog); + + GLenum status = 0; + mGL->fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, (GLint*)&status); + if (status == LOCAL_GL_TRUE || mGL->CheckContextLost()) { + const SaveRestoreCurrentProgram oldProg(mGL); + mGL->fUseProgram(prog); + const char* samplerNames[] = {"uTex0", "uTex1", "uTex2"}; + for (int i = 0; i < 3; i++) { + const auto loc = mGL->fGetUniformLocation(prog, samplerNames[i]); + if (loc == -1) continue; + mGL->fUniform1i(loc, i); + } + + return new DrawBlitProg(this, prog); + } + + GLuint progLogLen = 0; + mGL->fGetProgramiv(prog, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&progLogLen); + const UniquePtr<char[]> progLog(new char[progLogLen + 1]); + mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get()); + progLog[progLogLen] = 0; + + const auto& vs = mDrawBlitProg_VertShader; + GLuint vsLogLen = 0; + mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen); + const UniquePtr<char[]> vsLog(new char[vsLogLen + 1]); + mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get()); + vsLog[vsLogLen] = 0; + + GLuint fsLogLen = 0; + mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen); + const UniquePtr<char[]> fsLog(new char[fsLogLen + 1]); + mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get()); + fsLog[fsLogLen] = 0; + + const auto logs = + std::string("DrawBlitProg link failed:\n") + "progLog: " + progLog.get() + + "\n" + "vsLog: " + vsLog.get() + "\n" + "fsLog: " + fsLog.get() + "\n"; + gfxCriticalError() << logs; + + PrintFragSource(); + + MOZ_CRASH("DrawBlitProg link failed"); +} + +// ----------------------------------------------------------------------------- + +#ifdef XP_MACOSX +static RefPtr<MacIOSurface> LookupSurface( + const layers::SurfaceDescriptorMacIOSurface& sd) { + return MacIOSurface::LookupSurface(sd.surfaceId(), !sd.isOpaque(), + sd.yUVColorSpace()); +} +#endif + +bool GLBlitHelper::BlitSdToFramebuffer(const layers::SurfaceDescriptor& asd, + const gfx::IntSize& destSize, + const OriginPos destOrigin) { + const auto sdType = asd.type(); + switch (sdType) { + case layers::SurfaceDescriptor::TSurfaceDescriptorBuffer: { + const auto& sd = asd.get_SurfaceDescriptorBuffer(); + const auto yuvData = PlanarYCbCrData::From(sd); + if (!yuvData) { + gfxCriticalNote << "[GLBlitHelper::BlitSdToFramebuffer] " + "PlanarYCbCrData::From failed"; + return false; + } + return BlitPlanarYCbCr(*yuvData, destSize, destOrigin); + } +#ifdef XP_WIN + case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10: { + const auto& sd = asd.get_SurfaceDescriptorD3D10(); + return BlitDescriptor(sd, destSize, destOrigin); + } + case layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: { + const auto& sd = asd.get_SurfaceDescriptorDXGIYCbCr(); + return BlitDescriptor(sd, destSize, destOrigin); + } +#endif +#ifdef XP_MACOSX + case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { + const auto& sd = asd.get_SurfaceDescriptorMacIOSurface(); + const auto surf = LookupSurface(sd); + if (!surf) { + NS_WARNING("LookupSurface(MacIOSurface) failed"); + // Sometimes that frame for our handle gone already. That's life, for + // now. + return false; + } + return BlitImage(surf, destSize, destOrigin); + } +#endif +#ifdef MOZ_WIDGET_ANDROID + case layers::SurfaceDescriptor::TSurfaceTextureDescriptor: { + const auto& sd = asd.get_SurfaceTextureDescriptor(); + auto surfaceTexture = java::GeckoSurfaceTexture::Lookup(sd.handle()); + return Blit(surfaceTexture, destSize, destOrigin); + } +#endif +#ifdef MOZ_WIDGET_GTK + case layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf: { + const auto& sd = asd.get_SurfaceDescriptorDMABuf(); + RefPtr<DMABufSurface> surface = DMABufSurface::CreateDMABufSurface(sd); + return Blit(surface, destSize, destOrigin); + } +#endif + default: + return false; + } +} + +bool GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) { + switch (srcImage->GetFormat()) { + case ImageFormat::PLANAR_YCBCR: { + const auto srcImage2 = static_cast<PlanarYCbCrImage*>(srcImage); + const auto data = srcImage2->GetData(); + return BlitPlanarYCbCr(*data, destSize, destOrigin); + } + + case ImageFormat::SURFACE_TEXTURE: { +#ifdef MOZ_WIDGET_ANDROID + auto* image = srcImage->AsSurfaceTextureImage(); + MOZ_ASSERT(image); + auto surfaceTexture = + java::GeckoSurfaceTexture::Lookup(image->GetHandle()); + return Blit(surfaceTexture, destSize, destOrigin); +#else + MOZ_ASSERT(false); + return false; +#endif + } + case ImageFormat::MAC_IOSURFACE: +#ifdef XP_MACOSX + return BlitImage(srcImage->AsMacIOSurfaceImage(), destSize, destOrigin); +#else + MOZ_ASSERT(false); + return false; +#endif + + case ImageFormat::GPU_VIDEO: + return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize, + destOrigin); +#ifdef XP_WIN + case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE: + return BlitImage(static_cast<layers::D3D11ShareHandleImage*>(srcImage), + destSize, destOrigin); + case ImageFormat::D3D11_TEXTURE_IMF_SAMPLE: + return BlitImage( + static_cast<layers::D3D11TextureIMFSampleImage*>(srcImage), destSize, + destOrigin); + case ImageFormat::D3D11_YCBCR_IMAGE: + return BlitImage(static_cast<layers::D3D11YCbCrImage*>(srcImage), + destSize, destOrigin); + case ImageFormat::D3D9_RGB32_TEXTURE: + return false; // todo + case ImageFormat::DCOMP_SURFACE: + return false; +#else + case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE: + case ImageFormat::D3D11_TEXTURE_IMF_SAMPLE: + case ImageFormat::D3D11_YCBCR_IMAGE: + case ImageFormat::D3D9_RGB32_TEXTURE: + case ImageFormat::DCOMP_SURFACE: + MOZ_ASSERT(false); + return false; +#endif + case ImageFormat::DMABUF: +#ifdef MOZ_WIDGET_GTK + return BlitImage(static_cast<layers::DMABUFSurfaceImage*>(srcImage), + destSize, destOrigin); +#else + return false; +#endif + case ImageFormat::MOZ2D_SURFACE: + case ImageFormat::NV_IMAGE: + case ImageFormat::OVERLAY_IMAGE: + case ImageFormat::SHARED_RGB: + case ImageFormat::TEXTURE_WRAPPER: + return false; // todo + } + return false; +} + +// ------------------------------------- + +#ifdef MOZ_WIDGET_ANDROID +bool GLBlitHelper::Blit(const java::GeckoSurfaceTexture::Ref& surfaceTexture, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + if (!surfaceTexture) { + return false; + } + + const ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); + + if (!surfaceTexture->IsAttachedToGLContext((int64_t)mGL)) { + GLuint tex; + mGL->MakeCurrent(); + mGL->fGenTextures(1, &tex); + + if (NS_FAILED(surfaceTexture->AttachToGLContext((int64_t)mGL, tex))) { + mGL->fDeleteTextures(1, &tex); + return false; + } + } + + const ScopedBindTexture savedTex(mGL, surfaceTexture->GetTexName(), + LOCAL_GL_TEXTURE_EXTERNAL); + surfaceTexture->UpdateTexImage(); + const auto transform3 = Mat3::I(); + // const auto srcOrigin = OriginPos::TopLeft; + const auto srcOrigin = OriginPos::BottomLeft; + const bool yFlip = (srcOrigin != destOrigin); + const auto& prog = GetDrawBlitProg( + {kFragHeader_TexExt, {kFragSample_OnePlane, kFragConvert_None}}); + const DrawBlitProg::BaseArgs baseArgs = {transform3, yFlip, destSize, + Nothing()}; + prog->Draw(baseArgs, nullptr); + + if (surfaceTexture->IsSingleBuffer()) { + surfaceTexture->ReleaseTexImage(); + } + + return true; +} +#endif + +// ------------------------------------- + +bool GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize, + gfx::IntSize* const out_divisors) { + const gfx::IntSize divisors((ySize.width == uvSize.width) ? 1 : 2, + (ySize.height == uvSize.height) ? 1 : 2); + if (uvSize.width * divisors.width != ySize.width || + uvSize.height * divisors.height != ySize.height) { + return false; + } + *out_divisors = divisors; + return true; +} + +bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData, + const gfx::IntSize& destSize, + const OriginPos destOrigin) { + const auto& prog = GetDrawBlitProg( + {kFragHeader_Tex2D, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}}); + + if (!mYuvUploads[0]) { + mGL->fGenTextures(3, mYuvUploads); + const ScopedBindTexture bindTex(mGL, mYuvUploads[0]); + mGL->TexParams_SetClampNoMips(); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]); + mGL->TexParams_SetClampNoMips(); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]); + mGL->TexParams_SetClampNoMips(); + } + + // -- + + auto ySize = yuvData.YDataSize(); + auto cbcrSize = yuvData.CbCrDataSize(); + if (yuvData.mYSkip || yuvData.mCbSkip || yuvData.mCrSkip || ySize.width < 0 || + ySize.height < 0 || cbcrSize.width < 0 || cbcrSize.height < 0 || + yuvData.mYStride < 0 || yuvData.mCbCrStride < 0) { + gfxCriticalError() << "Unusual PlanarYCbCrData: " << yuvData.mYSkip << "," + << yuvData.mCbSkip << "," << yuvData.mCrSkip << ", " + << ySize.width << "," << ySize.height << ", " + << cbcrSize.width << "," << cbcrSize.height << ", " + << yuvData.mYStride << "," << yuvData.mCbCrStride; + return false; + } + + gfx::IntSize divisors; + switch (yuvData.mChromaSubsampling) { + case gfx::ChromaSubsampling::FULL: + divisors = gfx::IntSize(1, 1); + break; + case gfx::ChromaSubsampling::HALF_WIDTH: + divisors = gfx::IntSize(2, 1); + break; + case gfx::ChromaSubsampling::HALF_WIDTH_AND_HEIGHT: + divisors = gfx::IntSize(2, 2); + break; + default: + gfxCriticalError() << "Unknown chroma subsampling:" + << int(yuvData.mChromaSubsampling); + return false; + } + + // -- + + // RED textures aren't valid in GLES2, and ALPHA textures are not valid in + // desktop GL Core Profiles. So use R8 textures on GL3.0+ and GLES3.0+, but + // LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise. + GLenum internalFormat; + GLenum unpackFormat; + if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) || + mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300)) { + internalFormat = LOCAL_GL_R8; + unpackFormat = LOCAL_GL_RED; + } else { + internalFormat = LOCAL_GL_LUMINANCE; + unpackFormat = LOCAL_GL_LUMINANCE; + } + + // -- + + const ScopedSaveMultiTex saveTex(mGL, {0, 1, 2}, LOCAL_GL_TEXTURE_2D); + const ResetUnpackState reset(mGL); + const gfx::IntSize yTexSize(yuvData.mYStride, yuvData.YDataSize().height); + const gfx::IntSize uvTexSize(yuvData.mCbCrStride, + yuvData.CbCrDataSize().height); + + if (yTexSize != mYuvUploads_YSize || uvTexSize != mYuvUploads_UVSize) { + mYuvUploads_YSize = yTexSize; + mYuvUploads_UVSize = uvTexSize; + + mGL->fActiveTexture(LOCAL_GL_TEXTURE0); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]); + mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat, yTexSize.width, + yTexSize.height, 0, unpackFormat, LOCAL_GL_UNSIGNED_BYTE, + nullptr); + for (int i = 1; i < 3; i++) { + mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[i]); + mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat, uvTexSize.width, + uvTexSize.height, 0, unpackFormat, + LOCAL_GL_UNSIGNED_BYTE, nullptr); + } + } + + // -- + + mGL->fActiveTexture(LOCAL_GL_TEXTURE0); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]); + mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, yTexSize.width, + yTexSize.height, unpackFormat, LOCAL_GL_UNSIGNED_BYTE, + yuvData.mYChannel); + mGL->fActiveTexture(LOCAL_GL_TEXTURE1); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]); + mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, uvTexSize.width, + uvTexSize.height, unpackFormat, LOCAL_GL_UNSIGNED_BYTE, + yuvData.mCbChannel); + mGL->fActiveTexture(LOCAL_GL_TEXTURE2); + mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]); + mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, uvTexSize.width, + uvTexSize.height, unpackFormat, LOCAL_GL_UNSIGNED_BYTE, + yuvData.mCrChannel); + + // -- + + const auto& clipRect = yuvData.mPictureRect; + const auto srcOrigin = OriginPos::BottomLeft; + const bool yFlip = (destOrigin != srcOrigin); + + const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, yTexSize), + yFlip, destSize, Nothing()}; + const DrawBlitProg::YUVArgs yuvArgs = { + SubRectMat3(clipRect, uvTexSize, divisors), Some(yuvData.mYUVColorSpace)}; + prog->Draw(baseArgs, &yuvArgs); + return true; +} + +// ------------------------------------- + +#ifdef XP_MACOSX +bool GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + return BlitImage(srcImage->GetSurface(), destSize, destOrigin); +} + +static std::string IntAsAscii(const int x) { + std::string str; + str.reserve(6); + auto u = static_cast<unsigned int>(x); + while (u) { + str.insert(str.begin(), u & 0xff); + u >>= 8; + } + str.insert(str.begin(), '\''); + str.push_back('\''); + return str; +} + +bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + if (!iosurf) { + gfxCriticalError() << "Null MacIOSurface for GLBlitHelper::BlitImage"; + return false; + } + if (mGL->GetContextType() != GLContextType::CGL) { + MOZ_ASSERT(false); + return false; + } + const auto glCGL = static_cast<GLContextCGL*>(mGL); + const auto cglContext = glCGL->GetCGLContext(); + + const auto& srcOrigin = OriginPos::BottomLeft; + + DrawBlitProg::BaseArgs baseArgs; + baseArgs.yFlip = (destOrigin != srcOrigin); + baseArgs.destSize = destSize; + + // TODO: The colorspace is known by the IOSurface, why override it? + // See GetYUVColorSpace/GetFullRange() + DrawBlitProg::YUVArgs yuvArgs; + yuvArgs.colorSpaceForMatrix = Some(iosurf->GetYUVColorSpace()); + + const DrawBlitProg::YUVArgs* pYuvArgs = nullptr; + + auto planes = iosurf->GetPlaneCount(); + if (!planes) { + planes = 1; // Bad API. No cookie. + } + + const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE; + + std::vector<uint8_t> texUnits; + for (uint8_t i = 0; i < planes; i++) { + texUnits.push_back(i); + } + const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget); + const ScopedTexture tex0(mGL); + const ScopedTexture tex1(mGL); + const ScopedTexture tex2(mGL); + const GLuint texs[3] = {tex0, tex1, tex2}; + + const auto pixelFormat = iosurf->GetPixelFormat(); + if (mGL->ShouldSpew()) { + const auto formatStr = IntAsAscii(pixelFormat); + printf_stderr("iosurf format: %s (0x%08x)\n", formatStr.c_str(), + pixelFormat); + } + + const char* fragSample; + switch (planes) { + case 1: + switch (pixelFormat) { + case kCVPixelFormatType_24RGB: + case kCVPixelFormatType_24BGR: + case kCVPixelFormatType_32ARGB: + case kCVPixelFormatType_32BGRA: + case kCVPixelFormatType_32ABGR: + case kCVPixelFormatType_32RGBA: + case kCVPixelFormatType_64ARGB: + case kCVPixelFormatType_48RGB: + fragSample = kFragSample_OnePlane; + break; + case kCVPixelFormatType_422YpCbCr8: + case kCVPixelFormatType_422YpCbCr8_yuvs: + fragSample = kFragSample_OnePlane_YUV_via_GBR; + pYuvArgs = &yuvArgs; + break; + default: { + std::string str; + if (pixelFormat <= 0xff) { + str = std::to_string(pixelFormat); + } else { + str = IntAsAscii(pixelFormat); + } + gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str; + // Probably YUV though + fragSample = kFragSample_OnePlane_YUV_via_GBR; + pYuvArgs = &yuvArgs; + break; + } + } + break; + case 2: + fragSample = kFragSample_TwoPlane; + pYuvArgs = &yuvArgs; + break; + case 3: + fragSample = kFragSample_ThreePlane; + pYuvArgs = &yuvArgs; + break; + default: + gfxCriticalError() << "Unexpected plane count: " << planes; + return false; + } + + for (uint32_t p = 0; p < planes; p++) { + mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + p); + mGL->fBindTexture(texTarget, texs[p]); + mGL->TexParams_SetClampNoMips(texTarget); + + auto err = iosurf->CGLTexImageIOSurface2D(mGL, cglContext, p); + if (err) { + return false; + } + + if (p == 0) { + const auto width = iosurf->GetDevicePixelWidth(p); + const auto height = iosurf->GetDevicePixelHeight(p); + baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height); + yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0); + } + } + + const auto& prog = GetDrawBlitProg({ + kFragHeader_Tex2DRect, + {fragSample, kFragConvert_ColorMatrix}, + }); + prog->Draw(baseArgs, pYuvArgs); + return true; +} +#endif + +// ----------------------------------------------------------------------------- + +void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + const GLenum srcTarget, + const bool srcIsBGRA) const { + const char* fragHeader = nullptr; + Mat3 texMatrix0; + switch (srcTarget) { + case LOCAL_GL_TEXTURE_2D: + fragHeader = kFragHeader_Tex2D; + texMatrix0 = Mat3::I(); + break; + case LOCAL_GL_TEXTURE_RECTANGLE_ARB: + fragHeader = kFragHeader_Tex2DRect; + texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height); + break; + default: + gfxCriticalError() << "Unexpected srcTarget: " << srcTarget; + return; + } + const auto fragConvert = srcIsBGRA ? kFragConvert_BGR : kFragConvert_None; + const auto& prog = GetDrawBlitProg({ + fragHeader, + {kFragSample_OnePlane, fragConvert}, + }); + + const ScopedSaveMultiTex saveTex(mGL, {0}, srcTarget); + mGL->fActiveTexture(LOCAL_GL_TEXTURE0); + mGL->fBindTexture(srcTarget, srcTex); + + const bool yFlip = false; + const DrawBlitProg::BaseArgs baseArgs = {texMatrix0, yFlip, destSize, + Nothing()}; + prog->Draw(baseArgs); +} + +// ----------------------------------------------------------------------------- + +void GLBlitHelper::BlitFramebuffer(const gfx::IntRect& srcRect, + const gfx::IntRect& destRect, + GLuint filter) const { + MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); + + const ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); + mGL->fBlitFramebuffer(srcRect.x, srcRect.y, srcRect.XMost(), srcRect.YMost(), + destRect.x, destRect.y, destRect.XMost(), + destRect.YMost(), LOCAL_GL_COLOR_BUFFER_BIT, filter); +} + +// -- + +void GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB, + const GLuint destFB, + const gfx::IntRect& srcRect, + const gfx::IntRect& destRect, + GLuint filter) const { + MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); + MOZ_GL_ASSERT(mGL, !srcFB || mGL->fIsFramebuffer(srcFB)); + MOZ_GL_ASSERT(mGL, !destFB || mGL->fIsFramebuffer(destFB)); + + const ScopedBindFramebuffer boundFB(mGL); + mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB); + mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB); + + BlitFramebuffer(srcRect, destRect, filter); +} + +void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum srcTarget) const { + MOZ_GL_ASSERT(mGL, mGL->fIsTexture(srcTex)); + + if (mGL->IsSupported(GLFeature::framebuffer_blit)) { + const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); + const ScopedBindFramebuffer bindFB(mGL); + mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcWrapper.FB()); + BlitFramebuffer(gfx::IntRect({}, srcSize), gfx::IntRect({}, destSize)); + return; + } + + DrawBlitTextureToFramebuffer(srcTex, srcSize, destSize, srcTarget); +} + +void GLBlitHelper::BlitFramebufferToTexture(GLuint destTex, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum destTarget) const { + MOZ_GL_ASSERT(mGL, mGL->fIsTexture(destTex)); + + if (mGL->IsSupported(GLFeature::framebuffer_blit)) { + const ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget); + const ScopedBindFramebuffer bindFB(mGL); + mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destWrapper.FB()); + BlitFramebuffer(gfx::IntRect({}, srcSize), gfx::IntRect({}, destSize)); + return; + } + + ScopedBindTexture autoTex(mGL, destTex, destTarget); + ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); + mGL->fCopyTexSubImage2D(destTarget, 0, 0, 0, 0, 0, srcSize.width, + srcSize.height); +} + +void GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum srcTarget, + GLenum destTarget) const { + MOZ_GL_ASSERT(mGL, mGL->fIsTexture(srcTex)); + MOZ_GL_ASSERT(mGL, mGL->fIsTexture(destTex)); + + // Start down the CopyTexSubImage path, not the DrawBlit path. + const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); + const ScopedBindFramebuffer bindFB(mGL, srcWrapper.FB()); + BlitFramebufferToTexture(destTex, srcSize, destSize, destTarget); +} + +// ------------------------------------- + +bool GLBlitHelper::BlitImage(layers::GPUVideoImage* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& data = srcImage->GetData(); + if (!data) return false; + + const auto& desc = data->SD(); + + MOZ_ASSERT( + desc.type() == + layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder); + const auto& subdescUnion = + desc.get_SurfaceDescriptorRemoteDecoder().subdesc(); + switch (subdescUnion.type()) { +#ifdef MOZ_WIDGET_GTK + case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDMABuf: { + const auto& subdesc = subdescUnion.get_SurfaceDescriptorDMABuf(); + RefPtr<DMABufSurface> surface = + DMABufSurface::CreateDMABufSurface(subdesc); + return Blit(surface, destSize, destOrigin); + } +#endif +#ifdef XP_WIN + case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10: { + const auto& subdesc = subdescUnion.get_SurfaceDescriptorD3D10(); + return BlitDescriptor(subdesc, destSize, destOrigin); + } + case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDXGIYCbCr: { + const auto& subdesc = subdescUnion.get_SurfaceDescriptorDXGIYCbCr(); + return BlitDescriptor(subdesc, destSize, destOrigin); + } +#endif +#ifdef XP_MACOSX + case layers::RemoteDecoderVideoSubDescriptor:: + TSurfaceDescriptorMacIOSurface: { + const auto& subdesc = subdescUnion.get_SurfaceDescriptorMacIOSurface(); + RefPtr<MacIOSurface> surface = MacIOSurface::LookupSurface( + subdesc.surfaceId(), !subdesc.isOpaque(), subdesc.yUVColorSpace()); + MOZ_ASSERT(surface); + if (!surface) { + return false; + } + return BlitImage(surface, destSize, destOrigin); + } +#endif + case layers::RemoteDecoderVideoSubDescriptor::Tnull_t: + // This GPUVideoImage isn't directly readable outside the GPU process. + // Abort. + return false; + default: + gfxCriticalError() << "Unhandled subdesc type: " + << uint32_t(subdescUnion.type()); + return false; + } +} + +// ------------------------------------- +#ifdef MOZ_WIDGET_GTK +bool GLBlitHelper::Blit(DMABufSurface* surface, const gfx::IntSize& destSize, + OriginPos destOrigin) const { + const auto& srcOrigin = OriginPos::BottomLeft; + + DrawBlitProg::BaseArgs baseArgs; + baseArgs.yFlip = (destOrigin != srcOrigin); + baseArgs.destSize = destSize; + + // TODO: The colorspace is known by the DMABUFSurface, why override it? + // See GetYUVColorSpace/GetFullRange() + DrawBlitProg::YUVArgs yuvArgs; + yuvArgs.colorSpaceForMatrix = Some(surface->GetYUVColorSpace()); + + const DrawBlitProg::YUVArgs* pYuvArgs = nullptr; + const auto planes = surface->GetTextureCount(); + + // - + // Ensure textures for all planes have been created. + + const bool createTextures = [&]() { + for (int i = 0; i < planes; i++) { + if (!surface->GetTexture(i)) { + return true; + } + } + return false; + }(); + + bool didCreateTexture = false; + auto releaseTextures = mozilla::MakeScopeExit([&] { + if (didCreateTexture) { + surface->ReleaseTextures(); + } + }); + + if (createTextures) { + for (int i = 0; i < planes; i++) { + if (surface->GetTexture(i)) { + continue; + } + if (!surface->CreateTexture(mGL, i)) { + LOGDMABUF(("GLBlitHelper::Blit(): Failed to create DMABuf textures.")); + return false; + } + didCreateTexture = true; + } + } + + // - + + const GLenum texTarget = LOCAL_GL_TEXTURE_2D; + + std::vector<uint8_t> texUnits; + for (uint8_t i = 0; i < planes; i++) { + texUnits.push_back(i); + } + const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget); + const auto pixelFormat = surface->GetSurfaceType(); + + const char* fragSample; + auto fragConvert = kFragConvert_None; + switch (pixelFormat) { + case DMABufSurface::SURFACE_RGBA: + fragSample = kFragSample_OnePlane; + break; + case DMABufSurface::SURFACE_NV12: + fragSample = kFragSample_TwoPlane; + pYuvArgs = &yuvArgs; + fragConvert = kFragConvert_ColorMatrix; + break; + case DMABufSurface::SURFACE_YUV420: + fragSample = kFragSample_ThreePlane; + pYuvArgs = &yuvArgs; + fragConvert = kFragConvert_ColorMatrix; + break; + default: + gfxCriticalError() << "Unexpected pixel format: " << pixelFormat; + return false; + } + + for (const auto p : IntegerRange(planes)) { + mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + p); + mGL->fBindTexture(texTarget, surface->GetTexture(p)); + mGL->TexParams_SetClampNoMips(texTarget); + } + + // We support only NV12/YUV420 formats only with 1/2 texture scale. + // We don't set cliprect as DMABus textures are created without padding. + baseArgs.texMatrix0 = SubRectMat3(0, 0, 1, 1); + yuvArgs.texMatrix1 = SubRectMat3(0, 0, 1, 1); + + const auto& prog = + GetDrawBlitProg({kFragHeader_Tex2D, {fragSample, fragConvert}}); + prog->Draw(baseArgs, pYuvArgs); + + return true; +} + +bool GLBlitHelper::BlitImage(layers::DMABUFSurfaceImage* srcImage, + const gfx::IntSize& destSize, + OriginPos destOrigin) const { + DMABufSurface* surface = srcImage->GetSurface(); + if (!surface) { + gfxCriticalError() << "Null DMABUFSurface for GLBlitHelper::BlitImage"; + return false; + } + return Blit(surface, destSize, destOrigin); +} +#endif + +// - + +template <size_t N> +static void PushUnorm(uint32_t* const out, const float inVal) { + const uint32_t mask = (1 << N) - 1; + auto fval = inVal; + fval = std::max(0.0f, std::min(fval, 1.0f)); + fval *= mask; + fval = roundf(fval); + auto ival = static_cast<uint32_t>(fval); + ival &= mask; + + *out <<= N; + *out |= ival; +} + +static uint32_t toRgb10A2(const color::vec4& val) { + // R in LSB + uint32_t ret = 0; + PushUnorm<2>(&ret, val.w()); + PushUnorm<10>(&ret, val.z()); + PushUnorm<10>(&ret, val.y()); + PushUnorm<10>(&ret, val.x()); + return ret; +} + +std::shared_ptr<gl::Texture> GLBlitHelper::GetColorLutTex( + const ColorLutKey& key) const { + auto& weak = mColorLutTexMap[key]; + auto strong = weak.lock(); + if (!strong) { + auto& gl = *mGL; + strong = std::make_shared<gl::Texture>(gl); + weak = strong; + + const auto ct = color::ColorspaceTransform::Create(key.src, key.dst); + + // - + + const auto minLutSize = color::ivec3{2}; + const auto maxLutSize = color::ivec3{256}; + auto lutSize = minLutSize; + if (ct.srcSpace.yuv) { + lutSize.x(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_y())); + lutSize.y(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_cb())); + lutSize.z(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_cr())); + } else { + lutSize.x(int(StaticPrefs::gfx_blithelper_lut_size_rgb_r())); + lutSize.y(int(StaticPrefs::gfx_blithelper_lut_size_rgb_g())); + lutSize.z(int(StaticPrefs::gfx_blithelper_lut_size_rgb_b())); + } + lutSize = max(minLutSize, min(lutSize, maxLutSize)); // Clamp + + const auto lut = ct.ToLut3(lutSize); + const auto& size = lut.size; + + // - + + constexpr GLenum target = LOCAL_GL_TEXTURE_3D; + const auto bind = gl::ScopedBindTexture(&gl, strong->name, target); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + + bool useFloat16 = true; + if (useFloat16) { + // Use rgba16f, which we can thankfully upload as rgba32f + static_assert(sizeof(color::vec4) == sizeof(float) * 4); + std::vector<color::vec4> uploadData; + uploadData.reserve(lut.data.size()); + for (const auto& src : lut.data) { + const auto dst = color::vec4{src, 1}; + uploadData.push_back(dst); + } + + gl.fTexStorage3D(target, 1, LOCAL_GL_RGBA16F, size.x(), size.y(), + size.z()); + gl.fTexSubImage3D(target, 0, 0, 0, 0, size.x(), size.y(), size.z(), + LOCAL_GL_RGBA, LOCAL_GL_FLOAT, uploadData.data()); + } else { + // Use Rgb10A2 + std::vector<uint32_t> uploadData; + uploadData.reserve(lut.data.size()); + for (const auto& src : lut.data) { + const auto dst = toRgb10A2({src, 1}); + uploadData.push_back(dst); + } + + gl.fTexStorage3D(target, 1, LOCAL_GL_RGB10_A2, size.x(), size.y(), + size.z()); + gl.fTexSubImage3D(target, 0, 0, 0, 0, size.x(), size.y(), size.z(), + LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV, + uploadData.data()); + } + } + return strong; +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h new file mode 100644 index 0000000000..8391509097 --- /dev/null +++ b/gfx/gl/GLBlitHelper.h @@ -0,0 +1,338 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLBLITHELPER_H_ +#define GLBLITHELPER_H_ + +#include <array> +#include <cstdint> +#include <map> +#include <memory> +#include <unordered_map> +#include "Colorspaces.h" +#include "GLConsts.h" +#include "GLContextTypes.h" +#include "GLTypes.h" +#include "nsSize.h" +#include "nsString.h" +#include "nsTString.h" +#include "mozilla/ipc/IPCTypes.h" +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/gfx/Rect.h" +#include "mozilla/gfx/Types.h" + +#include <map> + +#ifdef XP_WIN +# include <windows.h> +# include "mozilla/RefPtr.h" +# include "mozilla/ipc/IPCTypes.h" +struct ID3D11Device; +struct ID3D11Texture2D; +#endif + +#ifdef XP_MACOSX +class MacIOSurface; +#endif + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/java/GeckoSurfaceTextureWrappers.h" +#endif + +#ifdef MOZ_WIDGET_GTK +class DMABufSurface; +#endif + +namespace mozilla { + +namespace layers { +class Image; +class GPUVideoImage; +struct PlanarYCbCrData; +class PlanarYCbCrImage; +class SurfaceDescriptor; +class SurfaceDescriptorBuffer; + +#ifdef XP_WIN +class D3D11ShareHandleImage; +class D3D11TextureIMFSampleImage; +class D3D11YCbCrImage; +class SurfaceDescriptorD3D10; +class SurfaceDescriptorDXGIYCbCr; +#endif + +#ifdef MOZ_WIDGET_ANDROID +class SurfaceTextureDescriptor; +#endif + +#ifdef XP_MACOSX +class MacIOSurfaceImage; +#endif + +#ifdef MOZ_WIDGET_GTK +class DMABUFSurfaceImage; +#endif +} // namespace layers + +namespace gl { + +class BindAnglePlanes; +class GLBlitHelper; +class GLContext; +class Texture; + +bool GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize, + gfx::IntSize* const out_divisors); + +template <uint8_t N> +struct Mat { + float m[N * N]; // column-major, for GL + + float& at(const uint8_t x, const uint8_t y) { return m[N * x + y]; } + + static Mat<N> I() { + auto ret = Mat<N>{}; + for (uint8_t i = 0; i < N; i++) { + ret.at(i, i) = 1.0f; + } + return ret; + } + + Mat<N> operator*(const Mat<N>& r) const { + Mat<N> ret; + for (uint8_t x = 0; x < N; x++) { + for (uint8_t y = 0; y < N; y++) { + float sum = 0.0f; + for (uint8_t i = 0; i < N; i++) { + sum += at(i, y) * r.at(x, i); + } + ret.at(x, y) = sum; + } + } + return ret; + } +}; +typedef Mat<3> Mat3; + +Mat3 SubRectMat3(float x, float y, float w, float h); +Mat3 SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size); +Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize, + const gfx::IntSize& divisors); + +class DrawBlitProg final { + const GLBlitHelper& mParent; + const GLuint mProg; + const GLint mLoc_uDestMatrix; + const GLint mLoc_uTexMatrix0; + const GLint mLoc_uTexMatrix1; + const GLint mLoc_uColorLut; + const GLint mLoc_uColorMatrix; + GLenum mType_uColorMatrix = 0; + + public: + struct Key final { + const char* fragHeader = nullptr; + std::array<const char*, 4> fragParts = {}; + + auto Members() const { return std::tie(fragHeader, fragParts); } + friend bool operator<(const Key& a, const Key& b) { + return a.Members() < b.Members(); + } + }; + + DrawBlitProg(const GLBlitHelper* parent, GLuint prog); + ~DrawBlitProg(); + + struct BaseArgs final { + Mat3 texMatrix0; + bool yFlip; + gfx::IntSize + destSize; // Always needed for (at least) setting the viewport. + Maybe<gfx::IntRect> destRect; + Maybe<uint32_t> texUnitForColorLut; + }; + struct YUVArgs final { + Mat3 texMatrix1; + Maybe<gfx::YUVColorSpace> colorSpaceForMatrix; + }; + + void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const; +}; + +class ScopedSaveMultiTex final { + GLContext& mGL; + const std::vector<uint8_t> mTexUnits; + const GLenum mTexTarget; + const GLuint mOldTexUnit; + GLuint mOldTexSampler[3]; + GLuint mOldTex[3]; + + public: + ScopedSaveMultiTex(GLContext* gl, const std::vector<uint8_t>& texUnits, + GLenum texTarget); + ~ScopedSaveMultiTex(); +}; + +/** Buffer blitting helper */ +class GLBlitHelper final { + friend class BindAnglePlanes; + friend class DrawBlitProg; + friend class GLContext; + + GLContext* const mGL; + mutable std::map<DrawBlitProg::Key, const DrawBlitProg*> mDrawBlitProgs; + + GLuint mQuadVAO = 0; + GLuint mQuadVBO = 0; + nsCString mDrawBlitProg_VersionLine; + const GLuint mDrawBlitProg_VertShader; + + GLuint mYuvUploads[3] = {}; + gfx::IntSize mYuvUploads_YSize = {0, 0}; + gfx::IntSize mYuvUploads_UVSize = {0, 0}; + + public: + struct ColorLutKey { + color::ColorspaceDesc src; + color::ColorspaceDesc dst; + + auto Members() const { return std::tie(src, dst); } + INLINE_AUTO_MAPPABLE(ColorLutKey) + }; + + private: + mutable std::unordered_map<ColorLutKey, std::weak_ptr<gl::Texture>, + ColorLutKey::Hasher> + mColorLutTexMap; + + public: + std::shared_ptr<gl::Texture> GetColorLutTex(const ColorLutKey& key) const; + +#ifdef XP_WIN + mutable RefPtr<ID3D11Device> mD3D11; + + ID3D11Device* GetD3D11() const; +#endif + + const DrawBlitProg* GetDrawBlitProg(const DrawBlitProg::Key& key) const; + + private: + const DrawBlitProg* CreateDrawBlitProg(const DrawBlitProg::Key& key) const; + + public: + bool BlitPlanarYCbCr(const layers::PlanarYCbCrData&, + const gfx::IntSize& destSize, OriginPos destOrigin); +#ifdef MOZ_WIDGET_ANDROID + bool Blit(const java::GeckoSurfaceTexture::Ref& surfaceTexture, + const gfx::IntSize& destSize, const OriginPos destOrigin) const; +#endif +#ifdef XP_MACOSX + bool BlitImage(layers::MacIOSurfaceImage* srcImage, + const gfx::IntSize& destSize, OriginPos destOrigin) const; +#endif +#ifdef MOZ_WIDGET_GTK + bool Blit(DMABufSurface* surface, const gfx::IntSize& destSize, + OriginPos destOrigin) const; + bool BlitImage(layers::DMABUFSurfaceImage* srcImage, + const gfx::IntSize& destSize, OriginPos destOrigin) const; +#endif + + explicit GLBlitHelper(GLContext* gl); + + public: + ~GLBlitHelper(); + + void BlitFramebuffer(const gfx::IntRect& srcRect, + const gfx::IntRect& destRect, + GLuint filter = LOCAL_GL_NEAREST) const; + void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, + const gfx::IntRect& srcRect, + const gfx::IntRect& destRect, + GLuint filter = LOCAL_GL_NEAREST) const; + void BlitFramebufferToTexture(GLuint destTex, const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum destTarget = LOCAL_GL_TEXTURE_2D) const; + void BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const; + void BlitTextureToTexture(GLuint srcTex, GLuint destTex, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum srcTarget = LOCAL_GL_TEXTURE_2D, + GLenum destTarget = LOCAL_GL_TEXTURE_2D) const; + + void DrawBlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, + GLenum srcTarget = LOCAL_GL_TEXTURE_2D, + bool srcIsBGRA = false) const; + + bool BlitImageToFramebuffer(layers::Image* srcImage, + const gfx::IntSize& destSize, + OriginPos destOrigin); + bool BlitSdToFramebuffer(const layers::SurfaceDescriptor&, + const gfx::IntSize& destSize, OriginPos destOrigin); + + private: + bool BlitImage(layers::GPUVideoImage* srcImage, const gfx::IntSize& destSize, + OriginPos destOrigin) const; +#ifdef XP_MACOSX + bool BlitImage(MacIOSurface* const iosurf, const gfx::IntSize& destSize, + OriginPos destOrigin) const; +#endif +#ifdef XP_WIN + // GLBlitHelperD3D.cpp: + bool BlitImage(layers::D3D11ShareHandleImage* srcImage, + const gfx::IntSize& destSize, OriginPos destOrigin) const; + bool BlitImage(layers::D3D11TextureIMFSampleImage* srcImage, + const gfx::IntSize& destSize, OriginPos destOrigin) const; + bool BlitImage(layers::D3D11YCbCrImage* srcImage, + const gfx::IntSize& destSize, OriginPos destOrigin) const; + + bool BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc, + const gfx::IntSize& destSize, OriginPos destOrigin) const; + bool BlitDescriptor(const layers::SurfaceDescriptorDXGIYCbCr& desc, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const; + bool BlitAngleYCbCr(const WindowsHandle (&handleList)[3], + const gfx::IntRect& clipRect, const gfx::IntSize& ySize, + const gfx::IntSize& uvSize, + const gfx::YUVColorSpace colorSpace, + const gfx::IntSize& destSize, OriginPos destOrigin) const; + + bool BlitAnglePlanes(uint8_t numPlanes, + const RefPtr<ID3D11Texture2D>* texD3DList, + const DrawBlitProg* prog, + const DrawBlitProg::BaseArgs& baseArgs, + const DrawBlitProg::YUVArgs* const yuvArgs) const; +#endif +}; + +// - +// For DrawBlitProg::Key::fragParts + +extern const char* const kFragHeader_Tex2D; +extern const char* const kFragHeader_Tex2DRect; +extern const char* const kFragHeader_TexExt; + +extern const char* const kFragSample_OnePlane; +extern const char* const kFragSample_TwoPlane; +extern const char* const kFragSample_ThreePlane; + +extern const char* const kFragConvert_None; +extern const char* const kFragConvert_BGR; +extern const char* const kFragConvert_ColorMatrix; +extern const char* const kFragConvert_ColorLut; + +extern const char* const kFragMixin_AlphaMultColors; +extern const char* const kFragMixin_AlphaClampColors; +extern const char* const kFragMixin_AlphaOne; + +} // namespace gl +} // namespace mozilla + +#endif // GLBLITHELPER_H_ diff --git a/gfx/gl/GLBlitHelperD3D.cpp b/gfx/gl/GLBlitHelperD3D.cpp new file mode 100644 index 0000000000..ae6362e278 --- /dev/null +++ b/gfx/gl/GLBlitHelperD3D.cpp @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLBlitHelper.h" + +#include <d3d11.h> +#include <d3d11_1.h> + +#include "GLContextEGL.h" +#include "GLLibraryEGL.h" +#include "GPUVideoImage.h" +#include "ScopedGLHelpers.h" + +#include "mozilla/layers/D3D11ShareHandleImage.h" +#include "mozilla/layers/D3D11TextureIMFSampleImage.h" +#include "mozilla/layers/D3D11YCbCrImage.h" +#include "mozilla/layers/GpuProcessD3D11TextureMap.h" +#include "mozilla/layers/TextureD3D11.h" +#include "mozilla/StaticPrefs_gl.h" + +namespace mozilla { +namespace gl { + +#define NOTE_IF_FALSE(expr) \ + do { \ + if (!(expr)) { \ + gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \ + } \ + } while (false) + +static EGLStreamKHR StreamFromD3DTexture(EglDisplay* const egl, + ID3D11Texture2D* const texD3D, + const EGLAttrib* const postAttribs) { + if (!egl->IsExtensionSupported( + EGLExtension::NV_stream_consumer_gltexture_yuv) || + !egl->IsExtensionSupported( + EGLExtension::ANGLE_stream_producer_d3d_texture)) { + return 0; + } + + const auto stream = egl->fCreateStreamKHR(nullptr); + MOZ_ASSERT(stream); + if (!stream) return 0; + bool ok = true; + NOTE_IF_FALSE(ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV( + stream, nullptr))); + NOTE_IF_FALSE( + ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(stream, nullptr))); + NOTE_IF_FALSE( + ok &= bool(egl->fStreamPostD3DTextureANGLE(stream, texD3D, postAttribs))); + if (ok) return stream; + + (void)egl->fDestroyStreamKHR(stream); + return 0; +} + +static RefPtr<ID3D11Texture2D> OpenSharedTexture(ID3D11Device* const d3d, + const WindowsHandle handle) { + RefPtr<ID3D11Device1> device1; + d3d->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); + if (!device1) { + gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; + return nullptr; + } + + RefPtr<ID3D11Texture2D> tex; + auto hr = device1->OpenSharedResource1( + (HANDLE)handle, __uuidof(ID3D11Texture2D), + (void**)(ID3D11Texture2D**)getter_AddRefs(tex)); + if (FAILED(hr)) { + gfxCriticalError() << "Error code from OpenSharedResource1: " + << gfx::hexa(hr); + return nullptr; + } + return tex; +} + +// ------------------------------------- + +class BindAnglePlanes final { + const GLBlitHelper& mParent; + const uint8_t mNumPlanes; + const ScopedSaveMultiTex mMultiTex; + GLuint mTempTexs[3]; + EGLStreamKHR mStreams[3]; + RefPtr<IDXGIKeyedMutex> mMutexList[3]; + bool mSuccess; + + public: + BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes, + const RefPtr<ID3D11Texture2D>* const texD3DList, + const EGLAttrib* const* postAttribsList = nullptr) + : mParent(*parent), + mNumPlanes(numPlanes), + mMultiTex( + mParent.mGL, + [&]() { + std::vector<uint8_t> ret; + for (int i = 0; i < numPlanes; i++) { + ret.push_back(i); + } + return ret; + }(), + LOCAL_GL_TEXTURE_EXTERNAL), + mTempTexs{0}, + mStreams{0}, + mSuccess(true) { + MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3); + + const auto& gl = mParent.mGL; + const auto& gle = GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + + gl->fGenTextures(numPlanes, mTempTexs); + + for (uint8_t i = 0; i < mNumPlanes; i++) { + gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); + gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]); + const EGLAttrib* postAttribs = nullptr; + if (postAttribsList) { + postAttribs = postAttribsList[i]; + } + mStreams[i] = StreamFromD3DTexture(egl.get(), texD3DList[i], postAttribs); + mSuccess &= bool(mStreams[i]); + } + + if (mSuccess) { + for (uint8_t i = 0; i < mNumPlanes; i++) { + NOTE_IF_FALSE(egl->fStreamConsumerAcquireKHR(mStreams[i])); + + auto& mutex = mMutexList[i]; + texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex, + (void**)getter_AddRefs(mutex)); + if (mutex) { + const auto hr = mutex->AcquireSync(0, 100); + if (FAILED(hr)) { + NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex."); + mSuccess = false; + } + } + } + } + } + + ~BindAnglePlanes() { + const auto& gl = mParent.mGL; + const auto& gle = GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + + if (mSuccess) { + for (uint8_t i = 0; i < mNumPlanes; i++) { + NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i])); + if (mMutexList[i]) { + mMutexList[i]->ReleaseSync(0); + } + } + } + + for (uint8_t i = 0; i < mNumPlanes; i++) { + (void)egl->fDestroyStreamKHR(mStreams[i]); + } + + gl->fDeleteTextures(mNumPlanes, mTempTexs); + } + + const bool& Success() const { return mSuccess; } +}; + +// ------------------------------------- + +ID3D11Device* GLBlitHelper::GetD3D11() const { + if (mD3D11) return mD3D11; + + if (!mGL->IsANGLE()) return nullptr; + + const auto& gle = GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + EGLDeviceEXT deviceEGL = 0; + NOTE_IF_FALSE(egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, + (EGLAttrib*)&deviceEGL)); + ID3D11Device* device = nullptr; + // ANGLE does not `AddRef` its returned pointer for `QueryDeviceAttrib`, so no + // `getter_AddRefs`. + if (!egl->mLib->fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE, + (EGLAttrib*)&device)) { + MOZ_ASSERT(false, "d3d9?"); + return nullptr; + } + mD3D11 = device; + return mD3D11; +} + +// ------------------------------------- + +bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& data = srcImage->GetData(); + if (!data) return false; + + layers::SurfaceDescriptorD3D10 desc; + if (!data->SerializeSpecific(&desc)) return false; + + return BlitDescriptor(desc, destSize, destOrigin); +} + +// ------------------------------------- + +bool GLBlitHelper::BlitImage(layers::D3D11TextureIMFSampleImage* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& data = srcImage->GetData(); + if (!data) return false; + + layers::SurfaceDescriptorD3D10 desc; + if (!data->SerializeSpecific(&desc)) return false; + + return BlitDescriptor(desc, destSize, destOrigin); +} + +// ------------------------------------- + +bool GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& data = srcImage->GetData(); + if (!data) return false; + + const WindowsHandle handles[3] = { + (WindowsHandle)(data->mHandles[0] ? data->mHandles[0]->GetHandle() + : nullptr), + (WindowsHandle)(data->mHandles[1] ? data->mHandles[1]->GetHandle() + : nullptr), + (WindowsHandle)(data->mHandles[2] ? data->mHandles[2]->GetHandle() + : nullptr)}; + return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->GetYSize(), + srcImage->GetCbCrSize(), srcImage->mColorSpace, + destSize, destOrigin); +} + +// ------------------------------------- + +bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& d3d = GetD3D11(); + if (!d3d) return false; + + const auto& gpuProcessTextureId = desc.gpuProcessTextureId(); + const auto& arrayIndex = desc.arrayIndex(); + const auto& format = desc.format(); + const auto& clipSize = desc.size(); + + const auto srcOrigin = OriginPos::BottomLeft; + const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height); + const auto colorSpace = desc.colorSpace(); + + if (format != gfx::SurfaceFormat::NV12 && + format != gfx::SurfaceFormat::P010 && + format != gfx::SurfaceFormat::P016) { + gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: " + << uint32_t(format); + return false; + } + + RefPtr<ID3D11Texture2D> tex; + if (gpuProcessTextureId.isSome()) { + auto* textureMap = layers::GpuProcessD3D11TextureMap::Get(); + if (textureMap) { + Maybe<HANDLE> handle = + textureMap->GetSharedHandleOfCopiedTexture(gpuProcessTextureId.ref()); + if (handle.isSome()) { + tex = OpenSharedTexture(d3d, (WindowsHandle)handle.ref()); + } + } + } else if (desc.handle()) { + tex = OpenSharedTexture(d3d, (WindowsHandle)desc.handle()->GetHandle()); + } + if (!tex) { + MOZ_GL_ASSERT(mGL, false); // Get a nullptr from OpenSharedResource1. + return false; + } + const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex}; + const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0, + LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, + static_cast<EGLAttrib>(arrayIndex), + LOCAL_EGL_NONE}; + const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1, + LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, + static_cast<EGLAttrib>(arrayIndex), + LOCAL_EGL_NONE}; + const EGLAttrib* const postAttribsList[2] = {postAttribs0, postAttribs1}; + // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12. + // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin); + + const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList); + if (!bindPlanes.Success()) { + MOZ_GL_ASSERT(mGL, false); // BindAnglePlanes failed. + return false; + } + + D3D11_TEXTURE2D_DESC texDesc = {0}; + tex->GetDesc(&texDesc); + + const gfx::IntSize ySize(texDesc.Width, texDesc.Height); + const gfx::IntSize divisors(2, 2); + MOZ_ASSERT(ySize.width % divisors.width == 0); + MOZ_ASSERT(ySize.height % divisors.height == 0); + const gfx::IntSize uvSize(ySize.width / divisors.width, + ySize.height / divisors.height); + + const auto yuvColorSpace = [&]() { + switch (colorSpace) { + case gfx::ColorSpace2::UNKNOWN: + case gfx::ColorSpace2::SRGB: + case gfx::ColorSpace2::DISPLAY_P3: + MOZ_CRASH("Expected BT* colorspace"); + case gfx::ColorSpace2::BT601_525: + return gfx::YUVColorSpace::BT601; + case gfx::ColorSpace2::BT709: + return gfx::YUVColorSpace::BT709; + case gfx::ColorSpace2::BT2020: + return gfx::YUVColorSpace::BT2020; + } + MOZ_ASSERT_UNREACHABLE(); + }(); + + const bool yFlip = destOrigin != srcOrigin; + const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, + destSize, Nothing()}; + const DrawBlitProg::YUVArgs yuvArgs = { + SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)}; + + const auto& prog = GetDrawBlitProg( + {kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}}); + prog->Draw(baseArgs, &yuvArgs); + return true; +} + +bool GLBlitHelper::BlitDescriptor( + const layers::SurfaceDescriptorDXGIYCbCr& desc, + const gfx::IntSize& destSize, const OriginPos destOrigin) const { + const auto& clipSize = desc.size(); + const auto& ySize = desc.sizeY(); + const auto& uvSize = desc.sizeCbCr(); + const auto& colorSpace = desc.yUVColorSpace(); + + const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height); + + auto handleY = desc.handleY() ? desc.handleY()->GetHandle() : nullptr; + auto handleCb = desc.handleCb() ? desc.handleCb()->GetHandle() : nullptr; + auto handleCr = desc.handleCr() ? desc.handleCr()->GetHandle() : nullptr; + + const WindowsHandle handles[3] = { + (WindowsHandle)handleY, (WindowsHandle)handleCb, (WindowsHandle)handleCr}; + return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize, + destOrigin); +} + +// -- + +bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3], + const gfx::IntRect& clipRect, + const gfx::IntSize& ySize, + const gfx::IntSize& uvSize, + const gfx::YUVColorSpace colorSpace, + const gfx::IntSize& destSize, + const OriginPos destOrigin) const { + const auto& d3d = GetD3D11(); + if (!d3d) return false; + + const auto srcOrigin = OriginPos::BottomLeft; + + gfx::IntSize divisors; + if (!GuessDivisors(ySize, uvSize, &divisors)) return false; + + const RefPtr<ID3D11Texture2D> texList[3] = { + OpenSharedTexture(d3d, handleList[0]), + OpenSharedTexture(d3d, handleList[1]), + OpenSharedTexture(d3d, handleList[2])}; + const BindAnglePlanes bindPlanes(this, 3, texList); + + const bool yFlip = destOrigin != srcOrigin; + const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, + destSize, Nothing()}; + const DrawBlitProg::YUVArgs yuvArgs = { + SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)}; + + const auto& prog = GetDrawBlitProg( + {kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}}); + prog->Draw(baseArgs, &yuvArgs); + return true; +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLConsts.h b/gfx/gl/GLConsts.h new file mode 100644 index 0000000000..97744d4215 --- /dev/null +++ b/gfx/gl/GLConsts.h @@ -0,0 +1,7204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// clang-format off + +#ifndef GLCONSTS_H_ +#define GLCONSTS_H_ + +/** + * GENERATED FILE, DO NOT MODIFY DIRECTLY. + * This is a file generated directly from the official OpenGL registry + * xml available http://www.opengl.org/registry/#specfiles. + * + * To generate this file, see tutorial in 'GLConsts.py'. + */ + +// GL +#define LOCAL_GL_1PASS_EXT 0x80A1 +#define LOCAL_GL_1PASS_SGIS 0x80A1 +#define LOCAL_GL_2D 0x0600 +#define LOCAL_GL_2PASS_0_EXT 0x80A2 +#define LOCAL_GL_2PASS_0_SGIS 0x80A2 +#define LOCAL_GL_2PASS_1_EXT 0x80A3 +#define LOCAL_GL_2PASS_1_SGIS 0x80A3 +#define LOCAL_GL_2X_BIT_ATI 0x00000001 +#define LOCAL_GL_2_BYTES 0x1407 +#define LOCAL_GL_2_BYTES_NV 0x1407 +#define LOCAL_GL_3D 0x0601 +#define LOCAL_GL_3DC_XY_AMD 0x87FA +#define LOCAL_GL_3DC_X_AMD 0x87F9 +#define LOCAL_GL_3D_COLOR 0x0602 +#define LOCAL_GL_3D_COLOR_TEXTURE 0x0603 +#define LOCAL_GL_3_BYTES 0x1408 +#define LOCAL_GL_3_BYTES_NV 0x1408 +#define LOCAL_GL_422_AVERAGE_EXT 0x80CE +#define LOCAL_GL_422_EXT 0x80CC +#define LOCAL_GL_422_REV_AVERAGE_EXT 0x80CF +#define LOCAL_GL_422_REV_EXT 0x80CD +#define LOCAL_GL_4D_COLOR_TEXTURE 0x0604 +#define LOCAL_GL_4PASS_0_EXT 0x80A4 +#define LOCAL_GL_4PASS_0_SGIS 0x80A4 +#define LOCAL_GL_4PASS_1_EXT 0x80A5 +#define LOCAL_GL_4PASS_1_SGIS 0x80A5 +#define LOCAL_GL_4PASS_2_EXT 0x80A6 +#define LOCAL_GL_4PASS_2_SGIS 0x80A6 +#define LOCAL_GL_4PASS_3_EXT 0x80A7 +#define LOCAL_GL_4PASS_3_SGIS 0x80A7 +#define LOCAL_GL_4X_BIT_ATI 0x00000002 +#define LOCAL_GL_4_BYTES 0x1409 +#define LOCAL_GL_4_BYTES_NV 0x1409 +#define LOCAL_GL_8X_BIT_ATI 0x00000004 +#define LOCAL_GL_ABGR_EXT 0x8000 +#define LOCAL_GL_ACCUM 0x0100 +#define LOCAL_GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define LOCAL_GL_ACCUM_ALPHA_BITS 0x0D5B +#define LOCAL_GL_ACCUM_BLUE_BITS 0x0D5A +#define LOCAL_GL_ACCUM_BUFFER_BIT 0x00000200 +#define LOCAL_GL_ACCUM_CLEAR_VALUE 0x0B80 +#define LOCAL_GL_ACCUM_GREEN_BITS 0x0D59 +#define LOCAL_GL_ACCUM_RED_BITS 0x0D58 +#define LOCAL_GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define LOCAL_GL_ACTIVE_ATTRIBUTES 0x8B89 +#define LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define LOCAL_GL_ACTIVE_PROGRAM 0x8259 +#define LOCAL_GL_ACTIVE_PROGRAM_EXT 0x8B8D +#define LOCAL_GL_ACTIVE_RESOURCES 0x92F5 +#define LOCAL_GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +#define LOCAL_GL_ACTIVE_SUBROUTINES 0x8DE5 +#define LOCAL_GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define LOCAL_GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define LOCAL_GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define LOCAL_GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define LOCAL_GL_ACTIVE_TEXTURE 0x84E0 +#define LOCAL_GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define LOCAL_GL_ACTIVE_UNIFORMS 0x8B86 +#define LOCAL_GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define LOCAL_GL_ACTIVE_VARIABLES 0x9305 +#define LOCAL_GL_ACTIVE_VARYINGS_NV 0x8C81 +#define LOCAL_GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 +#define LOCAL_GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 +#define LOCAL_GL_ADD 0x0104 +#define LOCAL_GL_ADD_ATI 0x8963 +#define LOCAL_GL_ADD_BLEND_IMG 0x8C09 +#define LOCAL_GL_ADD_SIGNED 0x8574 +#define LOCAL_GL_ADD_SIGNED_ARB 0x8574 +#define LOCAL_GL_ADD_SIGNED_EXT 0x8574 +#define LOCAL_GL_ADJACENT_PAIRS_NV 0x90AE +#define LOCAL_GL_AFFINE_2D_NV 0x9092 +#define LOCAL_GL_AFFINE_3D_NV 0x9094 +#define LOCAL_GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define LOCAL_GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define LOCAL_GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 +#define LOCAL_GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 +#define LOCAL_GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E +#define LOCAL_GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F +#define LOCAL_GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define LOCAL_GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define LOCAL_GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF +#define LOCAL_GL_ALL_COMPLETED_NV 0x84F2 +#define LOCAL_GL_ALL_PIXELS_AMD 0xFFFFFFFF +#define LOCAL_GL_ALL_SHADER_BITS 0xFFFFFFFF +#define LOCAL_GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF +#define LOCAL_GL_ALL_STATIC_DATA_IBM 103060 +#define LOCAL_GL_ALPHA 0x1906 +#define LOCAL_GL_ALPHA12 0x803D +#define LOCAL_GL_ALPHA12_EXT 0x803D +#define LOCAL_GL_ALPHA16 0x803E +#define LOCAL_GL_ALPHA16F_ARB 0x881C +#define LOCAL_GL_ALPHA16F_EXT 0x881C +#define LOCAL_GL_ALPHA16I_EXT 0x8D8A +#define LOCAL_GL_ALPHA16UI_EXT 0x8D78 +#define LOCAL_GL_ALPHA16_EXT 0x803E +#define LOCAL_GL_ALPHA16_SNORM 0x9018 +#define LOCAL_GL_ALPHA32F_ARB 0x8816 +#define LOCAL_GL_ALPHA32F_EXT 0x8816 +#define LOCAL_GL_ALPHA32I_EXT 0x8D84 +#define LOCAL_GL_ALPHA32UI_EXT 0x8D72 +#define LOCAL_GL_ALPHA4 0x803B +#define LOCAL_GL_ALPHA4_EXT 0x803B +#define LOCAL_GL_ALPHA8 0x803C +#define LOCAL_GL_ALPHA8I_EXT 0x8D90 +#define LOCAL_GL_ALPHA8UI_EXT 0x8D7E +#define LOCAL_GL_ALPHA8_EXT 0x803C +#define LOCAL_GL_ALPHA8_OES 0x803C +#define LOCAL_GL_ALPHA8_SNORM 0x9014 +#define LOCAL_GL_ALPHA_BIAS 0x0D1D +#define LOCAL_GL_ALPHA_BITS 0x0D55 +#define LOCAL_GL_ALPHA_FLOAT16_APPLE 0x881C +#define LOCAL_GL_ALPHA_FLOAT16_ATI 0x881C +#define LOCAL_GL_ALPHA_FLOAT32_APPLE 0x8816 +#define LOCAL_GL_ALPHA_FLOAT32_ATI 0x8816 +#define LOCAL_GL_ALPHA_INTEGER 0x8D97 +#define LOCAL_GL_ALPHA_INTEGER_EXT 0x8D97 +#define LOCAL_GL_ALPHA_MAX_CLAMP_INGR 0x8567 +#define LOCAL_GL_ALPHA_MAX_SGIX 0x8321 +#define LOCAL_GL_ALPHA_MIN_CLAMP_INGR 0x8563 +#define LOCAL_GL_ALPHA_MIN_SGIX 0x8320 +#define LOCAL_GL_ALPHA_REF_COMMAND_NV 0x000F +#define LOCAL_GL_ALPHA_SCALE 0x0D1C +#define LOCAL_GL_ALPHA_SNORM 0x9010 +#define LOCAL_GL_ALPHA_TEST 0x0BC0 +#define LOCAL_GL_ALPHA_TEST_FUNC 0x0BC1 +#define LOCAL_GL_ALPHA_TEST_FUNC_QCOM 0x0BC1 +#define LOCAL_GL_ALPHA_TEST_QCOM 0x0BC0 +#define LOCAL_GL_ALPHA_TEST_REF 0x0BC2 +#define LOCAL_GL_ALPHA_TEST_REF_QCOM 0x0BC2 +#define LOCAL_GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV 0x934D +#define LOCAL_GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV 0x934F +#define LOCAL_GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV 0x934E +#define LOCAL_GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV 0x92BF +#define LOCAL_GL_ALREADY_SIGNALED 0x911A +#define LOCAL_GL_ALREADY_SIGNALED_APPLE 0x911A +#define LOCAL_GL_ALWAYS 0x0207 +#define LOCAL_GL_ALWAYS_FAST_HINT_PGI 0x1A20C +#define LOCAL_GL_ALWAYS_SOFT_HINT_PGI 0x1A20D +#define LOCAL_GL_AMBIENT 0x1200 +#define LOCAL_GL_AMBIENT_AND_DIFFUSE 0x1602 +#define LOCAL_GL_AND 0x1501 +#define LOCAL_GL_AND_INVERTED 0x1504 +#define LOCAL_GL_AND_REVERSE 0x1502 +#define LOCAL_GL_ANY_SAMPLES_PASSED 0x8C2F +#define LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A +#define LOCAL_GL_ANY_SAMPLES_PASSED_EXT 0x8C2F +#define LOCAL_GL_ARC_TO_NV 0xFE +#define LOCAL_GL_ARRAY_BUFFER 0x8892 +#define LOCAL_GL_ARRAY_BUFFER_ARB 0x8892 +#define LOCAL_GL_ARRAY_BUFFER_BINDING 0x8894 +#define LOCAL_GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define LOCAL_GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 +#define LOCAL_GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define LOCAL_GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define LOCAL_GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +#define LOCAL_GL_ARRAY_SIZE 0x92FB +#define LOCAL_GL_ARRAY_STRIDE 0x92FE +#define LOCAL_GL_ASYNC_DRAW_PIXELS_SGIX 0x835D +#define LOCAL_GL_ASYNC_HISTOGRAM_SGIX 0x832C +#define LOCAL_GL_ASYNC_MARKER_SGIX 0x8329 +#define LOCAL_GL_ASYNC_READ_PIXELS_SGIX 0x835E +#define LOCAL_GL_ASYNC_TEX_IMAGE_SGIX 0x835C +#define LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE +#define LOCAL_GL_ATC_RGB_AMD 0x8C92 +#define LOCAL_GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define LOCAL_GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define LOCAL_GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define LOCAL_GL_ATTACHED_MEMORY_OBJECT_NV 0x95A4 +#define LOCAL_GL_ATTACHED_MEMORY_OFFSET_NV 0x95A5 +#define LOCAL_GL_ATTACHED_SHADERS 0x8B85 +#define LOCAL_GL_ATTENUATION_EXT 0x834D +#define LOCAL_GL_ATTRIBUTE_ADDRESS_COMMAND_NV 0x0009 +#define LOCAL_GL_ATTRIB_ARRAY_POINTER_NV 0x8645 +#define LOCAL_GL_ATTRIB_ARRAY_SIZE_NV 0x8623 +#define LOCAL_GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 +#define LOCAL_GL_ATTRIB_ARRAY_TYPE_NV 0x8625 +#define LOCAL_GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define LOCAL_GL_AUTO_GENERATE_MIPMAP 0x8295 +#define LOCAL_GL_AUTO_NORMAL 0x0D80 +#define LOCAL_GL_AUX0 0x0409 +#define LOCAL_GL_AUX1 0x040A +#define LOCAL_GL_AUX2 0x040B +#define LOCAL_GL_AUX3 0x040C +#define LOCAL_GL_AUX_BUFFERS 0x0C00 +#define LOCAL_GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 +#define LOCAL_GL_AVERAGE_EXT 0x8335 +#define LOCAL_GL_AVERAGE_HP 0x8160 +#define LOCAL_GL_BACK 0x0405 +#define LOCAL_GL_BACK_LEFT 0x0402 +#define LOCAL_GL_BACK_NORMALS_HINT_PGI 0x1A223 +#define LOCAL_GL_BACK_PRIMARY_COLOR_NV 0x8C77 +#define LOCAL_GL_BACK_RIGHT 0x0403 +#define LOCAL_GL_BACK_SECONDARY_COLOR_NV 0x8C78 +#define LOCAL_GL_BEVEL_NV 0x90A6 +#define LOCAL_GL_BGR 0x80E0 +#define LOCAL_GL_BGRA 0x80E1 +#define LOCAL_GL_BGRA8_EXT 0x93A1 +#define LOCAL_GL_BGRA_EXT 0x80E1 +#define LOCAL_GL_BGRA_IMG 0x80E1 +#define LOCAL_GL_BGRA_INTEGER 0x8D9B +#define LOCAL_GL_BGRA_INTEGER_EXT 0x8D9B +#define LOCAL_GL_BGR_EXT 0x80E0 +#define LOCAL_GL_BGR_INTEGER 0x8D9A +#define LOCAL_GL_BGR_INTEGER_EXT 0x8D9A +#define LOCAL_GL_BIAS_BIT_ATI 0x00000008 +#define LOCAL_GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define LOCAL_GL_BINNING_CONTROL_HINT_QCOM 0x8FB0 +#define LOCAL_GL_BINORMAL_ARRAY_EXT 0x843A +#define LOCAL_GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 +#define LOCAL_GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 +#define LOCAL_GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 +#define LOCAL_GL_BITMAP 0x1A00 +#define LOCAL_GL_BITMAP_TOKEN 0x0704 +#define LOCAL_GL_BLACKHOLE_RENDER_INTEL 0x83FC +#define LOCAL_GL_BLEND 0x0BE2 +#define LOCAL_GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#define LOCAL_GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#define LOCAL_GL_BLEND_COLOR 0x8005 +#define LOCAL_GL_BLEND_COLOR_COMMAND_NV 0x000B +#define LOCAL_GL_BLEND_COLOR_EXT 0x8005 +#define LOCAL_GL_BLEND_DST 0x0BE0 +#define LOCAL_GL_BLEND_DST_ALPHA 0x80CA +#define LOCAL_GL_BLEND_DST_ALPHA_EXT 0x80CA +#define LOCAL_GL_BLEND_DST_ALPHA_OES 0x80CA +#define LOCAL_GL_BLEND_DST_RGB 0x80C8 +#define LOCAL_GL_BLEND_DST_RGB_EXT 0x80C8 +#define LOCAL_GL_BLEND_DST_RGB_OES 0x80C8 +#define LOCAL_GL_BLEND_EQUATION 0x8009 +#define LOCAL_GL_BLEND_EQUATION_ALPHA 0x883D +#define LOCAL_GL_BLEND_EQUATION_ALPHA_EXT 0x883D +#define LOCAL_GL_BLEND_EQUATION_ALPHA_OES 0x883D +#define LOCAL_GL_BLEND_EQUATION_EXT 0x8009 +#define LOCAL_GL_BLEND_EQUATION_OES 0x8009 +#define LOCAL_GL_BLEND_EQUATION_RGB 0x8009 +#define LOCAL_GL_BLEND_EQUATION_RGB_EXT 0x8009 +#define LOCAL_GL_BLEND_EQUATION_RGB_OES 0x8009 +#define LOCAL_GL_BLEND_OVERLAP_NV 0x9281 +#define LOCAL_GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define LOCAL_GL_BLEND_SRC 0x0BE1 +#define LOCAL_GL_BLEND_SRC_ALPHA 0x80CB +#define LOCAL_GL_BLEND_SRC_ALPHA_EXT 0x80CB +#define LOCAL_GL_BLEND_SRC_ALPHA_OES 0x80CB +#define LOCAL_GL_BLEND_SRC_RGB 0x80C9 +#define LOCAL_GL_BLEND_SRC_RGB_EXT 0x80C9 +#define LOCAL_GL_BLEND_SRC_RGB_OES 0x80C9 +#define LOCAL_GL_BLOCK_INDEX 0x92FD +#define LOCAL_GL_BLUE 0x1905 +#define LOCAL_GL_BLUE_BIAS 0x0D1B +#define LOCAL_GL_BLUE_BITS 0x0D54 +#define LOCAL_GL_BLUE_BIT_ATI 0x00000004 +#define LOCAL_GL_BLUE_INTEGER 0x8D96 +#define LOCAL_GL_BLUE_INTEGER_EXT 0x8D96 +#define LOCAL_GL_BLUE_MAX_CLAMP_INGR 0x8566 +#define LOCAL_GL_BLUE_MIN_CLAMP_INGR 0x8562 +#define LOCAL_GL_BLUE_NV 0x1905 +#define LOCAL_GL_BLUE_SCALE 0x0D1A +#define LOCAL_GL_BOLD_BIT_NV 0x01 +#define LOCAL_GL_BOOL 0x8B56 +#define LOCAL_GL_BOOL_ARB 0x8B56 +#define LOCAL_GL_BOOL_VEC2 0x8B57 +#define LOCAL_GL_BOOL_VEC2_ARB 0x8B57 +#define LOCAL_GL_BOOL_VEC3 0x8B58 +#define LOCAL_GL_BOOL_VEC3_ARB 0x8B58 +#define LOCAL_GL_BOOL_VEC4 0x8B59 +#define LOCAL_GL_BOOL_VEC4_ARB 0x8B59 +#define LOCAL_GL_BOUNDING_BOX_NV 0x908D +#define LOCAL_GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define LOCAL_GL_BROWSER_DEFAULT_WEBGL 0x9244 +#define LOCAL_GL_BUFFER 0x82E0 +#define LOCAL_GL_BUFFER_ACCESS 0x88BB +#define LOCAL_GL_BUFFER_ACCESS_ARB 0x88BB +#define LOCAL_GL_BUFFER_ACCESS_FLAGS 0x911F +#define LOCAL_GL_BUFFER_ACCESS_OES 0x88BB +#define LOCAL_GL_BUFFER_BINDING 0x9302 +#define LOCAL_GL_BUFFER_DATA_SIZE 0x9303 +#define LOCAL_GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 +#define LOCAL_GL_BUFFER_GPU_ADDRESS_NV 0x8F1D +#define LOCAL_GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define LOCAL_GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F +#define LOCAL_GL_BUFFER_KHR 0x82E0 +#define LOCAL_GL_BUFFER_MAPPED 0x88BC +#define LOCAL_GL_BUFFER_MAPPED_ARB 0x88BC +#define LOCAL_GL_BUFFER_MAPPED_OES 0x88BC +#define LOCAL_GL_BUFFER_MAP_LENGTH 0x9120 +#define LOCAL_GL_BUFFER_MAP_OFFSET 0x9121 +#define LOCAL_GL_BUFFER_MAP_POINTER 0x88BD +#define LOCAL_GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define LOCAL_GL_BUFFER_MAP_POINTER_OES 0x88BD +#define LOCAL_GL_BUFFER_OBJECT_APPLE 0x85B3 +#define LOCAL_GL_BUFFER_OBJECT_EXT 0x9151 +#define LOCAL_GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 +#define LOCAL_GL_BUFFER_SIZE 0x8764 +#define LOCAL_GL_BUFFER_SIZE_ARB 0x8764 +#define LOCAL_GL_BUFFER_STORAGE_FLAGS 0x8220 +#define LOCAL_GL_BUFFER_STORAGE_FLAGS_EXT 0x8220 +#define LOCAL_GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define LOCAL_GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 +#define LOCAL_GL_BUFFER_USAGE 0x8765 +#define LOCAL_GL_BUFFER_USAGE_ARB 0x8765 +#define LOCAL_GL_BUFFER_VARIABLE 0x92E5 +#define LOCAL_GL_BUMP_ENVMAP_ATI 0x877B +#define LOCAL_GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 +#define LOCAL_GL_BUMP_ROT_MATRIX_ATI 0x8775 +#define LOCAL_GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 +#define LOCAL_GL_BUMP_TARGET_ATI 0x877C +#define LOCAL_GL_BUMP_TEX_UNITS_ATI 0x8778 +#define LOCAL_GL_BYTE 0x1400 +#define LOCAL_GL_C3F_V3F 0x2A24 +#define LOCAL_GL_C4F_N3F_V3F 0x2A26 +#define LOCAL_GL_C4UB_V2F 0x2A22 +#define LOCAL_GL_C4UB_V3F 0x2A23 +#define LOCAL_GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 +#define LOCAL_GL_CAVEAT_SUPPORT 0x82B8 +#define LOCAL_GL_CCW 0x0901 +#define LOCAL_GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define LOCAL_GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define LOCAL_GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define LOCAL_GL_CLAMP 0x2900 +#define LOCAL_GL_CLAMP_FRAGMENT_COLOR 0x891B +#define LOCAL_GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B +#define LOCAL_GL_CLAMP_READ_COLOR 0x891C +#define LOCAL_GL_CLAMP_READ_COLOR_ARB 0x891C +#define LOCAL_GL_CLAMP_TO_BORDER 0x812D +#define LOCAL_GL_CLAMP_TO_BORDER_ARB 0x812D +#define LOCAL_GL_CLAMP_TO_BORDER_EXT 0x812D +#define LOCAL_GL_CLAMP_TO_BORDER_NV 0x812D +#define LOCAL_GL_CLAMP_TO_BORDER_OES 0x812D +#define LOCAL_GL_CLAMP_TO_BORDER_SGIS 0x812D +#define LOCAL_GL_CLAMP_TO_EDGE 0x812F +#define LOCAL_GL_CLAMP_TO_EDGE_SGIS 0x812F +#define LOCAL_GL_CLAMP_VERTEX_COLOR 0x891A +#define LOCAL_GL_CLAMP_VERTEX_COLOR_ARB 0x891A +#define LOCAL_GL_CLEAR 0x1500 +#define LOCAL_GL_CLEAR_BUFFER 0x82B4 +#define LOCAL_GL_CLEAR_TEXTURE 0x9365 +#define LOCAL_GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define LOCAL_GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define LOCAL_GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define LOCAL_GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define LOCAL_GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define LOCAL_GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000 +#define LOCAL_GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define LOCAL_GL_CLIENT_STORAGE_BIT 0x0200 +#define LOCAL_GL_CLIENT_STORAGE_BIT_EXT 0x0200 +#define LOCAL_GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define LOCAL_GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 +#define LOCAL_GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 +#define LOCAL_GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 +#define LOCAL_GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 +#define LOCAL_GL_CLIP_DEPTH_MODE 0x935D +#define LOCAL_GL_CLIP_DEPTH_MODE_EXT 0x935D +#define LOCAL_GL_CLIP_DISTANCE0 0x3000 +#define LOCAL_GL_CLIP_DISTANCE0_APPLE 0x3000 +#define LOCAL_GL_CLIP_DISTANCE0_EXT 0x3000 +#define LOCAL_GL_CLIP_DISTANCE1 0x3001 +#define LOCAL_GL_CLIP_DISTANCE1_APPLE 0x3001 +#define LOCAL_GL_CLIP_DISTANCE1_EXT 0x3001 +#define LOCAL_GL_CLIP_DISTANCE2 0x3002 +#define LOCAL_GL_CLIP_DISTANCE2_APPLE 0x3002 +#define LOCAL_GL_CLIP_DISTANCE2_EXT 0x3002 +#define LOCAL_GL_CLIP_DISTANCE3 0x3003 +#define LOCAL_GL_CLIP_DISTANCE3_APPLE 0x3003 +#define LOCAL_GL_CLIP_DISTANCE3_EXT 0x3003 +#define LOCAL_GL_CLIP_DISTANCE4 0x3004 +#define LOCAL_GL_CLIP_DISTANCE4_APPLE 0x3004 +#define LOCAL_GL_CLIP_DISTANCE4_EXT 0x3004 +#define LOCAL_GL_CLIP_DISTANCE5 0x3005 +#define LOCAL_GL_CLIP_DISTANCE5_APPLE 0x3005 +#define LOCAL_GL_CLIP_DISTANCE5_EXT 0x3005 +#define LOCAL_GL_CLIP_DISTANCE6 0x3006 +#define LOCAL_GL_CLIP_DISTANCE6_APPLE 0x3006 +#define LOCAL_GL_CLIP_DISTANCE6_EXT 0x3006 +#define LOCAL_GL_CLIP_DISTANCE7 0x3007 +#define LOCAL_GL_CLIP_DISTANCE7_APPLE 0x3007 +#define LOCAL_GL_CLIP_DISTANCE7_EXT 0x3007 +#define LOCAL_GL_CLIP_DISTANCE_NV 0x8C7A +#define LOCAL_GL_CLIP_FAR_HINT_PGI 0x1A221 +#define LOCAL_GL_CLIP_NEAR_HINT_PGI 0x1A220 +#define LOCAL_GL_CLIP_ORIGIN 0x935C +#define LOCAL_GL_CLIP_ORIGIN_EXT 0x935C +#define LOCAL_GL_CLIP_PLANE0 0x3000 +#define LOCAL_GL_CLIP_PLANE0_IMG 0x3000 +#define LOCAL_GL_CLIP_PLANE1 0x3001 +#define LOCAL_GL_CLIP_PLANE1_IMG 0x3001 +#define LOCAL_GL_CLIP_PLANE2 0x3002 +#define LOCAL_GL_CLIP_PLANE2_IMG 0x3002 +#define LOCAL_GL_CLIP_PLANE3 0x3003 +#define LOCAL_GL_CLIP_PLANE3_IMG 0x3003 +#define LOCAL_GL_CLIP_PLANE4 0x3004 +#define LOCAL_GL_CLIP_PLANE4_IMG 0x3004 +#define LOCAL_GL_CLIP_PLANE5 0x3005 +#define LOCAL_GL_CLIP_PLANE5_IMG 0x3005 +#define LOCAL_GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 +#define LOCAL_GL_CLOSE_PATH_NV 0x00 +#define LOCAL_GL_CMYKA_EXT 0x800D +#define LOCAL_GL_CMYK_EXT 0x800C +#define LOCAL_GL_CND0_ATI 0x896B +#define LOCAL_GL_CND_ATI 0x896A +#define LOCAL_GL_COEFF 0x0A00 +#define LOCAL_GL_COLOR 0x1800 +#define LOCAL_GL_COLOR3_BIT_PGI 0x00010000 +#define LOCAL_GL_COLOR4_BIT_PGI 0x00020000 +#define LOCAL_GL_COLORBURN 0x929A +#define LOCAL_GL_COLORBURN_KHR 0x929A +#define LOCAL_GL_COLORBURN_NV 0x929A +#define LOCAL_GL_COLORDODGE 0x9299 +#define LOCAL_GL_COLORDODGE_KHR 0x9299 +#define LOCAL_GL_COLORDODGE_NV 0x9299 +#define LOCAL_GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define LOCAL_GL_COLOR_ARRAY 0x8076 +#define LOCAL_GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 +#define LOCAL_GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define LOCAL_GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define LOCAL_GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define LOCAL_GL_COLOR_ARRAY_EXT 0x8076 +#define LOCAL_GL_COLOR_ARRAY_LENGTH_NV 0x8F2D +#define LOCAL_GL_COLOR_ARRAY_LIST_IBM 103072 +#define LOCAL_GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 +#define LOCAL_GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 +#define LOCAL_GL_COLOR_ARRAY_POINTER 0x8090 +#define LOCAL_GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define LOCAL_GL_COLOR_ARRAY_SIZE 0x8081 +#define LOCAL_GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define LOCAL_GL_COLOR_ARRAY_STRIDE 0x8083 +#define LOCAL_GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define LOCAL_GL_COLOR_ARRAY_TYPE 0x8082 +#define LOCAL_GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define LOCAL_GL_COLOR_ATTACHMENT0 0x8CE0 +#define LOCAL_GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define LOCAL_GL_COLOR_ATTACHMENT0_NV 0x8CE0 +#define LOCAL_GL_COLOR_ATTACHMENT0_OES 0x8CE0 +#define LOCAL_GL_COLOR_ATTACHMENT1 0x8CE1 +#define LOCAL_GL_COLOR_ATTACHMENT10 0x8CEA +#define LOCAL_GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define LOCAL_GL_COLOR_ATTACHMENT10_NV 0x8CEA +#define LOCAL_GL_COLOR_ATTACHMENT11 0x8CEB +#define LOCAL_GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define LOCAL_GL_COLOR_ATTACHMENT11_NV 0x8CEB +#define LOCAL_GL_COLOR_ATTACHMENT12 0x8CEC +#define LOCAL_GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define LOCAL_GL_COLOR_ATTACHMENT12_NV 0x8CEC +#define LOCAL_GL_COLOR_ATTACHMENT13 0x8CED +#define LOCAL_GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define LOCAL_GL_COLOR_ATTACHMENT13_NV 0x8CED +#define LOCAL_GL_COLOR_ATTACHMENT14 0x8CEE +#define LOCAL_GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define LOCAL_GL_COLOR_ATTACHMENT14_NV 0x8CEE +#define LOCAL_GL_COLOR_ATTACHMENT15 0x8CEF +#define LOCAL_GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define LOCAL_GL_COLOR_ATTACHMENT15_NV 0x8CEF +#define LOCAL_GL_COLOR_ATTACHMENT16 0x8CF0 +#define LOCAL_GL_COLOR_ATTACHMENT17 0x8CF1 +#define LOCAL_GL_COLOR_ATTACHMENT18 0x8CF2 +#define LOCAL_GL_COLOR_ATTACHMENT19 0x8CF3 +#define LOCAL_GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define LOCAL_GL_COLOR_ATTACHMENT1_NV 0x8CE1 +#define LOCAL_GL_COLOR_ATTACHMENT2 0x8CE2 +#define LOCAL_GL_COLOR_ATTACHMENT20 0x8CF4 +#define LOCAL_GL_COLOR_ATTACHMENT21 0x8CF5 +#define LOCAL_GL_COLOR_ATTACHMENT22 0x8CF6 +#define LOCAL_GL_COLOR_ATTACHMENT23 0x8CF7 +#define LOCAL_GL_COLOR_ATTACHMENT24 0x8CF8 +#define LOCAL_GL_COLOR_ATTACHMENT25 0x8CF9 +#define LOCAL_GL_COLOR_ATTACHMENT26 0x8CFA +#define LOCAL_GL_COLOR_ATTACHMENT27 0x8CFB +#define LOCAL_GL_COLOR_ATTACHMENT28 0x8CFC +#define LOCAL_GL_COLOR_ATTACHMENT29 0x8CFD +#define LOCAL_GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define LOCAL_GL_COLOR_ATTACHMENT2_NV 0x8CE2 +#define LOCAL_GL_COLOR_ATTACHMENT3 0x8CE3 +#define LOCAL_GL_COLOR_ATTACHMENT30 0x8CFE +#define LOCAL_GL_COLOR_ATTACHMENT31 0x8CFF +#define LOCAL_GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define LOCAL_GL_COLOR_ATTACHMENT3_NV 0x8CE3 +#define LOCAL_GL_COLOR_ATTACHMENT4 0x8CE4 +#define LOCAL_GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define LOCAL_GL_COLOR_ATTACHMENT4_NV 0x8CE4 +#define LOCAL_GL_COLOR_ATTACHMENT5 0x8CE5 +#define LOCAL_GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define LOCAL_GL_COLOR_ATTACHMENT5_NV 0x8CE5 +#define LOCAL_GL_COLOR_ATTACHMENT6 0x8CE6 +#define LOCAL_GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define LOCAL_GL_COLOR_ATTACHMENT6_NV 0x8CE6 +#define LOCAL_GL_COLOR_ATTACHMENT7 0x8CE7 +#define LOCAL_GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define LOCAL_GL_COLOR_ATTACHMENT7_NV 0x8CE7 +#define LOCAL_GL_COLOR_ATTACHMENT8 0x8CE8 +#define LOCAL_GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define LOCAL_GL_COLOR_ATTACHMENT8_NV 0x8CE8 +#define LOCAL_GL_COLOR_ATTACHMENT9 0x8CE9 +#define LOCAL_GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define LOCAL_GL_COLOR_ATTACHMENT9_NV 0x8CE9 +#define LOCAL_GL_COLOR_ATTACHMENT_EXT 0x90F0 +#define LOCAL_GL_COLOR_BUFFER_BIT 0x00004000 +#define LOCAL_GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 +#define LOCAL_GL_COLOR_BUFFER_BIT1_QCOM 0x00000002 +#define LOCAL_GL_COLOR_BUFFER_BIT2_QCOM 0x00000004 +#define LOCAL_GL_COLOR_BUFFER_BIT3_QCOM 0x00000008 +#define LOCAL_GL_COLOR_BUFFER_BIT4_QCOM 0x00000010 +#define LOCAL_GL_COLOR_BUFFER_BIT5_QCOM 0x00000020 +#define LOCAL_GL_COLOR_BUFFER_BIT6_QCOM 0x00000040 +#define LOCAL_GL_COLOR_BUFFER_BIT7_QCOM 0x00000080 +#define LOCAL_GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 +#define LOCAL_GL_COLOR_CLEAR_VALUE 0x0C22 +#define LOCAL_GL_COLOR_COMPONENTS 0x8283 +#define LOCAL_GL_COLOR_ENCODING 0x8296 +#define LOCAL_GL_COLOR_EXT 0x1800 +#define LOCAL_GL_COLOR_FLOAT_APPLE 0x8A0F +#define LOCAL_GL_COLOR_INDEX 0x1900 +#define LOCAL_GL_COLOR_INDEX12_EXT 0x80E6 +#define LOCAL_GL_COLOR_INDEX16_EXT 0x80E7 +#define LOCAL_GL_COLOR_INDEX1_EXT 0x80E2 +#define LOCAL_GL_COLOR_INDEX2_EXT 0x80E3 +#define LOCAL_GL_COLOR_INDEX4_EXT 0x80E4 +#define LOCAL_GL_COLOR_INDEX8_EXT 0x80E5 +#define LOCAL_GL_COLOR_INDEXES 0x1603 +#define LOCAL_GL_COLOR_LOGIC_OP 0x0BF2 +#define LOCAL_GL_COLOR_MATERIAL 0x0B57 +#define LOCAL_GL_COLOR_MATERIAL_FACE 0x0B55 +#define LOCAL_GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define LOCAL_GL_COLOR_MATRIX 0x80B1 +#define LOCAL_GL_COLOR_MATRIX_SGI 0x80B1 +#define LOCAL_GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 +#define LOCAL_GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 +#define LOCAL_GL_COLOR_RENDERABLE 0x8286 +#define LOCAL_GL_COLOR_SAMPLES_NV 0x8E20 +#define LOCAL_GL_COLOR_SUM 0x8458 +#define LOCAL_GL_COLOR_SUM_ARB 0x8458 +#define LOCAL_GL_COLOR_SUM_CLAMP_NV 0x854F +#define LOCAL_GL_COLOR_SUM_EXT 0x8458 +#define LOCAL_GL_COLOR_TABLE 0x80D0 +#define LOCAL_GL_COLOR_TABLE_ALPHA_SIZE 0x80DD +#define LOCAL_GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD +#define LOCAL_GL_COLOR_TABLE_BIAS 0x80D7 +#define LOCAL_GL_COLOR_TABLE_BIAS_SGI 0x80D7 +#define LOCAL_GL_COLOR_TABLE_BLUE_SIZE 0x80DC +#define LOCAL_GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC +#define LOCAL_GL_COLOR_TABLE_FORMAT 0x80D8 +#define LOCAL_GL_COLOR_TABLE_FORMAT_SGI 0x80D8 +#define LOCAL_GL_COLOR_TABLE_GREEN_SIZE 0x80DB +#define LOCAL_GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB +#define LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF +#define LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF +#define LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE +#define LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE +#define LOCAL_GL_COLOR_TABLE_RED_SIZE 0x80DA +#define LOCAL_GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA +#define LOCAL_GL_COLOR_TABLE_SCALE 0x80D6 +#define LOCAL_GL_COLOR_TABLE_SCALE_SGI 0x80D6 +#define LOCAL_GL_COLOR_TABLE_SGI 0x80D0 +#define LOCAL_GL_COLOR_TABLE_WIDTH 0x80D9 +#define LOCAL_GL_COLOR_TABLE_WIDTH_SGI 0x80D9 +#define LOCAL_GL_COLOR_WRITEMASK 0x0C23 +#define LOCAL_GL_COMBINE 0x8570 +#define LOCAL_GL_COMBINE4_NV 0x8503 +#define LOCAL_GL_COMBINER0_NV 0x8550 +#define LOCAL_GL_COMBINER1_NV 0x8551 +#define LOCAL_GL_COMBINER2_NV 0x8552 +#define LOCAL_GL_COMBINER3_NV 0x8553 +#define LOCAL_GL_COMBINER4_NV 0x8554 +#define LOCAL_GL_COMBINER5_NV 0x8555 +#define LOCAL_GL_COMBINER6_NV 0x8556 +#define LOCAL_GL_COMBINER7_NV 0x8557 +#define LOCAL_GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define LOCAL_GL_COMBINER_AB_OUTPUT_NV 0x854A +#define LOCAL_GL_COMBINER_BIAS_NV 0x8549 +#define LOCAL_GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define LOCAL_GL_COMBINER_CD_OUTPUT_NV 0x854B +#define LOCAL_GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define LOCAL_GL_COMBINER_INPUT_NV 0x8542 +#define LOCAL_GL_COMBINER_MAPPING_NV 0x8543 +#define LOCAL_GL_COMBINER_MUX_SUM_NV 0x8547 +#define LOCAL_GL_COMBINER_SCALE_NV 0x8548 +#define LOCAL_GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define LOCAL_GL_COMBINE_ALPHA 0x8572 +#define LOCAL_GL_COMBINE_ALPHA_ARB 0x8572 +#define LOCAL_GL_COMBINE_ALPHA_EXT 0x8572 +#define LOCAL_GL_COMBINE_ARB 0x8570 +#define LOCAL_GL_COMBINE_EXT 0x8570 +#define LOCAL_GL_COMBINE_RGB 0x8571 +#define LOCAL_GL_COMBINE_RGB_ARB 0x8571 +#define LOCAL_GL_COMBINE_RGB_EXT 0x8571 +#define LOCAL_GL_COMMAND_BARRIER_BIT 0x00000040 +#define LOCAL_GL_COMMAND_BARRIER_BIT_EXT 0x00000040 +#define LOCAL_GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +#define LOCAL_GL_COMPARE_REF_TO_TEXTURE 0x884E +#define LOCAL_GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E +#define LOCAL_GL_COMPARE_R_TO_TEXTURE 0x884E +#define LOCAL_GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#define LOCAL_GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define LOCAL_GL_COMPILE 0x1300 +#define LOCAL_GL_COMPILE_AND_EXECUTE 0x1301 +#define LOCAL_GL_COMPILE_STATUS 0x8B81 +#define LOCAL_GL_COMPLETION_STATUS_ARB 0x91B1 +#define LOCAL_GL_COMPLETION_STATUS_KHR 0x91B1 +#define LOCAL_GL_COMPRESSED_ALPHA 0x84E9 +#define LOCAL_GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define LOCAL_GL_COMPRESSED_INTENSITY 0x84EC +#define LOCAL_GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define LOCAL_GL_COMPRESSED_LUMINANCE 0x84EA +#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI 0x8837 +#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define LOCAL_GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define LOCAL_GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define LOCAL_GL_COMPRESSED_R11_EAC 0x9270 +#define LOCAL_GL_COMPRESSED_R11_EAC_OES 0x9270 +#define LOCAL_GL_COMPRESSED_RED 0x8225 +#define LOCAL_GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define LOCAL_GL_COMPRESSED_RED_RGTC1 0x8DBB +#define LOCAL_GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define LOCAL_GL_COMPRESSED_RG 0x8226 +#define LOCAL_GL_COMPRESSED_RG11_EAC 0x9272 +#define LOCAL_GL_COMPRESSED_RG11_EAC_OES 0x9272 +#define LOCAL_GL_COMPRESSED_RGB 0x84ED +#define LOCAL_GL_COMPRESSED_RGB8_ETC2 0x9274 +#define LOCAL_GL_COMPRESSED_RGB8_ETC2_OES 0x9274 +#define LOCAL_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define LOCAL_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES 0x9276 +#define LOCAL_GL_COMPRESSED_RGBA 0x84EE +#define LOCAL_GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define LOCAL_GL_COMPRESSED_RGBA8_ETC2_EAC_OES 0x9278 +#define LOCAL_GL_COMPRESSED_RGBA_ARB 0x84EE +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7 +#define LOCAL_GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define LOCAL_GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define LOCAL_GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define LOCAL_GL_COMPRESSED_RGBA_BPTC_UNORM_EXT 0x8E8C +#define LOCAL_GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138 +#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 +#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 +#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define LOCAL_GL_COMPRESSED_RGB_ARB 0x84ED +#define LOCAL_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define LOCAL_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define LOCAL_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E +#define LOCAL_GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define LOCAL_GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#define LOCAL_GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F +#define LOCAL_GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 +#define LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define LOCAL_GL_COMPRESSED_RG_RGTC2 0x8DBD +#define LOCAL_GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#define LOCAL_GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define LOCAL_GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define LOCAL_GL_COMPRESSED_SIGNED_R11_EAC_OES 0x9271 +#define LOCAL_GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#define LOCAL_GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define LOCAL_GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define LOCAL_GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define LOCAL_GL_COMPRESSED_SIGNED_RG11_EAC_OES 0x9273 +#define LOCAL_GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define LOCAL_GL_COMPRESSED_SLUMINANCE 0x8C4A +#define LOCAL_GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define LOCAL_GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define LOCAL_GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define LOCAL_GL_COMPRESSED_SRGB 0x8C48 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_OES 0x9279 +#define LOCAL_GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define LOCAL_GL_COMPRESSED_SRGB8_ETC2_OES 0x9275 +#define LOCAL_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define LOCAL_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES 0x9277 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT 0x8E8D +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F +#define LOCAL_GL_COMPRESSED_SRGB_EXT 0x8C48 +#define LOCAL_GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define LOCAL_GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define LOCAL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define LOCAL_GL_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C +#define LOCAL_GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define LOCAL_GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +#define LOCAL_GL_COMPUTE_PROGRAM_NV 0x90FB +#define LOCAL_GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC +#define LOCAL_GL_COMPUTE_SHADER 0x91B9 +#define LOCAL_GL_COMPUTE_SHADER_BIT 0x00000020 +#define LOCAL_GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 +#define LOCAL_GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 +#define LOCAL_GL_COMPUTE_SUBROUTINE 0x92ED +#define LOCAL_GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define LOCAL_GL_COMPUTE_TEXTURE 0x82A0 +#define LOCAL_GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define LOCAL_GL_COMP_BIT_ATI 0x00000002 +#define LOCAL_GL_CONDITION_SATISFIED 0x911C +#define LOCAL_GL_CONDITION_SATISFIED_APPLE 0x911C +#define LOCAL_GL_CONFORMANT_NV 0x9374 +#define LOCAL_GL_CONIC_CURVE_TO_NV 0x1A +#define LOCAL_GL_CONJOINT_NV 0x9284 +#define LOCAL_GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE +#define LOCAL_GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 +#define LOCAL_GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B +#define LOCAL_GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379 +#define LOCAL_GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A +#define LOCAL_GL_CONSERVATIVE_RASTER_MODE_NV 0x954D +#define LOCAL_GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E +#define LOCAL_GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV 0x9550 +#define LOCAL_GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F +#define LOCAL_GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD +#define LOCAL_GL_CONSTANT 0x8576 +#define LOCAL_GL_CONSTANT_ALPHA 0x8003 +#define LOCAL_GL_CONSTANT_ALPHA_EXT 0x8003 +#define LOCAL_GL_CONSTANT_ARB 0x8576 +#define LOCAL_GL_CONSTANT_ATTENUATION 0x1207 +#define LOCAL_GL_CONSTANT_BORDER 0x8151 +#define LOCAL_GL_CONSTANT_BORDER_HP 0x8151 +#define LOCAL_GL_CONSTANT_COLOR 0x8001 +#define LOCAL_GL_CONSTANT_COLOR0_NV 0x852A +#define LOCAL_GL_CONSTANT_COLOR1_NV 0x852B +#define LOCAL_GL_CONSTANT_COLOR_EXT 0x8001 +#define LOCAL_GL_CONSTANT_EXT 0x8576 +#define LOCAL_GL_CONSTANT_NV 0x8576 +#define LOCAL_GL_CONST_EYE_NV 0x86E5 +#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define LOCAL_GL_CONTEXT_FLAGS 0x821E +#define LOCAL_GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define LOCAL_GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define LOCAL_GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define LOCAL_GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 +#define LOCAL_GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 +#define LOCAL_GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010 +#define LOCAL_GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 +#define LOCAL_GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define LOCAL_GL_CONTEXT_LOST 0x0507 +#define LOCAL_GL_CONTEXT_LOST_KHR 0x0507 +#define LOCAL_GL_CONTEXT_LOST_WEBGL 0x9242 +#define LOCAL_GL_CONTEXT_PROFILE_MASK 0x9126 +#define LOCAL_GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define LOCAL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC +#define LOCAL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC +#define LOCAL_GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS 0x90F3 +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_KHR 0x90F3 +#define LOCAL_GL_CONTINUOUS_AMD 0x9007 +#define LOCAL_GL_CONTRAST_NV 0x92A1 +#define LOCAL_GL_CONVEX_HULL_NV 0x908B +#define LOCAL_GL_CONVOLUTION_1D 0x8010 +#define LOCAL_GL_CONVOLUTION_1D_EXT 0x8010 +#define LOCAL_GL_CONVOLUTION_2D 0x8011 +#define LOCAL_GL_CONVOLUTION_2D_EXT 0x8011 +#define LOCAL_GL_CONVOLUTION_BORDER_COLOR 0x8154 +#define LOCAL_GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 +#define LOCAL_GL_CONVOLUTION_BORDER_MODE 0x8013 +#define LOCAL_GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 +#define LOCAL_GL_CONVOLUTION_FILTER_BIAS 0x8015 +#define LOCAL_GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 +#define LOCAL_GL_CONVOLUTION_FILTER_SCALE 0x8014 +#define LOCAL_GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 +#define LOCAL_GL_CONVOLUTION_FORMAT 0x8017 +#define LOCAL_GL_CONVOLUTION_FORMAT_EXT 0x8017 +#define LOCAL_GL_CONVOLUTION_HEIGHT 0x8019 +#define LOCAL_GL_CONVOLUTION_HEIGHT_EXT 0x8019 +#define LOCAL_GL_CONVOLUTION_HINT_SGIX 0x8316 +#define LOCAL_GL_CONVOLUTION_WIDTH 0x8018 +#define LOCAL_GL_CONVOLUTION_WIDTH_EXT 0x8018 +#define LOCAL_GL_CON_0_ATI 0x8941 +#define LOCAL_GL_CON_10_ATI 0x894B +#define LOCAL_GL_CON_11_ATI 0x894C +#define LOCAL_GL_CON_12_ATI 0x894D +#define LOCAL_GL_CON_13_ATI 0x894E +#define LOCAL_GL_CON_14_ATI 0x894F +#define LOCAL_GL_CON_15_ATI 0x8950 +#define LOCAL_GL_CON_16_ATI 0x8951 +#define LOCAL_GL_CON_17_ATI 0x8952 +#define LOCAL_GL_CON_18_ATI 0x8953 +#define LOCAL_GL_CON_19_ATI 0x8954 +#define LOCAL_GL_CON_1_ATI 0x8942 +#define LOCAL_GL_CON_20_ATI 0x8955 +#define LOCAL_GL_CON_21_ATI 0x8956 +#define LOCAL_GL_CON_22_ATI 0x8957 +#define LOCAL_GL_CON_23_ATI 0x8958 +#define LOCAL_GL_CON_24_ATI 0x8959 +#define LOCAL_GL_CON_25_ATI 0x895A +#define LOCAL_GL_CON_26_ATI 0x895B +#define LOCAL_GL_CON_27_ATI 0x895C +#define LOCAL_GL_CON_28_ATI 0x895D +#define LOCAL_GL_CON_29_ATI 0x895E +#define LOCAL_GL_CON_2_ATI 0x8943 +#define LOCAL_GL_CON_30_ATI 0x895F +#define LOCAL_GL_CON_31_ATI 0x8960 +#define LOCAL_GL_CON_3_ATI 0x8944 +#define LOCAL_GL_CON_4_ATI 0x8945 +#define LOCAL_GL_CON_5_ATI 0x8946 +#define LOCAL_GL_CON_6_ATI 0x8947 +#define LOCAL_GL_CON_7_ATI 0x8948 +#define LOCAL_GL_CON_8_ATI 0x8949 +#define LOCAL_GL_CON_9_ATI 0x894A +#define LOCAL_GL_COORD_REPLACE 0x8862 +#define LOCAL_GL_COORD_REPLACE_ARB 0x8862 +#define LOCAL_GL_COORD_REPLACE_NV 0x8862 +#define LOCAL_GL_COORD_REPLACE_OES 0x8862 +#define LOCAL_GL_COPY 0x1503 +#define LOCAL_GL_COPY_INVERTED 0x150C +#define LOCAL_GL_COPY_PIXEL_TOKEN 0x0706 +#define LOCAL_GL_COPY_READ_BUFFER 0x8F36 +#define LOCAL_GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define LOCAL_GL_COPY_READ_BUFFER_NV 0x8F36 +#define LOCAL_GL_COPY_WRITE_BUFFER 0x8F37 +#define LOCAL_GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define LOCAL_GL_COPY_WRITE_BUFFER_NV 0x8F37 +#define LOCAL_GL_COUNTER_RANGE_AMD 0x8BC1 +#define LOCAL_GL_COUNTER_TYPE_AMD 0x8BC0 +#define LOCAL_GL_COUNT_DOWN_NV 0x9089 +#define LOCAL_GL_COUNT_UP_NV 0x9088 +#define LOCAL_GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5 +#define LOCAL_GL_COVERAGE_ATTACHMENT_NV 0x8ED2 +#define LOCAL_GL_COVERAGE_AUTOMATIC_NV 0x8ED7 +#define LOCAL_GL_COVERAGE_BUFFERS_NV 0x8ED3 +#define LOCAL_GL_COVERAGE_BUFFER_BIT_NV 0x00008000 +#define LOCAL_GL_COVERAGE_COMPONENT4_NV 0x8ED1 +#define LOCAL_GL_COVERAGE_COMPONENT_NV 0x8ED0 +#define LOCAL_GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6 +#define LOCAL_GL_COVERAGE_MODULATION_NV 0x9332 +#define LOCAL_GL_COVERAGE_MODULATION_TABLE_NV 0x9331 +#define LOCAL_GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333 +#define LOCAL_GL_COVERAGE_SAMPLES_NV 0x8ED4 +#define LOCAL_GL_CPU_OPTIMIZED_QCOM 0x8FB1 +#define LOCAL_GL_CUBIC_CURVE_TO_NV 0x0C +#define LOCAL_GL_CUBIC_EXT 0x8334 +#define LOCAL_GL_CUBIC_HP 0x815F +#define LOCAL_GL_CUBIC_IMG 0x9139 +#define LOCAL_GL_CUBIC_MIPMAP_LINEAR_IMG 0x913B +#define LOCAL_GL_CUBIC_MIPMAP_NEAREST_IMG 0x913A +#define LOCAL_GL_CULL_FACE 0x0B44 +#define LOCAL_GL_CULL_FACE_MODE 0x0B45 +#define LOCAL_GL_CULL_FRAGMENT_NV 0x86E7 +#define LOCAL_GL_CULL_MODES_NV 0x86E0 +#define LOCAL_GL_CULL_VERTEX_EXT 0x81AA +#define LOCAL_GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define LOCAL_GL_CULL_VERTEX_IBM 103050 +#define LOCAL_GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC +#define LOCAL_GL_CURRENT_ATTRIB_NV 0x8626 +#define LOCAL_GL_CURRENT_BINORMAL_EXT 0x843C +#define LOCAL_GL_CURRENT_BIT 0x00000001 +#define LOCAL_GL_CURRENT_COLOR 0x0B00 +#define LOCAL_GL_CURRENT_FOG_COORD 0x8453 +#define LOCAL_GL_CURRENT_FOG_COORDINATE 0x8453 +#define LOCAL_GL_CURRENT_FOG_COORDINATE_EXT 0x8453 +#define LOCAL_GL_CURRENT_INDEX 0x0B01 +#define LOCAL_GL_CURRENT_MATRIX_ARB 0x8641 +#define LOCAL_GL_CURRENT_MATRIX_INDEX_ARB 0x8845 +#define LOCAL_GL_CURRENT_MATRIX_NV 0x8641 +#define LOCAL_GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define LOCAL_GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 +#define LOCAL_GL_CURRENT_NORMAL 0x0B02 +#define LOCAL_GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define LOCAL_GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 +#define LOCAL_GL_CURRENT_PALETTE_MATRIX_OES 0x8843 +#define LOCAL_GL_CURRENT_PROGRAM 0x8B8D +#define LOCAL_GL_CURRENT_QUERY 0x8865 +#define LOCAL_GL_CURRENT_QUERY_ARB 0x8865 +#define LOCAL_GL_CURRENT_QUERY_EXT 0x8865 +#define LOCAL_GL_CURRENT_RASTER_COLOR 0x0B04 +#define LOCAL_GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define LOCAL_GL_CURRENT_RASTER_INDEX 0x0B05 +#define LOCAL_GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 +#define LOCAL_GL_CURRENT_RASTER_POSITION 0x0B07 +#define LOCAL_GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define LOCAL_GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define LOCAL_GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define LOCAL_GL_CURRENT_SECONDARY_COLOR 0x8459 +#define LOCAL_GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 +#define LOCAL_GL_CURRENT_TANGENT_EXT 0x843B +#define LOCAL_GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define LOCAL_GL_CURRENT_TIME_NV 0x8E28 +#define LOCAL_GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define LOCAL_GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define LOCAL_GL_CURRENT_VERTEX_EXT 0x87E2 +#define LOCAL_GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B +#define LOCAL_GL_CURRENT_WEIGHT_ARB 0x86A8 +#define LOCAL_GL_CW 0x0900 +#define LOCAL_GL_D3D12_FENCE_VALUE_EXT 0x9595 +#define LOCAL_GL_DARKEN 0x9297 +#define LOCAL_GL_DARKEN_KHR 0x9297 +#define LOCAL_GL_DARKEN_NV 0x9297 +#define LOCAL_GL_DATA_BUFFER_AMD 0x9151 +#define LOCAL_GL_DEBUG_ASSERT_MESA 0x875B +#define LOCAL_GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define LOCAL_GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define LOCAL_GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define LOCAL_GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define LOCAL_GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define LOCAL_GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define LOCAL_GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 +#define LOCAL_GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F +#define LOCAL_GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B +#define LOCAL_GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 +#define LOCAL_GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D +#define LOCAL_GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E +#define LOCAL_GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C +#define LOCAL_GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A +#define LOCAL_GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define LOCAL_GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define LOCAL_GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define LOCAL_GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 +#define LOCAL_GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define LOCAL_GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define LOCAL_GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define LOCAL_GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define LOCAL_GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define LOCAL_GL_DEBUG_OBJECT_MESA 0x8759 +#define LOCAL_GL_DEBUG_OUTPUT 0x92E0 +#define LOCAL_GL_DEBUG_OUTPUT_KHR 0x92E0 +#define LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define LOCAL_GL_DEBUG_PRINT_MESA 0x875A +#define LOCAL_GL_DEBUG_SEVERITY_HIGH 0x9146 +#define LOCAL_GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 +#define LOCAL_GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define LOCAL_GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define LOCAL_GL_DEBUG_SEVERITY_LOW 0x9148 +#define LOCAL_GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#define LOCAL_GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +#define LOCAL_GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define LOCAL_GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define LOCAL_GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 +#define LOCAL_GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define LOCAL_GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define LOCAL_GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define LOCAL_GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define LOCAL_GL_DEBUG_SOURCE_API 0x8246 +#define LOCAL_GL_DEBUG_SOURCE_API_ARB 0x8246 +#define LOCAL_GL_DEBUG_SOURCE_API_KHR 0x8246 +#define LOCAL_GL_DEBUG_SOURCE_APPLICATION 0x824A +#define LOCAL_GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define LOCAL_GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define LOCAL_GL_DEBUG_SOURCE_OTHER 0x824B +#define LOCAL_GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define LOCAL_GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define LOCAL_GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define LOCAL_GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define LOCAL_GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define LOCAL_GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define LOCAL_GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define LOCAL_GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define LOCAL_GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define LOCAL_GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define LOCAL_GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define LOCAL_GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define LOCAL_GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define LOCAL_GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define LOCAL_GL_DEBUG_TYPE_ERROR 0x824C +#define LOCAL_GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define LOCAL_GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define LOCAL_GL_DEBUG_TYPE_MARKER 0x8268 +#define LOCAL_GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define LOCAL_GL_DEBUG_TYPE_OTHER 0x8251 +#define LOCAL_GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define LOCAL_GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define LOCAL_GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define LOCAL_GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define LOCAL_GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define LOCAL_GL_DEBUG_TYPE_POP_GROUP 0x826A +#define LOCAL_GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define LOCAL_GL_DEBUG_TYPE_PORTABILITY 0x824F +#define LOCAL_GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define LOCAL_GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define LOCAL_GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define LOCAL_GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define LOCAL_GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define LOCAL_GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define LOCAL_GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define LOCAL_GL_DECAL 0x2101 +#define LOCAL_GL_DECODE_EXT 0x8A49 +#define LOCAL_GL_DECR 0x1E03 +#define LOCAL_GL_DECR_WRAP 0x8508 +#define LOCAL_GL_DECR_WRAP_EXT 0x8508 +#define LOCAL_GL_DECR_WRAP_OES 0x8508 +#define LOCAL_GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 +#define LOCAL_GL_DEFORMATIONS_MASK_SGIX 0x8196 +#define LOCAL_GL_DELETE_STATUS 0x8B80 +#define LOCAL_GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 +#define LOCAL_GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA +#define LOCAL_GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 +#define LOCAL_GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 +#define LOCAL_GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A +#define LOCAL_GL_DEPTH 0x1801 +#define LOCAL_GL_DEPTH24_STENCIL8 0x88F0 +#define LOCAL_GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define LOCAL_GL_DEPTH24_STENCIL8_OES 0x88F0 +#define LOCAL_GL_DEPTH32F_STENCIL8 0x8CAD +#define LOCAL_GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define LOCAL_GL_DEPTH_ATTACHMENT 0x8D00 +#define LOCAL_GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define LOCAL_GL_DEPTH_ATTACHMENT_OES 0x8D00 +#define LOCAL_GL_DEPTH_BIAS 0x0D1F +#define LOCAL_GL_DEPTH_BITS 0x0D56 +#define LOCAL_GL_DEPTH_BOUNDS_EXT 0x8891 +#define LOCAL_GL_DEPTH_BOUNDS_TEST_EXT 0x8890 +#define LOCAL_GL_DEPTH_BUFFER_BIT 0x00000100 +#define LOCAL_GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100 +#define LOCAL_GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200 +#define LOCAL_GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400 +#define LOCAL_GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800 +#define LOCAL_GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000 +#define LOCAL_GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000 +#define LOCAL_GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000 +#define LOCAL_GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000 +#define LOCAL_GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +#define LOCAL_GL_DEPTH_CLAMP 0x864F +#define LOCAL_GL_DEPTH_CLAMP_EXT 0x864F +#define LOCAL_GL_DEPTH_CLAMP_FAR_AMD 0x901F +#define LOCAL_GL_DEPTH_CLAMP_NEAR_AMD 0x901E +#define LOCAL_GL_DEPTH_CLAMP_NV 0x864F +#define LOCAL_GL_DEPTH_CLEAR_VALUE 0x0B73 +#define LOCAL_GL_DEPTH_COMPONENT 0x1902 +#define LOCAL_GL_DEPTH_COMPONENT16 0x81A5 +#define LOCAL_GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define LOCAL_GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C +#define LOCAL_GL_DEPTH_COMPONENT16_OES 0x81A5 +#define LOCAL_GL_DEPTH_COMPONENT16_SGIX 0x81A5 +#define LOCAL_GL_DEPTH_COMPONENT24 0x81A6 +#define LOCAL_GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define LOCAL_GL_DEPTH_COMPONENT24_OES 0x81A6 +#define LOCAL_GL_DEPTH_COMPONENT24_SGIX 0x81A6 +#define LOCAL_GL_DEPTH_COMPONENT32 0x81A7 +#define LOCAL_GL_DEPTH_COMPONENT32F 0x8CAC +#define LOCAL_GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define LOCAL_GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define LOCAL_GL_DEPTH_COMPONENT32_OES 0x81A7 +#define LOCAL_GL_DEPTH_COMPONENT32_SGIX 0x81A7 +#define LOCAL_GL_DEPTH_COMPONENTS 0x8284 +#define LOCAL_GL_DEPTH_EXT 0x1801 +#define LOCAL_GL_DEPTH_FUNC 0x0B74 +#define LOCAL_GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 +#define LOCAL_GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 +#define LOCAL_GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 +#define LOCAL_GL_DEPTH_RANGE 0x0B70 +#define LOCAL_GL_DEPTH_RENDERABLE 0x8287 +#define LOCAL_GL_DEPTH_SAMPLES_NV 0x932D +#define LOCAL_GL_DEPTH_SCALE 0x0D1E +#define LOCAL_GL_DEPTH_STENCIL 0x84F9 +#define LOCAL_GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define LOCAL_GL_DEPTH_STENCIL_EXT 0x84F9 +#define LOCAL_GL_DEPTH_STENCIL_MESA 0x8750 +#define LOCAL_GL_DEPTH_STENCIL_NV 0x84F9 +#define LOCAL_GL_DEPTH_STENCIL_OES 0x84F9 +#define LOCAL_GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define LOCAL_GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F +#define LOCAL_GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E +#define LOCAL_GL_DEPTH_TEST 0x0B71 +#define LOCAL_GL_DEPTH_TEXTURE_MODE 0x884B +#define LOCAL_GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#define LOCAL_GL_DEPTH_WRITEMASK 0x0B72 +#define LOCAL_GL_DETACHED_BUFFERS_NV 0x95AB +#define LOCAL_GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9 +#define LOCAL_GL_DETACHED_TEXTURES_NV 0x95AA +#define LOCAL_GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 +#define LOCAL_GL_DETAIL_TEXTURE_2D_SGIS 0x8095 +#define LOCAL_GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C +#define LOCAL_GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A +#define LOCAL_GL_DETAIL_TEXTURE_MODE_SGIS 0x809B +#define LOCAL_GL_DEVICE_LUID_EXT 0x9599 +#define LOCAL_GL_DEVICE_NODE_MASK_EXT 0x959A +#define LOCAL_GL_DEVICE_UUID_EXT 0x9597 +#define LOCAL_GL_DIFFERENCE 0x929E +#define LOCAL_GL_DIFFERENCE_KHR 0x929E +#define LOCAL_GL_DIFFERENCE_NV 0x929E +#define LOCAL_GL_DIFFUSE 0x1201 +#define LOCAL_GL_DISCARD_ATI 0x8763 +#define LOCAL_GL_DISCARD_NV 0x8530 +#define LOCAL_GL_DISCRETE_AMD 0x9006 +#define LOCAL_GL_DISJOINT_NV 0x9283 +#define LOCAL_GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define LOCAL_GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define LOCAL_GL_DISPLAY_LIST 0x82E7 +#define LOCAL_GL_DISTANCE_ATTENUATION_EXT 0x8129 +#define LOCAL_GL_DISTANCE_ATTENUATION_SGIS 0x8129 +#define LOCAL_GL_DITHER 0x0BD0 +#define LOCAL_GL_DMP_PROGRAM_BINARY_DMP 0x9253 +#define LOCAL_GL_DOMAIN 0x0A02 +#define LOCAL_GL_DONT_CARE 0x1100 +#define LOCAL_GL_DOT2_ADD_ATI 0x896C +#define LOCAL_GL_DOT3_ATI 0x8966 +#define LOCAL_GL_DOT3_RGB 0x86AE +#define LOCAL_GL_DOT3_RGBA 0x86AF +#define LOCAL_GL_DOT3_RGBA_ARB 0x86AF +#define LOCAL_GL_DOT3_RGBA_EXT 0x8741 +#define LOCAL_GL_DOT3_RGBA_IMG 0x86AF +#define LOCAL_GL_DOT3_RGB_ARB 0x86AE +#define LOCAL_GL_DOT3_RGB_EXT 0x8740 +#define LOCAL_GL_DOT4_ATI 0x8967 +#define LOCAL_GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D +#define LOCAL_GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 +#define LOCAL_GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED +#define LOCAL_GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 +#define LOCAL_GL_DOT_PRODUCT_NV 0x86EC +#define LOCAL_GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B +#define LOCAL_GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 +#define LOCAL_GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C +#define LOCAL_GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE +#define LOCAL_GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF +#define LOCAL_GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 +#define LOCAL_GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E +#define LOCAL_GL_DOUBLE 0x140A +#define LOCAL_GL_DOUBLEBUFFER 0x0C32 +#define LOCAL_GL_DOUBLE_EXT 0x140A +#define LOCAL_GL_DOUBLE_MAT2 0x8F46 +#define LOCAL_GL_DOUBLE_MAT2_EXT 0x8F46 +#define LOCAL_GL_DOUBLE_MAT2x3 0x8F49 +#define LOCAL_GL_DOUBLE_MAT2x3_EXT 0x8F49 +#define LOCAL_GL_DOUBLE_MAT2x4 0x8F4A +#define LOCAL_GL_DOUBLE_MAT2x4_EXT 0x8F4A +#define LOCAL_GL_DOUBLE_MAT3 0x8F47 +#define LOCAL_GL_DOUBLE_MAT3_EXT 0x8F47 +#define LOCAL_GL_DOUBLE_MAT3x2 0x8F4B +#define LOCAL_GL_DOUBLE_MAT3x2_EXT 0x8F4B +#define LOCAL_GL_DOUBLE_MAT3x4 0x8F4C +#define LOCAL_GL_DOUBLE_MAT3x4_EXT 0x8F4C +#define LOCAL_GL_DOUBLE_MAT4 0x8F48 +#define LOCAL_GL_DOUBLE_MAT4_EXT 0x8F48 +#define LOCAL_GL_DOUBLE_MAT4x2 0x8F4D +#define LOCAL_GL_DOUBLE_MAT4x2_EXT 0x8F4D +#define LOCAL_GL_DOUBLE_MAT4x3 0x8F4E +#define LOCAL_GL_DOUBLE_MAT4x3_EXT 0x8F4E +#define LOCAL_GL_DOUBLE_VEC2 0x8FFC +#define LOCAL_GL_DOUBLE_VEC2_EXT 0x8FFC +#define LOCAL_GL_DOUBLE_VEC3 0x8FFD +#define LOCAL_GL_DOUBLE_VEC3_EXT 0x8FFD +#define LOCAL_GL_DOUBLE_VEC4 0x8FFE +#define LOCAL_GL_DOUBLE_VEC4_EXT 0x8FFE +#define LOCAL_GL_DOWNSAMPLE_SCALES_IMG 0x913E +#define LOCAL_GL_DRAW_ARRAYS_COMMAND_NV 0x0003 +#define LOCAL_GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007 +#define LOCAL_GL_DRAW_ARRAYS_STRIP_COMMAND_NV 0x0005 +#define LOCAL_GL_DRAW_BUFFER 0x0C01 +#define LOCAL_GL_DRAW_BUFFER0 0x8825 +#define LOCAL_GL_DRAW_BUFFER0_ARB 0x8825 +#define LOCAL_GL_DRAW_BUFFER0_ATI 0x8825 +#define LOCAL_GL_DRAW_BUFFER0_EXT 0x8825 +#define LOCAL_GL_DRAW_BUFFER0_NV 0x8825 +#define LOCAL_GL_DRAW_BUFFER1 0x8826 +#define LOCAL_GL_DRAW_BUFFER10 0x882F +#define LOCAL_GL_DRAW_BUFFER10_ARB 0x882F +#define LOCAL_GL_DRAW_BUFFER10_ATI 0x882F +#define LOCAL_GL_DRAW_BUFFER10_EXT 0x882F +#define LOCAL_GL_DRAW_BUFFER10_NV 0x882F +#define LOCAL_GL_DRAW_BUFFER11 0x8830 +#define LOCAL_GL_DRAW_BUFFER11_ARB 0x8830 +#define LOCAL_GL_DRAW_BUFFER11_ATI 0x8830 +#define LOCAL_GL_DRAW_BUFFER11_EXT 0x8830 +#define LOCAL_GL_DRAW_BUFFER11_NV 0x8830 +#define LOCAL_GL_DRAW_BUFFER12 0x8831 +#define LOCAL_GL_DRAW_BUFFER12_ARB 0x8831 +#define LOCAL_GL_DRAW_BUFFER12_ATI 0x8831 +#define LOCAL_GL_DRAW_BUFFER12_EXT 0x8831 +#define LOCAL_GL_DRAW_BUFFER12_NV 0x8831 +#define LOCAL_GL_DRAW_BUFFER13 0x8832 +#define LOCAL_GL_DRAW_BUFFER13_ARB 0x8832 +#define LOCAL_GL_DRAW_BUFFER13_ATI 0x8832 +#define LOCAL_GL_DRAW_BUFFER13_EXT 0x8832 +#define LOCAL_GL_DRAW_BUFFER13_NV 0x8832 +#define LOCAL_GL_DRAW_BUFFER14 0x8833 +#define LOCAL_GL_DRAW_BUFFER14_ARB 0x8833 +#define LOCAL_GL_DRAW_BUFFER14_ATI 0x8833 +#define LOCAL_GL_DRAW_BUFFER14_EXT 0x8833 +#define LOCAL_GL_DRAW_BUFFER14_NV 0x8833 +#define LOCAL_GL_DRAW_BUFFER15 0x8834 +#define LOCAL_GL_DRAW_BUFFER15_ARB 0x8834 +#define LOCAL_GL_DRAW_BUFFER15_ATI 0x8834 +#define LOCAL_GL_DRAW_BUFFER15_EXT 0x8834 +#define LOCAL_GL_DRAW_BUFFER15_NV 0x8834 +#define LOCAL_GL_DRAW_BUFFER1_ARB 0x8826 +#define LOCAL_GL_DRAW_BUFFER1_ATI 0x8826 +#define LOCAL_GL_DRAW_BUFFER1_EXT 0x8826 +#define LOCAL_GL_DRAW_BUFFER1_NV 0x8826 +#define LOCAL_GL_DRAW_BUFFER2 0x8827 +#define LOCAL_GL_DRAW_BUFFER2_ARB 0x8827 +#define LOCAL_GL_DRAW_BUFFER2_ATI 0x8827 +#define LOCAL_GL_DRAW_BUFFER2_EXT 0x8827 +#define LOCAL_GL_DRAW_BUFFER2_NV 0x8827 +#define LOCAL_GL_DRAW_BUFFER3 0x8828 +#define LOCAL_GL_DRAW_BUFFER3_ARB 0x8828 +#define LOCAL_GL_DRAW_BUFFER3_ATI 0x8828 +#define LOCAL_GL_DRAW_BUFFER3_EXT 0x8828 +#define LOCAL_GL_DRAW_BUFFER3_NV 0x8828 +#define LOCAL_GL_DRAW_BUFFER4 0x8829 +#define LOCAL_GL_DRAW_BUFFER4_ARB 0x8829 +#define LOCAL_GL_DRAW_BUFFER4_ATI 0x8829 +#define LOCAL_GL_DRAW_BUFFER4_EXT 0x8829 +#define LOCAL_GL_DRAW_BUFFER4_NV 0x8829 +#define LOCAL_GL_DRAW_BUFFER5 0x882A +#define LOCAL_GL_DRAW_BUFFER5_ARB 0x882A +#define LOCAL_GL_DRAW_BUFFER5_ATI 0x882A +#define LOCAL_GL_DRAW_BUFFER5_EXT 0x882A +#define LOCAL_GL_DRAW_BUFFER5_NV 0x882A +#define LOCAL_GL_DRAW_BUFFER6 0x882B +#define LOCAL_GL_DRAW_BUFFER6_ARB 0x882B +#define LOCAL_GL_DRAW_BUFFER6_ATI 0x882B +#define LOCAL_GL_DRAW_BUFFER6_EXT 0x882B +#define LOCAL_GL_DRAW_BUFFER6_NV 0x882B +#define LOCAL_GL_DRAW_BUFFER7 0x882C +#define LOCAL_GL_DRAW_BUFFER7_ARB 0x882C +#define LOCAL_GL_DRAW_BUFFER7_ATI 0x882C +#define LOCAL_GL_DRAW_BUFFER7_EXT 0x882C +#define LOCAL_GL_DRAW_BUFFER7_NV 0x882C +#define LOCAL_GL_DRAW_BUFFER8 0x882D +#define LOCAL_GL_DRAW_BUFFER8_ARB 0x882D +#define LOCAL_GL_DRAW_BUFFER8_ATI 0x882D +#define LOCAL_GL_DRAW_BUFFER8_EXT 0x882D +#define LOCAL_GL_DRAW_BUFFER8_NV 0x882D +#define LOCAL_GL_DRAW_BUFFER9 0x882E +#define LOCAL_GL_DRAW_BUFFER9_ARB 0x882E +#define LOCAL_GL_DRAW_BUFFER9_ATI 0x882E +#define LOCAL_GL_DRAW_BUFFER9_EXT 0x882E +#define LOCAL_GL_DRAW_BUFFER9_NV 0x882E +#define LOCAL_GL_DRAW_BUFFER_EXT 0x0C01 +#define LOCAL_GL_DRAW_ELEMENTS_COMMAND_NV 0x0002 +#define LOCAL_GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006 +#define LOCAL_GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004 +#define LOCAL_GL_DRAW_FRAMEBUFFER 0x8CA9 +#define LOCAL_GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9 +#define LOCAL_GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 +#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 +#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 +#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_NV 0x8CA6 +#define LOCAL_GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define LOCAL_GL_DRAW_FRAMEBUFFER_NV 0x8CA9 +#define LOCAL_GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 +#define LOCAL_GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define LOCAL_GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define LOCAL_GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 +#define LOCAL_GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 +#define LOCAL_GL_DRAW_PIXELS_APPLE 0x8A0A +#define LOCAL_GL_DRAW_PIXEL_TOKEN 0x0705 +#define LOCAL_GL_DRIVER_UUID_EXT 0x9598 +#define LOCAL_GL_DSDT8_MAG8_INTENSITY8_NV 0x870B +#define LOCAL_GL_DSDT8_MAG8_NV 0x870A +#define LOCAL_GL_DSDT8_NV 0x8709 +#define LOCAL_GL_DSDT_MAG_INTENSITY_NV 0x86DC +#define LOCAL_GL_DSDT_MAG_NV 0x86F6 +#define LOCAL_GL_DSDT_MAG_VIB_NV 0x86F7 +#define LOCAL_GL_DSDT_NV 0x86F5 +#define LOCAL_GL_DST_ALPHA 0x0304 +#define LOCAL_GL_DST_ATOP_NV 0x928F +#define LOCAL_GL_DST_COLOR 0x0306 +#define LOCAL_GL_DST_IN_NV 0x928B +#define LOCAL_GL_DST_NV 0x9287 +#define LOCAL_GL_DST_OUT_NV 0x928D +#define LOCAL_GL_DST_OVER_NV 0x9289 +#define LOCAL_GL_DS_BIAS_NV 0x8716 +#define LOCAL_GL_DS_SCALE_NV 0x8710 +#define LOCAL_GL_DT_BIAS_NV 0x8717 +#define LOCAL_GL_DT_SCALE_NV 0x8711 +#define LOCAL_GL_DU8DV8_ATI 0x877A +#define LOCAL_GL_DUAL_ALPHA12_SGIS 0x8112 +#define LOCAL_GL_DUAL_ALPHA16_SGIS 0x8113 +#define LOCAL_GL_DUAL_ALPHA4_SGIS 0x8110 +#define LOCAL_GL_DUAL_ALPHA8_SGIS 0x8111 +#define LOCAL_GL_DUAL_INTENSITY12_SGIS 0x811A +#define LOCAL_GL_DUAL_INTENSITY16_SGIS 0x811B +#define LOCAL_GL_DUAL_INTENSITY4_SGIS 0x8118 +#define LOCAL_GL_DUAL_INTENSITY8_SGIS 0x8119 +#define LOCAL_GL_DUAL_LUMINANCE12_SGIS 0x8116 +#define LOCAL_GL_DUAL_LUMINANCE16_SGIS 0x8117 +#define LOCAL_GL_DUAL_LUMINANCE4_SGIS 0x8114 +#define LOCAL_GL_DUAL_LUMINANCE8_SGIS 0x8115 +#define LOCAL_GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C +#define LOCAL_GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D +#define LOCAL_GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 +#define LOCAL_GL_DUDV_ATI 0x8779 +#define LOCAL_GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define LOCAL_GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define LOCAL_GL_DYNAMIC_ATI 0x8761 +#define LOCAL_GL_DYNAMIC_COPY 0x88EA +#define LOCAL_GL_DYNAMIC_COPY_ARB 0x88EA +#define LOCAL_GL_DYNAMIC_DRAW 0x88E8 +#define LOCAL_GL_DYNAMIC_DRAW_ARB 0x88E8 +#define LOCAL_GL_DYNAMIC_READ 0x88E9 +#define LOCAL_GL_DYNAMIC_READ_ARB 0x88E9 +#define LOCAL_GL_DYNAMIC_STORAGE_BIT 0x0100 +#define LOCAL_GL_DYNAMIC_STORAGE_BIT_EXT 0x0100 +#define LOCAL_GL_EDGEFLAG_BIT_PGI 0x00040000 +#define LOCAL_GL_EDGE_FLAG 0x0B43 +#define LOCAL_GL_EDGE_FLAG_ARRAY 0x8079 +#define LOCAL_GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 +#define LOCAL_GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define LOCAL_GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define LOCAL_GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define LOCAL_GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define LOCAL_GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 +#define LOCAL_GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 +#define LOCAL_GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 +#define LOCAL_GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define LOCAL_GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +#define LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define LOCAL_GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C +#define LOCAL_GL_EIGHTH_BIT_ATI 0x00000020 +#define LOCAL_GL_ELEMENT_ADDRESS_COMMAND_NV 0x0008 +#define LOCAL_GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 +#define LOCAL_GL_ELEMENT_ARRAY_APPLE 0x8A0C +#define LOCAL_GL_ELEMENT_ARRAY_ATI 0x8768 +#define LOCAL_GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define LOCAL_GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 +#define LOCAL_GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define LOCAL_GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 +#define LOCAL_GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E +#define LOCAL_GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +#define LOCAL_GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D +#define LOCAL_GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define LOCAL_GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F +#define LOCAL_GL_EMBOSS_CONSTANT_NV 0x855E +#define LOCAL_GL_EMBOSS_LIGHT_NV 0x855D +#define LOCAL_GL_EMBOSS_MAP_NV 0x855F +#define LOCAL_GL_EMISSION 0x1600 +#define LOCAL_GL_ENABLE_BIT 0x00002000 +#define LOCAL_GL_EQUAL 0x0202 +#define LOCAL_GL_EQUIV 0x1509 +#define LOCAL_GL_ETC1_RGB8_OES 0x8D64 +#define LOCAL_GL_ETC1_SRGB8_NV 0x88EE +#define LOCAL_GL_EVAL_2D_NV 0x86C0 +#define LOCAL_GL_EVAL_BIT 0x00010000 +#define LOCAL_GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 +#define LOCAL_GL_EVAL_TRIANGULAR_2D_NV 0x86C1 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 +#define LOCAL_GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA +#define LOCAL_GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB +#define LOCAL_GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC +#define LOCAL_GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD +#define LOCAL_GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE +#define LOCAL_GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF +#define LOCAL_GL_EXCLUSION 0x92A0 +#define LOCAL_GL_EXCLUSION_KHR 0x92A0 +#define LOCAL_GL_EXCLUSION_NV 0x92A0 +#define LOCAL_GL_EXCLUSIVE_EXT 0x8F11 +#define LOCAL_GL_EXP 0x0800 +#define LOCAL_GL_EXP2 0x0801 +#define LOCAL_GL_EXPAND_NEGATE_NV 0x8539 +#define LOCAL_GL_EXPAND_NORMAL_NV 0x8538 +#define LOCAL_GL_EXTENSIONS 0x1F03 +#define LOCAL_GL_EXTERNAL_STORAGE_BIT_NVX 0x2000 +#define LOCAL_GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 +#define LOCAL_GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 +#define LOCAL_GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 +#define LOCAL_GL_EYE_LINEAR 0x2400 +#define LOCAL_GL_EYE_LINEAR_NV 0x2400 +#define LOCAL_GL_EYE_LINE_SGIS 0x81F6 +#define LOCAL_GL_EYE_PLANE 0x2502 +#define LOCAL_GL_EYE_PLANE_ABSOLUTE_NV 0x855C +#define LOCAL_GL_EYE_POINT_SGIS 0x81F4 +#define LOCAL_GL_EYE_RADIAL_NV 0x855B +#define LOCAL_GL_E_TIMES_F_NV 0x8531 +#define LOCAL_GL_FACTOR_ALPHA_MODULATE_IMG 0x8C07 +#define LOCAL_GL_FACTOR_MAX_AMD 0x901D +#define LOCAL_GL_FACTOR_MIN_AMD 0x901C +#define LOCAL_GL_FAILURE_NV 0x9030 +#define LOCAL_GL_FALSE 0 +#define LOCAL_GL_FASTEST 0x1101 +#define LOCAL_GL_FEEDBACK 0x1C01 +#define LOCAL_GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define LOCAL_GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define LOCAL_GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define LOCAL_GL_FENCE_APPLE 0x8A0B +#define LOCAL_GL_FENCE_CONDITION_NV 0x84F4 +#define LOCAL_GL_FENCE_STATUS_NV 0x84F3 +#define LOCAL_GL_FETCH_PER_SAMPLE_ARM 0x8F65 +#define LOCAL_GL_FIELDS_NV 0x8E27 +#define LOCAL_GL_FIELD_LOWER_NV 0x9023 +#define LOCAL_GL_FIELD_UPPER_NV 0x9022 +#define LOCAL_GL_FILE_NAME_NV 0x9074 +#define LOCAL_GL_FILL 0x1B02 +#define LOCAL_GL_FILL_NV 0x1B02 +#define LOCAL_GL_FILL_RECTANGLE_NV 0x933C +#define LOCAL_GL_FILTER 0x829A +#define LOCAL_GL_FILTER4_SGIS 0x8146 +#define LOCAL_GL_FIRST_TO_REST_NV 0x90AF +#define LOCAL_GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define LOCAL_GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define LOCAL_GL_FIRST_VERTEX_CONVENTION_OES 0x8E4D +#define LOCAL_GL_FIXED 0x140C +#define LOCAL_GL_FIXED_OES 0x140C +#define LOCAL_GL_FIXED_ONLY 0x891D +#define LOCAL_GL_FIXED_ONLY_ARB 0x891D +#define LOCAL_GL_FLAT 0x1D00 +#define LOCAL_GL_FLOAT 0x1406 +#define LOCAL_GL_FLOAT16_MAT2_AMD 0x91C5 +#define LOCAL_GL_FLOAT16_MAT2x3_AMD 0x91C8 +#define LOCAL_GL_FLOAT16_MAT2x4_AMD 0x91C9 +#define LOCAL_GL_FLOAT16_MAT3_AMD 0x91C6 +#define LOCAL_GL_FLOAT16_MAT3x2_AMD 0x91CA +#define LOCAL_GL_FLOAT16_MAT3x4_AMD 0x91CB +#define LOCAL_GL_FLOAT16_MAT4_AMD 0x91C7 +#define LOCAL_GL_FLOAT16_MAT4x2_AMD 0x91CC +#define LOCAL_GL_FLOAT16_MAT4x3_AMD 0x91CD +#define LOCAL_GL_FLOAT16_NV 0x8FF8 +#define LOCAL_GL_FLOAT16_VEC2_NV 0x8FF9 +#define LOCAL_GL_FLOAT16_VEC3_NV 0x8FFA +#define LOCAL_GL_FLOAT16_VEC4_NV 0x8FFB +#define LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD +#define LOCAL_GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D +#define LOCAL_GL_FLOAT_MAT2 0x8B5A +#define LOCAL_GL_FLOAT_MAT2_ARB 0x8B5A +#define LOCAL_GL_FLOAT_MAT2x3 0x8B65 +#define LOCAL_GL_FLOAT_MAT2x3_NV 0x8B65 +#define LOCAL_GL_FLOAT_MAT2x4 0x8B66 +#define LOCAL_GL_FLOAT_MAT2x4_NV 0x8B66 +#define LOCAL_GL_FLOAT_MAT3 0x8B5B +#define LOCAL_GL_FLOAT_MAT3_ARB 0x8B5B +#define LOCAL_GL_FLOAT_MAT3x2 0x8B67 +#define LOCAL_GL_FLOAT_MAT3x2_NV 0x8B67 +#define LOCAL_GL_FLOAT_MAT3x4 0x8B68 +#define LOCAL_GL_FLOAT_MAT3x4_NV 0x8B68 +#define LOCAL_GL_FLOAT_MAT4 0x8B5C +#define LOCAL_GL_FLOAT_MAT4_ARB 0x8B5C +#define LOCAL_GL_FLOAT_MAT4x2 0x8B69 +#define LOCAL_GL_FLOAT_MAT4x2_NV 0x8B69 +#define LOCAL_GL_FLOAT_MAT4x3 0x8B6A +#define LOCAL_GL_FLOAT_MAT4x3_NV 0x8B6A +#define LOCAL_GL_FLOAT_R16_NV 0x8884 +#define LOCAL_GL_FLOAT_R32_NV 0x8885 +#define LOCAL_GL_FLOAT_RG16_NV 0x8886 +#define LOCAL_GL_FLOAT_RG32_NV 0x8887 +#define LOCAL_GL_FLOAT_RGB16_NV 0x8888 +#define LOCAL_GL_FLOAT_RGB32_NV 0x8889 +#define LOCAL_GL_FLOAT_RGBA16_NV 0x888A +#define LOCAL_GL_FLOAT_RGBA32_NV 0x888B +#define LOCAL_GL_FLOAT_RGBA_MODE_NV 0x888E +#define LOCAL_GL_FLOAT_RGBA_NV 0x8883 +#define LOCAL_GL_FLOAT_RGB_NV 0x8882 +#define LOCAL_GL_FLOAT_RG_NV 0x8881 +#define LOCAL_GL_FLOAT_R_NV 0x8880 +#define LOCAL_GL_FLOAT_VEC2 0x8B50 +#define LOCAL_GL_FLOAT_VEC2_ARB 0x8B50 +#define LOCAL_GL_FLOAT_VEC3 0x8B51 +#define LOCAL_GL_FLOAT_VEC3_ARB 0x8B51 +#define LOCAL_GL_FLOAT_VEC4 0x8B52 +#define LOCAL_GL_FLOAT_VEC4_ARB 0x8B52 +#define LOCAL_GL_FOG 0x0B60 +#define LOCAL_GL_FOG_BIT 0x00000080 +#define LOCAL_GL_FOG_COLOR 0x0B66 +#define LOCAL_GL_FOG_COORD 0x8451 +#define LOCAL_GL_FOG_COORDINATE 0x8451 +#define LOCAL_GL_FOG_COORDINATE_ARRAY 0x8457 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define LOCAL_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define LOCAL_GL_FOG_COORDINATE_ARRAY_EXT 0x8457 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define LOCAL_GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 +#define LOCAL_GL_FOG_COORDINATE_EXT 0x8451 +#define LOCAL_GL_FOG_COORDINATE_SOURCE 0x8450 +#define LOCAL_GL_FOG_COORDINATE_SOURCE_EXT 0x8450 +#define LOCAL_GL_FOG_COORD_ARRAY 0x8457 +#define LOCAL_GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 +#define LOCAL_GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define LOCAL_GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 +#define LOCAL_GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define LOCAL_GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define LOCAL_GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define LOCAL_GL_FOG_COORD_SRC 0x8450 +#define LOCAL_GL_FOG_DENSITY 0x0B62 +#define LOCAL_GL_FOG_DISTANCE_MODE_NV 0x855A +#define LOCAL_GL_FOG_END 0x0B64 +#define LOCAL_GL_FOG_FUNC_POINTS_SGIS 0x812B +#define LOCAL_GL_FOG_FUNC_SGIS 0x812A +#define LOCAL_GL_FOG_HINT 0x0C54 +#define LOCAL_GL_FOG_INDEX 0x0B61 +#define LOCAL_GL_FOG_MODE 0x0B65 +#define LOCAL_GL_FOG_OFFSET_SGIX 0x8198 +#define LOCAL_GL_FOG_OFFSET_VALUE_SGIX 0x8199 +#define LOCAL_GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC +#define LOCAL_GL_FOG_START 0x0B63 +#define LOCAL_GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define LOCAL_GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define LOCAL_GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define LOCAL_GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define LOCAL_GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define LOCAL_GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define LOCAL_GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define LOCAL_GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define LOCAL_GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define LOCAL_GL_FONT_UNAVAILABLE_NV 0x936A +#define LOCAL_GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define LOCAL_GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define LOCAL_GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define LOCAL_GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define LOCAL_GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define LOCAL_GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define LOCAL_GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define LOCAL_GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define LOCAL_GL_FORCE_BLUE_TO_ONE_NV 0x8860 +#define LOCAL_GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 +#define LOCAL_GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 +#define LOCAL_GL_FOVEATION_ENABLE_BIT_QCOM 0x00000001 +#define LOCAL_GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM 0x00000002 +#define LOCAL_GL_FOVEATION_SUBSAMPLED_LAYOUT_METHOD_BIT_QCOM 0x00000004 +#define LOCAL_GL_FRACTIONAL_EVEN 0x8E7C +#define LOCAL_GL_FRACTIONAL_EVEN_EXT 0x8E7C +#define LOCAL_GL_FRACTIONAL_EVEN_OES 0x8E7C +#define LOCAL_GL_FRACTIONAL_ODD 0x8E7B +#define LOCAL_GL_FRACTIONAL_ODD_EXT 0x8E7B +#define LOCAL_GL_FRACTIONAL_ODD_OES 0x8E7B +#define LOCAL_GL_FRAGMENTS_INSTRUMENT_COUNTERS_SGIX 0x8314 +#define LOCAL_GL_FRAGMENTS_INSTRUMENT_MAX_SGIX 0x8315 +#define LOCAL_GL_FRAGMENTS_INSTRUMENT_SGIX 0x8313 +#define LOCAL_GL_FRAGMENT_ALPHA_MODULATE_IMG 0x8C08 +#define LOCAL_GL_FRAGMENT_COLOR_EXT 0x834C +#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 +#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 +#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 +#define LOCAL_GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE +#define LOCAL_GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD +#define LOCAL_GL_FRAGMENT_DEPTH 0x8452 +#define LOCAL_GL_FRAGMENT_DEPTH_EXT 0x8452 +#define LOCAL_GL_FRAGMENT_INPUT_NV 0x936D +#define LOCAL_GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define LOCAL_GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES 0x8E5D +#define LOCAL_GL_FRAGMENT_LIGHT0_SGIX 0x840C +#define LOCAL_GL_FRAGMENT_LIGHT1_SGIX 0x840D +#define LOCAL_GL_FRAGMENT_LIGHT2_SGIX 0x840E +#define LOCAL_GL_FRAGMENT_LIGHT3_SGIX 0x840F +#define LOCAL_GL_FRAGMENT_LIGHT4_SGIX 0x8410 +#define LOCAL_GL_FRAGMENT_LIGHT5_SGIX 0x8411 +#define LOCAL_GL_FRAGMENT_LIGHT6_SGIX 0x8412 +#define LOCAL_GL_FRAGMENT_LIGHT7_SGIX 0x8413 +#define LOCAL_GL_FRAGMENT_LIGHTING_SGIX 0x8400 +#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A +#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 +#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B +#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 +#define LOCAL_GL_FRAGMENT_MATERIAL_EXT 0x8349 +#define LOCAL_GL_FRAGMENT_NORMAL_EXT 0x834A +#define LOCAL_GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define LOCAL_GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 +#define LOCAL_GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA 0x8BB3 +#define LOCAL_GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA 0x8BB2 +#define LOCAL_GL_FRAGMENT_PROGRAM_CALLBACK_MESA 0x8BB1 +#define LOCAL_GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D +#define LOCAL_GL_FRAGMENT_PROGRAM_NV 0x8870 +#define LOCAL_GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 +#define LOCAL_GL_FRAGMENT_PROGRAM_POSITION_MESA 0x8BB0 +#define LOCAL_GL_FRAGMENT_SHADER 0x8B30 +#define LOCAL_GL_FRAGMENT_SHADER_ARB 0x8B30 +#define LOCAL_GL_FRAGMENT_SHADER_ATI 0x8920 +#define LOCAL_GL_FRAGMENT_SHADER_BIT 0x00000002 +#define LOCAL_GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 +#define LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#define LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B +#define LOCAL_GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 +#define LOCAL_GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM 0x8F66 +#define LOCAL_GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 +#define LOCAL_GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 +#define LOCAL_GL_FRAGMENT_SUBROUTINE 0x92EC +#define LOCAL_GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define LOCAL_GL_FRAGMENT_TEXTURE 0x829F +#define LOCAL_GL_FRAMEBUFFER 0x8D40 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES 0x8DA7 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C +#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG 0x913F +#define LOCAL_GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define LOCAL_GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 +#define LOCAL_GL_FRAMEBUFFER_BINDING 0x8CA6 +#define LOCAL_GL_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 +#define LOCAL_GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define LOCAL_GL_FRAMEBUFFER_BINDING_OES 0x8CA6 +#define LOCAL_GL_FRAMEBUFFER_BLEND 0x828B +#define LOCAL_GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define LOCAL_GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define LOCAL_GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT 0x8218 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT 0x9312 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_LAYERS_OES 0x9312 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define LOCAL_GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define LOCAL_GL_FRAMEBUFFER_EXT 0x8D40 +#define LOCAL_GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM 0x96A2 +#define LOCAL_GL_FRAMEBUFFER_FLIP_X_MESA 0x8BBC +#define LOCAL_GL_FRAMEBUFFER_FLIP_Y_MESA 0x8BBB +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES 0x8CDB +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_FOVEATION_QCOM 0x8BFF +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES 0x8DA8 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG 0x913C +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56 +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES 0x8CDC +#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 +#define LOCAL_GL_FRAMEBUFFER_OES 0x8D40 +#define LOCAL_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 +#define LOCAL_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 +#define LOCAL_GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define LOCAL_GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define LOCAL_GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 +#define LOCAL_GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 +#define LOCAL_GL_FRAMEBUFFER_SRGB 0x8DB9 +#define LOCAL_GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#define LOCAL_GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define LOCAL_GL_FRAMEBUFFER_SWAP_XY_MESA 0x8BBD +#define LOCAL_GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define LOCAL_GL_FRAMEBUFFER_UNDEFINED_OES 0x8219 +#define LOCAL_GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define LOCAL_GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define LOCAL_GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD +#define LOCAL_GL_FRAMEZOOM_FACTOR_SGIX 0x818C +#define LOCAL_GL_FRAMEZOOM_SGIX 0x818B +#define LOCAL_GL_FRAME_NV 0x8E26 +#define LOCAL_GL_FRONT 0x0404 +#define LOCAL_GL_FRONT_AND_BACK 0x0408 +#define LOCAL_GL_FRONT_FACE 0x0B46 +#define LOCAL_GL_FRONT_FACE_COMMAND_NV 0x0012 +#define LOCAL_GL_FRONT_LEFT 0x0400 +#define LOCAL_GL_FRONT_RIGHT 0x0401 +#define LOCAL_GL_FULL_RANGE_EXT 0x87E1 +#define LOCAL_GL_FULL_STIPPLE_HINT_PGI 0x1A219 +#define LOCAL_GL_FULL_SUPPORT 0x82B7 +#define LOCAL_GL_FUNC_ADD 0x8006 +#define LOCAL_GL_FUNC_ADD_EXT 0x8006 +#define LOCAL_GL_FUNC_ADD_OES 0x8006 +#define LOCAL_GL_FUNC_REVERSE_SUBTRACT 0x800B +#define LOCAL_GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B +#define LOCAL_GL_FUNC_REVERSE_SUBTRACT_OES 0x800B +#define LOCAL_GL_FUNC_SUBTRACT 0x800A +#define LOCAL_GL_FUNC_SUBTRACT_EXT 0x800A +#define LOCAL_GL_FUNC_SUBTRACT_OES 0x800A +#define LOCAL_GL_GCCSO_SHADER_BINARY_FJ 0x9260 +#define LOCAL_GL_GENERATE_MIPMAP 0x8191 +#define LOCAL_GL_GENERATE_MIPMAP_HINT 0x8192 +#define LOCAL_GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#define LOCAL_GL_GENERATE_MIPMAP_SGIS 0x8191 +#define LOCAL_GL_GENERIC_ATTRIB_NV 0x8C7D +#define LOCAL_GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 +#define LOCAL_GL_GEOMETRY_DEFORMATION_SGIX 0x8194 +#define LOCAL_GL_GEOMETRY_INPUT_TYPE 0x8917 +#define LOCAL_GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define LOCAL_GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +#define LOCAL_GL_GEOMETRY_LINKED_INPUT_TYPE_EXT 0x8917 +#define LOCAL_GL_GEOMETRY_LINKED_INPUT_TYPE_OES 0x8917 +#define LOCAL_GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT 0x8918 +#define LOCAL_GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES 0x8918 +#define LOCAL_GL_GEOMETRY_LINKED_VERTICES_OUT_EXT 0x8916 +#define LOCAL_GL_GEOMETRY_LINKED_VERTICES_OUT_OES 0x8916 +#define LOCAL_GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define LOCAL_GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define LOCAL_GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +#define LOCAL_GL_GEOMETRY_PROGRAM_NV 0x8C26 +#define LOCAL_GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 +#define LOCAL_GL_GEOMETRY_SHADER 0x8DD9 +#define LOCAL_GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define LOCAL_GL_GEOMETRY_SHADER_BIT 0x00000004 +#define LOCAL_GL_GEOMETRY_SHADER_BIT_EXT 0x00000004 +#define LOCAL_GL_GEOMETRY_SHADER_BIT_OES 0x00000004 +#define LOCAL_GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define LOCAL_GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define LOCAL_GL_GEOMETRY_SHADER_INVOCATIONS_EXT 0x887F +#define LOCAL_GL_GEOMETRY_SHADER_INVOCATIONS_OES 0x887F +#define LOCAL_GL_GEOMETRY_SHADER_OES 0x8DD9 +#define LOCAL_GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3 +#define LOCAL_GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 +#define LOCAL_GL_GEOMETRY_SUBROUTINE 0x92EB +#define LOCAL_GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define LOCAL_GL_GEOMETRY_TEXTURE 0x829E +#define LOCAL_GL_GEOMETRY_VERTICES_OUT 0x8916 +#define LOCAL_GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define LOCAL_GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +#define LOCAL_GL_GEQUAL 0x0206 +#define LOCAL_GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define LOCAL_GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define LOCAL_GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA +#define LOCAL_GL_GLOBAL_ALPHA_SUN 0x81D9 +#define LOCAL_GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define LOCAL_GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define LOCAL_GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define LOCAL_GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define LOCAL_GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define LOCAL_GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define LOCAL_GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define LOCAL_GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define LOCAL_GL_GLYPH_WIDTH_BIT_NV 0x01 +#define LOCAL_GL_GPU_ADDRESS_NV 0x8F34 +#define LOCAL_GL_GPU_DISJOINT_EXT 0x8FBB +#define LOCAL_GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define LOCAL_GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define LOCAL_GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#define LOCAL_GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define LOCAL_GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define LOCAL_GL_GPU_OPTIMIZED_QCOM 0x8FB2 +#define LOCAL_GL_GREATER 0x0204 +#define LOCAL_GL_GREEN 0x1904 +#define LOCAL_GL_GREEN_BIAS 0x0D19 +#define LOCAL_GL_GREEN_BITS 0x0D53 +#define LOCAL_GL_GREEN_BIT_ATI 0x00000002 +#define LOCAL_GL_GREEN_INTEGER 0x8D95 +#define LOCAL_GL_GREEN_INTEGER_EXT 0x8D95 +#define LOCAL_GL_GREEN_MAX_CLAMP_INGR 0x8565 +#define LOCAL_GL_GREEN_MIN_CLAMP_INGR 0x8561 +#define LOCAL_GL_GREEN_NV 0x1904 +#define LOCAL_GL_GREEN_SCALE 0x0D18 +#define LOCAL_GL_GS_PROGRAM_BINARY_MTK 0x9641 +#define LOCAL_GL_GS_SHADER_BINARY_MTK 0x9640 +#define LOCAL_GL_GUILTY_CONTEXT_RESET 0x8253 +#define LOCAL_GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define LOCAL_GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define LOCAL_GL_GUILTY_CONTEXT_RESET_KHR 0x8253 +#define LOCAL_GL_HALF_APPLE 0x140B +#define LOCAL_GL_HALF_BIAS_NEGATE_NV 0x853B +#define LOCAL_GL_HALF_BIAS_NORMAL_NV 0x853A +#define LOCAL_GL_HALF_BIT_ATI 0x00000008 +#define LOCAL_GL_HALF_FLOAT 0x140B +#define LOCAL_GL_HALF_FLOAT_ARB 0x140B +#define LOCAL_GL_HALF_FLOAT_NV 0x140B +#define LOCAL_GL_HALF_FLOAT_OES 0x8D61 +#define LOCAL_GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B +#define LOCAL_GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C +#define LOCAL_GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 +#define LOCAL_GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A +#define LOCAL_GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 +#define LOCAL_GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 +#define LOCAL_GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 +#define LOCAL_GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 +#define LOCAL_GL_HARDLIGHT 0x929B +#define LOCAL_GL_HARDLIGHT_KHR 0x929B +#define LOCAL_GL_HARDLIGHT_NV 0x929B +#define LOCAL_GL_HARDMIX_NV 0x92A9 +#define LOCAL_GL_HIGH_FLOAT 0x8DF2 +#define LOCAL_GL_HIGH_INT 0x8DF5 +#define LOCAL_GL_HILO16_NV 0x86F8 +#define LOCAL_GL_HILO8_NV 0x885E +#define LOCAL_GL_HILO_NV 0x86F4 +#define LOCAL_GL_HINT_BIT 0x00008000 +#define LOCAL_GL_HISTOGRAM 0x8024 +#define LOCAL_GL_HISTOGRAM_ALPHA_SIZE 0x802B +#define LOCAL_GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B +#define LOCAL_GL_HISTOGRAM_BLUE_SIZE 0x802A +#define LOCAL_GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A +#define LOCAL_GL_HISTOGRAM_EXT 0x8024 +#define LOCAL_GL_HISTOGRAM_FORMAT 0x8027 +#define LOCAL_GL_HISTOGRAM_FORMAT_EXT 0x8027 +#define LOCAL_GL_HISTOGRAM_GREEN_SIZE 0x8029 +#define LOCAL_GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 +#define LOCAL_GL_HISTOGRAM_LUMINANCE_SIZE 0x802C +#define LOCAL_GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C +#define LOCAL_GL_HISTOGRAM_RED_SIZE 0x8028 +#define LOCAL_GL_HISTOGRAM_RED_SIZE_EXT 0x8028 +#define LOCAL_GL_HISTOGRAM_SINK 0x802D +#define LOCAL_GL_HISTOGRAM_SINK_EXT 0x802D +#define LOCAL_GL_HISTOGRAM_WIDTH 0x8026 +#define LOCAL_GL_HISTOGRAM_WIDTH_EXT 0x8026 +#define LOCAL_GL_HI_BIAS_NV 0x8714 +#define LOCAL_GL_HI_SCALE_NV 0x870E +#define LOCAL_GL_HORIZONTAL_LINE_TO_NV 0x06 +#define LOCAL_GL_HSL_COLOR 0x92AF +#define LOCAL_GL_HSL_COLOR_KHR 0x92AF +#define LOCAL_GL_HSL_COLOR_NV 0x92AF +#define LOCAL_GL_HSL_HUE 0x92AD +#define LOCAL_GL_HSL_HUE_KHR 0x92AD +#define LOCAL_GL_HSL_HUE_NV 0x92AD +#define LOCAL_GL_HSL_LUMINOSITY 0x92B0 +#define LOCAL_GL_HSL_LUMINOSITY_KHR 0x92B0 +#define LOCAL_GL_HSL_LUMINOSITY_NV 0x92B0 +#define LOCAL_GL_HSL_SATURATION 0x92AE +#define LOCAL_GL_HSL_SATURATION_KHR 0x92AE +#define LOCAL_GL_HSL_SATURATION_NV 0x92AE +#define LOCAL_GL_IDENTITY_NV 0x862A +#define LOCAL_GL_IGNORE_BORDER_HP 0x8150 +#define LOCAL_GL_IMAGE_1D 0x904C +#define LOCAL_GL_IMAGE_1D_ARRAY 0x9052 +#define LOCAL_GL_IMAGE_1D_ARRAY_EXT 0x9052 +#define LOCAL_GL_IMAGE_1D_EXT 0x904C +#define LOCAL_GL_IMAGE_2D 0x904D +#define LOCAL_GL_IMAGE_2D_ARRAY 0x9053 +#define LOCAL_GL_IMAGE_2D_ARRAY_EXT 0x9053 +#define LOCAL_GL_IMAGE_2D_EXT 0x904D +#define LOCAL_GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define LOCAL_GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define LOCAL_GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 +#define LOCAL_GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 +#define LOCAL_GL_IMAGE_2D_RECT 0x904F +#define LOCAL_GL_IMAGE_2D_RECT_EXT 0x904F +#define LOCAL_GL_IMAGE_3D 0x904E +#define LOCAL_GL_IMAGE_3D_EXT 0x904E +#define LOCAL_GL_IMAGE_BINDING_ACCESS 0x8F3E +#define LOCAL_GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E +#define LOCAL_GL_IMAGE_BINDING_FORMAT 0x906E +#define LOCAL_GL_IMAGE_BINDING_FORMAT_EXT 0x906E +#define LOCAL_GL_IMAGE_BINDING_LAYER 0x8F3D +#define LOCAL_GL_IMAGE_BINDING_LAYERED 0x8F3C +#define LOCAL_GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C +#define LOCAL_GL_IMAGE_BINDING_LAYER_EXT 0x8F3D +#define LOCAL_GL_IMAGE_BINDING_LEVEL 0x8F3B +#define LOCAL_GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B +#define LOCAL_GL_IMAGE_BINDING_NAME 0x8F3A +#define LOCAL_GL_IMAGE_BINDING_NAME_EXT 0x8F3A +#define LOCAL_GL_IMAGE_BUFFER 0x9051 +#define LOCAL_GL_IMAGE_BUFFER_EXT 0x9051 +#define LOCAL_GL_IMAGE_BUFFER_OES 0x9051 +#define LOCAL_GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define LOCAL_GL_IMAGE_CLASS_11_11_10 0x82C2 +#define LOCAL_GL_IMAGE_CLASS_1_X_16 0x82BE +#define LOCAL_GL_IMAGE_CLASS_1_X_32 0x82BB +#define LOCAL_GL_IMAGE_CLASS_1_X_8 0x82C1 +#define LOCAL_GL_IMAGE_CLASS_2_X_16 0x82BD +#define LOCAL_GL_IMAGE_CLASS_2_X_32 0x82BA +#define LOCAL_GL_IMAGE_CLASS_2_X_8 0x82C0 +#define LOCAL_GL_IMAGE_CLASS_4_X_16 0x82BC +#define LOCAL_GL_IMAGE_CLASS_4_X_32 0x82B9 +#define LOCAL_GL_IMAGE_CLASS_4_X_8 0x82BF +#define LOCAL_GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define LOCAL_GL_IMAGE_CUBE 0x9050 +#define LOCAL_GL_IMAGE_CUBE_EXT 0x9050 +#define LOCAL_GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define LOCAL_GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define LOCAL_GL_IMAGE_CUBE_MAP_ARRAY_OES 0x9054 +#define LOCAL_GL_IMAGE_CUBIC_WEIGHT_HP 0x815E +#define LOCAL_GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define LOCAL_GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define LOCAL_GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define LOCAL_GL_IMAGE_MAG_FILTER_HP 0x815C +#define LOCAL_GL_IMAGE_MIN_FILTER_HP 0x815D +#define LOCAL_GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define LOCAL_GL_IMAGE_PIXEL_TYPE 0x82AA +#define LOCAL_GL_IMAGE_ROTATE_ANGLE_HP 0x8159 +#define LOCAL_GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A +#define LOCAL_GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B +#define LOCAL_GL_IMAGE_SCALE_X_HP 0x8155 +#define LOCAL_GL_IMAGE_SCALE_Y_HP 0x8156 +#define LOCAL_GL_IMAGE_TEXEL_SIZE 0x82A7 +#define LOCAL_GL_IMAGE_TRANSFORM_2D_HP 0x8161 +#define LOCAL_GL_IMAGE_TRANSLATE_X_HP 0x8157 +#define LOCAL_GL_IMAGE_TRANSLATE_Y_HP 0x8158 +#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define LOCAL_GL_INCLUSIVE_EXT 0x8F10 +#define LOCAL_GL_INCR 0x1E02 +#define LOCAL_GL_INCR_WRAP 0x8507 +#define LOCAL_GL_INCR_WRAP_EXT 0x8507 +#define LOCAL_GL_INCR_WRAP_OES 0x8507 +#define LOCAL_GL_INDEX 0x8222 +#define LOCAL_GL_INDEX_ARRAY 0x8077 +#define LOCAL_GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 +#define LOCAL_GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define LOCAL_GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define LOCAL_GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define LOCAL_GL_INDEX_ARRAY_EXT 0x8077 +#define LOCAL_GL_INDEX_ARRAY_LENGTH_NV 0x8F2E +#define LOCAL_GL_INDEX_ARRAY_LIST_IBM 103073 +#define LOCAL_GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 +#define LOCAL_GL_INDEX_ARRAY_POINTER 0x8091 +#define LOCAL_GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define LOCAL_GL_INDEX_ARRAY_STRIDE 0x8086 +#define LOCAL_GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define LOCAL_GL_INDEX_ARRAY_TYPE 0x8085 +#define LOCAL_GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define LOCAL_GL_INDEX_BITS 0x0D51 +#define LOCAL_GL_INDEX_BIT_PGI 0x00080000 +#define LOCAL_GL_INDEX_CLEAR_VALUE 0x0C20 +#define LOCAL_GL_INDEX_LOGIC_OP 0x0BF1 +#define LOCAL_GL_INDEX_MATERIAL_EXT 0x81B8 +#define LOCAL_GL_INDEX_MATERIAL_FACE_EXT 0x81BA +#define LOCAL_GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 +#define LOCAL_GL_INDEX_MODE 0x0C30 +#define LOCAL_GL_INDEX_OFFSET 0x0D13 +#define LOCAL_GL_INDEX_SHIFT 0x0D12 +#define LOCAL_GL_INDEX_TEST_EXT 0x81B5 +#define LOCAL_GL_INDEX_TEST_FUNC_EXT 0x81B6 +#define LOCAL_GL_INDEX_TEST_REF_EXT 0x81B7 +#define LOCAL_GL_INDEX_WRITEMASK 0x0C21 +#define LOCAL_GL_INFO_LOG_LENGTH 0x8B84 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET 0x8254 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET_KHR 0x8254 +#define LOCAL_GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 +#define LOCAL_GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 +#define LOCAL_GL_INT 0x1404 +#define LOCAL_GL_INT16_NV 0x8FE4 +#define LOCAL_GL_INT16_VEC2_NV 0x8FE5 +#define LOCAL_GL_INT16_VEC3_NV 0x8FE6 +#define LOCAL_GL_INT16_VEC4_NV 0x8FE7 +#define LOCAL_GL_INT64_ARB 0x140E +#define LOCAL_GL_INT64_NV 0x140E +#define LOCAL_GL_INT64_VEC2_ARB 0x8FE9 +#define LOCAL_GL_INT64_VEC2_NV 0x8FE9 +#define LOCAL_GL_INT64_VEC3_ARB 0x8FEA +#define LOCAL_GL_INT64_VEC3_NV 0x8FEA +#define LOCAL_GL_INT64_VEC4_ARB 0x8FEB +#define LOCAL_GL_INT64_VEC4_NV 0x8FEB +#define LOCAL_GL_INT8_NV 0x8FE0 +#define LOCAL_GL_INT8_VEC2_NV 0x8FE1 +#define LOCAL_GL_INT8_VEC3_NV 0x8FE2 +#define LOCAL_GL_INT8_VEC4_NV 0x8FE3 +#define LOCAL_GL_INTENSITY 0x8049 +#define LOCAL_GL_INTENSITY12 0x804C +#define LOCAL_GL_INTENSITY12_EXT 0x804C +#define LOCAL_GL_INTENSITY16 0x804D +#define LOCAL_GL_INTENSITY16F_ARB 0x881D +#define LOCAL_GL_INTENSITY16I_EXT 0x8D8B +#define LOCAL_GL_INTENSITY16UI_EXT 0x8D79 +#define LOCAL_GL_INTENSITY16_EXT 0x804D +#define LOCAL_GL_INTENSITY16_SNORM 0x901B +#define LOCAL_GL_INTENSITY32F_ARB 0x8817 +#define LOCAL_GL_INTENSITY32I_EXT 0x8D85 +#define LOCAL_GL_INTENSITY32UI_EXT 0x8D73 +#define LOCAL_GL_INTENSITY4 0x804A +#define LOCAL_GL_INTENSITY4_EXT 0x804A +#define LOCAL_GL_INTENSITY8 0x804B +#define LOCAL_GL_INTENSITY8I_EXT 0x8D91 +#define LOCAL_GL_INTENSITY8UI_EXT 0x8D7F +#define LOCAL_GL_INTENSITY8_EXT 0x804B +#define LOCAL_GL_INTENSITY8_SNORM 0x9017 +#define LOCAL_GL_INTENSITY_EXT 0x8049 +#define LOCAL_GL_INTENSITY_FLOAT16_APPLE 0x881D +#define LOCAL_GL_INTENSITY_FLOAT16_ATI 0x881D +#define LOCAL_GL_INTENSITY_FLOAT32_APPLE 0x8817 +#define LOCAL_GL_INTENSITY_FLOAT32_ATI 0x8817 +#define LOCAL_GL_INTENSITY_SNORM 0x9013 +#define LOCAL_GL_INTERLACE_OML 0x8980 +#define LOCAL_GL_INTERLACE_READ_INGR 0x8568 +#define LOCAL_GL_INTERLACE_READ_OML 0x8981 +#define LOCAL_GL_INTERLACE_SGIX 0x8094 +#define LOCAL_GL_INTERLEAVED_ATTRIBS 0x8C8C +#define LOCAL_GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C +#define LOCAL_GL_INTERLEAVED_ATTRIBS_NV 0x8C8C +#define LOCAL_GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define LOCAL_GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define LOCAL_GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define LOCAL_GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define LOCAL_GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define LOCAL_GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define LOCAL_GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define LOCAL_GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define LOCAL_GL_INTERNALFORMAT_PREFERRED 0x8270 +#define LOCAL_GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define LOCAL_GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define LOCAL_GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define LOCAL_GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define LOCAL_GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define LOCAL_GL_INTERNALFORMAT_SUPPORTED 0x826F +#define LOCAL_GL_INTERPOLATE 0x8575 +#define LOCAL_GL_INTERPOLATE_ARB 0x8575 +#define LOCAL_GL_INTERPOLATE_EXT 0x8575 +#define LOCAL_GL_INT_10_10_10_2_OES 0x8DF7 +#define LOCAL_GL_INT_2_10_10_10_REV 0x8D9F +#define LOCAL_GL_INT_IMAGE_1D 0x9057 +#define LOCAL_GL_INT_IMAGE_1D_ARRAY 0x905D +#define LOCAL_GL_INT_IMAGE_1D_ARRAY_EXT 0x905D +#define LOCAL_GL_INT_IMAGE_1D_EXT 0x9057 +#define LOCAL_GL_INT_IMAGE_2D 0x9058 +#define LOCAL_GL_INT_IMAGE_2D_ARRAY 0x905E +#define LOCAL_GL_INT_IMAGE_2D_ARRAY_EXT 0x905E +#define LOCAL_GL_INT_IMAGE_2D_EXT 0x9058 +#define LOCAL_GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define LOCAL_GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define LOCAL_GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 +#define LOCAL_GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 +#define LOCAL_GL_INT_IMAGE_2D_RECT 0x905A +#define LOCAL_GL_INT_IMAGE_2D_RECT_EXT 0x905A +#define LOCAL_GL_INT_IMAGE_3D 0x9059 +#define LOCAL_GL_INT_IMAGE_3D_EXT 0x9059 +#define LOCAL_GL_INT_IMAGE_BUFFER 0x905C +#define LOCAL_GL_INT_IMAGE_BUFFER_EXT 0x905C +#define LOCAL_GL_INT_IMAGE_BUFFER_OES 0x905C +#define LOCAL_GL_INT_IMAGE_CUBE 0x905B +#define LOCAL_GL_INT_IMAGE_CUBE_EXT 0x905B +#define LOCAL_GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define LOCAL_GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define LOCAL_GL_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x905F +#define LOCAL_GL_INT_SAMPLER_1D 0x8DC9 +#define LOCAL_GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define LOCAL_GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define LOCAL_GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define LOCAL_GL_INT_SAMPLER_2D 0x8DCA +#define LOCAL_GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define LOCAL_GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define LOCAL_GL_INT_SAMPLER_2D_EXT 0x8DCA +#define LOCAL_GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define LOCAL_GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define LOCAL_GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910C +#define LOCAL_GL_INT_SAMPLER_2D_RECT 0x8DCD +#define LOCAL_GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define LOCAL_GL_INT_SAMPLER_3D 0x8DCB +#define LOCAL_GL_INT_SAMPLER_3D_EXT 0x8DCB +#define LOCAL_GL_INT_SAMPLER_BUFFER 0x8DD0 +#define LOCAL_GL_INT_SAMPLER_BUFFER_AMD 0x9002 +#define LOCAL_GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define LOCAL_GL_INT_SAMPLER_BUFFER_OES 0x8DD0 +#define LOCAL_GL_INT_SAMPLER_CUBE 0x8DCC +#define LOCAL_GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define LOCAL_GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define LOCAL_GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define LOCAL_GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900E +#define LOCAL_GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900E +#define LOCAL_GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 +#define LOCAL_GL_INT_VEC2 0x8B53 +#define LOCAL_GL_INT_VEC2_ARB 0x8B53 +#define LOCAL_GL_INT_VEC3 0x8B54 +#define LOCAL_GL_INT_VEC3_ARB 0x8B54 +#define LOCAL_GL_INT_VEC4 0x8B55 +#define LOCAL_GL_INT_VEC4_ARB 0x8B55 +#define LOCAL_GL_INVALID_ENUM 0x0500 +#define LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506 +#define LOCAL_GL_INVALID_INDEX 0xFFFFFFFF +#define LOCAL_GL_INVALID_OPERATION 0x0502 +#define LOCAL_GL_INVALID_VALUE 0x0501 +#define LOCAL_GL_INVARIANT_DATATYPE_EXT 0x87EB +#define LOCAL_GL_INVARIANT_EXT 0x87C2 +#define LOCAL_GL_INVARIANT_VALUE_EXT 0x87EA +#define LOCAL_GL_INVERSE_NV 0x862B +#define LOCAL_GL_INVERSE_TRANSPOSE_NV 0x862D +#define LOCAL_GL_INVERT 0x150A +#define LOCAL_GL_INVERTED_SCREEN_W_REND 0x8491 +#define LOCAL_GL_INVERT_OVG_NV 0x92B4 +#define LOCAL_GL_INVERT_RGB_NV 0x92A3 +#define LOCAL_GL_IR_INSTRUMENT1_SGIX 0x817F +#define LOCAL_GL_ISOLINES 0x8E7A +#define LOCAL_GL_ISOLINES_EXT 0x8E7A +#define LOCAL_GL_ISOLINES_OES 0x8E7A +#define LOCAL_GL_IS_PER_PATCH 0x92E7 +#define LOCAL_GL_IS_PER_PATCH_EXT 0x92E7 +#define LOCAL_GL_IS_PER_PATCH_OES 0x92E7 +#define LOCAL_GL_IS_ROW_MAJOR 0x9300 +#define LOCAL_GL_ITALIC_BIT_NV 0x02 +#define LOCAL_GL_IUI_N3F_V2F_EXT 0x81AF +#define LOCAL_GL_IUI_N3F_V3F_EXT 0x81B0 +#define LOCAL_GL_IUI_V2F_EXT 0x81AD +#define LOCAL_GL_IUI_V3F_EXT 0x81AE +#define LOCAL_GL_KEEP 0x1E00 +#define LOCAL_GL_LARGE_CCW_ARC_TO_NV 0x16 +#define LOCAL_GL_LARGE_CW_ARC_TO_NV 0x18 +#define LOCAL_GL_LAST_VERTEX_CONVENTION 0x8E4E +#define LOCAL_GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define LOCAL_GL_LAST_VERTEX_CONVENTION_OES 0x8E4E +#define LOCAL_GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 +#define LOCAL_GL_LAYER_NV 0x8DAA +#define LOCAL_GL_LAYER_PROVOKING_VERTEX 0x825E +#define LOCAL_GL_LAYER_PROVOKING_VERTEX_EXT 0x825E +#define LOCAL_GL_LAYER_PROVOKING_VERTEX_OES 0x825E +#define LOCAL_GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E +#define LOCAL_GL_LAYOUT_DEFAULT_INTEL 0 +#define LOCAL_GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 +#define LOCAL_GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 +#define LOCAL_GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F +#define LOCAL_GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 +#define LOCAL_GL_LAYOUT_GENERAL_EXT 0x958D +#define LOCAL_GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 +#define LOCAL_GL_LAYOUT_LINEAR_INTEL 1 +#define LOCAL_GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 +#define LOCAL_GL_LAYOUT_TRANSFER_DST_EXT 0x9593 +#define LOCAL_GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 +#define LOCAL_GL_LEFT 0x0406 +#define LOCAL_GL_LEQUAL 0x0203 +#define LOCAL_GL_LERP_ATI 0x8969 +#define LOCAL_GL_LESS 0x0201 +#define LOCAL_GL_LGPU_SEPARATE_STORAGE_BIT_NVX 0x0800 +#define LOCAL_GL_LIGHT0 0x4000 +#define LOCAL_GL_LIGHT1 0x4001 +#define LOCAL_GL_LIGHT2 0x4002 +#define LOCAL_GL_LIGHT3 0x4003 +#define LOCAL_GL_LIGHT4 0x4004 +#define LOCAL_GL_LIGHT5 0x4005 +#define LOCAL_GL_LIGHT6 0x4006 +#define LOCAL_GL_LIGHT7 0x4007 +#define LOCAL_GL_LIGHTEN 0x9298 +#define LOCAL_GL_LIGHTEN_KHR 0x9298 +#define LOCAL_GL_LIGHTEN_NV 0x9298 +#define LOCAL_GL_LIGHTING 0x0B50 +#define LOCAL_GL_LIGHTING_BIT 0x00000040 +#define LOCAL_GL_LIGHT_ENV_MODE_SGIX 0x8407 +#define LOCAL_GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define LOCAL_GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define LOCAL_GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define LOCAL_GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define LOCAL_GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 +#define LOCAL_GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define LOCAL_GL_LINE 0x1B01 +#define LOCAL_GL_LINEAR 0x2601 +#define LOCAL_GL_LINEARBURN_NV 0x92A5 +#define LOCAL_GL_LINEARDODGE_NV 0x92A4 +#define LOCAL_GL_LINEARLIGHT_NV 0x92A7 +#define LOCAL_GL_LINEAR_ATTENUATION 0x1208 +#define LOCAL_GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 +#define LOCAL_GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F +#define LOCAL_GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 +#define LOCAL_GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 +#define LOCAL_GL_LINEAR_DETAIL_SGIS 0x8097 +#define LOCAL_GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define LOCAL_GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define LOCAL_GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE +#define LOCAL_GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF +#define LOCAL_GL_LINEAR_SHARPEN_SGIS 0x80AD +#define LOCAL_GL_LINEAR_TILING_EXT 0x9585 +#define LOCAL_GL_LINES 0x0001 +#define LOCAL_GL_LINES_ADJACENCY 0x000A +#define LOCAL_GL_LINES_ADJACENCY_ARB 0x000A +#define LOCAL_GL_LINES_ADJACENCY_EXT 0x000A +#define LOCAL_GL_LINES_ADJACENCY_OES 0x000A +#define LOCAL_GL_LINE_BIT 0x00000004 +#define LOCAL_GL_LINE_LOOP 0x0002 +#define LOCAL_GL_LINE_NV 0x1B01 +#define LOCAL_GL_LINE_QUALITY_HINT_SGIX 0x835B +#define LOCAL_GL_LINE_RESET_TOKEN 0x0707 +#define LOCAL_GL_LINE_SMOOTH 0x0B20 +#define LOCAL_GL_LINE_SMOOTH_HINT 0x0C52 +#define LOCAL_GL_LINE_STIPPLE 0x0B24 +#define LOCAL_GL_LINE_STIPPLE_PATTERN 0x0B25 +#define LOCAL_GL_LINE_STIPPLE_REPEAT 0x0B26 +#define LOCAL_GL_LINE_STRIP 0x0003 +#define LOCAL_GL_LINE_STRIP_ADJACENCY 0x000B +#define LOCAL_GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define LOCAL_GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define LOCAL_GL_LINE_STRIP_ADJACENCY_OES 0x000B +#define LOCAL_GL_LINE_TOKEN 0x0702 +#define LOCAL_GL_LINE_TO_NV 0x04 +#define LOCAL_GL_LINE_WIDTH 0x0B21 +#define LOCAL_GL_LINE_WIDTH_COMMAND_NV 0x000D +#define LOCAL_GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define LOCAL_GL_LINE_WIDTH_RANGE 0x0B22 +#define LOCAL_GL_LINK_STATUS 0x8B82 +#define LOCAL_GL_LIST_BASE 0x0B32 +#define LOCAL_GL_LIST_BIT 0x00020000 +#define LOCAL_GL_LIST_INDEX 0x0B33 +#define LOCAL_GL_LIST_MODE 0x0B30 +#define LOCAL_GL_LIST_PRIORITY_SGIX 0x8182 +#define LOCAL_GL_LOAD 0x0101 +#define LOCAL_GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +#define LOCAL_GL_LOCAL_CONSTANT_EXT 0x87C3 +#define LOCAL_GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define LOCAL_GL_LOCAL_EXT 0x87C4 +#define LOCAL_GL_LOCATION 0x930E +#define LOCAL_GL_LOCATION_COMPONENT 0x934A +#define LOCAL_GL_LOCATION_INDEX 0x930F +#define LOCAL_GL_LOCATION_INDEX_EXT 0x930F +#define LOCAL_GL_LOGIC_OP 0x0BF1 +#define LOCAL_GL_LOGIC_OP_MODE 0x0BF0 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET 0x8252 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_KHR 0x8252 +#define LOCAL_GL_LOWER_LEFT 0x8CA1 +#define LOCAL_GL_LOWER_LEFT_EXT 0x8CA1 +#define LOCAL_GL_LOW_FLOAT 0x8DF0 +#define LOCAL_GL_LOW_INT 0x8DF3 +#define LOCAL_GL_LO_BIAS_NV 0x8715 +#define LOCAL_GL_LO_SCALE_NV 0x870F +#define LOCAL_GL_LUID_SIZE_EXT 8 +#define LOCAL_GL_LUMINANCE 0x1909 +#define LOCAL_GL_LUMINANCE12 0x8041 +#define LOCAL_GL_LUMINANCE12_ALPHA12 0x8047 +#define LOCAL_GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define LOCAL_GL_LUMINANCE12_ALPHA4 0x8046 +#define LOCAL_GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define LOCAL_GL_LUMINANCE12_EXT 0x8041 +#define LOCAL_GL_LUMINANCE16 0x8042 +#define LOCAL_GL_LUMINANCE16F_ARB 0x881E +#define LOCAL_GL_LUMINANCE16F_EXT 0x881E +#define LOCAL_GL_LUMINANCE16I_EXT 0x8D8C +#define LOCAL_GL_LUMINANCE16UI_EXT 0x8D7A +#define LOCAL_GL_LUMINANCE16_ALPHA16 0x8048 +#define LOCAL_GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define LOCAL_GL_LUMINANCE16_ALPHA16_SNORM 0x901A +#define LOCAL_GL_LUMINANCE16_EXT 0x8042 +#define LOCAL_GL_LUMINANCE16_SNORM 0x9019 +#define LOCAL_GL_LUMINANCE32F_ARB 0x8818 +#define LOCAL_GL_LUMINANCE32F_EXT 0x8818 +#define LOCAL_GL_LUMINANCE32I_EXT 0x8D86 +#define LOCAL_GL_LUMINANCE32UI_EXT 0x8D74 +#define LOCAL_GL_LUMINANCE4 0x803F +#define LOCAL_GL_LUMINANCE4_ALPHA4 0x8043 +#define LOCAL_GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define LOCAL_GL_LUMINANCE4_ALPHA4_OES 0x8043 +#define LOCAL_GL_LUMINANCE4_EXT 0x803F +#define LOCAL_GL_LUMINANCE6_ALPHA2 0x8044 +#define LOCAL_GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define LOCAL_GL_LUMINANCE8 0x8040 +#define LOCAL_GL_LUMINANCE8I_EXT 0x8D92 +#define LOCAL_GL_LUMINANCE8UI_EXT 0x8D80 +#define LOCAL_GL_LUMINANCE8_ALPHA8 0x8045 +#define LOCAL_GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define LOCAL_GL_LUMINANCE8_ALPHA8_OES 0x8045 +#define LOCAL_GL_LUMINANCE8_ALPHA8_SNORM 0x9016 +#define LOCAL_GL_LUMINANCE8_EXT 0x8040 +#define LOCAL_GL_LUMINANCE8_OES 0x8040 +#define LOCAL_GL_LUMINANCE8_SNORM 0x9015 +#define LOCAL_GL_LUMINANCE_ALPHA 0x190A +#define LOCAL_GL_LUMINANCE_ALPHA16F_ARB 0x881F +#define LOCAL_GL_LUMINANCE_ALPHA16F_EXT 0x881F +#define LOCAL_GL_LUMINANCE_ALPHA16I_EXT 0x8D8D +#define LOCAL_GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B +#define LOCAL_GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define LOCAL_GL_LUMINANCE_ALPHA32F_EXT 0x8819 +#define LOCAL_GL_LUMINANCE_ALPHA32I_EXT 0x8D87 +#define LOCAL_GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 +#define LOCAL_GL_LUMINANCE_ALPHA8I_EXT 0x8D93 +#define LOCAL_GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 +#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F +#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F +#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 +#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 +#define LOCAL_GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D +#define LOCAL_GL_LUMINANCE_ALPHA_SNORM 0x9012 +#define LOCAL_GL_LUMINANCE_FLOAT16_APPLE 0x881E +#define LOCAL_GL_LUMINANCE_FLOAT16_ATI 0x881E +#define LOCAL_GL_LUMINANCE_FLOAT32_APPLE 0x8818 +#define LOCAL_GL_LUMINANCE_FLOAT32_ATI 0x8818 +#define LOCAL_GL_LUMINANCE_INTEGER_EXT 0x8D9C +#define LOCAL_GL_LUMINANCE_SNORM 0x9011 +#define LOCAL_GL_MAD_ATI 0x8968 +#define LOCAL_GL_MAGNITUDE_BIAS_NV 0x8718 +#define LOCAL_GL_MAGNITUDE_SCALE_NV 0x8712 +#define LOCAL_GL_MAJOR_VERSION 0x821B +#define LOCAL_GL_MALI_PROGRAM_BINARY_ARM 0x8F61 +#define LOCAL_GL_MALI_SHADER_BINARY_ARM 0x8F60 +#define LOCAL_GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define LOCAL_GL_MAP1_BINORMAL_EXT 0x8446 +#define LOCAL_GL_MAP1_COLOR_4 0x0D90 +#define LOCAL_GL_MAP1_GRID_DOMAIN 0x0DD0 +#define LOCAL_GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define LOCAL_GL_MAP1_INDEX 0x0D91 +#define LOCAL_GL_MAP1_NORMAL 0x0D92 +#define LOCAL_GL_MAP1_TANGENT_EXT 0x8444 +#define LOCAL_GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define LOCAL_GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define LOCAL_GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define LOCAL_GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define LOCAL_GL_MAP1_VERTEX_3 0x0D97 +#define LOCAL_GL_MAP1_VERTEX_4 0x0D98 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A +#define LOCAL_GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B +#define LOCAL_GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C +#define LOCAL_GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D +#define LOCAL_GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E +#define LOCAL_GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F +#define LOCAL_GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 +#define LOCAL_GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 +#define LOCAL_GL_MAP2_BINORMAL_EXT 0x8447 +#define LOCAL_GL_MAP2_COLOR_4 0x0DB0 +#define LOCAL_GL_MAP2_GRID_DOMAIN 0x0DD2 +#define LOCAL_GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define LOCAL_GL_MAP2_INDEX 0x0DB1 +#define LOCAL_GL_MAP2_NORMAL 0x0DB2 +#define LOCAL_GL_MAP2_TANGENT_EXT 0x8445 +#define LOCAL_GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define LOCAL_GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define LOCAL_GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define LOCAL_GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define LOCAL_GL_MAP2_VERTEX_3 0x0DB7 +#define LOCAL_GL_MAP2_VERTEX_4 0x0DB8 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A +#define LOCAL_GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B +#define LOCAL_GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C +#define LOCAL_GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D +#define LOCAL_GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E +#define LOCAL_GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F +#define LOCAL_GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 +#define LOCAL_GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 +#define LOCAL_GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 +#define LOCAL_GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 +#define LOCAL_GL_MAP_COHERENT_BIT 0x0080 +#define LOCAL_GL_MAP_COHERENT_BIT_EXT 0x0080 +#define LOCAL_GL_MAP_COLOR 0x0D10 +#define LOCAL_GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define LOCAL_GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 +#define LOCAL_GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define LOCAL_GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 +#define LOCAL_GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define LOCAL_GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 +#define LOCAL_GL_MAP_PERSISTENT_BIT 0x0040 +#define LOCAL_GL_MAP_PERSISTENT_BIT_EXT 0x0040 +#define LOCAL_GL_MAP_READ_BIT 0x0001 +#define LOCAL_GL_MAP_READ_BIT_EXT 0x0001 +#define LOCAL_GL_MAP_STENCIL 0x0D11 +#define LOCAL_GL_MAP_TESSELLATION_NV 0x86C2 +#define LOCAL_GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define LOCAL_GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 +#define LOCAL_GL_MAP_WRITE_BIT 0x0002 +#define LOCAL_GL_MAP_WRITE_BIT_EXT 0x0002 +#define LOCAL_GL_MATERIAL_SIDE_HINT_PGI 0x1A22C +#define LOCAL_GL_MATRIX0_ARB 0x88C0 +#define LOCAL_GL_MATRIX0_NV 0x8630 +#define LOCAL_GL_MATRIX10_ARB 0x88CA +#define LOCAL_GL_MATRIX11_ARB 0x88CB +#define LOCAL_GL_MATRIX12_ARB 0x88CC +#define LOCAL_GL_MATRIX13_ARB 0x88CD +#define LOCAL_GL_MATRIX14_ARB 0x88CE +#define LOCAL_GL_MATRIX15_ARB 0x88CF +#define LOCAL_GL_MATRIX16_ARB 0x88D0 +#define LOCAL_GL_MATRIX17_ARB 0x88D1 +#define LOCAL_GL_MATRIX18_ARB 0x88D2 +#define LOCAL_GL_MATRIX19_ARB 0x88D3 +#define LOCAL_GL_MATRIX1_ARB 0x88C1 +#define LOCAL_GL_MATRIX1_NV 0x8631 +#define LOCAL_GL_MATRIX20_ARB 0x88D4 +#define LOCAL_GL_MATRIX21_ARB 0x88D5 +#define LOCAL_GL_MATRIX22_ARB 0x88D6 +#define LOCAL_GL_MATRIX23_ARB 0x88D7 +#define LOCAL_GL_MATRIX24_ARB 0x88D8 +#define LOCAL_GL_MATRIX25_ARB 0x88D9 +#define LOCAL_GL_MATRIX26_ARB 0x88DA +#define LOCAL_GL_MATRIX27_ARB 0x88DB +#define LOCAL_GL_MATRIX28_ARB 0x88DC +#define LOCAL_GL_MATRIX29_ARB 0x88DD +#define LOCAL_GL_MATRIX2_ARB 0x88C2 +#define LOCAL_GL_MATRIX2_NV 0x8632 +#define LOCAL_GL_MATRIX30_ARB 0x88DE +#define LOCAL_GL_MATRIX31_ARB 0x88DF +#define LOCAL_GL_MATRIX3_ARB 0x88C3 +#define LOCAL_GL_MATRIX3_NV 0x8633 +#define LOCAL_GL_MATRIX4_ARB 0x88C4 +#define LOCAL_GL_MATRIX4_NV 0x8634 +#define LOCAL_GL_MATRIX5_ARB 0x88C5 +#define LOCAL_GL_MATRIX5_NV 0x8635 +#define LOCAL_GL_MATRIX6_ARB 0x88C6 +#define LOCAL_GL_MATRIX6_NV 0x8636 +#define LOCAL_GL_MATRIX7_ARB 0x88C7 +#define LOCAL_GL_MATRIX7_NV 0x8637 +#define LOCAL_GL_MATRIX8_ARB 0x88C8 +#define LOCAL_GL_MATRIX9_ARB 0x88C9 +#define LOCAL_GL_MATRIX_EXT 0x87C0 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_ARB 0x8844 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES 0x8B9E +#define LOCAL_GL_MATRIX_INDEX_ARRAY_OES 0x8844 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_POINTER_OES 0x8849 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_SIZE_OES 0x8846 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_STRIDE_OES 0x8848 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 +#define LOCAL_GL_MATRIX_INDEX_ARRAY_TYPE_OES 0x8847 +#define LOCAL_GL_MATRIX_MODE 0x0BA0 +#define LOCAL_GL_MATRIX_PALETTE_ARB 0x8840 +#define LOCAL_GL_MATRIX_PALETTE_OES 0x8840 +#define LOCAL_GL_MATRIX_STRIDE 0x92FF +#define LOCAL_GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 +#define LOCAL_GL_MAT_AMBIENT_BIT_PGI 0x00100000 +#define LOCAL_GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 +#define LOCAL_GL_MAT_DIFFUSE_BIT_PGI 0x00400000 +#define LOCAL_GL_MAT_EMISSION_BIT_PGI 0x00800000 +#define LOCAL_GL_MAT_SHININESS_BIT_PGI 0x02000000 +#define LOCAL_GL_MAT_SPECULAR_BIT_PGI 0x04000000 +#define LOCAL_GL_MAX 0x8008 +#define LOCAL_GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define LOCAL_GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 +#define LOCAL_GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 +#define LOCAL_GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 +#define LOCAL_GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 +#define LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define LOCAL_GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 +#define LOCAL_GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D +#define LOCAL_GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 +#define LOCAL_GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F +#define LOCAL_GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define LOCAL_GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define LOCAL_GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define LOCAL_GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED +#define LOCAL_GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define LOCAL_GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 +#define LOCAL_GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 +#define LOCAL_GL_MAX_CLIP_DISTANCES 0x0D32 +#define LOCAL_GL_MAX_CLIP_DISTANCES_APPLE 0x0D32 +#define LOCAL_GL_MAX_CLIP_DISTANCES_EXT 0x0D32 +#define LOCAL_GL_MAX_CLIP_PLANES 0x0D32 +#define LOCAL_GL_MAX_CLIP_PLANES_IMG 0x0D32 +#define LOCAL_GL_MAX_COARSE_FRAGMENT_SAMPLES_NV 0x955F +#define LOCAL_GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define LOCAL_GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define LOCAL_GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF +#define LOCAL_GL_MAX_COLOR_FRAMEBUFFER_SAMPLES_AMD 0x91B3 +#define LOCAL_GL_MAX_COLOR_FRAMEBUFFER_STORAGE_SAMPLES_AMD 0x91B4 +#define LOCAL_GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 +#define LOCAL_GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 +#define LOCAL_GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define LOCAL_GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define LOCAL_GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define LOCAL_GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA +#define LOCAL_GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA +#define LOCAL_GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define LOCAL_GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define LOCAL_GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define LOCAL_GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define LOCAL_GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8A32 +#define LOCAL_GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8A32 +#define LOCAL_GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define LOCAL_GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define LOCAL_GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 +#define LOCAL_GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67 +#define LOCAL_GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define LOCAL_GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define LOCAL_GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F +#define LOCAL_GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define LOCAL_GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E1E +#define LOCAL_GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E1E +#define LOCAL_GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define LOCAL_GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E1F +#define LOCAL_GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E1F +#define LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define LOCAL_GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define LOCAL_GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define LOCAL_GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define LOCAL_GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define LOCAL_GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define LOCAL_GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +#define LOCAL_GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define LOCAL_GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define LOCAL_GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define LOCAL_GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define LOCAL_GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define LOCAL_GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define LOCAL_GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define LOCAL_GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 +#define LOCAL_GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define LOCAL_GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB +#define LOCAL_GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define LOCAL_GL_MAX_CONVOLUTION_HEIGHT 0x801B +#define LOCAL_GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B +#define LOCAL_GL_MAX_CONVOLUTION_WIDTH 0x801A +#define LOCAL_GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A +#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES 0x851C +#define LOCAL_GL_MAX_CULL_DISTANCES 0x82F9 +#define LOCAL_GL_MAX_CULL_DISTANCES_EXT 0x82F9 +#define LOCAL_GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define LOCAL_GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define LOCAL_GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define LOCAL_GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 +#define LOCAL_GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define LOCAL_GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define LOCAL_GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define LOCAL_GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 +#define LOCAL_GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define LOCAL_GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define LOCAL_GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 +#define LOCAL_GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 +#define LOCAL_GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 +#define LOCAL_GL_MAX_DEPTH 0x8280 +#define LOCAL_GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5 +#define LOCAL_GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define LOCAL_GL_MAX_DETACHED_BUFFERS_NV 0x95AD +#define LOCAL_GL_MAX_DETACHED_TEXTURES_NV 0x95AC +#define LOCAL_GL_MAX_DRAW_BUFFERS 0x8824 +#define LOCAL_GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define LOCAL_GL_MAX_DRAW_BUFFERS_ATI 0x8824 +#define LOCAL_GL_MAX_DRAW_BUFFERS_EXT 0x8824 +#define LOCAL_GL_MAX_DRAW_BUFFERS_NV 0x8824 +#define LOCAL_GL_MAX_DRAW_MESH_TASKS_COUNT_NV 0x953D +#define LOCAL_GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define LOCAL_GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC +#define LOCAL_GL_MAX_ELEMENTS_INDICES 0x80E9 +#define LOCAL_GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +#define LOCAL_GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define LOCAL_GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define LOCAL_GL_MAX_ELEMENT_INDEX 0x8D6B +#define LOCAL_GL_MAX_EVAL_ORDER 0x0D30 +#define LOCAL_GL_MAX_EXT 0x8008 +#define LOCAL_GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C +#define LOCAL_GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define LOCAL_GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define LOCAL_GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 +#define LOCAL_GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define LOCAL_GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define LOCAL_GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C +#define LOCAL_GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5C +#define LOCAL_GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 +#define LOCAL_GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 +#define LOCAL_GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define LOCAL_GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define LOCAL_GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define LOCAL_GL_MAX_FRAMEBUFFER_LAYERS_EXT 0x9317 +#define LOCAL_GL_MAX_FRAMEBUFFER_LAYERS_OES 0x9317 +#define LOCAL_GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define LOCAL_GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define LOCAL_GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D +#define LOCAL_GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT 0x92D5 +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES 0x92D5 +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT 0x92CF +#define LOCAL_GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES 0x92CF +#define LOCAL_GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 +#define LOCAL_GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define LOCAL_GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT 0x90CD +#define LOCAL_GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES 0x90CD +#define LOCAL_GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define LOCAL_GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT 0x9123 +#define LOCAL_GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES 0x9123 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT 0x9124 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES 0x9124 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define LOCAL_GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES 0x8DE0 +#define LOCAL_GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A +#define LOCAL_GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define LOCAL_GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT 0x8E5A +#define LOCAL_GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES 0x8E5A +#define LOCAL_GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define LOCAL_GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT 0x90D7 +#define LOCAL_GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES 0x90D7 +#define LOCAL_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define LOCAL_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define LOCAL_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define LOCAL_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES 0x8C29 +#define LOCAL_GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define LOCAL_GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +#define LOCAL_GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define LOCAL_GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES 0x8DE1 +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT 0x8A2C +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES 0x8A2C +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define LOCAL_GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8DDF +#define LOCAL_GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define LOCAL_GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +#define LOCAL_GL_MAX_HEIGHT 0x827F +#define LOCAL_GL_MAX_IMAGE_SAMPLES 0x906D +#define LOCAL_GL_MAX_IMAGE_SAMPLES_EXT 0x906D +#define LOCAL_GL_MAX_IMAGE_UNITS 0x8F38 +#define LOCAL_GL_MAX_IMAGE_UNITS_EXT 0x8F38 +#define LOCAL_GL_MAX_INTEGER_SAMPLES 0x9110 +#define LOCAL_GL_MAX_LABEL_LENGTH 0x82E8 +#define LOCAL_GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define LOCAL_GL_MAX_LAYERS 0x8281 +#define LOCAL_GL_MAX_LGPU_GPUS_NVX 0x92BA +#define LOCAL_GL_MAX_LIGHTS 0x0D31 +#define LOCAL_GL_MAX_LIST_NESTING 0x0B31 +#define LOCAL_GL_MAX_MAP_TESSELLATION_NV 0x86D6 +#define LOCAL_GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 +#define LOCAL_GL_MAX_MESH_ATOMIC_COUNTERS_NV 0x8E65 +#define LOCAL_GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64 +#define LOCAL_GL_MAX_MESH_IMAGE_UNIFORMS_NV 0x8E62 +#define LOCAL_GL_MAX_MESH_OUTPUT_PRIMITIVES_NV 0x9539 +#define LOCAL_GL_MAX_MESH_OUTPUT_VERTICES_NV 0x9538 +#define LOCAL_GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66 +#define LOCAL_GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61 +#define LOCAL_GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV 0x9536 +#define LOCAL_GL_MAX_MESH_UNIFORM_BLOCKS_NV 0x8E60 +#define LOCAL_GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63 +#define LOCAL_GL_MAX_MESH_VIEWS_NV 0x9557 +#define LOCAL_GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2 +#define LOCAL_GL_MAX_MESH_WORK_GROUP_SIZE_NV 0x953B +#define LOCAL_GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define LOCAL_GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 +#define LOCAL_GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2 +#define LOCAL_GL_MAX_NAME_LENGTH 0x92F6 +#define LOCAL_GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define LOCAL_GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define LOCAL_GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define LOCAL_GL_MAX_PALETTE_MATRICES_ARB 0x8842 +#define LOCAL_GL_MAX_PALETTE_MATRICES_OES 0x8842 +#define LOCAL_GL_MAX_PATCH_VERTICES 0x8E7D +#define LOCAL_GL_MAX_PATCH_VERTICES_EXT 0x8E7D +#define LOCAL_GL_MAX_PATCH_VERTICES_OES 0x8E7D +#define LOCAL_GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define LOCAL_GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 +#define LOCAL_GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 +#define LOCAL_GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define LOCAL_GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define LOCAL_GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define LOCAL_GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 +#define LOCAL_GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 +#define LOCAL_GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define LOCAL_GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 +#define LOCAL_GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 +#define LOCAL_GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 +#define LOCAL_GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 +#define LOCAL_GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define LOCAL_GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define LOCAL_GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 +#define LOCAL_GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 +#define LOCAL_GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define LOCAL_GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define LOCAL_GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +#define LOCAL_GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define LOCAL_GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define LOCAL_GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define LOCAL_GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define LOCAL_GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 +#define LOCAL_GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define LOCAL_GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 +#define LOCAL_GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 +#define LOCAL_GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 +#define LOCAL_GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 +#define LOCAL_GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 +#define LOCAL_GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 +#define LOCAL_GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define LOCAL_GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define LOCAL_GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +#define LOCAL_GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 +#define LOCAL_GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#define LOCAL_GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define LOCAL_GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define LOCAL_GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F +#define LOCAL_GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define LOCAL_GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define LOCAL_GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 +#define LOCAL_GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define LOCAL_GL_MAX_RASTER_SAMPLES_EXT 0x9329 +#define LOCAL_GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 +#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#define LOCAL_GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define LOCAL_GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define LOCAL_GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8 +#define LOCAL_GL_MAX_SAMPLES 0x8D57 +#define LOCAL_GL_MAX_SAMPLES_ANGLE 0x8D57 +#define LOCAL_GL_MAX_SAMPLES_APPLE 0x8D57 +#define LOCAL_GL_MAX_SAMPLES_EXT 0x8D57 +#define LOCAL_GL_MAX_SAMPLES_IMG 0x9135 +#define LOCAL_GL_MAX_SAMPLES_NV 0x8D57 +#define LOCAL_GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define LOCAL_GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 +#define LOCAL_GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define LOCAL_GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111 +#define LOCAL_GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 +#define LOCAL_GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650 +#define LOCAL_GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651 +#define LOCAL_GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0 +#define LOCAL_GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 +#define LOCAL_GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 +#define LOCAL_GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT 0x8F67 +#define LOCAL_GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define LOCAL_GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define LOCAL_GL_MAX_SHADER_SUBSAMPLED_IMAGE_UNITS_QCOM 0x8FA1 +#define LOCAL_GL_MAX_SHININESS_NV 0x8504 +#define LOCAL_GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 +#define LOCAL_GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 +#define LOCAL_GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT 0x9199 +#define LOCAL_GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A +#define LOCAL_GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A +#define LOCAL_GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT 0x919A +#define LOCAL_GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 +#define LOCAL_GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define LOCAL_GL_MAX_SPARSE_TEXTURE_SIZE_EXT 0x9198 +#define LOCAL_GL_MAX_SPOT_EXPONENT_NV 0x8505 +#define LOCAL_GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349 +#define LOCAL_GL_MAX_SUBROUTINES 0x8DE7 +#define LOCAL_GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define LOCAL_GL_MAX_TASK_ATOMIC_COUNTERS_NV 0x8E6D +#define LOCAL_GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C +#define LOCAL_GL_MAX_TASK_IMAGE_UNIFORMS_NV 0x8E6A +#define LOCAL_GL_MAX_TASK_OUTPUT_COUNT_NV 0x953A +#define LOCAL_GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E +#define LOCAL_GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69 +#define LOCAL_GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV 0x9537 +#define LOCAL_GL_MAX_TASK_UNIFORM_BLOCKS_NV 0x8E68 +#define LOCAL_GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B +#define LOCAL_GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3 +#define LOCAL_GL_MAX_TASK_WORK_GROUP_SIZE_NV 0x953C +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT 0x92D3 +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES 0x92D3 +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT 0x92CD +#define LOCAL_GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES 0x92CD +#define LOCAL_GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define LOCAL_GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT 0x90CB +#define LOCAL_GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES 0x90CB +#define LOCAL_GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define LOCAL_GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT 0x886C +#define LOCAL_GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES 0x886C +#define LOCAL_GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define LOCAL_GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT 0x8E83 +#define LOCAL_GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES 0x8E83 +#define LOCAL_GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define LOCAL_GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT 0x90D8 +#define LOCAL_GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES 0x90D8 +#define LOCAL_GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define LOCAL_GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT 0x8E81 +#define LOCAL_GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES 0x8E81 +#define LOCAL_GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define LOCAL_GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT 0x8E85 +#define LOCAL_GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES 0x8E85 +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT 0x8E89 +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES 0x8E89 +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E7F +#define LOCAL_GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E7F +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT 0x92D4 +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES 0x92D4 +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT 0x92CE +#define LOCAL_GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES 0x92CE +#define LOCAL_GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define LOCAL_GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT 0x90CC +#define LOCAL_GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES 0x90CC +#define LOCAL_GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define LOCAL_GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT 0x886D +#define LOCAL_GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES 0x886D +#define LOCAL_GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define LOCAL_GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT 0x8E86 +#define LOCAL_GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES 0x8E86 +#define LOCAL_GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define LOCAL_GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT 0x90D9 +#define LOCAL_GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES 0x90D9 +#define LOCAL_GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define LOCAL_GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT 0x8E82 +#define LOCAL_GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES 0x8E82 +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT 0x8E8A +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES 0x8E8A +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E80 +#define LOCAL_GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E80 +#define LOCAL_GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define LOCAL_GL_MAX_TESS_GEN_LEVEL_EXT 0x8E7E +#define LOCAL_GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E +#define LOCAL_GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define LOCAL_GL_MAX_TESS_PATCH_COMPONENTS_EXT 0x8E84 +#define LOCAL_GL_MAX_TESS_PATCH_COMPONENTS_OES 0x8E84 +#define LOCAL_GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define LOCAL_GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B +#define LOCAL_GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define LOCAL_GL_MAX_TEXTURE_BUFFER_SIZE_OES 0x8C2B +#define LOCAL_GL_MAX_TEXTURE_COORDS 0x8871 +#define LOCAL_GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define LOCAL_GL_MAX_TEXTURE_COORDS_NV 0x8871 +#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 +#define LOCAL_GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define LOCAL_GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define LOCAL_GL_MAX_TEXTURE_SIZE 0x0D33 +#define LOCAL_GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define LOCAL_GL_MAX_TEXTURE_UNITS 0x84E2 +#define LOCAL_GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +#define LOCAL_GL_MAX_TIMELINE_SEMAPHORE_VALUE_DIFFERENCE_NV 0x95B6 +#define LOCAL_GL_MAX_TRACK_MATRICES_NV 0x862F +#define LOCAL_GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 +#define LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 +#define LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define LOCAL_GL_MAX_UNIFORM_LOCATIONS 0x826E +#define LOCAL_GL_MAX_VARYING_COMPONENTS 0x8B4B +#define LOCAL_GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +#define LOCAL_GL_MAX_VARYING_FLOATS 0x8B4B +#define LOCAL_GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define LOCAL_GL_MAX_VARYING_VECTORS 0x8DFC +#define LOCAL_GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 +#define LOCAL_GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define LOCAL_GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define LOCAL_GL_MAX_VERTEX_ATTRIBS 0x8869 +#define LOCAL_GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define LOCAL_GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define LOCAL_GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define LOCAL_GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define LOCAL_GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 +#define LOCAL_GL_MAX_VERTEX_HINT_PGI 0x1A22D +#define LOCAL_GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define LOCAL_GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define LOCAL_GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define LOCAL_GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define LOCAL_GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define LOCAL_GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define LOCAL_GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define LOCAL_GL_MAX_VERTEX_STREAMS 0x8E71 +#define LOCAL_GL_MAX_VERTEX_STREAMS_ATI 0x876B +#define LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define LOCAL_GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define LOCAL_GL_MAX_VERTEX_UNITS_ARB 0x86A4 +#define LOCAL_GL_MAX_VERTEX_UNITS_OES 0x86A4 +#define LOCAL_GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define LOCAL_GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +#define LOCAL_GL_MAX_VIEWPORTS 0x825B +#define LOCAL_GL_MAX_VIEWPORTS_NV 0x825B +#define LOCAL_GL_MAX_VIEWPORTS_OES 0x825B +#define LOCAL_GL_MAX_VIEWPORT_DIMS 0x0D3A +#define LOCAL_GL_MAX_VIEWS_OVR 0x9631 +#define LOCAL_GL_MAX_WIDTH 0x827E +#define LOCAL_GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 +#define LOCAL_GL_MEDIUM_FLOAT 0x8DF1 +#define LOCAL_GL_MEDIUM_INT 0x8DF4 +#define LOCAL_GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6 +#define LOCAL_GL_MEMORY_ATTACHABLE_NV 0x95A8 +#define LOCAL_GL_MEMORY_ATTACHABLE_SIZE_NV 0x95A7 +#define LOCAL_GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543 +#define LOCAL_GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF +#define LOCAL_GL_MESH_OUTPUT_TYPE_NV 0x957B +#define LOCAL_GL_MESH_PRIMITIVES_OUT_NV 0x957A +#define LOCAL_GL_MESH_SHADER_BIT_NV 0x00000040 +#define LOCAL_GL_MESH_SHADER_NV 0x9559 +#define LOCAL_GL_MESH_SUBROUTINE_NV 0x957C +#define LOCAL_GL_MESH_SUBROUTINE_UNIFORM_NV 0x957E +#define LOCAL_GL_MESH_VERTICES_OUT_NV 0x9579 +#define LOCAL_GL_MESH_WORK_GROUP_SIZE_NV 0x953E +#define LOCAL_GL_MIN 0x8007 +#define LOCAL_GL_MINMAX 0x802E +#define LOCAL_GL_MINMAX_EXT 0x802E +#define LOCAL_GL_MINMAX_FORMAT 0x802F +#define LOCAL_GL_MINMAX_FORMAT_EXT 0x802F +#define LOCAL_GL_MINMAX_SINK 0x8030 +#define LOCAL_GL_MINMAX_SINK_EXT 0x8030 +#define LOCAL_GL_MINOR_VERSION 0x821C +#define LOCAL_GL_MINUS_CLAMPED_NV 0x92B3 +#define LOCAL_GL_MINUS_NV 0x929F +#define LOCAL_GL_MIN_EXT 0x8007 +#define LOCAL_GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define LOCAL_GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B +#define LOCAL_GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5B +#define LOCAL_GL_MIN_LOD_WARNING_AMD 0x919C +#define LOCAL_GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define LOCAL_GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define LOCAL_GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define LOCAL_GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 +#define LOCAL_GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define LOCAL_GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define LOCAL_GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E +#define LOCAL_GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define LOCAL_GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +#define LOCAL_GL_MIN_SAMPLE_SHADING_VALUE_OES 0x8C37 +#define LOCAL_GL_MIN_SPARSE_LEVEL_AMD 0x919B +#define LOCAL_GL_MIPMAP 0x8293 +#define LOCAL_GL_MIRRORED_REPEAT 0x8370 +#define LOCAL_GL_MIRRORED_REPEAT_ARB 0x8370 +#define LOCAL_GL_MIRRORED_REPEAT_IBM 0x8370 +#define LOCAL_GL_MIRRORED_REPEAT_OES 0x8370 +#define LOCAL_GL_MIRROR_CLAMP_ATI 0x8742 +#define LOCAL_GL_MIRROR_CLAMP_EXT 0x8742 +#define LOCAL_GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 +#define LOCAL_GL_MIRROR_CLAMP_TO_EDGE 0x8743 +#define LOCAL_GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 +#define LOCAL_GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define LOCAL_GL_MITER_REVERT_NV 0x90A7 +#define LOCAL_GL_MITER_TRUNCATE_NV 0x90A8 +#define LOCAL_GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F +#define LOCAL_GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330 +#define LOCAL_GL_MODELVIEW 0x1700 +#define LOCAL_GL_MODELVIEW0_ARB 0x1700 +#define LOCAL_GL_MODELVIEW0_EXT 0x1700 +#define LOCAL_GL_MODELVIEW0_MATRIX_EXT 0x0BA6 +#define LOCAL_GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 +#define LOCAL_GL_MODELVIEW10_ARB 0x872A +#define LOCAL_GL_MODELVIEW11_ARB 0x872B +#define LOCAL_GL_MODELVIEW12_ARB 0x872C +#define LOCAL_GL_MODELVIEW13_ARB 0x872D +#define LOCAL_GL_MODELVIEW14_ARB 0x872E +#define LOCAL_GL_MODELVIEW15_ARB 0x872F +#define LOCAL_GL_MODELVIEW16_ARB 0x8730 +#define LOCAL_GL_MODELVIEW17_ARB 0x8731 +#define LOCAL_GL_MODELVIEW18_ARB 0x8732 +#define LOCAL_GL_MODELVIEW19_ARB 0x8733 +#define LOCAL_GL_MODELVIEW1_ARB 0x850A +#define LOCAL_GL_MODELVIEW1_EXT 0x850A +#define LOCAL_GL_MODELVIEW1_MATRIX_EXT 0x8506 +#define LOCAL_GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 +#define LOCAL_GL_MODELVIEW20_ARB 0x8734 +#define LOCAL_GL_MODELVIEW21_ARB 0x8735 +#define LOCAL_GL_MODELVIEW22_ARB 0x8736 +#define LOCAL_GL_MODELVIEW23_ARB 0x8737 +#define LOCAL_GL_MODELVIEW24_ARB 0x8738 +#define LOCAL_GL_MODELVIEW25_ARB 0x8739 +#define LOCAL_GL_MODELVIEW26_ARB 0x873A +#define LOCAL_GL_MODELVIEW27_ARB 0x873B +#define LOCAL_GL_MODELVIEW28_ARB 0x873C +#define LOCAL_GL_MODELVIEW29_ARB 0x873D +#define LOCAL_GL_MODELVIEW2_ARB 0x8722 +#define LOCAL_GL_MODELVIEW30_ARB 0x873E +#define LOCAL_GL_MODELVIEW31_ARB 0x873F +#define LOCAL_GL_MODELVIEW3_ARB 0x8723 +#define LOCAL_GL_MODELVIEW4_ARB 0x8724 +#define LOCAL_GL_MODELVIEW5_ARB 0x8725 +#define LOCAL_GL_MODELVIEW6_ARB 0x8726 +#define LOCAL_GL_MODELVIEW7_ARB 0x8727 +#define LOCAL_GL_MODELVIEW8_ARB 0x8728 +#define LOCAL_GL_MODELVIEW9_ARB 0x8729 +#define LOCAL_GL_MODELVIEW_MATRIX 0x0BA6 +#define LOCAL_GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D +#define LOCAL_GL_MODELVIEW_PROJECTION_NV 0x8629 +#define LOCAL_GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define LOCAL_GL_MODULATE 0x2100 +#define LOCAL_GL_MODULATE_ADD_ATI 0x8744 +#define LOCAL_GL_MODULATE_COLOR_IMG 0x8C04 +#define LOCAL_GL_MODULATE_SIGNED_ADD_ATI 0x8745 +#define LOCAL_GL_MODULATE_SUBTRACT_ATI 0x8746 +#define LOCAL_GL_MOTION_ESTIMATION_SEARCH_BLOCK_X_QCOM 0x8C90 +#define LOCAL_GL_MOTION_ESTIMATION_SEARCH_BLOCK_Y_QCOM 0x8C91 +#define LOCAL_GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define LOCAL_GL_MOVE_TO_NV 0x02 +#define LOCAL_GL_MOVE_TO_RESETS_NV 0x90B5 +#define LOCAL_GL_MOV_ATI 0x8961 +#define LOCAL_GL_MULT 0x0103 +#define LOCAL_GL_MULTICAST_GPUS_NV 0x92BA +#define LOCAL_GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9549 +#define LOCAL_GL_MULTIPLY 0x9294 +#define LOCAL_GL_MULTIPLY_KHR 0x9294 +#define LOCAL_GL_MULTIPLY_NV 0x9294 +#define LOCAL_GL_MULTISAMPLE 0x809D +#define LOCAL_GL_MULTISAMPLES_NV 0x9371 +#define LOCAL_GL_MULTISAMPLE_3DFX 0x86B2 +#define LOCAL_GL_MULTISAMPLE_ARB 0x809D +#define LOCAL_GL_MULTISAMPLE_BIT 0x20000000 +#define LOCAL_GL_MULTISAMPLE_BIT_3DFX 0x20000000 +#define LOCAL_GL_MULTISAMPLE_BIT_ARB 0x20000000 +#define LOCAL_GL_MULTISAMPLE_BIT_EXT 0x20000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000 +#define LOCAL_GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000 +#define LOCAL_GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +#define LOCAL_GL_MULTISAMPLE_EXT 0x809D +#define LOCAL_GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 +#define LOCAL_GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY 0x9382 +#define LOCAL_GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 +#define LOCAL_GL_MULTISAMPLE_LINE_WIDTH_RANGE 0x9381 +#define LOCAL_GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 +#define LOCAL_GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B +#define LOCAL_GL_MULTISAMPLE_SGIS 0x809D +#define LOCAL_GL_MULTIVIEW_EXT 0x90F1 +#define LOCAL_GL_MUL_ATI 0x8964 +#define LOCAL_GL_MVP_MATRIX_EXT 0x87E3 +#define LOCAL_GL_N3F_V3F 0x2A25 +#define LOCAL_GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define LOCAL_GL_NAMED_STRING_TYPE_ARB 0x8DEA +#define LOCAL_GL_NAME_LENGTH 0x92F9 +#define LOCAL_GL_NAME_STACK_DEPTH 0x0D70 +#define LOCAL_GL_NAND 0x150E +#define LOCAL_GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 +#define LOCAL_GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 +#define LOCAL_GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 +#define LOCAL_GL_NEAREST 0x2600 +#define LOCAL_GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E +#define LOCAL_GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D +#define LOCAL_GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define LOCAL_GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define LOCAL_GL_NEGATE_BIT_ATI 0x00000004 +#define LOCAL_GL_NEGATIVE_ONE_EXT 0x87DF +#define LOCAL_GL_NEGATIVE_ONE_TO_ONE 0x935E +#define LOCAL_GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E +#define LOCAL_GL_NEGATIVE_W_EXT 0x87DC +#define LOCAL_GL_NEGATIVE_X_EXT 0x87D9 +#define LOCAL_GL_NEGATIVE_Y_EXT 0x87DA +#define LOCAL_GL_NEGATIVE_Z_EXT 0x87DB +#define LOCAL_GL_NEVER 0x0200 +#define LOCAL_GL_NEXT_BUFFER_NV -2 +#define LOCAL_GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 +#define LOCAL_GL_NICEST 0x1102 +#define LOCAL_GL_NONE 0 +#define LOCAL_GL_NONE_OES 0 +#define LOCAL_GL_NOOP 0x1505 +#define LOCAL_GL_NOP_COMMAND_NV 0x0001 +#define LOCAL_GL_NOR 0x1508 +#define LOCAL_GL_NORMALIZE 0x0BA1 +#define LOCAL_GL_NORMALIZED_RANGE_EXT 0x87E0 +#define LOCAL_GL_NORMAL_ARRAY 0x8075 +#define LOCAL_GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 +#define LOCAL_GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define LOCAL_GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define LOCAL_GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define LOCAL_GL_NORMAL_ARRAY_EXT 0x8075 +#define LOCAL_GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C +#define LOCAL_GL_NORMAL_ARRAY_LIST_IBM 103071 +#define LOCAL_GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 +#define LOCAL_GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 +#define LOCAL_GL_NORMAL_ARRAY_POINTER 0x808F +#define LOCAL_GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define LOCAL_GL_NORMAL_ARRAY_STRIDE 0x807F +#define LOCAL_GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define LOCAL_GL_NORMAL_ARRAY_TYPE 0x807E +#define LOCAL_GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define LOCAL_GL_NORMAL_BIT_PGI 0x08000000 +#define LOCAL_GL_NORMAL_MAP 0x8511 +#define LOCAL_GL_NORMAL_MAP_ARB 0x8511 +#define LOCAL_GL_NORMAL_MAP_EXT 0x8511 +#define LOCAL_GL_NORMAL_MAP_NV 0x8511 +#define LOCAL_GL_NORMAL_MAP_OES 0x8511 +#define LOCAL_GL_NOTEQUAL 0x0205 +#define LOCAL_GL_NO_ERROR 0 +#define LOCAL_GL_NO_RESET_NOTIFICATION 0x8261 +#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#define LOCAL_GL_NO_RESET_NOTIFICATION_KHR 0x8261 +#define LOCAL_GL_NUM_ACTIVE_VARIABLES 0x9304 +#define LOCAL_GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define LOCAL_GL_NUM_DEVICE_UUIDS_EXT 0x9596 +#define LOCAL_GL_NUM_DOWNSAMPLE_SCALES_IMG 0x913D +#define LOCAL_GL_NUM_EXTENSIONS 0x821D +#define LOCAL_GL_NUM_FILL_STREAMS_NV 0x8E29 +#define LOCAL_GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define LOCAL_GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define LOCAL_GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define LOCAL_GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define LOCAL_GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define LOCAL_GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define LOCAL_GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define LOCAL_GL_NUM_PASSES_ATI 0x8970 +#define LOCAL_GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define LOCAL_GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#define LOCAL_GL_NUM_SAMPLE_COUNTS 0x9380 +#define LOCAL_GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define LOCAL_GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define LOCAL_GL_NUM_SPARSE_LEVELS_ARB 0x91AA +#define LOCAL_GL_NUM_SPARSE_LEVELS_EXT 0x91AA +#define LOCAL_GL_NUM_SPIR_V_EXTENSIONS 0x9554 +#define LOCAL_GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6 +#define LOCAL_GL_NUM_TILING_TYPES_EXT 0x9582 +#define LOCAL_GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 +#define LOCAL_GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define LOCAL_GL_NUM_VIRTUAL_PAGE_SIZES_EXT 0x91A8 +#define LOCAL_GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 +#define LOCAL_GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define LOCAL_GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +#define LOCAL_GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define LOCAL_GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define LOCAL_GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define LOCAL_GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define LOCAL_GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define LOCAL_GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define LOCAL_GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define LOCAL_GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 +#define LOCAL_GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 +#define LOCAL_GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define LOCAL_GL_OBJECT_LINEAR 0x2401 +#define LOCAL_GL_OBJECT_LINEAR_NV 0x2401 +#define LOCAL_GL_OBJECT_LINE_SGIS 0x81F7 +#define LOCAL_GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define LOCAL_GL_OBJECT_PLANE 0x2501 +#define LOCAL_GL_OBJECT_POINT_SGIS 0x81F5 +#define LOCAL_GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +#define LOCAL_GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define LOCAL_GL_OBJECT_TYPE 0x9112 +#define LOCAL_GL_OBJECT_TYPE_APPLE 0x9112 +#define LOCAL_GL_OBJECT_TYPE_ARB 0x8B4E +#define LOCAL_GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define LOCAL_GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F +#define LOCAL_GL_OCCLUSION_TEST_HP 0x8165 +#define LOCAL_GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#define LOCAL_GL_OFFSET 0x92FC +#define LOCAL_GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 +#define LOCAL_GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 +#define LOCAL_GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 +#define LOCAL_GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 +#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 +#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 +#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 +#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 +#define LOCAL_GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 +#define LOCAL_GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 +#define LOCAL_GL_OFFSET_TEXTURE_2D_NV 0x86E8 +#define LOCAL_GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 +#define LOCAL_GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 +#define LOCAL_GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 +#define LOCAL_GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C +#define LOCAL_GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D +#define LOCAL_GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 +#define LOCAL_GL_ONE 1 +#define LOCAL_GL_ONE_EXT 0x87DE +#define LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define LOCAL_GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define LOCAL_GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define LOCAL_GL_ONE_MINUS_DST_ALPHA 0x0305 +#define LOCAL_GL_ONE_MINUS_DST_COLOR 0x0307 +#define LOCAL_GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define LOCAL_GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB +#define LOCAL_GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define LOCAL_GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA +#define LOCAL_GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define LOCAL_GL_ONE_MINUS_SRC_COLOR 0x0301 +#define LOCAL_GL_OPERAND0_ALPHA 0x8598 +#define LOCAL_GL_OPERAND0_ALPHA_ARB 0x8598 +#define LOCAL_GL_OPERAND0_ALPHA_EXT 0x8598 +#define LOCAL_GL_OPERAND0_RGB 0x8590 +#define LOCAL_GL_OPERAND0_RGB_ARB 0x8590 +#define LOCAL_GL_OPERAND0_RGB_EXT 0x8590 +#define LOCAL_GL_OPERAND1_ALPHA 0x8599 +#define LOCAL_GL_OPERAND1_ALPHA_ARB 0x8599 +#define LOCAL_GL_OPERAND1_ALPHA_EXT 0x8599 +#define LOCAL_GL_OPERAND1_RGB 0x8591 +#define LOCAL_GL_OPERAND1_RGB_ARB 0x8591 +#define LOCAL_GL_OPERAND1_RGB_EXT 0x8591 +#define LOCAL_GL_OPERAND2_ALPHA 0x859A +#define LOCAL_GL_OPERAND2_ALPHA_ARB 0x859A +#define LOCAL_GL_OPERAND2_ALPHA_EXT 0x859A +#define LOCAL_GL_OPERAND2_RGB 0x8592 +#define LOCAL_GL_OPERAND2_RGB_ARB 0x8592 +#define LOCAL_GL_OPERAND2_RGB_EXT 0x8592 +#define LOCAL_GL_OPERAND3_ALPHA_NV 0x859B +#define LOCAL_GL_OPERAND3_RGB_NV 0x8593 +#define LOCAL_GL_OPTIMAL_TILING_EXT 0x9584 +#define LOCAL_GL_OP_ADD_EXT 0x8787 +#define LOCAL_GL_OP_CLAMP_EXT 0x878E +#define LOCAL_GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define LOCAL_GL_OP_DOT3_EXT 0x8784 +#define LOCAL_GL_OP_DOT4_EXT 0x8785 +#define LOCAL_GL_OP_EXP_BASE_2_EXT 0x8791 +#define LOCAL_GL_OP_FLOOR_EXT 0x878F +#define LOCAL_GL_OP_FRAC_EXT 0x8789 +#define LOCAL_GL_OP_INDEX_EXT 0x8782 +#define LOCAL_GL_OP_LOG_BASE_2_EXT 0x8792 +#define LOCAL_GL_OP_MADD_EXT 0x8788 +#define LOCAL_GL_OP_MAX_EXT 0x878A +#define LOCAL_GL_OP_MIN_EXT 0x878B +#define LOCAL_GL_OP_MOV_EXT 0x8799 +#define LOCAL_GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define LOCAL_GL_OP_MUL_EXT 0x8786 +#define LOCAL_GL_OP_NEGATE_EXT 0x8783 +#define LOCAL_GL_OP_POWER_EXT 0x8793 +#define LOCAL_GL_OP_RECIP_EXT 0x8794 +#define LOCAL_GL_OP_RECIP_SQRT_EXT 0x8795 +#define LOCAL_GL_OP_ROUND_EXT 0x8790 +#define LOCAL_GL_OP_SET_GE_EXT 0x878C +#define LOCAL_GL_OP_SET_LT_EXT 0x878D +#define LOCAL_GL_OP_SUB_EXT 0x8796 +#define LOCAL_GL_OR 0x1507 +#define LOCAL_GL_ORDER 0x0A01 +#define LOCAL_GL_OR_INVERTED 0x150D +#define LOCAL_GL_OR_REVERSE 0x150B +#define LOCAL_GL_OUTPUT_COLOR0_EXT 0x879B +#define LOCAL_GL_OUTPUT_COLOR1_EXT 0x879C +#define LOCAL_GL_OUTPUT_FOG_EXT 0x87BD +#define LOCAL_GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define LOCAL_GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define LOCAL_GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define LOCAL_GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define LOCAL_GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define LOCAL_GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define LOCAL_GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define LOCAL_GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define LOCAL_GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define LOCAL_GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define LOCAL_GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define LOCAL_GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define LOCAL_GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define LOCAL_GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define LOCAL_GL_OUTPUT_VERTEX_EXT 0x879A +#define LOCAL_GL_OUT_OF_MEMORY 0x0505 +#define LOCAL_GL_OVERLAY 0x9296 +#define LOCAL_GL_OVERLAY_KHR 0x9296 +#define LOCAL_GL_OVERLAY_NV 0x9296 +#define LOCAL_GL_PACK_ALIGNMENT 0x0D05 +#define LOCAL_GL_PACK_CMYK_HINT_EXT 0x800E +#define LOCAL_GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define LOCAL_GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define LOCAL_GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define LOCAL_GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define LOCAL_GL_PACK_COMPRESSED_SIZE_SGIX 0x831C +#define LOCAL_GL_PACK_IMAGE_DEPTH_SGIS 0x8131 +#define LOCAL_GL_PACK_IMAGE_HEIGHT 0x806C +#define LOCAL_GL_PACK_IMAGE_HEIGHT_EXT 0x806C +#define LOCAL_GL_PACK_INVERT_MESA 0x8758 +#define LOCAL_GL_PACK_LSB_FIRST 0x0D01 +#define LOCAL_GL_PACK_MAX_COMPRESSED_SIZE_SGIX 0x831B +#define LOCAL_GL_PACK_RESAMPLE_OML 0x8984 +#define LOCAL_GL_PACK_RESAMPLE_SGIX 0x842E +#define LOCAL_GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 +#define LOCAL_GL_PACK_ROW_BYTES_APPLE 0x8A15 +#define LOCAL_GL_PACK_ROW_LENGTH 0x0D02 +#define LOCAL_GL_PACK_SKIP_IMAGES 0x806B +#define LOCAL_GL_PACK_SKIP_IMAGES_EXT 0x806B +#define LOCAL_GL_PACK_SKIP_PIXELS 0x0D04 +#define LOCAL_GL_PACK_SKIP_ROWS 0x0D03 +#define LOCAL_GL_PACK_SKIP_VOLUMES_SGIS 0x8130 +#define LOCAL_GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 +#define LOCAL_GL_PACK_SWAP_BYTES 0x0D00 +#define LOCAL_GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define LOCAL_GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define LOCAL_GL_PALETTE4_RGB8_OES 0x8B90 +#define LOCAL_GL_PALETTE4_RGBA4_OES 0x8B93 +#define LOCAL_GL_PALETTE4_RGBA8_OES 0x8B91 +#define LOCAL_GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define LOCAL_GL_PALETTE8_RGB5_A1_OES 0x8B99 +#define LOCAL_GL_PALETTE8_RGB8_OES 0x8B95 +#define LOCAL_GL_PALETTE8_RGBA4_OES 0x8B98 +#define LOCAL_GL_PALETTE8_RGBA8_OES 0x8B96 +#define LOCAL_GL_PARALLEL_ARRAYS_INTEL 0x83F4 +#define LOCAL_GL_PARAMETER_BUFFER 0x80EE +#define LOCAL_GL_PARAMETER_BUFFER_ARB 0x80EE +#define LOCAL_GL_PARAMETER_BUFFER_BINDING 0x80EF +#define LOCAL_GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF +#define LOCAL_GL_PARTIAL_SUCCESS_NV 0x902E +#define LOCAL_GL_PASS_THROUGH_NV 0x86E6 +#define LOCAL_GL_PASS_THROUGH_TOKEN 0x0700 +#define LOCAL_GL_PATCHES 0x000E +#define LOCAL_GL_PATCHES_EXT 0x000E +#define LOCAL_GL_PATCHES_OES 0x000E +#define LOCAL_GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define LOCAL_GL_PATCH_DEFAULT_INNER_LEVEL_EXT 0x8E73 +#define LOCAL_GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define LOCAL_GL_PATCH_DEFAULT_OUTER_LEVEL_EXT 0x8E74 +#define LOCAL_GL_PATCH_VERTICES 0x8E72 +#define LOCAL_GL_PATCH_VERTICES_EXT 0x8E72 +#define LOCAL_GL_PATCH_VERTICES_OES 0x8E72 +#define LOCAL_GL_PATH_CLIENT_LENGTH_NV 0x907F +#define LOCAL_GL_PATH_COMMAND_COUNT_NV 0x909D +#define LOCAL_GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define LOCAL_GL_PATH_COORD_COUNT_NV 0x909E +#define LOCAL_GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define LOCAL_GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define LOCAL_GL_PATH_DASH_CAPS_NV 0x907B +#define LOCAL_GL_PATH_DASH_OFFSET_NV 0x907E +#define LOCAL_GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define LOCAL_GL_PATH_END_CAPS_NV 0x9076 +#define LOCAL_GL_PATH_ERROR_POSITION_NV 0x90AB +#define LOCAL_GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define LOCAL_GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define LOCAL_GL_PATH_FILL_MASK_NV 0x9081 +#define LOCAL_GL_PATH_FILL_MODE_NV 0x9080 +#define LOCAL_GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define LOCAL_GL_PATH_FORMAT_PS_NV 0x9071 +#define LOCAL_GL_PATH_FORMAT_SVG_NV 0x9070 +#define LOCAL_GL_PATH_GEN_COEFF_NV 0x90B1 +#define LOCAL_GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define LOCAL_GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define LOCAL_GL_PATH_GEN_MODE_NV 0x90B0 +#define LOCAL_GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define LOCAL_GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define LOCAL_GL_PATH_JOIN_STYLE_NV 0x9079 +#define LOCAL_GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 +#define LOCAL_GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 +#define LOCAL_GL_PATH_MITER_LIMIT_NV 0x907A +#define LOCAL_GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define LOCAL_GL_PATH_MODELVIEW_NV 0x1700 +#define LOCAL_GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define LOCAL_GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define LOCAL_GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define LOCAL_GL_PATH_PROJECTION_NV 0x1701 +#define LOCAL_GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 +#define LOCAL_GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define LOCAL_GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define LOCAL_GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define LOCAL_GL_PATH_STENCIL_REF_NV 0x90B8 +#define LOCAL_GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define LOCAL_GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define LOCAL_GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define LOCAL_GL_PATH_STROKE_MASK_NV 0x9084 +#define LOCAL_GL_PATH_STROKE_WIDTH_NV 0x9075 +#define LOCAL_GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define LOCAL_GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define LOCAL_GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 +#define LOCAL_GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 +#define LOCAL_GL_PERCENTAGE_AMD 0x8BC3 +#define LOCAL_GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 +#define LOCAL_GL_PERFMON_RESULT_AMD 0x8BC6 +#define LOCAL_GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define LOCAL_GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define LOCAL_GL_PERFORMANCE_MONITOR_AMD 0x9152 +#define LOCAL_GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC +#define LOCAL_GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB +#define LOCAL_GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA +#define LOCAL_GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 +#define LOCAL_GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 +#define LOCAL_GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF +#define LOCAL_GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 +#define LOCAL_GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 +#define LOCAL_GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 +#define LOCAL_GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE +#define LOCAL_GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 +#define LOCAL_GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 +#define LOCAL_GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 +#define LOCAL_GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 +#define LOCAL_GL_PERFQUERY_FLUSH_INTEL 0x83FA +#define LOCAL_GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 +#define LOCAL_GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 +#define LOCAL_GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD +#define LOCAL_GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 +#define LOCAL_GL_PERFQUERY_WAIT_INTEL 0x83FB +#define LOCAL_GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define LOCAL_GL_PERTURB_EXT 0x85AE +#define LOCAL_GL_PER_GPU_STORAGE_BIT_NV 0x0800 +#define LOCAL_GL_PER_GPU_STORAGE_NV 0x9548 +#define LOCAL_GL_PER_STAGE_CONSTANTS_NV 0x8535 +#define LOCAL_GL_PHONG_HINT_WIN 0x80EB +#define LOCAL_GL_PHONG_WIN 0x80EA +#define LOCAL_GL_PINLIGHT_NV 0x92A8 +#define LOCAL_GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE +#define LOCAL_GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF +#define LOCAL_GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define LOCAL_GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 +#define LOCAL_GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define LOCAL_GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +#define LOCAL_GL_PIXEL_COUNT_NV 0x8866 +#define LOCAL_GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 +#define LOCAL_GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 +#define LOCAL_GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 +#define LOCAL_GL_PIXEL_GROUP_COLOR_SGIS 0x8356 +#define LOCAL_GL_PIXEL_MAG_FILTER_EXT 0x8331 +#define LOCAL_GL_PIXEL_MAP_A_TO_A 0x0C79 +#define LOCAL_GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define LOCAL_GL_PIXEL_MAP_B_TO_B 0x0C78 +#define LOCAL_GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define LOCAL_GL_PIXEL_MAP_G_TO_G 0x0C77 +#define LOCAL_GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define LOCAL_GL_PIXEL_MAP_I_TO_A 0x0C75 +#define LOCAL_GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define LOCAL_GL_PIXEL_MAP_I_TO_B 0x0C74 +#define LOCAL_GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define LOCAL_GL_PIXEL_MAP_I_TO_G 0x0C73 +#define LOCAL_GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define LOCAL_GL_PIXEL_MAP_I_TO_I 0x0C70 +#define LOCAL_GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define LOCAL_GL_PIXEL_MAP_I_TO_R 0x0C72 +#define LOCAL_GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define LOCAL_GL_PIXEL_MAP_R_TO_R 0x0C76 +#define LOCAL_GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define LOCAL_GL_PIXEL_MAP_S_TO_S 0x0C71 +#define LOCAL_GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define LOCAL_GL_PIXEL_MIN_FILTER_EXT 0x8332 +#define LOCAL_GL_PIXEL_MODE_BIT 0x00000020 +#define LOCAL_GL_PIXEL_PACK_BUFFER 0x88EB +#define LOCAL_GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED +#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING_NV 0x88ED +#define LOCAL_GL_PIXEL_PACK_BUFFER_EXT 0x88EB +#define LOCAL_GL_PIXEL_PACK_BUFFER_NV 0x88EB +#define LOCAL_GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 +#define LOCAL_GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 +#define LOCAL_GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 +#define LOCAL_GL_PIXEL_TEXTURE_SGIS 0x8353 +#define LOCAL_GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 +#define LOCAL_GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A +#define LOCAL_GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 +#define LOCAL_GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 +#define LOCAL_GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B +#define LOCAL_GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 +#define LOCAL_GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 +#define LOCAL_GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 +#define LOCAL_GL_PIXEL_TEX_GEN_SGIX 0x8139 +#define LOCAL_GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E +#define LOCAL_GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F +#define LOCAL_GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 +#define LOCAL_GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 +#define LOCAL_GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 +#define LOCAL_GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 +#define LOCAL_GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 +#define LOCAL_GL_PIXEL_TILE_WIDTH_SGIX 0x8140 +#define LOCAL_GL_PIXEL_TRANSFORM_2D_EXT 0x8330 +#define LOCAL_GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 +#define LOCAL_GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 +#define LOCAL_GL_PIXEL_UNPACK_BUFFER 0x88EC +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING_NV 0x88EF +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC +#define LOCAL_GL_PIXEL_UNPACK_BUFFER_NV 0x88EC +#define LOCAL_GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define LOCAL_GL_PLUS_CLAMPED_NV 0x92B1 +#define LOCAL_GL_PLUS_DARKER_NV 0x9292 +#define LOCAL_GL_PLUS_NV 0x9291 +#define LOCAL_GL_PN_TRIANGLES_ATI 0x87F0 +#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 +#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 +#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 +#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 +#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 +#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 +#define LOCAL_GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 +#define LOCAL_GL_POINT 0x1B00 +#define LOCAL_GL_POINTS 0x0000 +#define LOCAL_GL_POINT_BIT 0x00000002 +#define LOCAL_GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define LOCAL_GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 +#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 +#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 +#define LOCAL_GL_POINT_NV 0x1B00 +#define LOCAL_GL_POINT_SIZE 0x0B11 +#define LOCAL_GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F +#define LOCAL_GL_POINT_SIZE_ARRAY_OES 0x8B9C +#define LOCAL_GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C +#define LOCAL_GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B +#define LOCAL_GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A +#define LOCAL_GL_POINT_SIZE_GRANULARITY 0x0B13 +#define LOCAL_GL_POINT_SIZE_MAX 0x8127 +#define LOCAL_GL_POINT_SIZE_MAX_ARB 0x8127 +#define LOCAL_GL_POINT_SIZE_MAX_EXT 0x8127 +#define LOCAL_GL_POINT_SIZE_MAX_SGIS 0x8127 +#define LOCAL_GL_POINT_SIZE_MIN 0x8126 +#define LOCAL_GL_POINT_SIZE_MIN_ARB 0x8126 +#define LOCAL_GL_POINT_SIZE_MIN_EXT 0x8126 +#define LOCAL_GL_POINT_SIZE_MIN_SGIS 0x8126 +#define LOCAL_GL_POINT_SIZE_RANGE 0x0B12 +#define LOCAL_GL_POINT_SMOOTH 0x0B10 +#define LOCAL_GL_POINT_SMOOTH_HINT 0x0C51 +#define LOCAL_GL_POINT_SPRITE 0x8861 +#define LOCAL_GL_POINT_SPRITE_ARB 0x8861 +#define LOCAL_GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define LOCAL_GL_POINT_SPRITE_NV 0x8861 +#define LOCAL_GL_POINT_SPRITE_OES 0x8861 +#define LOCAL_GL_POINT_SPRITE_R_MODE_NV 0x8863 +#define LOCAL_GL_POINT_TOKEN 0x0701 +#define LOCAL_GL_POLYGON 0x0009 +#define LOCAL_GL_POLYGON_BIT 0x00000008 +#define LOCAL_GL_POLYGON_MODE 0x0B40 +#define LOCAL_GL_POLYGON_MODE_NV 0x0B40 +#define LOCAL_GL_POLYGON_OFFSET_BIAS_EXT 0x8039 +#define LOCAL_GL_POLYGON_OFFSET_CLAMP 0x8E1B +#define LOCAL_GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +#define LOCAL_GL_POLYGON_OFFSET_COMMAND_NV 0x000E +#define LOCAL_GL_POLYGON_OFFSET_EXT 0x8037 +#define LOCAL_GL_POLYGON_OFFSET_FACTOR 0x8038 +#define LOCAL_GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 +#define LOCAL_GL_POLYGON_OFFSET_FILL 0x8037 +#define LOCAL_GL_POLYGON_OFFSET_LINE 0x2A02 +#define LOCAL_GL_POLYGON_OFFSET_LINE_NV 0x2A02 +#define LOCAL_GL_POLYGON_OFFSET_POINT 0x2A01 +#define LOCAL_GL_POLYGON_OFFSET_POINT_NV 0x2A01 +#define LOCAL_GL_POLYGON_OFFSET_UNITS 0x2A00 +#define LOCAL_GL_POLYGON_SMOOTH 0x0B41 +#define LOCAL_GL_POLYGON_SMOOTH_HINT 0x0C53 +#define LOCAL_GL_POLYGON_STIPPLE 0x0B42 +#define LOCAL_GL_POLYGON_STIPPLE_BIT 0x00000010 +#define LOCAL_GL_POLYGON_TOKEN 0x0703 +#define LOCAL_GL_POSITION 0x1203 +#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB +#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB +#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 +#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 +#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA +#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA +#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 +#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 +#define LOCAL_GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 +#define LOCAL_GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 +#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 +#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 +#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 +#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 +#define LOCAL_GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 +#define LOCAL_GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 +#define LOCAL_GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 +#define LOCAL_GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 +#define LOCAL_GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 +#define LOCAL_GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 +#define LOCAL_GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F +#define LOCAL_GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F +#define LOCAL_GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 +#define LOCAL_GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 +#define LOCAL_GL_POST_CONVOLUTION_BLUE_SCALE 0x801E +#define LOCAL_GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E +#define LOCAL_GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 +#define LOCAL_GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 +#define LOCAL_GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 +#define LOCAL_GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 +#define LOCAL_GL_POST_CONVOLUTION_GREEN_SCALE 0x801D +#define LOCAL_GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D +#define LOCAL_GL_POST_CONVOLUTION_RED_BIAS 0x8020 +#define LOCAL_GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 +#define LOCAL_GL_POST_CONVOLUTION_RED_SCALE 0x801C +#define LOCAL_GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C +#define LOCAL_GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 +#define LOCAL_GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B +#define LOCAL_GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 +#define LOCAL_GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C +#define LOCAL_GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A +#define LOCAL_GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 +#define LOCAL_GL_PRESENT_DURATION_NV 0x8E2B +#define LOCAL_GL_PRESENT_TIME_NV 0x8E2A +#define LOCAL_GL_PRESERVE_ATI 0x8762 +#define LOCAL_GL_PREVIOUS 0x8578 +#define LOCAL_GL_PREVIOUS_ARB 0x8578 +#define LOCAL_GL_PREVIOUS_EXT 0x8578 +#define LOCAL_GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 +#define LOCAL_GL_PRIMARY_COLOR 0x8577 +#define LOCAL_GL_PRIMARY_COLOR_ARB 0x8577 +#define LOCAL_GL_PRIMARY_COLOR_EXT 0x8577 +#define LOCAL_GL_PRIMARY_COLOR_NV 0x852C +#define LOCAL_GL_PRIMITIVES_GENERATED 0x8C87 +#define LOCAL_GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define LOCAL_GL_PRIMITIVES_GENERATED_NV 0x8C87 +#define LOCAL_GL_PRIMITIVES_GENERATED_OES 0x8C87 +#define LOCAL_GL_PRIMITIVES_SUBMITTED 0x82EF +#define LOCAL_GL_PRIMITIVES_SUBMITTED_ARB 0x82EF +#define LOCAL_GL_PRIMITIVE_BOUNDING_BOX 0x92BE +#define LOCAL_GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE +#define LOCAL_GL_PRIMITIVE_BOUNDING_BOX_EXT 0x92BE +#define LOCAL_GL_PRIMITIVE_BOUNDING_BOX_OES 0x92BE +#define LOCAL_GL_PRIMITIVE_ID_NV 0x8C7C +#define LOCAL_GL_PRIMITIVE_RESTART 0x8F9D +#define LOCAL_GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define LOCAL_GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define LOCAL_GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES 0x8221 +#define LOCAL_GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define LOCAL_GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 +#define LOCAL_GL_PRIMITIVE_RESTART_NV 0x8558 +#define LOCAL_GL_PROGRAM 0x82E2 +#define LOCAL_GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 +#define LOCAL_GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 +#define LOCAL_GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 +#define LOCAL_GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340 +#define LOCAL_GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define LOCAL_GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define LOCAL_GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define LOCAL_GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 +#define LOCAL_GL_PROGRAM_BINARY_ANGLE 0x93A6 +#define LOCAL_GL_PROGRAM_BINARY_FORMATS 0x87FF +#define LOCAL_GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#define LOCAL_GL_PROGRAM_BINARY_FORMAT_MESA 0x875F +#define LOCAL_GL_PROGRAM_BINARY_LENGTH 0x8741 +#define LOCAL_GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#define LOCAL_GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define LOCAL_GL_PROGRAM_BINDING_ARB 0x8677 +#define LOCAL_GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define LOCAL_GL_PROGRAM_ERROR_POSITION_NV 0x864B +#define LOCAL_GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define LOCAL_GL_PROGRAM_ERROR_STRING_NV 0x8874 +#define LOCAL_GL_PROGRAM_FORMAT_ARB 0x8876 +#define LOCAL_GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define LOCAL_GL_PROGRAM_INPUT 0x92E3 +#define LOCAL_GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define LOCAL_GL_PROGRAM_KHR 0x82E2 +#define LOCAL_GL_PROGRAM_LENGTH_ARB 0x8627 +#define LOCAL_GL_PROGRAM_LENGTH_NV 0x8627 +#define LOCAL_GL_PROGRAM_MATRIX_EXT 0x8E2D +#define LOCAL_GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F +#define LOCAL_GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define LOCAL_GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define LOCAL_GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define LOCAL_GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define LOCAL_GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define LOCAL_GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define LOCAL_GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define LOCAL_GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define LOCAL_GL_PROGRAM_OBJECT_ARB 0x8B40 +#define LOCAL_GL_PROGRAM_OBJECT_EXT 0x8B40 +#define LOCAL_GL_PROGRAM_OUTPUT 0x92E4 +#define LOCAL_GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define LOCAL_GL_PROGRAM_PARAMETER_NV 0x8644 +#define LOCAL_GL_PROGRAM_PIPELINE 0x82E4 +#define LOCAL_GL_PROGRAM_PIPELINE_BINDING 0x825A +#define LOCAL_GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A +#define LOCAL_GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define LOCAL_GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define LOCAL_GL_PROGRAM_POINT_SIZE 0x8642 +#define LOCAL_GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define LOCAL_GL_PROGRAM_POINT_SIZE_EXT 0x8642 +#define LOCAL_GL_PROGRAM_RESIDENT_NV 0x8647 +#define LOCAL_GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 +#define LOCAL_GL_PROGRAM_SEPARABLE 0x8258 +#define LOCAL_GL_PROGRAM_SEPARABLE_EXT 0x8258 +#define LOCAL_GL_PROGRAM_STRING_ARB 0x8628 +#define LOCAL_GL_PROGRAM_STRING_NV 0x8628 +#define LOCAL_GL_PROGRAM_TARGET_NV 0x8646 +#define LOCAL_GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define LOCAL_GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define LOCAL_GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define LOCAL_GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define LOCAL_GL_PROJECTION 0x1701 +#define LOCAL_GL_PROJECTION_MATRIX 0x0BA7 +#define LOCAL_GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E +#define LOCAL_GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define LOCAL_GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B +#define LOCAL_GL_PROVOKING_VERTEX 0x8E4F +#define LOCAL_GL_PROVOKING_VERTEX_EXT 0x8E4F +#define LOCAL_GL_PROXY_COLOR_TABLE 0x80D3 +#define LOCAL_GL_PROXY_COLOR_TABLE_SGI 0x80D3 +#define LOCAL_GL_PROXY_HISTOGRAM 0x8025 +#define LOCAL_GL_PROXY_HISTOGRAM_EXT 0x8025 +#define LOCAL_GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 +#define LOCAL_GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 +#define LOCAL_GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 +#define LOCAL_GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 +#define LOCAL_GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 +#define LOCAL_GL_PROXY_TEXTURE_1D 0x8063 +#define LOCAL_GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define LOCAL_GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define LOCAL_GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define LOCAL_GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B +#define LOCAL_GL_PROXY_TEXTURE_2D 0x8064 +#define LOCAL_GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define LOCAL_GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define LOCAL_GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define LOCAL_GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define LOCAL_GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define LOCAL_GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C +#define LOCAL_GL_PROXY_TEXTURE_3D 0x8070 +#define LOCAL_GL_PROXY_TEXTURE_3D_EXT 0x8070 +#define LOCAL_GL_PROXY_TEXTURE_4D_SGIS 0x8135 +#define LOCAL_GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD +#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define LOCAL_GL_PURGEABLE_APPLE 0x8A1D +#define LOCAL_GL_PURGED_CONTEXT_RESET_NV 0x92BB +#define LOCAL_GL_Q 0x2003 +#define LOCAL_GL_QUADRATIC_ATTENUATION 0x1209 +#define LOCAL_GL_QUADRATIC_CURVE_TO_NV 0x0A +#define LOCAL_GL_QUADS 0x0007 +#define LOCAL_GL_QUADS_EXT 0x0007 +#define LOCAL_GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define LOCAL_GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C +#define LOCAL_GL_QUADS_OES 0x0007 +#define LOCAL_GL_QUAD_ALPHA4_SGIS 0x811E +#define LOCAL_GL_QUAD_ALPHA8_SGIS 0x811F +#define LOCAL_GL_QUAD_INTENSITY4_SGIS 0x8122 +#define LOCAL_GL_QUAD_INTENSITY8_SGIS 0x8123 +#define LOCAL_GL_QUAD_LUMINANCE4_SGIS 0x8120 +#define LOCAL_GL_QUAD_LUMINANCE8_SGIS 0x8121 +#define LOCAL_GL_QUAD_MESH_SUN 0x8614 +#define LOCAL_GL_QUAD_STRIP 0x0008 +#define LOCAL_GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 +#define LOCAL_GL_QUARTER_BIT_ATI 0x00000010 +#define LOCAL_GL_QUERY 0x82E3 +#define LOCAL_GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF +#define LOCAL_GL_QUERY_BUFFER 0x9192 +#define LOCAL_GL_QUERY_BUFFER_AMD 0x9192 +#define LOCAL_GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define LOCAL_GL_QUERY_BUFFER_BINDING 0x9193 +#define LOCAL_GL_QUERY_BUFFER_BINDING_AMD 0x9193 +#define LOCAL_GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define LOCAL_GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A +#define LOCAL_GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 +#define LOCAL_GL_QUERY_BY_REGION_WAIT 0x8E15 +#define LOCAL_GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 +#define LOCAL_GL_QUERY_BY_REGION_WAIT_NV 0x8E15 +#define LOCAL_GL_QUERY_COUNTER_BITS 0x8864 +#define LOCAL_GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define LOCAL_GL_QUERY_COUNTER_BITS_EXT 0x8864 +#define LOCAL_GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 +#define LOCAL_GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 +#define LOCAL_GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 +#define LOCAL_GL_QUERY_KHR 0x82E3 +#define LOCAL_GL_QUERY_NO_WAIT 0x8E14 +#define LOCAL_GL_QUERY_NO_WAIT_INVERTED 0x8E18 +#define LOCAL_GL_QUERY_NO_WAIT_NV 0x8E14 +#define LOCAL_GL_QUERY_OBJECT_AMD 0x9153 +#define LOCAL_GL_QUERY_OBJECT_EXT 0x9153 +#define LOCAL_GL_QUERY_RESOURCE_BUFFEROBJECT_NV 0x9547 +#define LOCAL_GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV 0x9542 +#define LOCAL_GL_QUERY_RESOURCE_RENDERBUFFER_NV 0x9546 +#define LOCAL_GL_QUERY_RESOURCE_SYS_RESERVED_NV 0x9544 +#define LOCAL_GL_QUERY_RESOURCE_TEXTURE_NV 0x9545 +#define LOCAL_GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV 0x9540 +#define LOCAL_GL_QUERY_RESULT 0x8866 +#define LOCAL_GL_QUERY_RESULT_ARB 0x8866 +#define LOCAL_GL_QUERY_RESULT_AVAILABLE 0x8867 +#define LOCAL_GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +#define LOCAL_GL_QUERY_RESULT_EXT 0x8866 +#define LOCAL_GL_QUERY_RESULT_NO_WAIT 0x9194 +#define LOCAL_GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 +#define LOCAL_GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 +#define LOCAL_GL_QUERY_TARGET 0x82EA +#define LOCAL_GL_QUERY_WAIT 0x8E13 +#define LOCAL_GL_QUERY_WAIT_INVERTED 0x8E17 +#define LOCAL_GL_QUERY_WAIT_NV 0x8E13 +#define LOCAL_GL_R 0x2002 +#define LOCAL_GL_R11F_G11F_B10F 0x8C3A +#define LOCAL_GL_R11F_G11F_B10F_APPLE 0x8C3A +#define LOCAL_GL_R11F_G11F_B10F_EXT 0x8C3A +#define LOCAL_GL_R16 0x822A +#define LOCAL_GL_R16F 0x822D +#define LOCAL_GL_R16F_EXT 0x822D +#define LOCAL_GL_R16I 0x8233 +#define LOCAL_GL_R16UI 0x8234 +#define LOCAL_GL_R16_EXT 0x822A +#define LOCAL_GL_R16_SNORM 0x8F98 +#define LOCAL_GL_R16_SNORM_EXT 0x8F98 +#define LOCAL_GL_R1UI_C3F_V3F_SUN 0x85C6 +#define LOCAL_GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 +#define LOCAL_GL_R1UI_C4UB_V3F_SUN 0x85C5 +#define LOCAL_GL_R1UI_N3F_V3F_SUN 0x85C7 +#define LOCAL_GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB +#define LOCAL_GL_R1UI_T2F_N3F_V3F_SUN 0x85CA +#define LOCAL_GL_R1UI_T2F_V3F_SUN 0x85C9 +#define LOCAL_GL_R1UI_V3F_SUN 0x85C4 +#define LOCAL_GL_R32F 0x822E +#define LOCAL_GL_R32F_EXT 0x822E +#define LOCAL_GL_R32I 0x8235 +#define LOCAL_GL_R32UI 0x8236 +#define LOCAL_GL_R3_G3_B2 0x2A10 +#define LOCAL_GL_R8 0x8229 +#define LOCAL_GL_R8I 0x8231 +#define LOCAL_GL_R8UI 0x8232 +#define LOCAL_GL_R8_EXT 0x8229 +#define LOCAL_GL_R8_SNORM 0x8F94 +#define LOCAL_GL_RASTERIZER_DISCARD 0x8C89 +#define LOCAL_GL_RASTERIZER_DISCARD_EXT 0x8C89 +#define LOCAL_GL_RASTERIZER_DISCARD_NV 0x8C89 +#define LOCAL_GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A +#define LOCAL_GL_RASTER_MULTISAMPLE_EXT 0x9327 +#define LOCAL_GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 +#define LOCAL_GL_RASTER_SAMPLES_EXT 0x9328 +#define LOCAL_GL_READ_BUFFER 0x0C02 +#define LOCAL_GL_READ_BUFFER_EXT 0x0C02 +#define LOCAL_GL_READ_BUFFER_NV 0x0C02 +#define LOCAL_GL_READ_FRAMEBUFFER 0x8CA8 +#define LOCAL_GL_READ_FRAMEBUFFER_ANGLE 0x8CA8 +#define LOCAL_GL_READ_FRAMEBUFFER_APPLE 0x8CA8 +#define LOCAL_GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define LOCAL_GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA +#define LOCAL_GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA +#define LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +#define LOCAL_GL_READ_FRAMEBUFFER_BINDING_NV 0x8CAA +#define LOCAL_GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define LOCAL_GL_READ_FRAMEBUFFER_NV 0x8CA8 +#define LOCAL_GL_READ_ONLY 0x88B8 +#define LOCAL_GL_READ_ONLY_ARB 0x88B8 +#define LOCAL_GL_READ_PIXELS 0x828C +#define LOCAL_GL_READ_PIXELS_FORMAT 0x828D +#define LOCAL_GL_READ_PIXELS_TYPE 0x828E +#define LOCAL_GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B +#define LOCAL_GL_READ_PIXEL_DATA_RANGE_NV 0x8879 +#define LOCAL_GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D +#define LOCAL_GL_READ_WRITE 0x88BA +#define LOCAL_GL_READ_WRITE_ARB 0x88BA +#define LOCAL_GL_RECIP_ADD_SIGNED_ALPHA_IMG 0x8C05 +#define LOCAL_GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE +#define LOCAL_GL_RECT_NV 0xF6 +#define LOCAL_GL_RED 0x1903 +#define LOCAL_GL_REDUCE 0x8016 +#define LOCAL_GL_REDUCE_EXT 0x8016 +#define LOCAL_GL_RED_BIAS 0x0D15 +#define LOCAL_GL_RED_BITS 0x0D52 +#define LOCAL_GL_RED_BIT_ATI 0x00000001 +#define LOCAL_GL_RED_EXT 0x1903 +#define LOCAL_GL_RED_INTEGER 0x8D94 +#define LOCAL_GL_RED_INTEGER_EXT 0x8D94 +#define LOCAL_GL_RED_MAX_CLAMP_INGR 0x8564 +#define LOCAL_GL_RED_MIN_CLAMP_INGR 0x8560 +#define LOCAL_GL_RED_NV 0x1903 +#define LOCAL_GL_RED_SCALE 0x0D14 +#define LOCAL_GL_RED_SNORM 0x8F90 +#define LOCAL_GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define LOCAL_GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define LOCAL_GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define LOCAL_GL_REFERENCED_BY_GEOMETRY_SHADER_EXT 0x9309 +#define LOCAL_GL_REFERENCED_BY_GEOMETRY_SHADER_OES 0x9309 +#define LOCAL_GL_REFERENCED_BY_MESH_SHADER_NV 0x95A0 +#define LOCAL_GL_REFERENCED_BY_TASK_SHADER_NV 0x95A1 +#define LOCAL_GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define LOCAL_GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT 0x9307 +#define LOCAL_GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES 0x9307 +#define LOCAL_GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define LOCAL_GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT 0x9308 +#define LOCAL_GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES 0x9308 +#define LOCAL_GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define LOCAL_GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E +#define LOCAL_GL_REFERENCE_PLANE_SGIX 0x817D +#define LOCAL_GL_REFLECTION_MAP 0x8512 +#define LOCAL_GL_REFLECTION_MAP_ARB 0x8512 +#define LOCAL_GL_REFLECTION_MAP_EXT 0x8512 +#define LOCAL_GL_REFLECTION_MAP_NV 0x8512 +#define LOCAL_GL_REFLECTION_MAP_OES 0x8512 +#define LOCAL_GL_REGISTER_COMBINERS_NV 0x8522 +#define LOCAL_GL_REG_0_ATI 0x8921 +#define LOCAL_GL_REG_10_ATI 0x892B +#define LOCAL_GL_REG_11_ATI 0x892C +#define LOCAL_GL_REG_12_ATI 0x892D +#define LOCAL_GL_REG_13_ATI 0x892E +#define LOCAL_GL_REG_14_ATI 0x892F +#define LOCAL_GL_REG_15_ATI 0x8930 +#define LOCAL_GL_REG_16_ATI 0x8931 +#define LOCAL_GL_REG_17_ATI 0x8932 +#define LOCAL_GL_REG_18_ATI 0x8933 +#define LOCAL_GL_REG_19_ATI 0x8934 +#define LOCAL_GL_REG_1_ATI 0x8922 +#define LOCAL_GL_REG_20_ATI 0x8935 +#define LOCAL_GL_REG_21_ATI 0x8936 +#define LOCAL_GL_REG_22_ATI 0x8937 +#define LOCAL_GL_REG_23_ATI 0x8938 +#define LOCAL_GL_REG_24_ATI 0x8939 +#define LOCAL_GL_REG_25_ATI 0x893A +#define LOCAL_GL_REG_26_ATI 0x893B +#define LOCAL_GL_REG_27_ATI 0x893C +#define LOCAL_GL_REG_28_ATI 0x893D +#define LOCAL_GL_REG_29_ATI 0x893E +#define LOCAL_GL_REG_2_ATI 0x8923 +#define LOCAL_GL_REG_30_ATI 0x893F +#define LOCAL_GL_REG_31_ATI 0x8940 +#define LOCAL_GL_REG_3_ATI 0x8924 +#define LOCAL_GL_REG_4_ATI 0x8925 +#define LOCAL_GL_REG_5_ATI 0x8926 +#define LOCAL_GL_REG_6_ATI 0x8927 +#define LOCAL_GL_REG_7_ATI 0x8928 +#define LOCAL_GL_REG_8_ATI 0x8929 +#define LOCAL_GL_REG_9_ATI 0x892A +#define LOCAL_GL_RELATIVE_ARC_TO_NV 0xFF +#define LOCAL_GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define LOCAL_GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define LOCAL_GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define LOCAL_GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define LOCAL_GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define LOCAL_GL_RELATIVE_LINE_TO_NV 0x05 +#define LOCAL_GL_RELATIVE_MOVE_TO_NV 0x03 +#define LOCAL_GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define LOCAL_GL_RELATIVE_RECT_NV 0xF7 +#define LOCAL_GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define LOCAL_GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define LOCAL_GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define LOCAL_GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define LOCAL_GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define LOCAL_GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define LOCAL_GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define LOCAL_GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define LOCAL_GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define LOCAL_GL_RELEASED_APPLE 0x8A19 +#define LOCAL_GL_RENDER 0x1C00 +#define LOCAL_GL_RENDERBUFFER 0x8D41 +#define LOCAL_GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define LOCAL_GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define LOCAL_GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53 +#define LOCAL_GL_RENDERBUFFER_BINDING 0x8CA7 +#define LOCAL_GL_RENDERBUFFER_BINDING_ANGLE 0x8CA7 +#define LOCAL_GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define LOCAL_GL_RENDERBUFFER_BINDING_OES 0x8CA7 +#define LOCAL_GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define LOCAL_GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define LOCAL_GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52 +#define LOCAL_GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define LOCAL_GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB +#define LOCAL_GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define LOCAL_GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define LOCAL_GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54 +#define LOCAL_GL_RENDERBUFFER_EXT 0x8D41 +#define LOCAL_GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD +#define LOCAL_GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define LOCAL_GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define LOCAL_GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51 +#define LOCAL_GL_RENDERBUFFER_HEIGHT 0x8D43 +#define LOCAL_GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define LOCAL_GL_RENDERBUFFER_HEIGHT_OES 0x8D43 +#define LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44 +#define LOCAL_GL_RENDERBUFFER_OES 0x8D41 +#define LOCAL_GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define LOCAL_GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define LOCAL_GL_RENDERBUFFER_RED_SIZE_OES 0x8D50 +#define LOCAL_GL_RENDERBUFFER_SAMPLES 0x8CAB +#define LOCAL_GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB +#define LOCAL_GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB +#define LOCAL_GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define LOCAL_GL_RENDERBUFFER_SAMPLES_IMG 0x9133 +#define LOCAL_GL_RENDERBUFFER_SAMPLES_NV 0x8CAB +#define LOCAL_GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define LOCAL_GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#define LOCAL_GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55 +#define LOCAL_GL_RENDERBUFFER_STORAGE_SAMPLES_AMD 0x91B2 +#define LOCAL_GL_RENDERBUFFER_WIDTH 0x8D42 +#define LOCAL_GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define LOCAL_GL_RENDERBUFFER_WIDTH_OES 0x8D42 +#define LOCAL_GL_RENDERER 0x1F01 +#define LOCAL_GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM 0x8FB3 +#define LOCAL_GL_RENDER_GPU_MASK_NV 0x9558 +#define LOCAL_GL_RENDER_MODE 0x0C40 +#define LOCAL_GL_REPEAT 0x2901 +#define LOCAL_GL_REPLACE 0x1E01 +#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 +#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 +#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 +#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 +#define LOCAL_GL_REPLACEMENT_CODE_SUN 0x81D8 +#define LOCAL_GL_REPLACE_EXT 0x8062 +#define LOCAL_GL_REPLACE_MIDDLE_SUN 0x0002 +#define LOCAL_GL_REPLACE_OLDEST_SUN 0x0003 +#define LOCAL_GL_REPLACE_VALUE_AMD 0x874B +#define LOCAL_GL_REPLICATE_BORDER 0x8153 +#define LOCAL_GL_REPLICATE_BORDER_HP 0x8153 +#define LOCAL_GL_REPRESENTATIVE_FRAGMENT_TEST_NV 0x937F +#define LOCAL_GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 +#define LOCAL_GL_RESAMPLE_AVERAGE_OML 0x8988 +#define LOCAL_GL_RESAMPLE_DECIMATE_OML 0x8989 +#define LOCAL_GL_RESAMPLE_DECIMATE_SGIX 0x8430 +#define LOCAL_GL_RESAMPLE_REPLICATE_OML 0x8986 +#define LOCAL_GL_RESAMPLE_REPLICATE_SGIX 0x8433 +#define LOCAL_GL_RESAMPLE_ZERO_FILL_OML 0x8987 +#define LOCAL_GL_RESAMPLE_ZERO_FILL_SGIX 0x8434 +#define LOCAL_GL_RESCALE_NORMAL 0x803A +#define LOCAL_GL_RESCALE_NORMAL_EXT 0x803A +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY 0x8256 +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_KHR 0x8256 +#define LOCAL_GL_RESTART_PATH_NV 0xF0 +#define LOCAL_GL_RESTART_SUN 0x0001 +#define LOCAL_GL_RETAINED_APPLE 0x8A1B +#define LOCAL_GL_RETURN 0x0102 +#define LOCAL_GL_RG 0x8227 +#define LOCAL_GL_RG16 0x822C +#define LOCAL_GL_RG16F 0x822F +#define LOCAL_GL_RG16F_EXT 0x822F +#define LOCAL_GL_RG16I 0x8239 +#define LOCAL_GL_RG16UI 0x823A +#define LOCAL_GL_RG16_EXT 0x822C +#define LOCAL_GL_RG16_SNORM 0x8F99 +#define LOCAL_GL_RG16_SNORM_EXT 0x8F99 +#define LOCAL_GL_RG32F 0x8230 +#define LOCAL_GL_RG32F_EXT 0x8230 +#define LOCAL_GL_RG32I 0x823B +#define LOCAL_GL_RG32UI 0x823C +#define LOCAL_GL_RG8 0x822B +#define LOCAL_GL_RG8I 0x8237 +#define LOCAL_GL_RG8UI 0x8238 +#define LOCAL_GL_RG8_EXT 0x822B +#define LOCAL_GL_RG8_SNORM 0x8F95 +#define LOCAL_GL_RGB 0x1907 +#define LOCAL_GL_RGB10 0x8052 +#define LOCAL_GL_RGB10_A2 0x8059 +#define LOCAL_GL_RGB10_A2UI 0x906F +#define LOCAL_GL_RGB10_A2_EXT 0x8059 +#define LOCAL_GL_RGB10_EXT 0x8052 +#define LOCAL_GL_RGB12 0x8053 +#define LOCAL_GL_RGB12_EXT 0x8053 +#define LOCAL_GL_RGB16 0x8054 +#define LOCAL_GL_RGB16F 0x881B +#define LOCAL_GL_RGB16F_ARB 0x881B +#define LOCAL_GL_RGB16F_EXT 0x881B +#define LOCAL_GL_RGB16I 0x8D89 +#define LOCAL_GL_RGB16I_EXT 0x8D89 +#define LOCAL_GL_RGB16UI 0x8D77 +#define LOCAL_GL_RGB16UI_EXT 0x8D77 +#define LOCAL_GL_RGB16_EXT 0x8054 +#define LOCAL_GL_RGB16_SNORM 0x8F9A +#define LOCAL_GL_RGB16_SNORM_EXT 0x8F9A +#define LOCAL_GL_RGB2_EXT 0x804E +#define LOCAL_GL_RGB32F 0x8815 +#define LOCAL_GL_RGB32F_ARB 0x8815 +#define LOCAL_GL_RGB32F_EXT 0x8815 +#define LOCAL_GL_RGB32I 0x8D83 +#define LOCAL_GL_RGB32I_EXT 0x8D83 +#define LOCAL_GL_RGB32UI 0x8D71 +#define LOCAL_GL_RGB32UI_EXT 0x8D71 +#define LOCAL_GL_RGB4 0x804F +#define LOCAL_GL_RGB4_EXT 0x804F +#define LOCAL_GL_RGB4_S3TC 0x83A1 +#define LOCAL_GL_RGB5 0x8050 +#define LOCAL_GL_RGB565 0x8D62 +#define LOCAL_GL_RGB565_OES 0x8D62 +#define LOCAL_GL_RGB5_A1 0x8057 +#define LOCAL_GL_RGB5_A1_EXT 0x8057 +#define LOCAL_GL_RGB5_A1_OES 0x8057 +#define LOCAL_GL_RGB5_EXT 0x8050 +#define LOCAL_GL_RGB8 0x8051 +#define LOCAL_GL_RGB8I 0x8D8F +#define LOCAL_GL_RGB8I_EXT 0x8D8F +#define LOCAL_GL_RGB8UI 0x8D7D +#define LOCAL_GL_RGB8UI_EXT 0x8D7D +#define LOCAL_GL_RGB8_EXT 0x8051 +#define LOCAL_GL_RGB8_OES 0x8051 +#define LOCAL_GL_RGB8_SNORM 0x8F96 +#define LOCAL_GL_RGB9_E5 0x8C3D +#define LOCAL_GL_RGB9_E5_APPLE 0x8C3D +#define LOCAL_GL_RGB9_E5_EXT 0x8C3D +#define LOCAL_GL_RGBA 0x1908 +#define LOCAL_GL_RGBA12 0x805A +#define LOCAL_GL_RGBA12_EXT 0x805A +#define LOCAL_GL_RGBA16 0x805B +#define LOCAL_GL_RGBA16F 0x881A +#define LOCAL_GL_RGBA16F_ARB 0x881A +#define LOCAL_GL_RGBA16F_EXT 0x881A +#define LOCAL_GL_RGBA16I 0x8D88 +#define LOCAL_GL_RGBA16I_EXT 0x8D88 +#define LOCAL_GL_RGBA16UI 0x8D76 +#define LOCAL_GL_RGBA16UI_EXT 0x8D76 +#define LOCAL_GL_RGBA16_EXT 0x805B +#define LOCAL_GL_RGBA16_SNORM 0x8F9B +#define LOCAL_GL_RGBA16_SNORM_EXT 0x8F9B +#define LOCAL_GL_RGBA2 0x8055 +#define LOCAL_GL_RGBA2_EXT 0x8055 +#define LOCAL_GL_RGBA32F 0x8814 +#define LOCAL_GL_RGBA32F_ARB 0x8814 +#define LOCAL_GL_RGBA32F_EXT 0x8814 +#define LOCAL_GL_RGBA32I 0x8D82 +#define LOCAL_GL_RGBA32I_EXT 0x8D82 +#define LOCAL_GL_RGBA32UI 0x8D70 +#define LOCAL_GL_RGBA32UI_EXT 0x8D70 +#define LOCAL_GL_RGBA4 0x8056 +#define LOCAL_GL_RGBA4_DXT5_S3TC 0x83A5 +#define LOCAL_GL_RGBA4_EXT 0x8056 +#define LOCAL_GL_RGBA4_OES 0x8056 +#define LOCAL_GL_RGBA4_S3TC 0x83A3 +#define LOCAL_GL_RGBA8 0x8058 +#define LOCAL_GL_RGBA8I 0x8D8E +#define LOCAL_GL_RGBA8I_EXT 0x8D8E +#define LOCAL_GL_RGBA8UI 0x8D7C +#define LOCAL_GL_RGBA8UI_EXT 0x8D7C +#define LOCAL_GL_RGBA8_EXT 0x8058 +#define LOCAL_GL_RGBA8_OES 0x8058 +#define LOCAL_GL_RGBA8_SNORM 0x8F97 +#define LOCAL_GL_RGBA_DXT5_S3TC 0x83A4 +#define LOCAL_GL_RGBA_FLOAT16_APPLE 0x881A +#define LOCAL_GL_RGBA_FLOAT16_ATI 0x881A +#define LOCAL_GL_RGBA_FLOAT32_APPLE 0x8814 +#define LOCAL_GL_RGBA_FLOAT32_ATI 0x8814 +#define LOCAL_GL_RGBA_FLOAT_MODE_ARB 0x8820 +#define LOCAL_GL_RGBA_FLOAT_MODE_ATI 0x8820 +#define LOCAL_GL_RGBA_INTEGER 0x8D99 +#define LOCAL_GL_RGBA_INTEGER_EXT 0x8D99 +#define LOCAL_GL_RGBA_INTEGER_MODE_EXT 0x8D9E +#define LOCAL_GL_RGBA_MODE 0x0C31 +#define LOCAL_GL_RGBA_S3TC 0x83A2 +#define LOCAL_GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C +#define LOCAL_GL_RGBA_SNORM 0x8F93 +#define LOCAL_GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 +#define LOCAL_GL_RGB_422_APPLE 0x8A1F +#define LOCAL_GL_RGB_FLOAT16_APPLE 0x881B +#define LOCAL_GL_RGB_FLOAT16_ATI 0x881B +#define LOCAL_GL_RGB_FLOAT32_APPLE 0x8815 +#define LOCAL_GL_RGB_FLOAT32_ATI 0x8815 +#define LOCAL_GL_RGB_INTEGER 0x8D98 +#define LOCAL_GL_RGB_INTEGER_EXT 0x8D98 +#define LOCAL_GL_RGB_RAW_422_APPLE 0x8A51 +#define LOCAL_GL_RGB_S3TC 0x83A0 +#define LOCAL_GL_RGB_SCALE 0x8573 +#define LOCAL_GL_RGB_SCALE_ARB 0x8573 +#define LOCAL_GL_RGB_SCALE_EXT 0x8573 +#define LOCAL_GL_RGB_SNORM 0x8F92 +#define LOCAL_GL_RG_EXT 0x8227 +#define LOCAL_GL_RG_INTEGER 0x8228 +#define LOCAL_GL_RG_SNORM 0x8F91 +#define LOCAL_GL_RIGHT 0x0407 +#define LOCAL_GL_ROBUST_GPU_TIMEOUT_MS_KHR 0x82FD +#define LOCAL_GL_ROUNDED_RECT2_NV 0xEA +#define LOCAL_GL_ROUNDED_RECT4_NV 0xEC +#define LOCAL_GL_ROUNDED_RECT8_NV 0xEE +#define LOCAL_GL_ROUNDED_RECT_NV 0xE8 +#define LOCAL_GL_ROUND_NV 0x90A4 +#define LOCAL_GL_S 0x2000 +#define LOCAL_GL_SAMPLER 0x82E6 +#define LOCAL_GL_SAMPLER_1D 0x8B5D +#define LOCAL_GL_SAMPLER_1D_ARB 0x8B5D +#define LOCAL_GL_SAMPLER_1D_ARRAY 0x8DC0 +#define LOCAL_GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define LOCAL_GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define LOCAL_GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define LOCAL_GL_SAMPLER_1D_SHADOW 0x8B61 +#define LOCAL_GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define LOCAL_GL_SAMPLER_2D 0x8B5E +#define LOCAL_GL_SAMPLER_2D_ARB 0x8B5E +#define LOCAL_GL_SAMPLER_2D_ARRAY 0x8DC1 +#define LOCAL_GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW_NV 0x8DC4 +#define LOCAL_GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define LOCAL_GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define LOCAL_GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910B +#define LOCAL_GL_SAMPLER_2D_RECT 0x8B63 +#define LOCAL_GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define LOCAL_GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define LOCAL_GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define LOCAL_GL_SAMPLER_2D_SHADOW 0x8B62 +#define LOCAL_GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define LOCAL_GL_SAMPLER_2D_SHADOW_EXT 0x8B62 +#define LOCAL_GL_SAMPLER_3D 0x8B5F +#define LOCAL_GL_SAMPLER_3D_ARB 0x8B5F +#define LOCAL_GL_SAMPLER_3D_OES 0x8B5F +#define LOCAL_GL_SAMPLER_BINDING 0x8919 +#define LOCAL_GL_SAMPLER_BUFFER 0x8DC2 +#define LOCAL_GL_SAMPLER_BUFFER_AMD 0x9001 +#define LOCAL_GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define LOCAL_GL_SAMPLER_BUFFER_OES 0x8DC2 +#define LOCAL_GL_SAMPLER_CUBE 0x8B60 +#define LOCAL_GL_SAMPLER_CUBE_ARB 0x8B60 +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900C +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_OES 0x900C +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT 0x900D +#define LOCAL_GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES 0x900D +#define LOCAL_GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define LOCAL_GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define LOCAL_GL_SAMPLER_CUBE_SHADOW_NV 0x8DC5 +#define LOCAL_GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 +#define LOCAL_GL_SAMPLER_EXTERNAL_OES 0x8D66 +#define LOCAL_GL_SAMPLER_KHR 0x82E6 +#define LOCAL_GL_SAMPLER_OBJECT_AMD 0x9155 +#define LOCAL_GL_SAMPLER_RENDERBUFFER_NV 0x8E56 +#define LOCAL_GL_SAMPLES 0x80A9 +#define LOCAL_GL_SAMPLES_3DFX 0x86B4 +#define LOCAL_GL_SAMPLES_ARB 0x80A9 +#define LOCAL_GL_SAMPLES_EXT 0x80A9 +#define LOCAL_GL_SAMPLES_PASSED 0x8914 +#define LOCAL_GL_SAMPLES_PASSED_ARB 0x8914 +#define LOCAL_GL_SAMPLES_SGIS 0x80A9 +#define LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define LOCAL_GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E +#define LOCAL_GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E +#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F +#define LOCAL_GL_SAMPLE_BUFFERS 0x80A8 +#define LOCAL_GL_SAMPLE_BUFFERS_3DFX 0x86B3 +#define LOCAL_GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define LOCAL_GL_SAMPLE_BUFFERS_EXT 0x80A8 +#define LOCAL_GL_SAMPLE_BUFFERS_SGIS 0x80A8 +#define LOCAL_GL_SAMPLE_COVERAGE 0x80A0 +#define LOCAL_GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define LOCAL_GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define LOCAL_GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define LOCAL_GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define LOCAL_GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define LOCAL_GL_SAMPLE_LOCATION_ARB 0x8E50 +#define LOCAL_GL_SAMPLE_LOCATION_NV 0x8E50 +#define LOCAL_GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F +#define LOCAL_GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F +#define LOCAL_GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E +#define LOCAL_GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E +#define LOCAL_GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D +#define LOCAL_GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D +#define LOCAL_GL_SAMPLE_MASK 0x8E51 +#define LOCAL_GL_SAMPLE_MASK_EXT 0x80A0 +#define LOCAL_GL_SAMPLE_MASK_INVERT_EXT 0x80AB +#define LOCAL_GL_SAMPLE_MASK_INVERT_SGIS 0x80AB +#define LOCAL_GL_SAMPLE_MASK_NV 0x8E51 +#define LOCAL_GL_SAMPLE_MASK_SGIS 0x80A0 +#define LOCAL_GL_SAMPLE_MASK_VALUE 0x8E52 +#define LOCAL_GL_SAMPLE_MASK_VALUE_EXT 0x80AA +#define LOCAL_GL_SAMPLE_MASK_VALUE_NV 0x8E52 +#define LOCAL_GL_SAMPLE_MASK_VALUE_SGIS 0x80AA +#define LOCAL_GL_SAMPLE_PATTERN_EXT 0x80AC +#define LOCAL_GL_SAMPLE_PATTERN_SGIS 0x80AC +#define LOCAL_GL_SAMPLE_POSITION 0x8E50 +#define LOCAL_GL_SAMPLE_POSITION_NV 0x8E50 +#define LOCAL_GL_SAMPLE_SHADING 0x8C36 +#define LOCAL_GL_SAMPLE_SHADING_ARB 0x8C36 +#define LOCAL_GL_SAMPLE_SHADING_OES 0x8C36 +#define LOCAL_GL_SATURATE_BIT_ATI 0x00000040 +#define LOCAL_GL_SCALAR_EXT 0x87BE +#define LOCAL_GL_SCALEBIAS_HINT_SGIX 0x8322 +#define LOCAL_GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define LOCAL_GL_SCALED_RESOLVE_NICEST_EXT 0x90BB +#define LOCAL_GL_SCALE_BY_FOUR_NV 0x853F +#define LOCAL_GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define LOCAL_GL_SCALE_BY_TWO_NV 0x853E +#define LOCAL_GL_SCISSOR_BIT 0x00080000 +#define LOCAL_GL_SCISSOR_BOX 0x0C10 +#define LOCAL_GL_SCISSOR_BOX_EXCLUSIVE_NV 0x9556 +#define LOCAL_GL_SCISSOR_COMMAND_NV 0x0011 +#define LOCAL_GL_SCISSOR_TEST 0x0C11 +#define LOCAL_GL_SCISSOR_TEST_EXCLUSIVE_NV 0x9555 +#define LOCAL_GL_SCREEN 0x9295 +#define LOCAL_GL_SCREEN_COORDINATES_REND 0x8490 +#define LOCAL_GL_SCREEN_KHR 0x9295 +#define LOCAL_GL_SCREEN_NV 0x9295 +#define LOCAL_GL_SECONDARY_COLOR_ARRAY 0x845E +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_EXT 0x845E +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define LOCAL_GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B +#define LOCAL_GL_SECONDARY_COLOR_NV 0x852D +#define LOCAL_GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define LOCAL_GL_SELECT 0x1C02 +#define LOCAL_GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define LOCAL_GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define LOCAL_GL_SEMAPHORE_TYPE_BINARY_NV 0x95B4 +#define LOCAL_GL_SEMAPHORE_TYPE_NV 0x95B3 +#define LOCAL_GL_SEMAPHORE_TYPE_TIMELINE_NV 0x95B5 +#define LOCAL_GL_SEPARABLE_2D 0x8012 +#define LOCAL_GL_SEPARABLE_2D_EXT 0x8012 +#define LOCAL_GL_SEPARATE_ATTRIBS 0x8C8D +#define LOCAL_GL_SEPARATE_ATTRIBS_EXT 0x8C8D +#define LOCAL_GL_SEPARATE_ATTRIBS_NV 0x8C8D +#define LOCAL_GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define LOCAL_GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#define LOCAL_GL_SET 0x150F +#define LOCAL_GL_SET_AMD 0x874A +#define LOCAL_GL_SGX_BINARY_IMG 0x8C0A +#define LOCAL_GL_SGX_PROGRAM_BINARY_IMG 0x9130 +#define LOCAL_GL_SHADER 0x82E1 +#define LOCAL_GL_SHADER_BINARY_DMP 0x9250 +#define LOCAL_GL_SHADER_BINARY_FORMATS 0x8DF8 +#define LOCAL_GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 +#define LOCAL_GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 +#define LOCAL_GL_SHADER_BINARY_VIV 0x8FC4 +#define LOCAL_GL_SHADER_COMPILER 0x8DFA +#define LOCAL_GL_SHADER_CONSISTENT_NV 0x86DD +#define LOCAL_GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 +#define LOCAL_GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define LOCAL_GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 +#define LOCAL_GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define LOCAL_GL_SHADER_IMAGE_LOAD 0x82A4 +#define LOCAL_GL_SHADER_IMAGE_STORE 0x82A5 +#define LOCAL_GL_SHADER_INCLUDE_ARB 0x8DAE +#define LOCAL_GL_SHADER_KHR 0x82E1 +#define LOCAL_GL_SHADER_OBJECT_ARB 0x8B48 +#define LOCAL_GL_SHADER_OBJECT_EXT 0x8B48 +#define LOCAL_GL_SHADER_OPERATION_NV 0x86DF +#define LOCAL_GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 +#define LOCAL_GL_SHADER_SOURCE_LENGTH 0x8B88 +#define LOCAL_GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define LOCAL_GL_SHADER_STORAGE_BLOCK 0x92E6 +#define LOCAL_GL_SHADER_STORAGE_BUFFER 0x90D2 +#define LOCAL_GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define LOCAL_GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define LOCAL_GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define LOCAL_GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define LOCAL_GL_SHADER_TYPE 0x8B4F +#define LOCAL_GL_SHADE_MODEL 0x0B54 +#define LOCAL_GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define LOCAL_GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#define LOCAL_GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F +#define LOCAL_GL_SHADING_RATE_1X1_PIXELS_QCOM 0x96A6 +#define LOCAL_GL_SHADING_RATE_1X2_PIXELS_QCOM 0x96A7 +#define LOCAL_GL_SHADING_RATE_1X4_PIXELS_QCOM 0x96AA +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566 +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV 0x9567 +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV 0x9568 +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV 0x9569 +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV 0x956A +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV 0x956B +#define LOCAL_GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565 +#define LOCAL_GL_SHADING_RATE_2X1_PIXELS_QCOM 0x96A8 +#define LOCAL_GL_SHADING_RATE_2X2_PIXELS_QCOM 0x96A9 +#define LOCAL_GL_SHADING_RATE_2X4_PIXELS_QCOM 0x96AD +#define LOCAL_GL_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV 0x956C +#define LOCAL_GL_SHADING_RATE_4X1_PIXELS_QCOM 0x96AB +#define LOCAL_GL_SHADING_RATE_4X2_PIXELS_QCOM 0x96AC +#define LOCAL_GL_SHADING_RATE_4X4_PIXELS_QCOM 0x96AE +#define LOCAL_GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D +#define LOCAL_GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E +#define LOCAL_GL_SHADING_RATE_IMAGE_BINDING_NV 0x955B +#define LOCAL_GL_SHADING_RATE_IMAGE_NV 0x9563 +#define LOCAL_GL_SHADING_RATE_IMAGE_PALETTE_COUNT_NV 0x95B2 +#define LOCAL_GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E +#define LOCAL_GL_SHADING_RATE_IMAGE_PER_PRIMITIVE_NV 0x95B1 +#define LOCAL_GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D +#define LOCAL_GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C +#define LOCAL_GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564 +#define LOCAL_GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM 0x96A5 +#define LOCAL_GL_SHADING_RATE_QCOM 0x96A4 +#define LOCAL_GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE +#define LOCAL_GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF +#define LOCAL_GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0 +#define LOCAL_GL_SHADOW_AMBIENT_SGIX 0x80BF +#define LOCAL_GL_SHADOW_ATTENUATION_EXT 0x834E +#define LOCAL_GL_SHARED_EDGE_NV 0xC0 +#define LOCAL_GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#define LOCAL_GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 +#define LOCAL_GL_SHININESS 0x1601 +#define LOCAL_GL_SHORT 0x1402 +#define LOCAL_GL_SIGNALED 0x9119 +#define LOCAL_GL_SIGNALED_APPLE 0x9119 +#define LOCAL_GL_SIGNED_ALPHA8_NV 0x8706 +#define LOCAL_GL_SIGNED_ALPHA_NV 0x8705 +#define LOCAL_GL_SIGNED_HILO16_NV 0x86FA +#define LOCAL_GL_SIGNED_HILO8_NV 0x885F +#define LOCAL_GL_SIGNED_HILO_NV 0x86F9 +#define LOCAL_GL_SIGNED_IDENTITY_NV 0x853C +#define LOCAL_GL_SIGNED_INTENSITY8_NV 0x8708 +#define LOCAL_GL_SIGNED_INTENSITY_NV 0x8707 +#define LOCAL_GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 +#define LOCAL_GL_SIGNED_LUMINANCE8_NV 0x8702 +#define LOCAL_GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 +#define LOCAL_GL_SIGNED_LUMINANCE_NV 0x8701 +#define LOCAL_GL_SIGNED_NEGATE_NV 0x853D +#define LOCAL_GL_SIGNED_NORMALIZED 0x8F9C +#define LOCAL_GL_SIGNED_RGB8_NV 0x86FF +#define LOCAL_GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D +#define LOCAL_GL_SIGNED_RGBA8_NV 0x86FC +#define LOCAL_GL_SIGNED_RGBA_NV 0x86FB +#define LOCAL_GL_SIGNED_RGB_NV 0x86FE +#define LOCAL_GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C +#define LOCAL_GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define LOCAL_GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define LOCAL_GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define LOCAL_GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define LOCAL_GL_SINGLE_COLOR 0x81F9 +#define LOCAL_GL_SINGLE_COLOR_EXT 0x81F9 +#define LOCAL_GL_SKIP_COMPONENTS1_NV -6 +#define LOCAL_GL_SKIP_COMPONENTS2_NV -5 +#define LOCAL_GL_SKIP_COMPONENTS3_NV -4 +#define LOCAL_GL_SKIP_COMPONENTS4_NV -3 +#define LOCAL_GL_SKIP_DECODE_EXT 0x8A4A +#define LOCAL_GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define LOCAL_GL_SLICE_ACCUM_SUN 0x85CC +#define LOCAL_GL_SLIM10U_SGIX 0x831E +#define LOCAL_GL_SLIM12S_SGIX 0x831F +#define LOCAL_GL_SLIM8U_SGIX 0x831D +#define LOCAL_GL_SLUMINANCE 0x8C46 +#define LOCAL_GL_SLUMINANCE8 0x8C47 +#define LOCAL_GL_SLUMINANCE8_ALPHA8 0x8C45 +#define LOCAL_GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define LOCAL_GL_SLUMINANCE8_ALPHA8_NV 0x8C45 +#define LOCAL_GL_SLUMINANCE8_EXT 0x8C47 +#define LOCAL_GL_SLUMINANCE8_NV 0x8C47 +#define LOCAL_GL_SLUMINANCE_ALPHA 0x8C44 +#define LOCAL_GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define LOCAL_GL_SLUMINANCE_ALPHA_NV 0x8C44 +#define LOCAL_GL_SLUMINANCE_EXT 0x8C46 +#define LOCAL_GL_SLUMINANCE_NV 0x8C46 +#define LOCAL_GL_SMALL_CCW_ARC_TO_NV 0x12 +#define LOCAL_GL_SMALL_CW_ARC_TO_NV 0x14 +#define LOCAL_GL_SMAPHS30_PROGRAM_BINARY_DMP 0x9251 +#define LOCAL_GL_SMAPHS_PROGRAM_BINARY_DMP 0x9252 +#define LOCAL_GL_SMOOTH 0x1D01 +#define LOCAL_GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define LOCAL_GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define LOCAL_GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define LOCAL_GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define LOCAL_GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define LOCAL_GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define LOCAL_GL_SM_COUNT_NV 0x933B +#define LOCAL_GL_SOFTLIGHT 0x929C +#define LOCAL_GL_SOFTLIGHT_KHR 0x929C +#define LOCAL_GL_SOFTLIGHT_NV 0x929C +#define LOCAL_GL_SOURCE0_ALPHA 0x8588 +#define LOCAL_GL_SOURCE0_ALPHA_ARB 0x8588 +#define LOCAL_GL_SOURCE0_ALPHA_EXT 0x8588 +#define LOCAL_GL_SOURCE0_RGB 0x8580 +#define LOCAL_GL_SOURCE0_RGB_ARB 0x8580 +#define LOCAL_GL_SOURCE0_RGB_EXT 0x8580 +#define LOCAL_GL_SOURCE1_ALPHA 0x8589 +#define LOCAL_GL_SOURCE1_ALPHA_ARB 0x8589 +#define LOCAL_GL_SOURCE1_ALPHA_EXT 0x8589 +#define LOCAL_GL_SOURCE1_RGB 0x8581 +#define LOCAL_GL_SOURCE1_RGB_ARB 0x8581 +#define LOCAL_GL_SOURCE1_RGB_EXT 0x8581 +#define LOCAL_GL_SOURCE2_ALPHA 0x858A +#define LOCAL_GL_SOURCE2_ALPHA_ARB 0x858A +#define LOCAL_GL_SOURCE2_ALPHA_EXT 0x858A +#define LOCAL_GL_SOURCE2_RGB 0x8582 +#define LOCAL_GL_SOURCE2_RGB_ARB 0x8582 +#define LOCAL_GL_SOURCE2_RGB_EXT 0x8582 +#define LOCAL_GL_SOURCE3_ALPHA_NV 0x858B +#define LOCAL_GL_SOURCE3_RGB_NV 0x8583 +#define LOCAL_GL_SPARE0_NV 0x852E +#define LOCAL_GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +#define LOCAL_GL_SPARE1_NV 0x852F +#define LOCAL_GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 +#define LOCAL_GL_SPARSE_STORAGE_BIT_ARB 0x0400 +#define LOCAL_GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +#define LOCAL_GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT 0x91A9 +#define LOCAL_GL_SPECULAR 0x1202 +#define LOCAL_GL_SPHERE_MAP 0x2402 +#define LOCAL_GL_SPIR_V_BINARY 0x9552 +#define LOCAL_GL_SPIR_V_BINARY_ARB 0x9552 +#define LOCAL_GL_SPIR_V_EXTENSIONS 0x9553 +#define LOCAL_GL_SPOT_CUTOFF 0x1206 +#define LOCAL_GL_SPOT_DIRECTION 0x1204 +#define LOCAL_GL_SPOT_EXPONENT 0x1205 +#define LOCAL_GL_SPRITE_AXIAL_SGIX 0x814C +#define LOCAL_GL_SPRITE_AXIS_SGIX 0x814A +#define LOCAL_GL_SPRITE_EYE_ALIGNED_SGIX 0x814E +#define LOCAL_GL_SPRITE_MODE_SGIX 0x8149 +#define LOCAL_GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D +#define LOCAL_GL_SPRITE_SGIX 0x8148 +#define LOCAL_GL_SPRITE_TRANSLATION_SGIX 0x814B +#define LOCAL_GL_SQUARE_NV 0x90A3 +#define LOCAL_GL_SR8_EXT 0x8FBD +#define LOCAL_GL_SRC0_ALPHA 0x8588 +#define LOCAL_GL_SRC0_RGB 0x8580 +#define LOCAL_GL_SRC1_ALPHA 0x8589 +#define LOCAL_GL_SRC1_ALPHA_EXT 0x8589 +#define LOCAL_GL_SRC1_COLOR 0x88F9 +#define LOCAL_GL_SRC1_COLOR_EXT 0x88F9 +#define LOCAL_GL_SRC1_RGB 0x8581 +#define LOCAL_GL_SRC2_ALPHA 0x858A +#define LOCAL_GL_SRC2_RGB 0x8582 +#define LOCAL_GL_SRC_ALPHA 0x0302 +#define LOCAL_GL_SRC_ALPHA_SATURATE 0x0308 +#define LOCAL_GL_SRC_ALPHA_SATURATE_EXT 0x0308 +#define LOCAL_GL_SRC_ATOP_NV 0x928E +#define LOCAL_GL_SRC_COLOR 0x0300 +#define LOCAL_GL_SRC_IN_NV 0x928A +#define LOCAL_GL_SRC_NV 0x9286 +#define LOCAL_GL_SRC_OUT_NV 0x928C +#define LOCAL_GL_SRC_OVER_NV 0x9288 +#define LOCAL_GL_SRG8_EXT 0x8FBE +#define LOCAL_GL_SRGB 0x8C40 +#define LOCAL_GL_SRGB8 0x8C41 +#define LOCAL_GL_SRGB8_ALPHA8 0x8C43 +#define LOCAL_GL_SRGB8_ALPHA8_EXT 0x8C43 +#define LOCAL_GL_SRGB8_EXT 0x8C41 +#define LOCAL_GL_SRGB8_NV 0x8C41 +#define LOCAL_GL_SRGB_ALPHA 0x8C42 +#define LOCAL_GL_SRGB_ALPHA_EXT 0x8C42 +#define LOCAL_GL_SRGB_DECODE_ARB 0x8299 +#define LOCAL_GL_SRGB_EXT 0x8C40 +#define LOCAL_GL_SRGB_READ 0x8297 +#define LOCAL_GL_SRGB_WRITE 0x8298 +#define LOCAL_GL_STACK_OVERFLOW 0x0503 +#define LOCAL_GL_STACK_OVERFLOW_KHR 0x0503 +#define LOCAL_GL_STACK_UNDERFLOW 0x0504 +#define LOCAL_GL_STACK_UNDERFLOW_KHR 0x0504 +#define LOCAL_GL_STANDARD_FONT_FORMAT_NV 0x936C +#define LOCAL_GL_STANDARD_FONT_NAME_NV 0x9072 +#define LOCAL_GL_STATE_RESTORE 0x8BDC +#define LOCAL_GL_STATIC_ATI 0x8760 +#define LOCAL_GL_STATIC_COPY 0x88E6 +#define LOCAL_GL_STATIC_COPY_ARB 0x88E6 +#define LOCAL_GL_STATIC_DRAW 0x88E4 +#define LOCAL_GL_STATIC_DRAW_ARB 0x88E4 +#define LOCAL_GL_STATIC_READ 0x88E5 +#define LOCAL_GL_STATIC_READ_ARB 0x88E5 +#define LOCAL_GL_STATIC_VERTEX_ARRAY_IBM 103061 +#define LOCAL_GL_STENCIL 0x1802 +#define LOCAL_GL_STENCIL_ATTACHMENT 0x8D20 +#define LOCAL_GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define LOCAL_GL_STENCIL_ATTACHMENT_OES 0x8D20 +#define LOCAL_GL_STENCIL_BACK_FAIL 0x8801 +#define LOCAL_GL_STENCIL_BACK_FAIL_ATI 0x8801 +#define LOCAL_GL_STENCIL_BACK_FUNC 0x8800 +#define LOCAL_GL_STENCIL_BACK_FUNC_ATI 0x8800 +#define LOCAL_GL_STENCIL_BACK_OP_VALUE_AMD 0x874D +#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 +#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 +#define LOCAL_GL_STENCIL_BACK_REF 0x8CA3 +#define LOCAL_GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define LOCAL_GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define LOCAL_GL_STENCIL_BITS 0x0D57 +#define LOCAL_GL_STENCIL_BUFFER_BIT 0x00000400 +#define LOCAL_GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000 +#define LOCAL_GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000 +#define LOCAL_GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000 +#define LOCAL_GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000 +#define LOCAL_GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000 +#define LOCAL_GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000 +#define LOCAL_GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000 +#define LOCAL_GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000 +#define LOCAL_GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 +#define LOCAL_GL_STENCIL_CLEAR_VALUE 0x0B91 +#define LOCAL_GL_STENCIL_COMPONENTS 0x8285 +#define LOCAL_GL_STENCIL_EXT 0x1802 +#define LOCAL_GL_STENCIL_FAIL 0x0B94 +#define LOCAL_GL_STENCIL_FUNC 0x0B92 +#define LOCAL_GL_STENCIL_INDEX 0x1901 +#define LOCAL_GL_STENCIL_INDEX1 0x8D46 +#define LOCAL_GL_STENCIL_INDEX16 0x8D49 +#define LOCAL_GL_STENCIL_INDEX16_EXT 0x8D49 +#define LOCAL_GL_STENCIL_INDEX1_EXT 0x8D46 +#define LOCAL_GL_STENCIL_INDEX1_OES 0x8D46 +#define LOCAL_GL_STENCIL_INDEX4 0x8D47 +#define LOCAL_GL_STENCIL_INDEX4_EXT 0x8D47 +#define LOCAL_GL_STENCIL_INDEX4_OES 0x8D47 +#define LOCAL_GL_STENCIL_INDEX8 0x8D48 +#define LOCAL_GL_STENCIL_INDEX8_EXT 0x8D48 +#define LOCAL_GL_STENCIL_INDEX8_OES 0x8D48 +#define LOCAL_GL_STENCIL_INDEX_OES 0x1901 +#define LOCAL_GL_STENCIL_OP_VALUE_AMD 0x874C +#define LOCAL_GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define LOCAL_GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define LOCAL_GL_STENCIL_REF 0x0B97 +#define LOCAL_GL_STENCIL_REF_COMMAND_NV 0x000C +#define LOCAL_GL_STENCIL_RENDERABLE 0x8288 +#define LOCAL_GL_STENCIL_SAMPLES_NV 0x932E +#define LOCAL_GL_STENCIL_TAG_BITS_EXT 0x88F2 +#define LOCAL_GL_STENCIL_TEST 0x0B90 +#define LOCAL_GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define LOCAL_GL_STENCIL_VALUE_MASK 0x0B93 +#define LOCAL_GL_STENCIL_WRITEMASK 0x0B98 +#define LOCAL_GL_STEREO 0x0C33 +#define LOCAL_GL_STORAGE_CACHED_APPLE 0x85BE +#define LOCAL_GL_STORAGE_CLIENT_APPLE 0x85B4 +#define LOCAL_GL_STORAGE_PRIVATE_APPLE 0x85BD +#define LOCAL_GL_STORAGE_SHARED_APPLE 0x85BF +#define LOCAL_GL_STREAM_COPY 0x88E2 +#define LOCAL_GL_STREAM_COPY_ARB 0x88E2 +#define LOCAL_GL_STREAM_DRAW 0x88E0 +#define LOCAL_GL_STREAM_DRAW_ARB 0x88E0 +#define LOCAL_GL_STREAM_RASTERIZATION_AMD 0x91A0 +#define LOCAL_GL_STREAM_READ 0x88E1 +#define LOCAL_GL_STREAM_READ_ARB 0x88E1 +#define LOCAL_GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 +#define LOCAL_GL_STRICT_LIGHTING_HINT_PGI 0x1A217 +#define LOCAL_GL_STRICT_SCISSOR_HINT_PGI 0x1A218 +#define LOCAL_GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 +#define LOCAL_GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 +#define LOCAL_GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 +#define LOCAL_GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 +#define LOCAL_GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV 0x00000100 +#define LOCAL_GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 +#define LOCAL_GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 +#define LOCAL_GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 +#define LOCAL_GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 +#define LOCAL_GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 +#define LOCAL_GL_SUBGROUP_SIZE_KHR 0x9532 +#define LOCAL_GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 +#define LOCAL_GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 +#define LOCAL_GL_SUBPIXEL_BITS 0x0D50 +#define LOCAL_GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347 +#define LOCAL_GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348 +#define LOCAL_GL_SUBSAMPLE_DISTANCE_AMD 0x883F +#define LOCAL_GL_SUBTRACT 0x84E7 +#define LOCAL_GL_SUBTRACT_ARB 0x84E7 +#define LOCAL_GL_SUB_ATI 0x8965 +#define LOCAL_GL_SUCCESS_NV 0x902F +#define LOCAL_GL_SUPERSAMPLE_SCALE_X_NV 0x9372 +#define LOCAL_GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 +#define LOCAL_GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7 +#define LOCAL_GL_SURFACE_MAPPED_NV 0x8700 +#define LOCAL_GL_SURFACE_REGISTERED_NV 0x86FD +#define LOCAL_GL_SURFACE_STATE_NV 0x86EB +#define LOCAL_GL_SWIZZLE_STQ_ATI 0x8977 +#define LOCAL_GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define LOCAL_GL_SWIZZLE_STRQ_ATI 0x897A +#define LOCAL_GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define LOCAL_GL_SWIZZLE_STR_ATI 0x8976 +#define LOCAL_GL_SWIZZLE_STR_DR_ATI 0x8978 +#define LOCAL_GL_SYNC_CL_EVENT_ARB 0x8240 +#define LOCAL_GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +#define LOCAL_GL_SYNC_CONDITION 0x9113 +#define LOCAL_GL_SYNC_CONDITION_APPLE 0x9113 +#define LOCAL_GL_SYNC_FENCE 0x9116 +#define LOCAL_GL_SYNC_FENCE_APPLE 0x9116 +#define LOCAL_GL_SYNC_FLAGS 0x9115 +#define LOCAL_GL_SYNC_FLAGS_APPLE 0x9115 +#define LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001 +#define LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117 +#define LOCAL_GL_SYNC_OBJECT_APPLE 0x8A53 +#define LOCAL_GL_SYNC_STATUS 0x9114 +#define LOCAL_GL_SYNC_STATUS_APPLE 0x9114 +#define LOCAL_GL_SYNC_X11_FENCE_EXT 0x90E1 +#define LOCAL_GL_SYSTEM_FONT_NAME_NV 0x9073 +#define LOCAL_GL_T 0x2001 +#define LOCAL_GL_T2F_C3F_V3F 0x2A2A +#define LOCAL_GL_T2F_C4F_N3F_V3F 0x2A2C +#define LOCAL_GL_T2F_C4UB_V3F 0x2A29 +#define LOCAL_GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define LOCAL_GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#define LOCAL_GL_T2F_IUI_V2F_EXT 0x81B1 +#define LOCAL_GL_T2F_IUI_V3F_EXT 0x81B2 +#define LOCAL_GL_T2F_N3F_V3F 0x2A2B +#define LOCAL_GL_T2F_V3F 0x2A27 +#define LOCAL_GL_T4F_C4F_N3F_V4F 0x2A2D +#define LOCAL_GL_T4F_V4F 0x2A28 +#define LOCAL_GL_TABLE_TOO_LARGE 0x8031 +#define LOCAL_GL_TABLE_TOO_LARGE_EXT 0x8031 +#define LOCAL_GL_TANGENT_ARRAY_EXT 0x8439 +#define LOCAL_GL_TANGENT_ARRAY_POINTER_EXT 0x8442 +#define LOCAL_GL_TANGENT_ARRAY_STRIDE_EXT 0x843F +#define LOCAL_GL_TANGENT_ARRAY_TYPE_EXT 0x843E +#define LOCAL_GL_TASK_SHADER_BIT_NV 0x00000080 +#define LOCAL_GL_TASK_SHADER_NV 0x955A +#define LOCAL_GL_TASK_SUBROUTINE_NV 0x957D +#define LOCAL_GL_TASK_SUBROUTINE_UNIFORM_NV 0x957F +#define LOCAL_GL_TASK_WORK_GROUP_SIZE_NV 0x953F +#define LOCAL_GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000 +#define LOCAL_GL_TESSELLATION_FACTOR_AMD 0x9005 +#define LOCAL_GL_TESSELLATION_MODE_AMD 0x9004 +#define LOCAL_GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define LOCAL_GL_TESS_CONTROL_OUTPUT_VERTICES_EXT 0x8E75 +#define LOCAL_GL_TESS_CONTROL_OUTPUT_VERTICES_OES 0x8E75 +#define LOCAL_GL_TESS_CONTROL_PROGRAM_NV 0x891E +#define LOCAL_GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 +#define LOCAL_GL_TESS_CONTROL_SHADER 0x8E88 +#define LOCAL_GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define LOCAL_GL_TESS_CONTROL_SHADER_BIT_EXT 0x00000008 +#define LOCAL_GL_TESS_CONTROL_SHADER_BIT_OES 0x00000008 +#define LOCAL_GL_TESS_CONTROL_SHADER_EXT 0x8E88 +#define LOCAL_GL_TESS_CONTROL_SHADER_OES 0x8E88 +#define LOCAL_GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 +#define LOCAL_GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 +#define LOCAL_GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define LOCAL_GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define LOCAL_GL_TESS_CONTROL_TEXTURE 0x829C +#define LOCAL_GL_TESS_EVALUATION_PROGRAM_NV 0x891F +#define LOCAL_GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 +#define LOCAL_GL_TESS_EVALUATION_SHADER 0x8E87 +#define LOCAL_GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define LOCAL_GL_TESS_EVALUATION_SHADER_BIT_EXT 0x00000010 +#define LOCAL_GL_TESS_EVALUATION_SHADER_BIT_OES 0x00000010 +#define LOCAL_GL_TESS_EVALUATION_SHADER_EXT 0x8E87 +#define LOCAL_GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2 +#define LOCAL_GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 +#define LOCAL_GL_TESS_EVALUATION_SHADER_OES 0x8E87 +#define LOCAL_GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define LOCAL_GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define LOCAL_GL_TESS_EVALUATION_TEXTURE 0x829D +#define LOCAL_GL_TESS_GEN_MODE 0x8E76 +#define LOCAL_GL_TESS_GEN_MODE_EXT 0x8E76 +#define LOCAL_GL_TESS_GEN_MODE_OES 0x8E76 +#define LOCAL_GL_TESS_GEN_POINT_MODE 0x8E79 +#define LOCAL_GL_TESS_GEN_POINT_MODE_EXT 0x8E79 +#define LOCAL_GL_TESS_GEN_POINT_MODE_OES 0x8E79 +#define LOCAL_GL_TESS_GEN_SPACING 0x8E77 +#define LOCAL_GL_TESS_GEN_SPACING_EXT 0x8E77 +#define LOCAL_GL_TESS_GEN_SPACING_OES 0x8E77 +#define LOCAL_GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define LOCAL_GL_TESS_GEN_VERTEX_ORDER_EXT 0x8E78 +#define LOCAL_GL_TESS_GEN_VERTEX_ORDER_OES 0x8E78 +#define LOCAL_GL_TEXCOORD1_BIT_PGI 0x10000000 +#define LOCAL_GL_TEXCOORD2_BIT_PGI 0x20000000 +#define LOCAL_GL_TEXCOORD3_BIT_PGI 0x40000000 +#define LOCAL_GL_TEXCOORD4_BIT_PGI 0x80000000 +#define LOCAL_GL_TEXTURE 0x1702 +#define LOCAL_GL_TEXTURE0 0x84C0 +#define LOCAL_GL_TEXTURE0_ARB 0x84C0 +#define LOCAL_GL_TEXTURE1 0x84C1 +#define LOCAL_GL_TEXTURE10 0x84CA +#define LOCAL_GL_TEXTURE10_ARB 0x84CA +#define LOCAL_GL_TEXTURE11 0x84CB +#define LOCAL_GL_TEXTURE11_ARB 0x84CB +#define LOCAL_GL_TEXTURE12 0x84CC +#define LOCAL_GL_TEXTURE12_ARB 0x84CC +#define LOCAL_GL_TEXTURE13 0x84CD +#define LOCAL_GL_TEXTURE13_ARB 0x84CD +#define LOCAL_GL_TEXTURE14 0x84CE +#define LOCAL_GL_TEXTURE14_ARB 0x84CE +#define LOCAL_GL_TEXTURE15 0x84CF +#define LOCAL_GL_TEXTURE15_ARB 0x84CF +#define LOCAL_GL_TEXTURE16 0x84D0 +#define LOCAL_GL_TEXTURE16_ARB 0x84D0 +#define LOCAL_GL_TEXTURE17 0x84D1 +#define LOCAL_GL_TEXTURE17_ARB 0x84D1 +#define LOCAL_GL_TEXTURE18 0x84D2 +#define LOCAL_GL_TEXTURE18_ARB 0x84D2 +#define LOCAL_GL_TEXTURE19 0x84D3 +#define LOCAL_GL_TEXTURE19_ARB 0x84D3 +#define LOCAL_GL_TEXTURE1_ARB 0x84C1 +#define LOCAL_GL_TEXTURE2 0x84C2 +#define LOCAL_GL_TEXTURE20 0x84D4 +#define LOCAL_GL_TEXTURE20_ARB 0x84D4 +#define LOCAL_GL_TEXTURE21 0x84D5 +#define LOCAL_GL_TEXTURE21_ARB 0x84D5 +#define LOCAL_GL_TEXTURE22 0x84D6 +#define LOCAL_GL_TEXTURE22_ARB 0x84D6 +#define LOCAL_GL_TEXTURE23 0x84D7 +#define LOCAL_GL_TEXTURE23_ARB 0x84D7 +#define LOCAL_GL_TEXTURE24 0x84D8 +#define LOCAL_GL_TEXTURE24_ARB 0x84D8 +#define LOCAL_GL_TEXTURE25 0x84D9 +#define LOCAL_GL_TEXTURE25_ARB 0x84D9 +#define LOCAL_GL_TEXTURE26 0x84DA +#define LOCAL_GL_TEXTURE26_ARB 0x84DA +#define LOCAL_GL_TEXTURE27 0x84DB +#define LOCAL_GL_TEXTURE27_ARB 0x84DB +#define LOCAL_GL_TEXTURE28 0x84DC +#define LOCAL_GL_TEXTURE28_ARB 0x84DC +#define LOCAL_GL_TEXTURE29 0x84DD +#define LOCAL_GL_TEXTURE29_ARB 0x84DD +#define LOCAL_GL_TEXTURE2_ARB 0x84C2 +#define LOCAL_GL_TEXTURE3 0x84C3 +#define LOCAL_GL_TEXTURE30 0x84DE +#define LOCAL_GL_TEXTURE30_ARB 0x84DE +#define LOCAL_GL_TEXTURE31 0x84DF +#define LOCAL_GL_TEXTURE31_ARB 0x84DF +#define LOCAL_GL_TEXTURE3_ARB 0x84C3 +#define LOCAL_GL_TEXTURE4 0x84C4 +#define LOCAL_GL_TEXTURE4_ARB 0x84C4 +#define LOCAL_GL_TEXTURE5 0x84C5 +#define LOCAL_GL_TEXTURE5_ARB 0x84C5 +#define LOCAL_GL_TEXTURE6 0x84C6 +#define LOCAL_GL_TEXTURE6_ARB 0x84C6 +#define LOCAL_GL_TEXTURE7 0x84C7 +#define LOCAL_GL_TEXTURE7_ARB 0x84C7 +#define LOCAL_GL_TEXTURE8 0x84C8 +#define LOCAL_GL_TEXTURE8_ARB 0x84C8 +#define LOCAL_GL_TEXTURE9 0x84C9 +#define LOCAL_GL_TEXTURE9_ARB 0x84C9 +#define LOCAL_GL_TEXTURE_1D 0x0DE0 +#define LOCAL_GL_TEXTURE_1D_ARRAY 0x8C18 +#define LOCAL_GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define LOCAL_GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define LOCAL_GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D +#define LOCAL_GL_TEXTURE_1D_STACK_MESAX 0x8759 +#define LOCAL_GL_TEXTURE_2D 0x0DE1 +#define LOCAL_GL_TEXTURE_2D_ARRAY 0x8C1A +#define LOCAL_GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define LOCAL_GL_TEXTURE_2D_BINDING_EXT 0x8069 +#define LOCAL_GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define LOCAL_GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define LOCAL_GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES 0x9102 +#define LOCAL_GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E +#define LOCAL_GL_TEXTURE_2D_STACK_MESAX 0x875A +#define LOCAL_GL_TEXTURE_3D 0x806F +#define LOCAL_GL_TEXTURE_3D_BINDING_EXT 0x806A +#define LOCAL_GL_TEXTURE_3D_BINDING_OES 0x806A +#define LOCAL_GL_TEXTURE_3D_EXT 0x806F +#define LOCAL_GL_TEXTURE_3D_OES 0x806F +#define LOCAL_GL_TEXTURE_4DSIZE_SGIS 0x8136 +#define LOCAL_GL_TEXTURE_4D_BINDING_SGIS 0x814F +#define LOCAL_GL_TEXTURE_4D_SGIS 0x8134 +#define LOCAL_GL_TEXTURE_ALPHA_MODULATE_IMG 0x8C06 +#define LOCAL_GL_TEXTURE_ALPHA_SIZE 0x805F +#define LOCAL_GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define LOCAL_GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define LOCAL_GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define LOCAL_GL_TEXTURE_APPLICATION_MODE_EXT 0x834F +#define LOCAL_GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69 +#define LOCAL_GL_TEXTURE_BASE_LEVEL 0x813C +#define LOCAL_GL_TEXTURE_BASE_LEVEL_SGIS 0x813C +#define LOCAL_GL_TEXTURE_BINDING_1D 0x8068 +#define LOCAL_GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define LOCAL_GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define LOCAL_GL_TEXTURE_BINDING_2D 0x8069 +#define LOCAL_GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define LOCAL_GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define LOCAL_GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define LOCAL_GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define LOCAL_GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES 0x9105 +#define LOCAL_GL_TEXTURE_BINDING_3D 0x806A +#define LOCAL_GL_TEXTURE_BINDING_3D_OES 0x806A +#define LOCAL_GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define LOCAL_GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C +#define LOCAL_GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define LOCAL_GL_TEXTURE_BINDING_BUFFER_OES 0x8C2C +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT 0x900A +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES 0x900A +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_OES 0x8514 +#define LOCAL_GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 +#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define LOCAL_GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 +#define LOCAL_GL_TEXTURE_BIT 0x00040000 +#define LOCAL_GL_TEXTURE_BLUE_SIZE 0x805E +#define LOCAL_GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define LOCAL_GL_TEXTURE_BLUE_TYPE 0x8C12 +#define LOCAL_GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define LOCAL_GL_TEXTURE_BORDER 0x1005 +#define LOCAL_GL_TEXTURE_BORDER_COLOR 0x1004 +#define LOCAL_GL_TEXTURE_BORDER_COLOR_EXT 0x1004 +#define LOCAL_GL_TEXTURE_BORDER_COLOR_NV 0x1004 +#define LOCAL_GL_TEXTURE_BORDER_COLOR_OES 0x1004 +#define LOCAL_GL_TEXTURE_BORDER_VALUES_NV 0x871A +#define LOCAL_GL_TEXTURE_BUFFER 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_ARB 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_BINDING_EXT 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_BINDING_OES 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define LOCAL_GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D +#define LOCAL_GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define LOCAL_GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES 0x8C2D +#define LOCAL_GL_TEXTURE_BUFFER_EXT 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +#define LOCAL_GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E +#define LOCAL_GL_TEXTURE_BUFFER_OES 0x8C2A +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET 0x919D +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT 0x919F +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES 0x919F +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET_EXT 0x919D +#define LOCAL_GL_TEXTURE_BUFFER_OFFSET_OES 0x919D +#define LOCAL_GL_TEXTURE_BUFFER_SIZE 0x919E +#define LOCAL_GL_TEXTURE_BUFFER_SIZE_EXT 0x919E +#define LOCAL_GL_TEXTURE_BUFFER_SIZE_OES 0x919E +#define LOCAL_GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 +#define LOCAL_GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 +#define LOCAL_GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 +#define LOCAL_GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 +#define LOCAL_GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 +#define LOCAL_GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 +#define LOCAL_GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 +#define LOCAL_GL_TEXTURE_COLOR_TABLE_SGI 0x80BC +#define LOCAL_GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF +#define LOCAL_GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF +#define LOCAL_GL_TEXTURE_COMPARE_FUNC 0x884D +#define LOCAL_GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define LOCAL_GL_TEXTURE_COMPARE_FUNC_EXT 0x884D +#define LOCAL_GL_TEXTURE_COMPARE_MODE 0x884C +#define LOCAL_GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define LOCAL_GL_TEXTURE_COMPARE_MODE_EXT 0x884C +#define LOCAL_GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B +#define LOCAL_GL_TEXTURE_COMPARE_SGIX 0x819A +#define LOCAL_GL_TEXTURE_COMPONENTS 0x1003 +#define LOCAL_GL_TEXTURE_COMPRESSED 0x86A1 +#define LOCAL_GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define LOCAL_GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define LOCAL_GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define LOCAL_GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define LOCAL_GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define LOCAL_GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define LOCAL_GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define LOCAL_GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define LOCAL_GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 +#define LOCAL_GL_TEXTURE_COORD_ARRAY 0x8078 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define LOCAL_GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define LOCAL_GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define LOCAL_GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F +#define LOCAL_GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define LOCAL_GL_TEXTURE_COORD_NV 0x8C79 +#define LOCAL_GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 +#define LOCAL_GL_TEXTURE_CROP_RECT_OES 0x8B9D +#define LOCAL_GL_TEXTURE_CUBE_MAP 0x8513 +#define LOCAL_GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define LOCAL_GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define LOCAL_GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define LOCAL_GL_TEXTURE_CUBE_MAP_ARRAY_EXT 0x9009 +#define LOCAL_GL_TEXTURE_CUBE_MAP_ARRAY_OES 0x9009 +#define LOCAL_GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES 0x8516 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES 0x8518 +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES 0x851A +#define LOCAL_GL_TEXTURE_CUBE_MAP_OES 0x8513 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES 0x8515 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES 0x8517 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES 0x8519 +#define LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define LOCAL_GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 +#define LOCAL_GL_TEXTURE_DEFORMATION_SGIX 0x8195 +#define LOCAL_GL_TEXTURE_DEPTH 0x8071 +#define LOCAL_GL_TEXTURE_DEPTH_EXT 0x8071 +#define LOCAL_GL_TEXTURE_DEPTH_QCOM 0x8BD4 +#define LOCAL_GL_TEXTURE_DEPTH_SIZE 0x884A +#define LOCAL_GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define LOCAL_GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define LOCAL_GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 +#define LOCAL_GL_TEXTURE_DS_SIZE_NV 0x871D +#define LOCAL_GL_TEXTURE_DT_SIZE_NV 0x871E +#define LOCAL_GL_TEXTURE_ENV 0x2300 +#define LOCAL_GL_TEXTURE_ENV_BIAS_SGIX 0x80BE +#define LOCAL_GL_TEXTURE_ENV_COLOR 0x2201 +#define LOCAL_GL_TEXTURE_ENV_MODE 0x2200 +#define LOCAL_GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define LOCAL_GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define LOCAL_GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 +#define LOCAL_GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 +#define LOCAL_GL_TEXTURE_FILTER_CONTROL 0x8500 +#define LOCAL_GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define LOCAL_GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define LOCAL_GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C +#define LOCAL_GL_TEXTURE_FORMAT_QCOM 0x8BD6 +#define LOCAL_GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT 0x8FBF +#define LOCAL_GL_TEXTURE_FOVEATED_CUTOFF_DENSITY_QCOM 0x96A0 +#define LOCAL_GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM 0x8BFB +#define LOCAL_GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM 0x8BFD +#define LOCAL_GL_TEXTURE_FOVEATED_MIN_PIXEL_DENSITY_QCOM 0x8BFC +#define LOCAL_GL_TEXTURE_FOVEATED_NUM_FOCAL_POINTS_QUERY_QCOM 0x8BFE +#define LOCAL_GL_TEXTURE_FREE_MEMORY_ATI 0x87FC +#define LOCAL_GL_TEXTURE_GATHER 0x82A2 +#define LOCAL_GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define LOCAL_GL_TEXTURE_GEN_MODE 0x2500 +#define LOCAL_GL_TEXTURE_GEN_MODE_OES 0x2500 +#define LOCAL_GL_TEXTURE_GEN_Q 0x0C63 +#define LOCAL_GL_TEXTURE_GEN_R 0x0C62 +#define LOCAL_GL_TEXTURE_GEN_S 0x0C60 +#define LOCAL_GL_TEXTURE_GEN_STR_OES 0x8D60 +#define LOCAL_GL_TEXTURE_GEN_T 0x0C61 +#define LOCAL_GL_TEXTURE_GEQUAL_R_SGIX 0x819D +#define LOCAL_GL_TEXTURE_GREEN_SIZE 0x805D +#define LOCAL_GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define LOCAL_GL_TEXTURE_GREEN_TYPE 0x8C11 +#define LOCAL_GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define LOCAL_GL_TEXTURE_HEIGHT 0x1001 +#define LOCAL_GL_TEXTURE_HEIGHT_QCOM 0x8BD3 +#define LOCAL_GL_TEXTURE_HI_SIZE_NV 0x871B +#define LOCAL_GL_TEXTURE_IMAGE_FORMAT 0x828F +#define LOCAL_GL_TEXTURE_IMAGE_TYPE 0x8290 +#define LOCAL_GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 +#define LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +#define LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define LOCAL_GL_TEXTURE_INDEX_SIZE_EXT 0x80ED +#define LOCAL_GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define LOCAL_GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define LOCAL_GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define LOCAL_GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define LOCAL_GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define LOCAL_GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 +#define LOCAL_GL_TEXTURE_LEQUAL_R_SGIX 0x819C +#define LOCAL_GL_TEXTURE_LIGHTING_MODE_HP 0x8167 +#define LOCAL_GL_TEXTURE_LIGHT_EXT 0x8350 +#define LOCAL_GL_TEXTURE_LOD_BIAS 0x8501 +#define LOCAL_GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#define LOCAL_GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 +#define LOCAL_GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E +#define LOCAL_GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F +#define LOCAL_GL_TEXTURE_LO_SIZE_NV 0x871C +#define LOCAL_GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define LOCAL_GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define LOCAL_GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define LOCAL_GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define LOCAL_GL_TEXTURE_MAG_FILTER 0x2800 +#define LOCAL_GL_TEXTURE_MAG_SIZE_NV 0x871F +#define LOCAL_GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 +#define LOCAL_GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 +#define LOCAL_GL_TEXTURE_MATRIX 0x0BA8 +#define LOCAL_GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F +#define LOCAL_GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define LOCAL_GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B +#define LOCAL_GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 +#define LOCAL_GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A +#define LOCAL_GL_TEXTURE_MAX_LEVEL 0x813D +#define LOCAL_GL_TEXTURE_MAX_LEVEL_APPLE 0x813D +#define LOCAL_GL_TEXTURE_MAX_LEVEL_SGIS 0x813D +#define LOCAL_GL_TEXTURE_MAX_LOD 0x813B +#define LOCAL_GL_TEXTURE_MAX_LOD_SGIS 0x813B +#define LOCAL_GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF +#define LOCAL_GL_TEXTURE_MIN_FILTER 0x2801 +#define LOCAL_GL_TEXTURE_MIN_LOD 0x813A +#define LOCAL_GL_TEXTURE_MIN_LOD_SGIS 0x813A +#define LOCAL_GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E +#define LOCAL_GL_TEXTURE_NORMAL_EXT 0x85AF +#define LOCAL_GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 +#define LOCAL_GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB +#define LOCAL_GL_TEXTURE_POST_SPECULAR_HP 0x8168 +#define LOCAL_GL_TEXTURE_PRE_SPECULAR_HP 0x8169 +#define LOCAL_GL_TEXTURE_PRIORITY 0x8066 +#define LOCAL_GL_TEXTURE_PRIORITY_EXT 0x8066 +#define LOCAL_GL_TEXTURE_PROTECTED_EXT 0x8BFA +#define LOCAL_GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 +#define LOCAL_GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 +#define LOCAL_GL_TEXTURE_RECTANGLE 0x84F5 +#define LOCAL_GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define LOCAL_GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define LOCAL_GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 +#define LOCAL_GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 +#define LOCAL_GL_TEXTURE_RED_SIZE 0x805C +#define LOCAL_GL_TEXTURE_RED_SIZE_EXT 0x805C +#define LOCAL_GL_TEXTURE_RED_TYPE 0x8C10 +#define LOCAL_GL_TEXTURE_RED_TYPE_ARB 0x8C10 +#define LOCAL_GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 +#define LOCAL_GL_TEXTURE_RENDERBUFFER_NV 0x8E55 +#define LOCAL_GL_TEXTURE_RESIDENT 0x8067 +#define LOCAL_GL_TEXTURE_RESIDENT_EXT 0x8067 +#define LOCAL_GL_TEXTURE_SAMPLES 0x9106 +#define LOCAL_GL_TEXTURE_SAMPLES_IMG 0x9136 +#define LOCAL_GL_TEXTURE_SHADER_NV 0x86DE +#define LOCAL_GL_TEXTURE_SHADOW 0x82A1 +#define LOCAL_GL_TEXTURE_SHARED_SIZE 0x8C3F +#define LOCAL_GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F +#define LOCAL_GL_TEXTURE_SPARSE_ARB 0x91A6 +#define LOCAL_GL_TEXTURE_SPARSE_EXT 0x91A6 +#define LOCAL_GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define LOCAL_GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define LOCAL_GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define LOCAL_GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#define LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC +#define LOCAL_GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 +#define LOCAL_GL_TEXTURE_SWIZZLE_A 0x8E45 +#define LOCAL_GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define LOCAL_GL_TEXTURE_SWIZZLE_B 0x8E44 +#define LOCAL_GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define LOCAL_GL_TEXTURE_SWIZZLE_G 0x8E43 +#define LOCAL_GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define LOCAL_GL_TEXTURE_SWIZZLE_R 0x8E42 +#define LOCAL_GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define LOCAL_GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#define LOCAL_GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define LOCAL_GL_TEXTURE_TARGET 0x1006 +#define LOCAL_GL_TEXTURE_TARGET_QCOM 0x8BDA +#define LOCAL_GL_TEXTURE_TILING_EXT 0x9580 +#define LOCAL_GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#define LOCAL_GL_TEXTURE_TYPE_QCOM 0x8BD7 +#define LOCAL_GL_TEXTURE_UNNORMALIZED_COORDINATES_ARM 0x8F6A +#define LOCAL_GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F +#define LOCAL_GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define LOCAL_GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 +#define LOCAL_GL_TEXTURE_USAGE_ANGLE 0x93A2 +#define LOCAL_GL_TEXTURE_VIEW 0x82B5 +#define LOCAL_GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define LOCAL_GL_TEXTURE_VIEW_MIN_LAYER_EXT 0x82DD +#define LOCAL_GL_TEXTURE_VIEW_MIN_LAYER_OES 0x82DD +#define LOCAL_GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define LOCAL_GL_TEXTURE_VIEW_MIN_LEVEL_EXT 0x82DB +#define LOCAL_GL_TEXTURE_VIEW_MIN_LEVEL_OES 0x82DB +#define LOCAL_GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define LOCAL_GL_TEXTURE_VIEW_NUM_LAYERS_EXT 0x82DE +#define LOCAL_GL_TEXTURE_VIEW_NUM_LAYERS_OES 0x82DE +#define LOCAL_GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define LOCAL_GL_TEXTURE_VIEW_NUM_LEVELS_EXT 0x82DC +#define LOCAL_GL_TEXTURE_VIEW_NUM_LEVELS_OES 0x82DC +#define LOCAL_GL_TEXTURE_WIDTH 0x1000 +#define LOCAL_GL_TEXTURE_WIDTH_QCOM 0x8BD2 +#define LOCAL_GL_TEXTURE_WRAP_Q_SGIS 0x8137 +#define LOCAL_GL_TEXTURE_WRAP_R 0x8072 +#define LOCAL_GL_TEXTURE_WRAP_R_EXT 0x8072 +#define LOCAL_GL_TEXTURE_WRAP_R_OES 0x8072 +#define LOCAL_GL_TEXTURE_WRAP_S 0x2802 +#define LOCAL_GL_TEXTURE_WRAP_T 0x2803 +#define LOCAL_GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 +#define LOCAL_GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8 +#define LOCAL_GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9 +#define LOCAL_GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA +#define LOCAL_GL_TILING_TYPES_EXT 0x9583 +#define LOCAL_GL_TIMELINE_SEMAPHORE_VALUE_NV 0x9595 +#define LOCAL_GL_TIMEOUT_EXPIRED 0x911B +#define LOCAL_GL_TIMEOUT_EXPIRED_APPLE 0x911B +#define LOCAL_GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define LOCAL_GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFF +#define LOCAL_GL_TIMESTAMP 0x8E28 +#define LOCAL_GL_TIMESTAMP_EXT 0x8E28 +#define LOCAL_GL_TIME_ELAPSED 0x88BF +#define LOCAL_GL_TIME_ELAPSED_EXT 0x88BF +#define LOCAL_GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define LOCAL_GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define LOCAL_GL_TRACE_ALL_BITS_MESA 0xFFFF +#define LOCAL_GL_TRACE_ARRAYS_BIT_MESA 0x0004 +#define LOCAL_GL_TRACE_ERRORS_BIT_MESA 0x0020 +#define LOCAL_GL_TRACE_MASK_MESA 0x8755 +#define LOCAL_GL_TRACE_NAME_MESA 0x8756 +#define LOCAL_GL_TRACE_OPERATIONS_BIT_MESA 0x0001 +#define LOCAL_GL_TRACE_PIXELS_BIT_MESA 0x0010 +#define LOCAL_GL_TRACE_PRIMITIVES_BIT_MESA 0x0002 +#define LOCAL_GL_TRACE_TEXTURES_BIT_MESA 0x0008 +#define LOCAL_GL_TRACK_MATRIX_NV 0x8648 +#define LOCAL_GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 +#define LOCAL_GL_TRANSFORM_BIT 0x00001000 +#define LOCAL_GL_TRANSFORM_FEEDBACK 0x8E22 +#define LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define LOCAL_GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E +#define LOCAL_GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 +#define LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C +#define LOCAL_GL_TRANSFORM_FEEDBACK_NV 0x8E22 +#define LOCAL_GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC +#define LOCAL_GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC +#define LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 +#define LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 +#define LOCAL_GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 +#define LOCAL_GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED +#define LOCAL_GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 +#define LOCAL_GL_TRANSFORM_HINT_APPLE 0x85B1 +#define LOCAL_GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 +#define LOCAL_GL_TRANSLATE_2D_NV 0x9090 +#define LOCAL_GL_TRANSLATE_3D_NV 0x9091 +#define LOCAL_GL_TRANSLATE_X_NV 0x908E +#define LOCAL_GL_TRANSLATE_Y_NV 0x908F +#define LOCAL_GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define LOCAL_GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define LOCAL_GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define LOCAL_GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 +#define LOCAL_GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define LOCAL_GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define LOCAL_GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 +#define LOCAL_GL_TRANSPOSE_NV 0x862C +#define LOCAL_GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define LOCAL_GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define LOCAL_GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 +#define LOCAL_GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define LOCAL_GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 +#define LOCAL_GL_TRIANGLES 0x0004 +#define LOCAL_GL_TRIANGLES_ADJACENCY 0x000C +#define LOCAL_GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define LOCAL_GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define LOCAL_GL_TRIANGLES_ADJACENCY_OES 0x000C +#define LOCAL_GL_TRIANGLE_FAN 0x0006 +#define LOCAL_GL_TRIANGLE_LIST_SUN 0x81D7 +#define LOCAL_GL_TRIANGLE_MESH_SUN 0x8615 +#define LOCAL_GL_TRIANGLE_STRIP 0x0005 +#define LOCAL_GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define LOCAL_GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define LOCAL_GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define LOCAL_GL_TRIANGLE_STRIP_ADJACENCY_OES 0x000D +#define LOCAL_GL_TRIANGULAR_NV 0x90A5 +#define LOCAL_GL_TRUE 1 +#define LOCAL_GL_TYPE 0x92FA +#define LOCAL_GL_UNCORRELATED_NV 0x9282 +#define LOCAL_GL_UNDEFINED_APPLE 0x8A1C +#define LOCAL_GL_UNDEFINED_VERTEX 0x8260 +#define LOCAL_GL_UNDEFINED_VERTEX_EXT 0x8260 +#define LOCAL_GL_UNDEFINED_VERTEX_OES 0x8260 +#define LOCAL_GL_UNIFORM 0x92E1 +#define LOCAL_GL_UNIFORM_ADDRESS_COMMAND_NV 0x000A +#define LOCAL_GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define LOCAL_GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define LOCAL_GL_UNIFORM_BARRIER_BIT 0x00000004 +#define LOCAL_GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 +#define LOCAL_GL_UNIFORM_BLOCK 0x92E2 +#define LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define LOCAL_GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define LOCAL_GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define LOCAL_GL_UNIFORM_BUFFER 0x8A11 +#define LOCAL_GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F +#define LOCAL_GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define LOCAL_GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF +#define LOCAL_GL_UNIFORM_BUFFER_EXT 0x8DEE +#define LOCAL_GL_UNIFORM_BUFFER_LENGTH_NV 0x9370 +#define LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define LOCAL_GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define LOCAL_GL_UNIFORM_BUFFER_START 0x8A29 +#define LOCAL_GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E +#define LOCAL_GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define LOCAL_GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define LOCAL_GL_UNIFORM_NAME_LENGTH 0x8A39 +#define LOCAL_GL_UNIFORM_OFFSET 0x8A3B +#define LOCAL_GL_UNIFORM_SIZE 0x8A38 +#define LOCAL_GL_UNIFORM_TYPE 0x8A37 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET 0x8255 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_KHR 0x8255 +#define LOCAL_GL_UNPACK_ALIGNMENT 0x0CF5 +#define LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#define LOCAL_GL_UNPACK_CMYK_HINT_EXT 0x800F +#define LOCAL_GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243 +#define LOCAL_GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define LOCAL_GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define LOCAL_GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define LOCAL_GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define LOCAL_GL_UNPACK_COMPRESSED_SIZE_SGIX 0x831A +#define LOCAL_GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 +#define LOCAL_GL_UNPACK_FLIP_Y_WEBGL 0x9240 +#define LOCAL_GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 +#define LOCAL_GL_UNPACK_IMAGE_HEIGHT 0x806E +#define LOCAL_GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E +#define LOCAL_GL_UNPACK_LSB_FIRST 0x0CF1 +#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241 +#define LOCAL_GL_UNPACK_RESAMPLE_OML 0x8985 +#define LOCAL_GL_UNPACK_RESAMPLE_SGIX 0x842F +#define LOCAL_GL_UNPACK_ROW_BYTES_APPLE 0x8A16 +#define LOCAL_GL_UNPACK_ROW_LENGTH 0x0CF2 +#define LOCAL_GL_UNPACK_ROW_LENGTH_EXT 0x0CF2 +#define LOCAL_GL_UNPACK_SKIP_IMAGES 0x806D +#define LOCAL_GL_UNPACK_SKIP_IMAGES_EXT 0x806D +#define LOCAL_GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define LOCAL_GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 +#define LOCAL_GL_UNPACK_SKIP_ROWS 0x0CF3 +#define LOCAL_GL_UNPACK_SKIP_ROWS_EXT 0x0CF3 +#define LOCAL_GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 +#define LOCAL_GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 +#define LOCAL_GL_UNPACK_SWAP_BYTES 0x0CF0 +#define LOCAL_GL_UNSIGNALED 0x9118 +#define LOCAL_GL_UNSIGNALED_APPLE 0x9118 +#define LOCAL_GL_UNSIGNED_BYTE 0x1401 +#define LOCAL_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define LOCAL_GL_UNSIGNED_BYTE_2_3_3_REV_EXT 0x8362 +#define LOCAL_GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define LOCAL_GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define LOCAL_GL_UNSIGNED_IDENTITY_NV 0x8536 +#define LOCAL_GL_UNSIGNED_INT 0x1405 +#define LOCAL_GL_UNSIGNED_INT16_NV 0x8FF0 +#define LOCAL_GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define LOCAL_GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define LOCAL_GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define LOCAL_GL_UNSIGNED_INT64_AMD 0x8BC2 +#define LOCAL_GL_UNSIGNED_INT64_ARB 0x140F +#define LOCAL_GL_UNSIGNED_INT64_NV 0x140F +#define LOCAL_GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 +#define LOCAL_GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define LOCAL_GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 +#define LOCAL_GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define LOCAL_GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 +#define LOCAL_GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define LOCAL_GL_UNSIGNED_INT8_NV 0x8FEC +#define LOCAL_GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define LOCAL_GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define LOCAL_GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE 0x8C3B +#define LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B +#define LOCAL_GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define LOCAL_GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 +#define LOCAL_GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 +#define LOCAL_GL_UNSIGNED_INT_24_8 0x84FA +#define LOCAL_GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define LOCAL_GL_UNSIGNED_INT_24_8_MESA 0x8751 +#define LOCAL_GL_UNSIGNED_INT_24_8_NV 0x84FA +#define LOCAL_GL_UNSIGNED_INT_24_8_OES 0x84FA +#define LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 +#define LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV_APPLE 0x8C3E +#define LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E +#define LOCAL_GL_UNSIGNED_INT_8_24_REV_MESA 0x8752 +#define LOCAL_GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define LOCAL_GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV_EXT 0x8367 +#define LOCAL_GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB +#define LOCAL_GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define LOCAL_GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_BUFFER_OES 0x9067 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 +#define LOCAL_GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define LOCAL_GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define LOCAL_GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x906A +#define LOCAL_GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910D +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_BUFFER_OES 0x8DD8 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900F +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900F +#define LOCAL_GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 +#define LOCAL_GL_UNSIGNED_INT_VEC2 0x8DC6 +#define LOCAL_GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define LOCAL_GL_UNSIGNED_INT_VEC3 0x8DC7 +#define LOCAL_GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define LOCAL_GL_UNSIGNED_INT_VEC4 0x8DC8 +#define LOCAL_GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define LOCAL_GL_UNSIGNED_INVERT_NV 0x8537 +#define LOCAL_GL_UNSIGNED_NORMALIZED 0x8C17 +#define LOCAL_GL_UNSIGNED_NORMALIZED_ARB 0x8C17 +#define LOCAL_GL_UNSIGNED_NORMALIZED_EXT 0x8C17 +#define LOCAL_GL_UNSIGNED_SHORT 0x1403 +#define LOCAL_GL_UNSIGNED_SHORT_15_1_MESA 0x8753 +#define LOCAL_GL_UNSIGNED_SHORT_1_15_REV_MESA 0x8754 +#define LOCAL_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define LOCAL_GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 +#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 +#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365 +#define LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define LOCAL_GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define LOCAL_GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define LOCAL_GL_UNSIGNED_SHORT_5_6_5_EXT 0x8363 +#define LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV_EXT 0x8364 +#define LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define LOCAL_GL_UNSIGNED_SHORT_8_8_MESA 0x85BA +#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB +#define LOCAL_GL_UPLOAD_GPU_MASK_NVX 0x954A +#define LOCAL_GL_UPPER_LEFT 0x8CA2 +#define LOCAL_GL_UPPER_LEFT_EXT 0x8CA2 +#define LOCAL_GL_USE_MISSING_GLYPH_NV 0x90AA +#define LOCAL_GL_UTF16_NV 0x909B +#define LOCAL_GL_UTF8_NV 0x909A +#define LOCAL_GL_UUID_SIZE_EXT 16 +#define LOCAL_GL_V2F 0x2A20 +#define LOCAL_GL_V3F 0x2A21 +#define LOCAL_GL_VALIDATE_SHADER_BINARY_QCOM 0x96A3 +#define LOCAL_GL_VALIDATE_STATUS 0x8B83 +#define LOCAL_GL_VARIABLE_A_NV 0x8523 +#define LOCAL_GL_VARIABLE_B_NV 0x8524 +#define LOCAL_GL_VARIABLE_C_NV 0x8525 +#define LOCAL_GL_VARIABLE_D_NV 0x8526 +#define LOCAL_GL_VARIABLE_E_NV 0x8527 +#define LOCAL_GL_VARIABLE_F_NV 0x8528 +#define LOCAL_GL_VARIABLE_G_NV 0x8529 +#define LOCAL_GL_VARIANT_ARRAY_EXT 0x87E8 +#define LOCAL_GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define LOCAL_GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define LOCAL_GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define LOCAL_GL_VARIANT_DATATYPE_EXT 0x87E5 +#define LOCAL_GL_VARIANT_EXT 0x87C1 +#define LOCAL_GL_VARIANT_VALUE_EXT 0x87E4 +#define LOCAL_GL_VBO_FREE_MEMORY_ATI 0x87FB +#define LOCAL_GL_VECTOR_EXT 0x87BF +#define LOCAL_GL_VENDOR 0x1F00 +#define LOCAL_GL_VERSION 0x1F02 +#define LOCAL_GL_VERSION_ES_CL_1_0 1 +#define LOCAL_GL_VERSION_ES_CL_1_1 1 +#define LOCAL_GL_VERSION_ES_CM_1_1 1 +#define LOCAL_GL_VERTEX23_BIT_PGI 0x00000004 +#define LOCAL_GL_VERTEX4_BIT_PGI 0x00000008 +#define LOCAL_GL_VERTEX_ARRAY 0x8074 +#define LOCAL_GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 +#define LOCAL_GL_VERTEX_ARRAY_BINDING 0x85B5 +#define LOCAL_GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 +#define LOCAL_GL_VERTEX_ARRAY_BINDING_OES 0x85B5 +#define LOCAL_GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define LOCAL_GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define LOCAL_GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define LOCAL_GL_VERTEX_ARRAY_EXT 0x8074 +#define LOCAL_GL_VERTEX_ARRAY_KHR 0x8074 +#define LOCAL_GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B +#define LOCAL_GL_VERTEX_ARRAY_LIST_IBM 103070 +#define LOCAL_GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 +#define LOCAL_GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 +#define LOCAL_GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +#define LOCAL_GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 +#define LOCAL_GL_VERTEX_ARRAY_POINTER 0x808E +#define LOCAL_GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define LOCAL_GL_VERTEX_ARRAY_RANGE_APPLE 0x851D +#define LOCAL_GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E +#define LOCAL_GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E +#define LOCAL_GL_VERTEX_ARRAY_RANGE_NV 0x851D +#define LOCAL_GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 +#define LOCAL_GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 +#define LOCAL_GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F +#define LOCAL_GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 +#define LOCAL_GL_VERTEX_ARRAY_SIZE 0x807A +#define LOCAL_GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define LOCAL_GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F +#define LOCAL_GL_VERTEX_ARRAY_STRIDE 0x807C +#define LOCAL_GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define LOCAL_GL_VERTEX_ARRAY_TYPE 0x807B +#define LOCAL_GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT 0x88FE +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E +#define LOCAL_GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define LOCAL_GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 +#define LOCAL_GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 +#define LOCAL_GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 +#define LOCAL_GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 +#define LOCAL_GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 +#define LOCAL_GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 +#define LOCAL_GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 +#define LOCAL_GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 +#define LOCAL_GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 +#define LOCAL_GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 +#define LOCAL_GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define LOCAL_GL_VERTEX_BINDING_BUFFER 0x8F4F +#define LOCAL_GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define LOCAL_GL_VERTEX_BINDING_OFFSET 0x82D7 +#define LOCAL_GL_VERTEX_BINDING_STRIDE 0x82D8 +#define LOCAL_GL_VERTEX_BLEND_ARB 0x86A7 +#define LOCAL_GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B +#define LOCAL_GL_VERTEX_DATA_HINT_PGI 0x1A22A +#define LOCAL_GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 +#define LOCAL_GL_VERTEX_ID_NV 0x8C7B +#define LOCAL_GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 +#define LOCAL_GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF +#define LOCAL_GL_VERTEX_PRECLIP_SGIX 0x83EE +#define LOCAL_GL_VERTEX_PROGRAM_ARB 0x8620 +#define LOCAL_GL_VERTEX_PROGRAM_BINDING_NV 0x864A +#define LOCAL_GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA 0x8BB7 +#define LOCAL_GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA 0x8BB6 +#define LOCAL_GL_VERTEX_PROGRAM_CALLBACK_MESA 0x8BB5 +#define LOCAL_GL_VERTEX_PROGRAM_NV 0x8620 +#define LOCAL_GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 +#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 +#define LOCAL_GL_VERTEX_PROGRAM_POSITION_MESA 0x8BB4 +#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 +#define LOCAL_GL_VERTEX_SHADER 0x8B31 +#define LOCAL_GL_VERTEX_SHADER_ARB 0x8B31 +#define LOCAL_GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define LOCAL_GL_VERTEX_SHADER_BIT 0x00000001 +#define LOCAL_GL_VERTEX_SHADER_BIT_EXT 0x00000001 +#define LOCAL_GL_VERTEX_SHADER_EXT 0x8780 +#define LOCAL_GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define LOCAL_GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define LOCAL_GL_VERTEX_SHADER_INVOCATIONS 0x82F0 +#define LOCAL_GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 +#define LOCAL_GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define LOCAL_GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define LOCAL_GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define LOCAL_GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define LOCAL_GL_VERTEX_SOURCE_ATI 0x8774 +#define LOCAL_GL_VERTEX_STATE_PROGRAM_NV 0x8621 +#define LOCAL_GL_VERTEX_STREAM0_ATI 0x876C +#define LOCAL_GL_VERTEX_STREAM1_ATI 0x876D +#define LOCAL_GL_VERTEX_STREAM2_ATI 0x876E +#define LOCAL_GL_VERTEX_STREAM3_ATI 0x876F +#define LOCAL_GL_VERTEX_STREAM4_ATI 0x8770 +#define LOCAL_GL_VERTEX_STREAM5_ATI 0x8771 +#define LOCAL_GL_VERTEX_STREAM6_ATI 0x8772 +#define LOCAL_GL_VERTEX_STREAM7_ATI 0x8773 +#define LOCAL_GL_VERTEX_SUBROUTINE 0x92E8 +#define LOCAL_GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define LOCAL_GL_VERTEX_TEXTURE 0x829B +#define LOCAL_GL_VERTEX_WEIGHTING_EXT 0x8509 +#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C +#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 +#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D +#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F +#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E +#define LOCAL_GL_VERTICAL_LINE_TO_NV 0x08 +#define LOCAL_GL_VERTICES_SUBMITTED 0x82EE +#define LOCAL_GL_VERTICES_SUBMITTED_ARB 0x82EE +#define LOCAL_GL_VIBRANCE_BIAS_NV 0x8719 +#define LOCAL_GL_VIBRANCE_SCALE_NV 0x8713 +#define LOCAL_GL_VIDEO_BUFFER_BINDING_NV 0x9021 +#define LOCAL_GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D +#define LOCAL_GL_VIDEO_BUFFER_NV 0x9020 +#define LOCAL_GL_VIDEO_BUFFER_PITCH_NV 0x9028 +#define LOCAL_GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B +#define LOCAL_GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A +#define LOCAL_GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 +#define LOCAL_GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 +#define LOCAL_GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C +#define LOCAL_GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 +#define LOCAL_GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 +#define LOCAL_GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A +#define LOCAL_GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B +#define LOCAL_GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C +#define LOCAL_GL_VIEWPORT 0x0BA2 +#define LOCAL_GL_VIEWPORT_BIT 0x00000800 +#define LOCAL_GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define LOCAL_GL_VIEWPORT_BOUNDS_RANGE_EXT 0x825D +#define LOCAL_GL_VIEWPORT_BOUNDS_RANGE_NV 0x825D +#define LOCAL_GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D +#define LOCAL_GL_VIEWPORT_COMMAND_NV 0x0010 +#define LOCAL_GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define LOCAL_GL_VIEWPORT_INDEX_PROVOKING_VERTEX_EXT 0x825F +#define LOCAL_GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV 0x825F +#define LOCAL_GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F +#define LOCAL_GL_VIEWPORT_POSITION_W_SCALE_NV 0x937C +#define LOCAL_GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D +#define LOCAL_GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E +#define LOCAL_GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define LOCAL_GL_VIEWPORT_SUBPIXEL_BITS_EXT 0x825C +#define LOCAL_GL_VIEWPORT_SUBPIXEL_BITS_NV 0x825C +#define LOCAL_GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C +#define LOCAL_GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357 +#define LOCAL_GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351 +#define LOCAL_GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353 +#define LOCAL_GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355 +#define LOCAL_GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356 +#define LOCAL_GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350 +#define LOCAL_GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352 +#define LOCAL_GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354 +#define LOCAL_GL_VIEWPORT_SWIZZLE_W_NV 0x935B +#define LOCAL_GL_VIEWPORT_SWIZZLE_X_NV 0x9358 +#define LOCAL_GL_VIEWPORT_SWIZZLE_Y_NV 0x9359 +#define LOCAL_GL_VIEWPORT_SWIZZLE_Z_NV 0x935A +#define LOCAL_GL_VIEW_CLASS_128_BITS 0x82C4 +#define LOCAL_GL_VIEW_CLASS_16_BITS 0x82CA +#define LOCAL_GL_VIEW_CLASS_24_BITS 0x82C9 +#define LOCAL_GL_VIEW_CLASS_32_BITS 0x82C8 +#define LOCAL_GL_VIEW_CLASS_48_BITS 0x82C7 +#define LOCAL_GL_VIEW_CLASS_64_BITS 0x82C6 +#define LOCAL_GL_VIEW_CLASS_8_BITS 0x82CB +#define LOCAL_GL_VIEW_CLASS_96_BITS 0x82C5 +#define LOCAL_GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393 +#define LOCAL_GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390 +#define LOCAL_GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391 +#define LOCAL_GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392 +#define LOCAL_GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394 +#define LOCAL_GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395 +#define LOCAL_GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388 +#define LOCAL_GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389 +#define LOCAL_GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A +#define LOCAL_GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B +#define LOCAL_GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C +#define LOCAL_GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D +#define LOCAL_GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E +#define LOCAL_GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F +#define LOCAL_GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define LOCAL_GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define LOCAL_GL_VIEW_CLASS_EAC_R11 0x9383 +#define LOCAL_GL_VIEW_CLASS_EAC_RG11 0x9384 +#define LOCAL_GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387 +#define LOCAL_GL_VIEW_CLASS_ETC2_RGB 0x9385 +#define LOCAL_GL_VIEW_CLASS_ETC2_RGBA 0x9386 +#define LOCAL_GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define LOCAL_GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define LOCAL_GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define LOCAL_GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define LOCAL_GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define LOCAL_GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define LOCAL_GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_INDEX_EXT 0x91A7 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_X_EXT 0x9195 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Y_EXT 0x9196 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define LOCAL_GL_VIRTUAL_PAGE_SIZE_Z_EXT 0x9197 +#define LOCAL_GL_VIVIDLIGHT_NV 0x92A6 +#define LOCAL_GL_VOLATILE_APPLE 0x8A1A +#define LOCAL_GL_WAIT_FAILED 0x911D +#define LOCAL_GL_WAIT_FAILED_APPLE 0x911D +#define LOCAL_GL_WARPS_PER_SM_NV 0x933A +#define LOCAL_GL_WARP_SIZE_NV 0x9339 +#define LOCAL_GL_WEIGHTED_AVERAGE_ARB 0x9367 +#define LOCAL_GL_WEIGHTED_AVERAGE_EXT 0x9367 +#define LOCAL_GL_WEIGHT_ARRAY_ARB 0x86AD +#define LOCAL_GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define LOCAL_GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define LOCAL_GL_WEIGHT_ARRAY_BUFFER_BINDING_OES 0x889E +#define LOCAL_GL_WEIGHT_ARRAY_OES 0x86AD +#define LOCAL_GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC +#define LOCAL_GL_WEIGHT_ARRAY_POINTER_OES 0x86AC +#define LOCAL_GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB +#define LOCAL_GL_WEIGHT_ARRAY_SIZE_OES 0x86AB +#define LOCAL_GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA +#define LOCAL_GL_WEIGHT_ARRAY_STRIDE_OES 0x86AA +#define LOCAL_GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 +#define LOCAL_GL_WEIGHT_ARRAY_TYPE_OES 0x86A9 +#define LOCAL_GL_WEIGHT_SUM_UNITY_ARB 0x86A6 +#define LOCAL_GL_WIDE_LINE_HINT_PGI 0x1A222 +#define LOCAL_GL_WINDOW_RECTANGLE_EXT 0x8F12 +#define LOCAL_GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 +#define LOCAL_GL_WRAP_BORDER_SUN 0x81D4 +#define LOCAL_GL_WRITEONLY_RENDERING_QCOM 0x8823 +#define LOCAL_GL_WRITE_DISCARD_NV 0x88BE +#define LOCAL_GL_WRITE_ONLY 0x88B9 +#define LOCAL_GL_WRITE_ONLY_ARB 0x88B9 +#define LOCAL_GL_WRITE_ONLY_OES 0x88B9 +#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A +#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 +#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C +#define LOCAL_GL_W_EXT 0x87D8 +#define LOCAL_GL_XOR 0x1506 +#define LOCAL_GL_XOR_NV 0x1506 +#define LOCAL_GL_X_EXT 0x87D5 +#define LOCAL_GL_YCBAYCR8A_4224_NV 0x9032 +#define LOCAL_GL_YCBCR_422_APPLE 0x85B9 +#define LOCAL_GL_YCBCR_MESA 0x8757 +#define LOCAL_GL_YCBYCR8_422_NV 0x9031 +#define LOCAL_GL_YCRCBA_SGIX 0x8319 +#define LOCAL_GL_YCRCB_422_SGIX 0x81BB +#define LOCAL_GL_YCRCB_444_SGIX 0x81BC +#define LOCAL_GL_YCRCB_SGIX 0x8318 +#define LOCAL_GL_Y_EXT 0x87D6 +#define LOCAL_GL_Z400_BINARY_AMD 0x8740 +#define LOCAL_GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 +#define LOCAL_GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 +#define LOCAL_GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 +#define LOCAL_GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 +#define LOCAL_GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 +#define LOCAL_GL_ZERO 0 +#define LOCAL_GL_ZERO_EXT 0x87DD +#define LOCAL_GL_ZERO_TO_ONE 0x935F +#define LOCAL_GL_ZERO_TO_ONE_EXT 0x935F +#define LOCAL_GL_ZOOM_X 0x0D16 +#define LOCAL_GL_ZOOM_Y 0x0D17 +#define LOCAL_GL_Z_EXT 0x87D7 + +// EGL +#define LOCAL_EGL_ALPHA_FORMAT 0x3088 +#define LOCAL_EGL_ALPHA_FORMAT_NONPRE 0x308B +#define LOCAL_EGL_ALPHA_FORMAT_PRE 0x308C +#define LOCAL_EGL_ALPHA_MASK_SIZE 0x303E +#define LOCAL_EGL_ALPHA_SIZE 0x3021 +#define LOCAL_EGL_ALREADY_SIGNALED_NV 0x30EA +#define LOCAL_EGL_AUTO_STEREO_NV 0x3136 +#define LOCAL_EGL_BACK_BUFFER 0x3084 +#define LOCAL_EGL_BAD_ACCESS 0x3002 +#define LOCAL_EGL_BAD_ALLOC 0x3003 +#define LOCAL_EGL_BAD_ATTRIBUTE 0x3004 +#define LOCAL_EGL_BAD_CONFIG 0x3005 +#define LOCAL_EGL_BAD_CONTEXT 0x3006 +#define LOCAL_EGL_BAD_CURRENT_SURFACE 0x3007 +#define LOCAL_EGL_BAD_DEVICE_EXT 0x322B +#define LOCAL_EGL_BAD_DISPLAY 0x3008 +#define LOCAL_EGL_BAD_MATCH 0x3009 +#define LOCAL_EGL_BAD_NATIVE_PIXMAP 0x300A +#define LOCAL_EGL_BAD_NATIVE_WINDOW 0x300B +#define LOCAL_EGL_BAD_OUTPUT_LAYER_EXT 0x322D +#define LOCAL_EGL_BAD_OUTPUT_PORT_EXT 0x322E +#define LOCAL_EGL_BAD_PARAMETER 0x300C +#define LOCAL_EGL_BAD_STATE_KHR 0x321C +#define LOCAL_EGL_BAD_STREAM_KHR 0x321B +#define LOCAL_EGL_BAD_SURFACE 0x300D +#define LOCAL_EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define LOCAL_EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define LOCAL_EGL_BITMAP_ORIGIN_KHR 0x30C8 +#define LOCAL_EGL_BITMAP_PITCH_KHR 0x30C7 +#define LOCAL_EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC +#define LOCAL_EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB +#define LOCAL_EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA +#define LOCAL_EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD +#define LOCAL_EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 +#define LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 +#define LOCAL_EGL_BITMAP_POINTER_KHR 0x30C6 +#define LOCAL_EGL_BLUE_SIZE 0x3022 +#define LOCAL_EGL_BOTTOM_NV 0x336E +#define LOCAL_EGL_BUFFER_AGE_EXT 0x313D +#define LOCAL_EGL_BUFFER_AGE_KHR 0x313D +#define LOCAL_EGL_BUFFER_COUNT_NV 0x321D +#define LOCAL_EGL_BUFFER_DESTROYED 0x3095 +#define LOCAL_EGL_BUFFER_PRESERVED 0x3094 +#define LOCAL_EGL_BUFFER_SIZE 0x3020 +#define LOCAL_EGL_CLIENT_APIS 0x308D +#define LOCAL_EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74 +#define LOCAL_EGL_CL_EVENT_HANDLE 0x309C +#define LOCAL_EGL_CL_EVENT_HANDLE_KHR 0x309C +#define LOCAL_EGL_COLORSPACE 0x3087 +#define LOCAL_EGL_COLORSPACE_LINEAR 0x308A +#define LOCAL_EGL_COLORSPACE_sRGB 0x3089 +#define LOCAL_EGL_COLOR_ARGB_HI 0x8F73 +#define LOCAL_EGL_COLOR_BUFFER_TYPE 0x303F +#define LOCAL_EGL_COLOR_COMPONENT_TYPE_EXT 0x3339 +#define LOCAL_EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A +#define LOCAL_EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B +#define LOCAL_EGL_COLOR_COMPONENT_TYPE_INTEGER_ARM 0x3288 +#define LOCAL_EGL_COLOR_COMPONENT_TYPE_UNSIGNED_INTEGER_ARM 0x3287 +#define LOCAL_EGL_COLOR_FORMAT_HI 0x8F70 +#define LOCAL_EGL_COLOR_RGBA_HI 0x8F72 +#define LOCAL_EGL_COLOR_RGB_HI 0x8F71 +#define LOCAL_EGL_COMPOSITE_DEADLINE_ANDROID 0x3431 +#define LOCAL_EGL_COMPOSITE_INTERVAL_ANDROID 0x3432 +#define LOCAL_EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433 +#define LOCAL_EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436 +#define LOCAL_EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462 +#define LOCAL_EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463 +#define LOCAL_EGL_CONDITION_SATISFIED 0x30F6 +#define LOCAL_EGL_CONDITION_SATISFIED_KHR 0x30F6 +#define LOCAL_EGL_CONDITION_SATISFIED_NV 0x30EC +#define LOCAL_EGL_CONFIG_CAVEAT 0x3027 +#define LOCAL_EGL_CONFIG_ID 0x3028 +#define LOCAL_EGL_CONFIG_SELECT_GROUP_EXT 0x34C0 +#define LOCAL_EGL_CONFORMANT 0x3042 +#define LOCAL_EGL_CONFORMANT_KHR 0x3042 +#define LOCAL_EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E +#define LOCAL_EGL_CONSUMER_AUTO_ORIENTATION_NV 0x3369 +#define LOCAL_EGL_CONSUMER_FRAME_KHR 0x3213 +#define LOCAL_EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 +#define LOCAL_EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338 +#define LOCAL_EGL_CONSUMER_METADATA_NV 0x3254 +#define LOCAL_EGL_CONTEXT_CLIENT_TYPE 0x3097 +#define LOCAL_EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define LOCAL_EGL_CONTEXT_FLAGS_KHR 0x30FC +#define LOCAL_EGL_CONTEXT_LOST 0x300E +#define LOCAL_EGL_CONTEXT_MAJOR_VERSION 0x3098 +#define LOCAL_EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define LOCAL_EGL_CONTEXT_MINOR_VERSION 0x30FB +#define LOCAL_EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 +#define LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define LOCAL_EGL_CONTEXT_OPENGL_DEBUG 0x31B0 +#define LOCAL_EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define LOCAL_EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 +#define LOCAL_EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 +#define LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD +#define LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD +#define LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 +#define LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define LOCAL_EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 +#define LOCAL_EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 +#define LOCAL_EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 +#define LOCAL_EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 +#define LOCAL_EGL_CONTEXT_PRIORITY_REALTIME_NV 0x3357 +#define LOCAL_EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 +#define LOCAL_EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define LOCAL_EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define LOCAL_EGL_CORE_NATIVE_ENGINE 0x305B +#define LOCAL_EGL_COVERAGE_BUFFERS_NV 0x30E0 +#define LOCAL_EGL_COVERAGE_SAMPLES_NV 0x30E1 +#define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 +#define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 +#define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 +#define LOCAL_EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360 +#define LOCAL_EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361 +#define LOCAL_EGL_CUDA_DEVICE_NV 0x323A +#define LOCAL_EGL_CUDA_EVENT_HANDLE_NV 0x323B +#define LOCAL_EGL_D3D11_DEVICE_ANGLE 0x33A1 +#define LOCAL_EGL_D3D9_DEVICE_ANGLE 0x33A0 +#define LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 +#define LOCAL_EGL_DEBUG_CALLBACK_KHR 0x33B8 +#define LOCAL_EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9 +#define LOCAL_EGL_DEBUG_MSG_ERROR_KHR 0x33BA +#define LOCAL_EGL_DEBUG_MSG_INFO_KHR 0x33BC +#define LOCAL_EGL_DEBUG_MSG_WARN_KHR 0x33BB +#define LOCAL_EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) +#define LOCAL_EGL_DEPTH_ENCODING_NONE_NV 0 +#define LOCAL_EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 +#define LOCAL_EGL_DEPTH_ENCODING_NV 0x30E2 +#define LOCAL_EGL_DEPTH_SIZE 0x3025 +#define LOCAL_EGL_DEQUEUE_READY_TIME_ANDROID 0x343B +#define LOCAL_EGL_DEVICE_EXT 0x322C +#define LOCAL_EGL_DEVICE_UUID_EXT 0x335C +#define LOCAL_EGL_DISCARD_SAMPLES_ARM 0x3286 +#define LOCAL_EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A +#define LOCAL_EGL_DISPLAY_SCALING 10000 +#define LOCAL_EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 +#define LOCAL_EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define LOCAL_EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define LOCAL_EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 +#define LOCAL_EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 +#define LOCAL_EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 +#define LOCAL_EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define LOCAL_EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define LOCAL_EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 +#define LOCAL_EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 +#define LOCAL_EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 +#define LOCAL_EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define LOCAL_EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define LOCAL_EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 +#define LOCAL_EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A +#define LOCAL_EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define LOCAL_EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A +#define LOCAL_EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define LOCAL_EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define LOCAL_EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define LOCAL_EGL_DONT_CARE EGL_CAST(EGLint,-1) +#define LOCAL_EGL_DRAW 0x3059 +#define LOCAL_EGL_DRIVER_NAME_EXT 0x335E +#define LOCAL_EGL_DRIVER_UUID_EXT 0x335D +#define LOCAL_EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 +#define LOCAL_EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 +#define LOCAL_EGL_DRM_BUFFER_MESA 0x31D3 +#define LOCAL_EGL_DRM_BUFFER_STRIDE_MESA 0x31D4 +#define LOCAL_EGL_DRM_BUFFER_USE_CURSOR_MESA 0x00000004 +#define LOCAL_EGL_DRM_BUFFER_USE_MESA 0x31D1 +#define LOCAL_EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 +#define LOCAL_EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 +#define LOCAL_EGL_DRM_CONNECTOR_EXT 0x3236 +#define LOCAL_EGL_DRM_CRTC_EXT 0x3234 +#define LOCAL_EGL_DRM_DEVICE_FILE_EXT 0x3233 +#define LOCAL_EGL_DRM_MASTER_FD_EXT 0x333C +#define LOCAL_EGL_DRM_PLANE_EXT 0x3235 +#define LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT 0x3377 +#define LOCAL_EGL_EXTENSIONS 0x3055 +#define LOCAL_EGL_EXTERNAL_REF_ID_EXT 0x3461 +#define LOCAL_EGL_FALSE 0 +#define LOCAL_EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439 +#define LOCAL_EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437 +#define LOCAL_EGL_FIXED_SIZE_ANGLE 0x3201 +#define LOCAL_EGL_FOREVER 0xFFFFFFFFFFFFFFFF +#define LOCAL_EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFF +#define LOCAL_EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFF +#define LOCAL_EGL_FORMAT_ASTC_10X10_QCOM 0x33ED +#define LOCAL_EGL_FORMAT_ASTC_10X10_SRGB_QCOM 0x340B +#define LOCAL_EGL_FORMAT_ASTC_10X5_QCOM 0x33EA +#define LOCAL_EGL_FORMAT_ASTC_10X5_SRGB_QCOM 0x3408 +#define LOCAL_EGL_FORMAT_ASTC_10X6_QCOM 0x33EB +#define LOCAL_EGL_FORMAT_ASTC_10X6_SRGB_QCOM 0x3409 +#define LOCAL_EGL_FORMAT_ASTC_10X8_QCOM 0x33EC +#define LOCAL_EGL_FORMAT_ASTC_10X8_SRGB_QCOM 0x340A +#define LOCAL_EGL_FORMAT_ASTC_12X10_QCOM 0x33EE +#define LOCAL_EGL_FORMAT_ASTC_12X10_SRGB_QCOM 0x340C +#define LOCAL_EGL_FORMAT_ASTC_12X12_QCOM 0x33EF +#define LOCAL_EGL_FORMAT_ASTC_12X12_SRGB_QCOM 0x340D +#define LOCAL_EGL_FORMAT_ASTC_4X4_QCOM 0x33E2 +#define LOCAL_EGL_FORMAT_ASTC_4X4_SRGB_QCOM 0x3400 +#define LOCAL_EGL_FORMAT_ASTC_5X4_QCOM 0x33E3 +#define LOCAL_EGL_FORMAT_ASTC_5X4_SRGB_QCOM 0x3401 +#define LOCAL_EGL_FORMAT_ASTC_5X5_QCOM 0x33E4 +#define LOCAL_EGL_FORMAT_ASTC_5X5_SRGB_QCOM 0x3402 +#define LOCAL_EGL_FORMAT_ASTC_6X5_QCOM 0x33E5 +#define LOCAL_EGL_FORMAT_ASTC_6X5_SRGB_QCOM 0x3403 +#define LOCAL_EGL_FORMAT_ASTC_6X6_QCOM 0x33E6 +#define LOCAL_EGL_FORMAT_ASTC_6X6_SRGB_QCOM 0x3404 +#define LOCAL_EGL_FORMAT_ASTC_8X5_QCOM 0x33E7 +#define LOCAL_EGL_FORMAT_ASTC_8X5_SRGB_QCOM 0x3405 +#define LOCAL_EGL_FORMAT_ASTC_8X6_QCOM 0x33E8 +#define LOCAL_EGL_FORMAT_ASTC_8X6_SRGB_QCOM 0x3406 +#define LOCAL_EGL_FORMAT_ASTC_8X8_QCOM 0x33E9 +#define LOCAL_EGL_FORMAT_ASTC_8X8_SRGB_QCOM 0x3407 +#define LOCAL_EGL_FORMAT_BGRA_8888_QCOM 0x3129 +#define LOCAL_EGL_FORMAT_BGRX_8888_QCOM 0x312A +#define LOCAL_EGL_FORMAT_FLAG_MACROTILE_QCOM 0x33E1 +#define LOCAL_EGL_FORMAT_FLAG_QCOM 0x31CF +#define LOCAL_EGL_FORMAT_FLAG_UBWC_QCOM 0x33E0 +#define LOCAL_EGL_FORMAT_IYUV_QCOM 0x31C7 +#define LOCAL_EGL_FORMAT_NV12_4R_QCOM 0x3412 +#define LOCAL_EGL_FORMAT_NV12_4R_UV_QCOM 0x3414 +#define LOCAL_EGL_FORMAT_NV12_4R_Y_QCOM 0x3413 +#define LOCAL_EGL_FORMAT_NV12_QCOM 0x31C2 +#define LOCAL_EGL_FORMAT_NV12_TILED_QCOM 0x3128 +#define LOCAL_EGL_FORMAT_NV12_UV_QCOM 0x3410 +#define LOCAL_EGL_FORMAT_NV12_Y_QCOM 0x340F +#define LOCAL_EGL_FORMAT_NV21_QCOM 0x3127 +#define LOCAL_EGL_FORMAT_NV21_VU_QCOM 0x3411 +#define LOCAL_EGL_FORMAT_P010_QCOM 0x3415 +#define LOCAL_EGL_FORMAT_P010_UV_QCOM 0x3417 +#define LOCAL_EGL_FORMAT_P010_Y_QCOM 0x3416 +#define LOCAL_EGL_FORMAT_R8_QCOM 0x31C0 +#define LOCAL_EGL_FORMAT_RG88_QCOM 0x31C1 +#define LOCAL_EGL_FORMAT_RGBA_1010102_QCOM 0x31CE +#define LOCAL_EGL_FORMAT_RGBA_16_FLOAT_QCOM 0x31CD +#define LOCAL_EGL_FORMAT_RGBA_4444_QCOM 0x31CA +#define LOCAL_EGL_FORMAT_RGBA_5551_QCOM 0x31C9 +#define LOCAL_EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 +#define LOCAL_EGL_FORMAT_RGBA_8888_KHR 0x30C3 +#define LOCAL_EGL_FORMAT_RGBA_8888_QCOM 0x3122 +#define LOCAL_EGL_FORMAT_RGBX_8888_QCOM 0x312F +#define LOCAL_EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 +#define LOCAL_EGL_FORMAT_RGB_565_KHR 0x30C1 +#define LOCAL_EGL_FORMAT_RGB_565_QCOM 0x3123 +#define LOCAL_EGL_FORMAT_RGB_888_QCOM 0x31C8 +#define LOCAL_EGL_FORMAT_RG_1616_FLOAT_QCOM 0x31CC +#define LOCAL_EGL_FORMAT_R_16_FLOAT_QCOM 0x31CB +#define LOCAL_EGL_FORMAT_SRGBA_8888_QCOM 0x31C4 +#define LOCAL_EGL_FORMAT_SRGBX_8888_QCOM 0x31C3 +#define LOCAL_EGL_FORMAT_TP10_QCOM 0x340E +#define LOCAL_EGL_FORMAT_TP10_UV_QCOM 0x3419 +#define LOCAL_EGL_FORMAT_TP10_Y_QCOM 0x3418 +#define LOCAL_EGL_FORMAT_UYVY_QCOM 0x3125 +#define LOCAL_EGL_FORMAT_VYUY_QCOM 0x31C6 +#define LOCAL_EGL_FORMAT_YUYV_QCOM 0x3124 +#define LOCAL_EGL_FORMAT_YV12_QCOM 0x3126 +#define LOCAL_EGL_FORMAT_YVYU_QCOM 0x31C5 +#define LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 +#define LOCAL_EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C +#define LOCAL_EGL_FRONT_BUFFER_EXT 0x3464 +#define LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C +#define LOCAL_EGL_GENERIC_TOKEN_1_QCOM 0x3420 +#define LOCAL_EGL_GENERIC_TOKEN_2_QCOM 0x3421 +#define LOCAL_EGL_GENERIC_TOKEN_3_QCOM 0x3422 +#define LOCAL_EGL_GL_COLORSPACE 0x309D +#define LOCAL_EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F +#define LOCAL_EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340 +#define LOCAL_EGL_GL_COLORSPACE_DEFAULT_EXT 0x314D +#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363 +#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362 +#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490 +#define LOCAL_EGL_GL_COLORSPACE_KHR 0x309D +#define LOCAL_EGL_GL_COLORSPACE_LINEAR 0x308A +#define LOCAL_EGL_GL_COLORSPACE_LINEAR_KHR 0x308A +#define LOCAL_EGL_GL_COLORSPACE_SCRGB_EXT 0x3351 +#define LOCAL_EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350 +#define LOCAL_EGL_GL_COLORSPACE_SRGB 0x3089 +#define LOCAL_EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define LOCAL_EGL_GL_RENDERBUFFER 0x30B9 +#define LOCAL_EGL_GL_RENDERBUFFER_KHR 0x30B9 +#define LOCAL_EGL_GL_TEXTURE_2D 0x30B1 +#define LOCAL_EGL_GL_TEXTURE_2D_KHR 0x30B1 +#define LOCAL_EGL_GL_TEXTURE_3D 0x30B2 +#define LOCAL_EGL_GL_TEXTURE_3D_KHR 0x30B2 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 +#define LOCAL_EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 +#define LOCAL_EGL_GL_TEXTURE_LEVEL 0x30BC +#define LOCAL_EGL_GL_TEXTURE_LEVEL_KHR 0x30BC +#define LOCAL_EGL_GL_TEXTURE_ZOFFSET 0x30BD +#define LOCAL_EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD +#define LOCAL_EGL_GPU_PERF_HINT_QCOM 0x32D0 +#define LOCAL_EGL_GREEN_SIZE 0x3023 +#define LOCAL_EGL_HEIGHT 0x3056 +#define LOCAL_EGL_HINT_PERSISTENT_QCOM 0x32D1 +#define LOCAL_EGL_HORIZONTAL_RESOLUTION 0x3090 +#define LOCAL_EGL_IMAGE_FORMAT_QCOM 0x3121 +#define LOCAL_EGL_IMAGE_NUM_PLANES_QCOM 0x32B0 +#define LOCAL_EGL_IMAGE_PLANE_DEPTH_0_QCOM 0x32B4 +#define LOCAL_EGL_IMAGE_PLANE_DEPTH_1_QCOM 0x32B5 +#define LOCAL_EGL_IMAGE_PLANE_DEPTH_2_QCOM 0x32B6 +#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_0_QCOM 0x32BA +#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_1_QCOM 0x32BB +#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_2_QCOM 0x32BC +#define LOCAL_EGL_IMAGE_PLANE_PITCH_0_QCOM 0x32B1 +#define LOCAL_EGL_IMAGE_PLANE_PITCH_1_QCOM 0x32B2 +#define LOCAL_EGL_IMAGE_PLANE_PITCH_2_QCOM 0x32B3 +#define LOCAL_EGL_IMAGE_PLANE_POINTER_0_QCOM 0x32BD +#define LOCAL_EGL_IMAGE_PLANE_POINTER_1_QCOM 0x32BE +#define LOCAL_EGL_IMAGE_PLANE_POINTER_2_QCOM 0x32BF +#define LOCAL_EGL_IMAGE_PLANE_WIDTH_0_QCOM 0x32B7 +#define LOCAL_EGL_IMAGE_PLANE_WIDTH_1_QCOM 0x32B8 +#define LOCAL_EGL_IMAGE_PLANE_WIDTH_2_QCOM 0x32B9 +#define LOCAL_EGL_IMAGE_PRESERVED 0x30D2 +#define LOCAL_EGL_IMAGE_PRESERVED_KHR 0x30D2 +#define LOCAL_EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472 +#define LOCAL_EGL_IMPORT_IMPLICIT_SYNC_EXT 0x3471 +#define LOCAL_EGL_IMPORT_SYNC_TYPE_EXT 0x3470 +#define LOCAL_EGL_INTEROP_BIT_KHR 0x0010 +#define LOCAL_EGL_ITU_REC2020_EXT 0x3281 +#define LOCAL_EGL_ITU_REC601_EXT 0x327F +#define LOCAL_EGL_ITU_REC709_EXT 0x3280 +#define LOCAL_EGL_LARGEST_PBUFFER 0x3058 +#define LOCAL_EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438 +#define LOCAL_EGL_LEFT_NV 0x336B +#define LOCAL_EGL_LEVEL 0x3029 +#define LOCAL_EGL_LINUX_DMA_BUF_EXT 0x3270 +#define LOCAL_EGL_LINUX_DRM_FOURCC_EXT 0x3271 +#define LOCAL_EGL_LOCK_SURFACE_BIT_KHR 0x0080 +#define LOCAL_EGL_LOCK_USAGE_HINT_KHR 0x30C5 +#define LOCAL_EGL_LOSE_CONTEXT_ON_RESET 0x31BF +#define LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF +#define LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define LOCAL_EGL_LOWER_LEFT_KHR 0x30CE +#define LOCAL_EGL_LUMINANCE_BUFFER 0x308F +#define LOCAL_EGL_LUMINANCE_SIZE 0x303D +#define LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 +#define LOCAL_EGL_MATCH_FORMAT_KHR 0x3043 +#define LOCAL_EGL_MATCH_NATIVE_PIXMAP 0x3041 +#define LOCAL_EGL_MAX_PBUFFER_HEIGHT 0x302A +#define LOCAL_EGL_MAX_PBUFFER_PIXELS 0x302B +#define LOCAL_EGL_MAX_PBUFFER_WIDTH 0x302C +#define LOCAL_EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250 +#define LOCAL_EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251 +#define LOCAL_EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252 +#define LOCAL_EGL_MAX_SWAP_INTERVAL 0x303C +#define LOCAL_EGL_METADATA0_SIZE_NV 0x3255 +#define LOCAL_EGL_METADATA0_TYPE_NV 0x3259 +#define LOCAL_EGL_METADATA1_SIZE_NV 0x3256 +#define LOCAL_EGL_METADATA1_TYPE_NV 0x325A +#define LOCAL_EGL_METADATA2_SIZE_NV 0x3257 +#define LOCAL_EGL_METADATA2_TYPE_NV 0x325B +#define LOCAL_EGL_METADATA3_SIZE_NV 0x3258 +#define LOCAL_EGL_METADATA3_TYPE_NV 0x325C +#define LOCAL_EGL_METADATA_SCALING_EXT 50000 +#define LOCAL_EGL_MIN_SWAP_INTERVAL 0x303B +#define LOCAL_EGL_MIPMAP_LEVEL 0x3083 +#define LOCAL_EGL_MIPMAP_TEXTURE 0x3082 +#define LOCAL_EGL_MULTISAMPLE_RESOLVE 0x3099 +#define LOCAL_EGL_MULTISAMPLE_RESOLVE_BOX 0x309B +#define LOCAL_EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 +#define LOCAL_EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A +#define LOCAL_EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134 +#define LOCAL_EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000 +#define LOCAL_EGL_NATIVE_BUFFER_ANDROID 0x3140 +#define LOCAL_EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105 +#define LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106 +#define LOCAL_EGL_NATIVE_BUFFER_TIZEN 0x32A0 +#define LOCAL_EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 +#define LOCAL_EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 +#define LOCAL_EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 +#define LOCAL_EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 +#define LOCAL_EGL_NATIVE_PIXMAP_KHR 0x30B0 +#define LOCAL_EGL_NATIVE_RENDERABLE 0x302D +#define LOCAL_EGL_NATIVE_SURFACE_TIZEN 0x32A1 +#define LOCAL_EGL_NATIVE_VISUAL_ID 0x302E +#define LOCAL_EGL_NATIVE_VISUAL_TYPE 0x302F +#define LOCAL_EGL_NEW_IMAGE_QCOM 0x3120 +#define LOCAL_EGL_NONE 0x3038 +#define LOCAL_EGL_NON_CONFORMANT_CONFIG 0x3051 +#define LOCAL_EGL_NOT_INITIALIZED 0x3001 +#define LOCAL_EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) +#define LOCAL_EGL_NO_CONTEXT EGL_CAST(EGLContext,0) +#define LOCAL_EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0) +#define LOCAL_EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) +#define LOCAL_EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR,-1) +#define LOCAL_EGL_NO_IMAGE EGL_CAST(EGLImage,0) +#define LOCAL_EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0) +#define LOCAL_EGL_NO_NATIVE_FENCE_FD_ANDROID -1 +#define LOCAL_EGL_NO_OUTPUT_LAYER_EXT EGL_CAST(EGLOutputLayerEXT,0) +#define LOCAL_EGL_NO_OUTPUT_PORT_EXT EGL_CAST(EGLOutputPortEXT,0) +#define LOCAL_EGL_NO_RESET_NOTIFICATION 0x31BE +#define LOCAL_EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define LOCAL_EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define LOCAL_EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR,0) +#define LOCAL_EGL_NO_SURFACE EGL_CAST(EGLSurface,0) +#define LOCAL_EGL_NO_SYNC EGL_CAST(EGLSync,0) +#define LOCAL_EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR,0) +#define LOCAL_EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV,0) +#define LOCAL_EGL_NO_TEXTURE 0x305C +#define LOCAL_EGL_OBJECT_CONTEXT_KHR 0x33B2 +#define LOCAL_EGL_OBJECT_DISPLAY_KHR 0x33B1 +#define LOCAL_EGL_OBJECT_IMAGE_KHR 0x33B4 +#define LOCAL_EGL_OBJECT_STREAM_KHR 0x33B6 +#define LOCAL_EGL_OBJECT_SURFACE_KHR 0x33B3 +#define LOCAL_EGL_OBJECT_SYNC_KHR 0x33B5 +#define LOCAL_EGL_OBJECT_THREAD_KHR 0x33B0 +#define LOCAL_EGL_OPENGL_API 0x30A2 +#define LOCAL_EGL_OPENGL_BIT 0x0008 +#define LOCAL_EGL_OPENGL_ES2_BIT 0x0004 +#define LOCAL_EGL_OPENGL_ES3_BIT 0x00000040 +#define LOCAL_EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#define LOCAL_EGL_OPENGL_ES_API 0x30A0 +#define LOCAL_EGL_OPENGL_ES_BIT 0x0001 +#define LOCAL_EGL_OPENMAX_IL_BIT_KHR 0x0020 +#define LOCAL_EGL_OPENVG_API 0x30A1 +#define LOCAL_EGL_OPENVG_BIT 0x0002 +#define LOCAL_EGL_OPENVG_IMAGE 0x3096 +#define LOCAL_EGL_OPENWF_DEVICE_ID_EXT 0x3237 +#define LOCAL_EGL_OPENWF_PIPELINE_ID_EXT 0x3238 +#define LOCAL_EGL_OPENWF_PORT_ID_EXT 0x3239 +#define LOCAL_EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 +#define LOCAL_EGL_PBUFFER_BIT 0x0001 +#define LOCAL_EGL_PBUFFER_IMAGE_BIT_TAO 0x0008 +#define LOCAL_EGL_PBUFFER_PALETTE_IMAGE_BIT_TAO 0x0010 +#define LOCAL_EGL_PENDING_FRAME_NV 0x3329 +#define LOCAL_EGL_PENDING_METADATA_NV 0x3328 +#define LOCAL_EGL_PIXEL_ASPECT_RATIO 0x3092 +#define LOCAL_EGL_PIXMAP_BIT 0x0002 +#define LOCAL_EGL_PLATFORM_ANDROID_KHR 0x3141 +#define LOCAL_EGL_PLATFORM_DEVICE_EXT 0x313F +#define LOCAL_EGL_PLATFORM_GBM_KHR 0x31D7 +#define LOCAL_EGL_PLATFORM_GBM_MESA 0x31D7 +#define LOCAL_EGL_PLATFORM_SURFACELESS_MESA 0x31DD +#define LOCAL_EGL_PLATFORM_WAYLAND_EXT 0x31D8 +#define LOCAL_EGL_PLATFORM_WAYLAND_KHR 0x31D8 +#define LOCAL_EGL_PLATFORM_X11_EXT 0x31D5 +#define LOCAL_EGL_PLATFORM_X11_KHR 0x31D5 +#define LOCAL_EGL_PLATFORM_X11_SCREEN_EXT 0x31D6 +#define LOCAL_EGL_PLATFORM_X11_SCREEN_KHR 0x31D6 +#define LOCAL_EGL_PLATFORM_XCB_EXT 0x31DC +#define LOCAL_EGL_PLATFORM_XCB_SCREEN_EXT 0x31DE +#define LOCAL_EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE +#define LOCAL_EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460 +#define LOCAL_EGL_PRODUCER_AUTO_ORIENTATION_NV 0x336A +#define LOCAL_EGL_PRODUCER_FRAME_KHR 0x3212 +#define LOCAL_EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337 +#define LOCAL_EGL_PRODUCER_METADATA_NV 0x3253 +#define LOCAL_EGL_PROTECTED_CONTENT_EXT 0x32C0 +#define LOCAL_EGL_QUADRUPLE_BUFFER_NV 0x3231 +#define LOCAL_EGL_READ 0x305A +#define LOCAL_EGL_READS_DONE_TIME_ANDROID 0x343C +#define LOCAL_EGL_READ_SURFACE_BIT_KHR 0x0001 +#define LOCAL_EGL_RECORDABLE_ANDROID 0x3142 +#define LOCAL_EGL_RED_SIZE 0x3024 +#define LOCAL_EGL_RENDERABLE_TYPE 0x3040 +#define LOCAL_EGL_RENDERER_EXT 0x335F +#define LOCAL_EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435 +#define LOCAL_EGL_RENDER_BUFFER 0x3086 +#define LOCAL_EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434 +#define LOCAL_EGL_RGB_BUFFER 0x308E +#define LOCAL_EGL_RIGHT_NV 0x336C +#define LOCAL_EGL_SAMPLES 0x3031 +#define LOCAL_EGL_SAMPLE_BUFFERS 0x3032 +#define LOCAL_EGL_SAMPLE_RANGE_HINT_EXT 0x327C +#define LOCAL_EGL_SHARED_IMAGE_NOK 0x30DA +#define LOCAL_EGL_SIGNALED 0x30F2 +#define LOCAL_EGL_SIGNALED_KHR 0x30F2 +#define LOCAL_EGL_SIGNALED_NV 0x30E8 +#define LOCAL_EGL_SINGLE_BUFFER 0x3085 +#define LOCAL_EGL_SLOW_CONFIG 0x3050 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341 +#define LOCAL_EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342 +#define LOCAL_EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349 +#define LOCAL_EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A +#define LOCAL_EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347 +#define LOCAL_EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348 +#define LOCAL_EGL_SOCKET_HANDLE_NV 0x324C +#define LOCAL_EGL_SOCKET_TYPE_INET_NV 0x324F +#define LOCAL_EGL_SOCKET_TYPE_NV 0x324D +#define LOCAL_EGL_SOCKET_TYPE_UNIX_NV 0x324E +#define LOCAL_EGL_STENCIL_SIZE 0x3026 +#define LOCAL_EGL_STREAM_BIT_KHR 0x0800 +#define LOCAL_EGL_STREAM_CONSUMER_IMAGE_NV 0x3373 +#define LOCAL_EGL_STREAM_CONSUMER_NV 0x3248 +#define LOCAL_EGL_STREAM_CROSS_DISPLAY_NV 0x334E +#define LOCAL_EGL_STREAM_CROSS_OBJECT_NV 0x334D +#define LOCAL_EGL_STREAM_CROSS_PARTITION_NV 0x323F +#define LOCAL_EGL_STREAM_CROSS_PROCESS_NV 0x3245 +#define LOCAL_EGL_STREAM_CROSS_SYSTEM_NV 0x334F +#define LOCAL_EGL_STREAM_DMA_NV 0x3371 +#define LOCAL_EGL_STREAM_DMA_SERVER_NV 0x3372 +#define LOCAL_EGL_STREAM_ENDPOINT_NV 0x3243 +#define LOCAL_EGL_STREAM_FIFO_LENGTH_KHR 0x31FC +#define LOCAL_EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336 +#define LOCAL_EGL_STREAM_FRAME_MAJOR_AXIS_NV 0x3368 +#define LOCAL_EGL_STREAM_FRAME_ORIGIN_X_NV 0x3366 +#define LOCAL_EGL_STREAM_FRAME_ORIGIN_Y_NV 0x3367 +#define LOCAL_EGL_STREAM_IMAGE_ADD_NV 0x3374 +#define LOCAL_EGL_STREAM_IMAGE_AVAILABLE_NV 0x3376 +#define LOCAL_EGL_STREAM_IMAGE_REMOVE_NV 0x3375 +#define LOCAL_EGL_STREAM_LOCAL_NV 0x3244 +#define LOCAL_EGL_STREAM_PRODUCER_NV 0x3247 +#define LOCAL_EGL_STREAM_PROTOCOL_FD_NV 0x3246 +#define LOCAL_EGL_STREAM_PROTOCOL_NV 0x3242 +#define LOCAL_EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B +#define LOCAL_EGL_STREAM_STATE_CONNECTING_KHR 0x3216 +#define LOCAL_EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define LOCAL_EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A +#define LOCAL_EGL_STREAM_STATE_EMPTY_KHR 0x3217 +#define LOCAL_EGL_STREAM_STATE_INITIALIZING_NV 0x3240 +#define LOCAL_EGL_STREAM_STATE_KHR 0x3214 +#define LOCAL_EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 +#define LOCAL_EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 +#define LOCAL_EGL_STREAM_TIME_CONSUMER_KHR 0x31FE +#define LOCAL_EGL_STREAM_TIME_NOW_KHR 0x31FD +#define LOCAL_EGL_STREAM_TIME_PENDING_NV 0x332A +#define LOCAL_EGL_STREAM_TIME_PRODUCER_KHR 0x31FF +#define LOCAL_EGL_STREAM_TYPE_NV 0x3241 +#define LOCAL_EGL_SUCCESS 0x3000 +#define LOCAL_EGL_SUPPORT_RESET_NV 0x3334 +#define LOCAL_EGL_SUPPORT_REUSE_NV 0x3335 +#define LOCAL_EGL_SURFACE_TYPE 0x3033 +#define LOCAL_EGL_SWAP_BEHAVIOR 0x3093 +#define LOCAL_EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 +#define LOCAL_EGL_SWAP_INTERVAL_EXT 0x322F +#define LOCAL_EGL_SYNC_CLIENT_EXT 0x3364 +#define LOCAL_EGL_SYNC_CLIENT_SIGNAL_EXT 0x3365 +#define LOCAL_EGL_SYNC_CL_EVENT 0x30FE +#define LOCAL_EGL_SYNC_CL_EVENT_COMPLETE 0x30FF +#define LOCAL_EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF +#define LOCAL_EGL_SYNC_CL_EVENT_KHR 0x30FE +#define LOCAL_EGL_SYNC_CONDITION 0x30F8 +#define LOCAL_EGL_SYNC_CONDITION_KHR 0x30F8 +#define LOCAL_EGL_SYNC_CONDITION_NV 0x30EE +#define LOCAL_EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D +#define LOCAL_EGL_SYNC_CUDA_EVENT_NV 0x323C +#define LOCAL_EGL_SYNC_FENCE 0x30F9 +#define LOCAL_EGL_SYNC_FENCE_KHR 0x30F9 +#define LOCAL_EGL_SYNC_FENCE_NV 0x30EF +#define LOCAL_EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 +#define LOCAL_EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 +#define LOCAL_EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 +#define LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 +#define LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 +#define LOCAL_EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 +#define LOCAL_EGL_SYNC_NEW_FRAME_NV 0x321F +#define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 +#define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 +#define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 +#define LOCAL_EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A +#define LOCAL_EGL_SYNC_REUSABLE_KHR 0x30FA +#define LOCAL_EGL_SYNC_STATUS 0x30F1 +#define LOCAL_EGL_SYNC_STATUS_KHR 0x30F1 +#define LOCAL_EGL_SYNC_STATUS_NV 0x30E7 +#define LOCAL_EGL_SYNC_TYPE 0x30F7 +#define LOCAL_EGL_SYNC_TYPE_KHR 0x30F7 +#define LOCAL_EGL_SYNC_TYPE_NV 0x30ED +#define LOCAL_EGL_TEXTURE_2D 0x305F +#define LOCAL_EGL_TEXTURE_EXTERNAL_WL 0x31DA +#define LOCAL_EGL_TEXTURE_FORMAT 0x3080 +#define LOCAL_EGL_TEXTURE_RGB 0x305D +#define LOCAL_EGL_TEXTURE_RGBA 0x305E +#define LOCAL_EGL_TEXTURE_TARGET 0x3081 +#define LOCAL_EGL_TEXTURE_Y_UV_WL 0x31D8 +#define LOCAL_EGL_TEXTURE_Y_U_V_WL 0x31D7 +#define LOCAL_EGL_TEXTURE_Y_XUXV_WL 0x31D9 +#define LOCAL_EGL_TIMEOUT_EXPIRED 0x30F5 +#define LOCAL_EGL_TIMEOUT_EXPIRED_KHR 0x30F5 +#define LOCAL_EGL_TIMEOUT_EXPIRED_NV 0x30EB +#define LOCAL_EGL_TIMESTAMPS_ANDROID 0x3430 +#define LOCAL_EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID,-1) +#define LOCAL_EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID,-2) +#define LOCAL_EGL_TOP_NV 0x336D +#define LOCAL_EGL_TRACK_REFERENCES_KHR 0x3352 +#define LOCAL_EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define LOCAL_EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define LOCAL_EGL_TRANSPARENT_RED_VALUE 0x3037 +#define LOCAL_EGL_TRANSPARENT_RGB 0x3052 +#define LOCAL_EGL_TRANSPARENT_TYPE 0x3034 +#define LOCAL_EGL_TRIPLE_BUFFER_NV 0x3230 +#define LOCAL_EGL_TRUE 1 +#define LOCAL_EGL_UNKNOWN EGL_CAST(EGLint,-1) +#define LOCAL_EGL_UNSIGNALED 0x30F3 +#define LOCAL_EGL_UNSIGNALED_KHR 0x30F3 +#define LOCAL_EGL_UNSIGNALED_NV 0x30E9 +#define LOCAL_EGL_UPPER_LEFT_KHR 0x30CF +#define LOCAL_EGL_VENDOR 0x3053 +#define LOCAL_EGL_VERSION 0x3054 +#define LOCAL_EGL_VERTICAL_RESOLUTION 0x3091 +#define LOCAL_EGL_VG_ALPHA_FORMAT 0x3088 +#define LOCAL_EGL_VG_ALPHA_FORMAT_NONPRE 0x308B +#define LOCAL_EGL_VG_ALPHA_FORMAT_PRE 0x308C +#define LOCAL_EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 +#define LOCAL_EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 +#define LOCAL_EGL_VG_COLORSPACE 0x3087 +#define LOCAL_EGL_VG_COLORSPACE_LINEAR 0x308A +#define LOCAL_EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 +#define LOCAL_EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 +#define LOCAL_EGL_VG_COLORSPACE_sRGB 0x3089 +#define LOCAL_EGL_VG_PARENT_IMAGE_KHR 0x30BA +#define LOCAL_EGL_WAYLAND_BUFFER_WL 0x31D5 +#define LOCAL_EGL_WAYLAND_PLANE_WL 0x31D6 +#define LOCAL_EGL_WAYLAND_Y_INVERTED_WL 0x31DB +#define LOCAL_EGL_WIDTH 0x3057 +#define LOCAL_EGL_WINDOW_BIT 0x0004 +#define LOCAL_EGL_WRITE_SURFACE_BIT_KHR 0x0002 +#define LOCAL_EGL_X_AXIS_NV 0x336F +#define LOCAL_EGL_YUV_BUFFER_EXT 0x3300 +#define LOCAL_EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D +#define LOCAL_EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285 +#define LOCAL_EGL_YUV_CHROMA_SITING_0_EXT 0x3284 +#define LOCAL_EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E +#define LOCAL_EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B +#define LOCAL_EGL_YUV_CSC_STANDARD_2020_EXT 0x330D +#define LOCAL_EGL_YUV_CSC_STANDARD_601_EXT 0x330B +#define LOCAL_EGL_YUV_CSC_STANDARD_709_EXT 0x330C +#define LOCAL_EGL_YUV_CSC_STANDARD_EXT 0x330A +#define LOCAL_EGL_YUV_DEPTH_RANGE_EXT 0x3317 +#define LOCAL_EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319 +#define LOCAL_EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318 +#define LOCAL_EGL_YUV_FULL_RANGE_EXT 0x3282 +#define LOCAL_EGL_YUV_NARROW_RANGE_EXT 0x3283 +#define LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311 +#define LOCAL_EGL_YUV_ORDER_AYUV_EXT 0x3308 +#define LOCAL_EGL_YUV_ORDER_EXT 0x3301 +#define LOCAL_EGL_YUV_ORDER_UYVY_EXT 0x3305 +#define LOCAL_EGL_YUV_ORDER_VYUY_EXT 0x3307 +#define LOCAL_EGL_YUV_ORDER_YUV_EXT 0x3302 +#define LOCAL_EGL_YUV_ORDER_YUYV_EXT 0x3304 +#define LOCAL_EGL_YUV_ORDER_YVU_EXT 0x3303 +#define LOCAL_EGL_YUV_ORDER_YVYU_EXT 0x3306 +#define LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C +#define LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D +#define LOCAL_EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E +#define LOCAL_EGL_YUV_PLANE_BPP_0_EXT 0x331B +#define LOCAL_EGL_YUV_PLANE_BPP_10_EXT 0x331D +#define LOCAL_EGL_YUV_PLANE_BPP_8_EXT 0x331C +#define LOCAL_EGL_YUV_PLANE_BPP_EXT 0x331A +#define LOCAL_EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313 +#define LOCAL_EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314 +#define LOCAL_EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315 +#define LOCAL_EGL_YUV_SUBSAMPLE_EXT 0x3312 +#define LOCAL_EGL_Y_AXIS_NV 0x3370 +#define LOCAL_EGL_Y_INVERTED_NOK 0x307F + +// GLX +#define LOCAL_GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 +#define LOCAL_GLX_3DFX_WINDOW_MODE_MESA 0x1 +#define LOCAL_GLX_ACCUM_ALPHA_SIZE 17 +#define LOCAL_GLX_ACCUM_BLUE_SIZE 16 +#define LOCAL_GLX_ACCUM_BUFFER_BIT 0x00000080 +#define LOCAL_GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 +#define LOCAL_GLX_ACCUM_GREEN_SIZE 15 +#define LOCAL_GLX_ACCUM_RED_SIZE 14 +#define LOCAL_GLX_ALPHA_SIZE 11 +#define LOCAL_GLX_AUX0_EXT 0x20E2 +#define LOCAL_GLX_AUX1_EXT 0x20E3 +#define LOCAL_GLX_AUX2_EXT 0x20E4 +#define LOCAL_GLX_AUX3_EXT 0x20E5 +#define LOCAL_GLX_AUX4_EXT 0x20E6 +#define LOCAL_GLX_AUX5_EXT 0x20E7 +#define LOCAL_GLX_AUX6_EXT 0x20E8 +#define LOCAL_GLX_AUX7_EXT 0x20E9 +#define LOCAL_GLX_AUX8_EXT 0x20EA +#define LOCAL_GLX_AUX9_EXT 0x20EB +#define LOCAL_GLX_AUX_BUFFERS 7 +#define LOCAL_GLX_AUX_BUFFERS_BIT 0x00000010 +#define LOCAL_GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 +#define LOCAL_GLX_BACK_BUFFER_AGE_EXT 0x20F4 +#define LOCAL_GLX_BACK_EXT 0x20E0 +#define LOCAL_GLX_BACK_LEFT_BUFFER_BIT 0x00000004 +#define LOCAL_GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 +#define LOCAL_GLX_BACK_LEFT_EXT 0x20E0 +#define LOCAL_GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 +#define LOCAL_GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 +#define LOCAL_GLX_BACK_RIGHT_EXT 0x20E1 +#define LOCAL_GLX_BAD_ATTRIBUTE 2 +#define LOCAL_GLX_BAD_CONTEXT 5 +#define LOCAL_GLX_BAD_ENUM 7 +#define LOCAL_GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 +#define LOCAL_GLX_BAD_HYPERPIPE_SGIX 92 +#define LOCAL_GLX_BAD_SCREEN 1 +#define LOCAL_GLX_BAD_VALUE 6 +#define LOCAL_GLX_BAD_VISUAL 4 +#define LOCAL_GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 +#define LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 +#define LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 +#define LOCAL_GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 +#define LOCAL_GLX_BLENDED_RGBA_SGIS 0x8025 +#define LOCAL_GLX_BLUE_SIZE 10 +#define LOCAL_GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 +#define LOCAL_GLX_BUFFER_SIZE 2 +#define LOCAL_GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 +#define LOCAL_GLX_BufferSwapComplete 1 +#define LOCAL_GLX_COLOR_INDEX_BIT 0x00000002 +#define LOCAL_GLX_COLOR_INDEX_BIT_SGIX 0x00000002 +#define LOCAL_GLX_COLOR_INDEX_TYPE 0x8015 +#define LOCAL_GLX_COLOR_INDEX_TYPE_SGIX 0x8015 +#define LOCAL_GLX_COLOR_SAMPLES_NV 0x20B3 +#define LOCAL_GLX_CONFIG_CAVEAT 0x20 +#define LOCAL_GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 +#define LOCAL_GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define LOCAL_GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define LOCAL_GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#define LOCAL_GLX_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_GLX_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC +#define LOCAL_GLX_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD +#define LOCAL_GLX_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE +#define LOCAL_GLX_CONTEXT_MULTIGPU_ATTRIB_NV 0x20AA +#define LOCAL_GLX_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB +#define LOCAL_GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 +#define LOCAL_GLX_CONTEXT_PRIORITY_HIGH_EXT 0x3101 +#define LOCAL_GLX_CONTEXT_PRIORITY_LEVEL_EXT 0x3100 +#define LOCAL_GLX_CONTEXT_PRIORITY_LOW_EXT 0x3103 +#define LOCAL_GLX_CONTEXT_PRIORITY_MEDIUM_EXT 0x3102 +#define LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define LOCAL_GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define LOCAL_GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define LOCAL_GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define LOCAL_GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#define LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define LOCAL_GLX_COPY_COMPLETE_INTEL 0x8181 +#define LOCAL_GLX_COVERAGE_SAMPLES_NV 100001 +#define LOCAL_GLX_DAMAGED 0x8020 +#define LOCAL_GLX_DAMAGED_SGIX 0x8020 +#define LOCAL_GLX_DEPTH_BUFFER_BIT 0x00000020 +#define LOCAL_GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 +#define LOCAL_GLX_DEPTH_SIZE 12 +#define LOCAL_GLX_DEVICE_ID_NV 0x20CD +#define LOCAL_GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 +#define LOCAL_GLX_DIRECT_COLOR 0x8003 +#define LOCAL_GLX_DIRECT_COLOR_EXT 0x8003 +#define LOCAL_GLX_DONT_CARE 0xFFFFFFFF +#define LOCAL_GLX_DOUBLEBUFFER 5 +#define LOCAL_GLX_DRAWABLE_TYPE 0x8010 +#define LOCAL_GLX_DRAWABLE_TYPE_SGIX 0x8010 +#define LOCAL_GLX_EVENT_MASK 0x801F +#define LOCAL_GLX_EVENT_MASK_SGIX 0x801F +#define LOCAL_GLX_EXCHANGE_COMPLETE_INTEL 0x8180 +#define LOCAL_GLX_EXTENSIONS 0x3 +#define LOCAL_GLX_EXTENSION_NAME "GLX" +#define LOCAL_GLX_FBCONFIG_ID 0x8013 +#define LOCAL_GLX_FBCONFIG_ID_SGIX 0x8013 +#define LOCAL_GLX_FLIP_COMPLETE_INTEL 0x8182 +#define LOCAL_GLX_FLOAT_COMPONENTS_NV 0x20B0 +#define LOCAL_GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#define LOCAL_GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 +#define LOCAL_GLX_FRONT_EXT 0x20DE +#define LOCAL_GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 +#define LOCAL_GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 +#define LOCAL_GLX_FRONT_LEFT_EXT 0x20DE +#define LOCAL_GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 +#define LOCAL_GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 +#define LOCAL_GLX_FRONT_RIGHT_EXT 0x20DF +#define LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 +#define LOCAL_GLX_GPU_CLOCK_AMD 0x21A4 +#define LOCAL_GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define LOCAL_GLX_GPU_NUM_PIPES_AMD 0x21A5 +#define LOCAL_GLX_GPU_NUM_RB_AMD 0x21A7 +#define LOCAL_GLX_GPU_NUM_SIMD_AMD 0x21A6 +#define LOCAL_GLX_GPU_NUM_SPI_AMD 0x21A8 +#define LOCAL_GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define LOCAL_GLX_GPU_RAM_AMD 0x21A3 +#define LOCAL_GLX_GPU_RENDERER_STRING_AMD 0x1F01 +#define LOCAL_GLX_GPU_VENDOR_AMD 0x1F00 +#define LOCAL_GLX_GRAY_SCALE 0x8006 +#define LOCAL_GLX_GRAY_SCALE_EXT 0x8006 +#define LOCAL_GLX_GREEN_SIZE 9 +#define LOCAL_GLX_HEIGHT 0x801E +#define LOCAL_GLX_HEIGHT_SGIX 0x801E +#define LOCAL_GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 +#define LOCAL_GLX_HYPERPIPE_ID_SGIX 0x8030 +#define LOCAL_GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 +#define LOCAL_GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 +#define LOCAL_GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 +#define LOCAL_GLX_HYPERPIPE_STEREO_SGIX 0x00000003 +#define LOCAL_GLX_LARGEST_PBUFFER 0x801C +#define LOCAL_GLX_LARGEST_PBUFFER_SGIX 0x801C +#define LOCAL_GLX_LATE_SWAPS_TEAR_EXT 0x20F3 +#define LOCAL_GLX_LEVEL 3 +#define LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define LOCAL_GLX_MAX_PBUFFER_HEIGHT 0x8017 +#define LOCAL_GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 +#define LOCAL_GLX_MAX_PBUFFER_PIXELS 0x8018 +#define LOCAL_GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 +#define LOCAL_GLX_MAX_PBUFFER_WIDTH 0x8016 +#define LOCAL_GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 +#define LOCAL_GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 +#define LOCAL_GLX_MIPMAP_TEXTURE_EXT 0x20D7 +#define LOCAL_GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 +#define LOCAL_GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 +#define LOCAL_GLX_NONE 0x8000 +#define LOCAL_GLX_NONE_EXT 0x8000 +#define LOCAL_GLX_NON_CONFORMANT_CONFIG 0x800D +#define LOCAL_GLX_NON_CONFORMANT_VISUAL_EXT 0x800D +#define LOCAL_GLX_NO_EXTENSION 3 +#define LOCAL_GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +#define LOCAL_GLX_NUM_VIDEO_SLOTS_NV 0x20F0 +#define LOCAL_GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A +#define LOCAL_GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 +#define LOCAL_GLX_PBUFFER 0x8023 +#define LOCAL_GLX_PBUFFER_BIT 0x00000004 +#define LOCAL_GLX_PBUFFER_BIT_SGIX 0x00000004 +#define LOCAL_GLX_PBUFFER_CLOBBER_MASK 0x08000000 +#define LOCAL_GLX_PBUFFER_HEIGHT 0x8040 +#define LOCAL_GLX_PBUFFER_SGIX 0x8023 +#define LOCAL_GLX_PBUFFER_WIDTH 0x8041 +#define LOCAL_GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 +#define LOCAL_GLX_PIPE_RECT_SGIX 0x00000001 +#define LOCAL_GLX_PIXMAP_BIT 0x00000002 +#define LOCAL_GLX_PIXMAP_BIT_SGIX 0x00000002 +#define LOCAL_GLX_PRESERVED_CONTENTS 0x801B +#define LOCAL_GLX_PRESERVED_CONTENTS_SGIX 0x801B +#define LOCAL_GLX_PSEUDO_COLOR 0x8004 +#define LOCAL_GLX_PSEUDO_COLOR_EXT 0x8004 +#define LOCAL_GLX_PbufferClobber 0 +#define LOCAL_GLX_RED_SIZE 8 +#define LOCAL_GLX_RENDERER_ACCELERATED_MESA 0x8186 +#define LOCAL_GLX_RENDERER_DEVICE_ID_MESA 0x8184 +#define LOCAL_GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B +#define LOCAL_GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A +#define LOCAL_GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D +#define LOCAL_GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C +#define LOCAL_GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 +#define LOCAL_GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 +#define LOCAL_GLX_RENDERER_VENDOR_ID_MESA 0x8183 +#define LOCAL_GLX_RENDERER_VERSION_MESA 0x8185 +#define LOCAL_GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 +#define LOCAL_GLX_RENDER_TYPE 0x8011 +#define LOCAL_GLX_RENDER_TYPE_SGIX 0x8011 +#define LOCAL_GLX_RGBA 4 +#define LOCAL_GLX_RGBA_BIT 0x00000001 +#define LOCAL_GLX_RGBA_BIT_SGIX 0x00000001 +#define LOCAL_GLX_RGBA_FLOAT_BIT_ARB 0x00000004 +#define LOCAL_GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 +#define LOCAL_GLX_RGBA_TYPE 0x8014 +#define LOCAL_GLX_RGBA_TYPE_SGIX 0x8014 +#define LOCAL_GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 +#define LOCAL_GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 +#define LOCAL_GLX_SAMPLES 100001 +#define LOCAL_GLX_SAMPLES_3DFX 0x8051 +#define LOCAL_GLX_SAMPLES_ARB 100001 +#define LOCAL_GLX_SAMPLES_SGIS 100001 +#define LOCAL_GLX_SAMPLE_BUFFERS 100000 +#define LOCAL_GLX_SAMPLE_BUFFERS_3DFX 0x8050 +#define LOCAL_GLX_SAMPLE_BUFFERS_ARB 100000 +#define LOCAL_GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 +#define LOCAL_GLX_SAMPLE_BUFFERS_SGIS 100000 +#define LOCAL_GLX_SAVED 0x8021 +#define LOCAL_GLX_SAVED_SGIX 0x8021 +#define LOCAL_GLX_SCREEN 0x800C +#define LOCAL_GLX_SCREEN_EXT 0x800C +#define LOCAL_GLX_SHARE_CONTEXT_EXT 0x800A +#define LOCAL_GLX_SLOW_CONFIG 0x8001 +#define LOCAL_GLX_SLOW_VISUAL_EXT 0x8001 +#define LOCAL_GLX_STATIC_COLOR 0x8005 +#define LOCAL_GLX_STATIC_COLOR_EXT 0x8005 +#define LOCAL_GLX_STATIC_GRAY 0x8007 +#define LOCAL_GLX_STATIC_GRAY_EXT 0x8007 +#define LOCAL_GLX_STENCIL_BUFFER_BIT 0x00000040 +#define LOCAL_GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 +#define LOCAL_GLX_STENCIL_SIZE 13 +#define LOCAL_GLX_STEREO 6 +#define LOCAL_GLX_STEREO_NOTIFY_EXT 0x00000000 +#define LOCAL_GLX_STEREO_NOTIFY_MASK_EXT 0x00000001 +#define LOCAL_GLX_STEREO_TREE_EXT 0x20F5 +#define LOCAL_GLX_SWAP_COPY_OML 0x8062 +#define LOCAL_GLX_SWAP_EXCHANGE_OML 0x8061 +#define LOCAL_GLX_SWAP_INTERVAL_EXT 0x20F1 +#define LOCAL_GLX_SWAP_METHOD_OML 0x8060 +#define LOCAL_GLX_SWAP_UNDEFINED_OML 0x8063 +#define LOCAL_GLX_SYNC_FRAME_SGIX 0x00000000 +#define LOCAL_GLX_SYNC_SWAP_SGIX 0x00000001 +#define LOCAL_GLX_TEXTURE_1D_BIT_EXT 0x00000001 +#define LOCAL_GLX_TEXTURE_1D_EXT 0x20DB +#define LOCAL_GLX_TEXTURE_2D_BIT_EXT 0x00000002 +#define LOCAL_GLX_TEXTURE_2D_EXT 0x20DC +#define LOCAL_GLX_TEXTURE_FORMAT_EXT 0x20D5 +#define LOCAL_GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 +#define LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA +#define LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 +#define LOCAL_GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 +#define LOCAL_GLX_TEXTURE_RECTANGLE_EXT 0x20DD +#define LOCAL_GLX_TEXTURE_TARGET_EXT 0x20D6 +#define LOCAL_GLX_TRANSPARENT_ALPHA_VALUE 0x28 +#define LOCAL_GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 +#define LOCAL_GLX_TRANSPARENT_BLUE_VALUE 0x27 +#define LOCAL_GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 +#define LOCAL_GLX_TRANSPARENT_GREEN_VALUE 0x26 +#define LOCAL_GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 +#define LOCAL_GLX_TRANSPARENT_INDEX 0x8009 +#define LOCAL_GLX_TRANSPARENT_INDEX_EXT 0x8009 +#define LOCAL_GLX_TRANSPARENT_INDEX_VALUE 0x24 +#define LOCAL_GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 +#define LOCAL_GLX_TRANSPARENT_RED_VALUE 0x25 +#define LOCAL_GLX_TRANSPARENT_RED_VALUE_EXT 0x25 +#define LOCAL_GLX_TRANSPARENT_RGB 0x8008 +#define LOCAL_GLX_TRANSPARENT_RGB_EXT 0x8008 +#define LOCAL_GLX_TRANSPARENT_TYPE 0x23 +#define LOCAL_GLX_TRANSPARENT_TYPE_EXT 0x23 +#define LOCAL_GLX_TRUE_COLOR 0x8002 +#define LOCAL_GLX_TRUE_COLOR_EXT 0x8002 +#define LOCAL_GLX_UNIQUE_ID_NV 0x20CE +#define LOCAL_GLX_USE_GL 1 +#define LOCAL_GLX_VENDOR 0x1 +#define LOCAL_GLX_VENDOR_NAMES_EXT 0x20F6 +#define LOCAL_GLX_VERSION 0x2 +#define LOCAL_GLX_VIDEO_OUT_ALPHA_NV 0x20C4 +#define LOCAL_GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define LOCAL_GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define LOCAL_GLX_VIDEO_OUT_COLOR_NV 0x20C3 +#define LOCAL_GLX_VIDEO_OUT_DEPTH_NV 0x20C5 +#define LOCAL_GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 +#define LOCAL_GLX_VIDEO_OUT_FIELD_2_NV 0x20CA +#define LOCAL_GLX_VIDEO_OUT_FRAME_NV 0x20C8 +#define LOCAL_GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB +#define LOCAL_GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC +#define LOCAL_GLX_VISUAL_CAVEAT_EXT 0x20 +#define LOCAL_GLX_VISUAL_ID 0x800B +#define LOCAL_GLX_VISUAL_ID_EXT 0x800B +#define LOCAL_GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 +#define LOCAL_GLX_WIDTH 0x801D +#define LOCAL_GLX_WIDTH_SGIX 0x801D +#define LOCAL_GLX_WINDOW 0x8022 +#define LOCAL_GLX_WINDOW_BIT 0x00000001 +#define LOCAL_GLX_WINDOW_BIT_SGIX 0x00000001 +#define LOCAL_GLX_WINDOW_SGIX 0x8022 +#define LOCAL_GLX_X_RENDERABLE 0x8012 +#define LOCAL_GLX_X_RENDERABLE_SGIX 0x8012 +#define LOCAL_GLX_X_VISUAL_TYPE 0x22 +#define LOCAL_GLX_X_VISUAL_TYPE_EXT 0x22 +#define LOCAL_GLX_Y_INVERTED_EXT 0x20D4 + +// WGL +#define LOCAL_WGL_ACCELERATION_ARB 0x2003 +#define LOCAL_WGL_ACCELERATION_EXT 0x2003 +#define LOCAL_WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define LOCAL_WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define LOCAL_WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +#define LOCAL_WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define LOCAL_WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +#define LOCAL_WGL_ACCUM_BITS_ARB 0x201D +#define LOCAL_WGL_ACCUM_BITS_EXT 0x201D +#define LOCAL_WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define LOCAL_WGL_ACCUM_BLUE_BITS_EXT 0x2020 +#define LOCAL_WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define LOCAL_WGL_ACCUM_GREEN_BITS_EXT 0x201F +#define LOCAL_WGL_ACCUM_RED_BITS_ARB 0x201E +#define LOCAL_WGL_ACCUM_RED_BITS_EXT 0x201E +#define LOCAL_WGL_ALPHA_BITS_ARB 0x201B +#define LOCAL_WGL_ALPHA_BITS_EXT 0x201B +#define LOCAL_WGL_ALPHA_SHIFT_ARB 0x201C +#define LOCAL_WGL_ALPHA_SHIFT_EXT 0x201C +#define LOCAL_WGL_AUX0_ARB 0x2087 +#define LOCAL_WGL_AUX1_ARB 0x2088 +#define LOCAL_WGL_AUX2_ARB 0x2089 +#define LOCAL_WGL_AUX3_ARB 0x208A +#define LOCAL_WGL_AUX4_ARB 0x208B +#define LOCAL_WGL_AUX5_ARB 0x208C +#define LOCAL_WGL_AUX6_ARB 0x208D +#define LOCAL_WGL_AUX7_ARB 0x208E +#define LOCAL_WGL_AUX8_ARB 0x208F +#define LOCAL_WGL_AUX9_ARB 0x2090 +#define LOCAL_WGL_AUX_BUFFERS_ARB 0x2024 +#define LOCAL_WGL_AUX_BUFFERS_EXT 0x2024 +#define LOCAL_WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +#define LOCAL_WGL_BACK_LEFT_ARB 0x2085 +#define LOCAL_WGL_BACK_RIGHT_ARB 0x2086 +#define LOCAL_WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +#define LOCAL_WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +#define LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define LOCAL_WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +#define LOCAL_WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +#define LOCAL_WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +#define LOCAL_WGL_BLUE_BITS_ARB 0x2019 +#define LOCAL_WGL_BLUE_BITS_EXT 0x2019 +#define LOCAL_WGL_BLUE_SHIFT_ARB 0x201A +#define LOCAL_WGL_BLUE_SHIFT_EXT 0x201A +#define LOCAL_WGL_COLORSPACE_EXT 0x309D +#define LOCAL_WGL_COLORSPACE_LINEAR_EXT 0x308A +#define LOCAL_WGL_COLORSPACE_SRGB_EXT 0x3089 +#define LOCAL_WGL_COLOR_BITS_ARB 0x2014 +#define LOCAL_WGL_COLOR_BITS_EXT 0x2014 +#define LOCAL_WGL_COLOR_SAMPLES_NV 0x20B9 +#define LOCAL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define LOCAL_WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define LOCAL_WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#define LOCAL_WGL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define LOCAL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define LOCAL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC +#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD +#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE +#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_NV 0x20AA +#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB +#define LOCAL_WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 +#define LOCAL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define LOCAL_WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define LOCAL_WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define LOCAL_WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define LOCAL_WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#define LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define LOCAL_WGL_COVERAGE_SAMPLES_NV 0x2042 +#define LOCAL_WGL_CUBE_MAP_FACE_ARB 0x207C +#define LOCAL_WGL_DEPTH_BITS_ARB 0x2022 +#define LOCAL_WGL_DEPTH_BITS_EXT 0x2022 +#define LOCAL_WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +#define LOCAL_WGL_DEPTH_COMPONENT_NV 0x20A7 +#define LOCAL_WGL_DEPTH_FLOAT_EXT 0x2040 +#define LOCAL_WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define LOCAL_WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +#define LOCAL_WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +#define LOCAL_WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +#define LOCAL_WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 +#define LOCAL_WGL_DOUBLE_BUFFER_ARB 0x2011 +#define LOCAL_WGL_DOUBLE_BUFFER_EXT 0x2011 +#define LOCAL_WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define LOCAL_WGL_DRAW_TO_BITMAP_EXT 0x2002 +#define LOCAL_WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define LOCAL_WGL_DRAW_TO_PBUFFER_EXT 0x202D +#define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define LOCAL_WGL_DRAW_TO_WINDOW_EXT 0x2001 +#define LOCAL_WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define LOCAL_WGL_FONT_LINES 0 +#define LOCAL_WGL_FONT_POLYGONS 1 +#define LOCAL_WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#define LOCAL_WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#define LOCAL_WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +#define LOCAL_WGL_FRONT_LEFT_ARB 0x2083 +#define LOCAL_WGL_FRONT_RIGHT_ARB 0x2084 +#define LOCAL_WGL_FULL_ACCELERATION_ARB 0x2027 +#define LOCAL_WGL_FULL_ACCELERATION_EXT 0x2027 +#define LOCAL_WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +#define LOCAL_WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define LOCAL_WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define LOCAL_WGL_GENERIC_ACCELERATION_EXT 0x2026 +#define LOCAL_WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +#define LOCAL_WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +#define LOCAL_WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C +#define LOCAL_WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +#define LOCAL_WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +#define LOCAL_WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +#define LOCAL_WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +#define LOCAL_WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 +#define LOCAL_WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define LOCAL_WGL_GPU_CLOCK_AMD 0x21A4 +#define LOCAL_WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define LOCAL_WGL_GPU_NUM_PIPES_AMD 0x21A5 +#define LOCAL_WGL_GPU_NUM_RB_AMD 0x21A7 +#define LOCAL_WGL_GPU_NUM_SIMD_AMD 0x21A6 +#define LOCAL_WGL_GPU_NUM_SPI_AMD 0x21A8 +#define LOCAL_WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define LOCAL_WGL_GPU_RAM_AMD 0x21A3 +#define LOCAL_WGL_GPU_RENDERER_STRING_AMD 0x1F01 +#define LOCAL_WGL_GPU_VENDOR_AMD 0x1F00 +#define LOCAL_WGL_GREEN_BITS_ARB 0x2017 +#define LOCAL_WGL_GREEN_BITS_EXT 0x2017 +#define LOCAL_WGL_GREEN_SHIFT_ARB 0x2018 +#define LOCAL_WGL_GREEN_SHIFT_EXT 0x2018 +#define LOCAL_WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +#define LOCAL_WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define LOCAL_WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +#define LOCAL_WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define LOCAL_WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +#define LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define LOCAL_WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +#define LOCAL_WGL_MIPMAP_LEVEL_ARB 0x207B +#define LOCAL_WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define LOCAL_WGL_NEED_PALETTE_ARB 0x2004 +#define LOCAL_WGL_NEED_PALETTE_EXT 0x2004 +#define LOCAL_WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define LOCAL_WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +#define LOCAL_WGL_NO_ACCELERATION_ARB 0x2025 +#define LOCAL_WGL_NO_ACCELERATION_EXT 0x2025 +#define LOCAL_WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_WGL_NO_TEXTURE_ARB 0x2077 +#define LOCAL_WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define LOCAL_WGL_NUMBER_OVERLAYS_EXT 0x2008 +#define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define LOCAL_WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +#define LOCAL_WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define LOCAL_WGL_NUMBER_UNDERLAYS_EXT 0x2009 +#define LOCAL_WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +#define LOCAL_WGL_NUM_VIDEO_SLOTS_NV 0x20F0 +#define LOCAL_WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +#define LOCAL_WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +#define LOCAL_WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define LOCAL_WGL_PBUFFER_HEIGHT_EXT 0x2035 +#define LOCAL_WGL_PBUFFER_LARGEST_ARB 0x2033 +#define LOCAL_WGL_PBUFFER_LARGEST_EXT 0x2033 +#define LOCAL_WGL_PBUFFER_LOST_ARB 0x2036 +#define LOCAL_WGL_PBUFFER_WIDTH_ARB 0x2034 +#define LOCAL_WGL_PBUFFER_WIDTH_EXT 0x2034 +#define LOCAL_WGL_PIXEL_TYPE_ARB 0x2013 +#define LOCAL_WGL_PIXEL_TYPE_EXT 0x2013 +#define LOCAL_WGL_RED_BITS_ARB 0x2015 +#define LOCAL_WGL_RED_BITS_EXT 0x2015 +#define LOCAL_WGL_RED_SHIFT_ARB 0x2016 +#define LOCAL_WGL_RED_SHIFT_EXT 0x2016 +#define LOCAL_WGL_SAMPLES_3DFX 0x2061 +#define LOCAL_WGL_SAMPLES_ARB 0x2042 +#define LOCAL_WGL_SAMPLES_EXT 0x2042 +#define LOCAL_WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define LOCAL_WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define LOCAL_WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define LOCAL_WGL_SHARE_ACCUM_ARB 0x200E +#define LOCAL_WGL_SHARE_ACCUM_EXT 0x200E +#define LOCAL_WGL_SHARE_DEPTH_ARB 0x200C +#define LOCAL_WGL_SHARE_DEPTH_EXT 0x200C +#define LOCAL_WGL_SHARE_STENCIL_ARB 0x200D +#define LOCAL_WGL_SHARE_STENCIL_EXT 0x200D +#define LOCAL_WGL_STENCIL_BITS_ARB 0x2023 +#define LOCAL_WGL_STENCIL_BITS_EXT 0x2023 +#define LOCAL_WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 +#define LOCAL_WGL_STEREO_ARB 0x2012 +#define LOCAL_WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define LOCAL_WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define LOCAL_WGL_STEREO_EXT 0x2012 +#define LOCAL_WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +#define LOCAL_WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define LOCAL_WGL_SUPPORT_GDI_ARB 0x200F +#define LOCAL_WGL_SUPPORT_GDI_EXT 0x200F +#define LOCAL_WGL_SUPPORT_OPENGL_ARB 0x2010 +#define LOCAL_WGL_SUPPORT_OPENGL_EXT 0x2010 +#define LOCAL_WGL_SWAP_COPY_ARB 0x2029 +#define LOCAL_WGL_SWAP_COPY_EXT 0x2029 +#define LOCAL_WGL_SWAP_EXCHANGE_ARB 0x2028 +#define LOCAL_WGL_SWAP_EXCHANGE_EXT 0x2028 +#define LOCAL_WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define LOCAL_WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +#define LOCAL_WGL_SWAP_MAIN_PLANE 0x00000001 +#define LOCAL_WGL_SWAP_METHOD_ARB 0x2007 +#define LOCAL_WGL_SWAP_METHOD_EXT 0x2007 +#define LOCAL_WGL_SWAP_OVERLAY1 0x00000002 +#define LOCAL_WGL_SWAP_OVERLAY10 0x00000400 +#define LOCAL_WGL_SWAP_OVERLAY11 0x00000800 +#define LOCAL_WGL_SWAP_OVERLAY12 0x00001000 +#define LOCAL_WGL_SWAP_OVERLAY13 0x00002000 +#define LOCAL_WGL_SWAP_OVERLAY14 0x00004000 +#define LOCAL_WGL_SWAP_OVERLAY15 0x00008000 +#define LOCAL_WGL_SWAP_OVERLAY2 0x00000004 +#define LOCAL_WGL_SWAP_OVERLAY3 0x00000008 +#define LOCAL_WGL_SWAP_OVERLAY4 0x00000010 +#define LOCAL_WGL_SWAP_OVERLAY5 0x00000020 +#define LOCAL_WGL_SWAP_OVERLAY6 0x00000040 +#define LOCAL_WGL_SWAP_OVERLAY7 0x00000080 +#define LOCAL_WGL_SWAP_OVERLAY8 0x00000100 +#define LOCAL_WGL_SWAP_OVERLAY9 0x00000200 +#define LOCAL_WGL_SWAP_UNDEFINED_ARB 0x202A +#define LOCAL_WGL_SWAP_UNDEFINED_EXT 0x202A +#define LOCAL_WGL_SWAP_UNDERLAY1 0x00010000 +#define LOCAL_WGL_SWAP_UNDERLAY10 0x02000000 +#define LOCAL_WGL_SWAP_UNDERLAY11 0x04000000 +#define LOCAL_WGL_SWAP_UNDERLAY12 0x08000000 +#define LOCAL_WGL_SWAP_UNDERLAY13 0x10000000 +#define LOCAL_WGL_SWAP_UNDERLAY14 0x20000000 +#define LOCAL_WGL_SWAP_UNDERLAY15 0x40000000 +#define LOCAL_WGL_SWAP_UNDERLAY2 0x00020000 +#define LOCAL_WGL_SWAP_UNDERLAY3 0x00040000 +#define LOCAL_WGL_SWAP_UNDERLAY4 0x00080000 +#define LOCAL_WGL_SWAP_UNDERLAY5 0x00100000 +#define LOCAL_WGL_SWAP_UNDERLAY6 0x00200000 +#define LOCAL_WGL_SWAP_UNDERLAY7 0x00400000 +#define LOCAL_WGL_SWAP_UNDERLAY8 0x00800000 +#define LOCAL_WGL_SWAP_UNDERLAY9 0x01000000 +#define LOCAL_WGL_TEXTURE_1D_ARB 0x2079 +#define LOCAL_WGL_TEXTURE_2D_ARB 0x207A +#define LOCAL_WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define LOCAL_WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define LOCAL_WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define LOCAL_WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define LOCAL_WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define LOCAL_WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define LOCAL_WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define LOCAL_WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define LOCAL_WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#define LOCAL_WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define LOCAL_WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define LOCAL_WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define LOCAL_WGL_TEXTURE_FORMAT_ARB 0x2072 +#define LOCAL_WGL_TEXTURE_RECTANGLE_ATI 0x21A5 +#define LOCAL_WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#define LOCAL_WGL_TEXTURE_RGBA_ARB 0x2076 +#define LOCAL_WGL_TEXTURE_RGB_ARB 0x2075 +#define LOCAL_WGL_TEXTURE_TARGET_ARB 0x2073 +#define LOCAL_WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define LOCAL_WGL_TRANSPARENT_ARB 0x200A +#define LOCAL_WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define LOCAL_WGL_TRANSPARENT_EXT 0x200A +#define LOCAL_WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define LOCAL_WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define LOCAL_WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define LOCAL_WGL_TRANSPARENT_VALUE_EXT 0x200B +#define LOCAL_WGL_TYPE_COLORINDEX_ARB 0x202C +#define LOCAL_WGL_TYPE_COLORINDEX_EXT 0x202C +#define LOCAL_WGL_TYPE_RGBA_ARB 0x202B +#define LOCAL_WGL_TYPE_RGBA_EXT 0x202B +#define LOCAL_WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#define LOCAL_WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#define LOCAL_WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#define LOCAL_WGL_UNIQUE_ID_NV 0x20CE +#define LOCAL_WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +#define LOCAL_WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define LOCAL_WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define LOCAL_WGL_VIDEO_OUT_COLOR_NV 0x20C3 +#define LOCAL_WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +#define LOCAL_WGL_VIDEO_OUT_FIELD_1 0x20C9 +#define LOCAL_WGL_VIDEO_OUT_FIELD_2 0x20CA +#define LOCAL_WGL_VIDEO_OUT_FRAME 0x20C8 +#define LOCAL_WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +#define LOCAL_WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC + +#endif // GLCONSTS_H_ + +// clang-format on diff --git a/gfx/gl/GLConsts.py b/gfx/gl/GLConsts.py new file mode 100755 index 0000000000..07d70c662a --- /dev/null +++ b/gfx/gl/GLConsts.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 + +""" +This script will regenerate and update GLConsts.h. + +Step 1: + Download the last gl.xml, egl.xml, glx.xml and wgl.xml from + http://www.opengl.org/registry/#specfiles into some XML_DIR: + wget https://www.khronos.org/registry/OpenGL/xml/gl.xml + wget https://www.khronos.org/registry/OpenGL/xml/glx.xml + wget https://www.khronos.org/registry/OpenGL/xml/wgl.xml + wget https://www.khronos.org/registry/EGL/api/egl.xml + +Step 2: + `py ./GLConsts.py <XML_DIR>` + +Step 3: + Do not add the downloaded XML in the patch + +Step 4: + Enjoy =) +""" + +# includes +import pathlib +import sys +import xml.etree.ElementTree +from typing import List # mypy! + +# - + +(_, XML_DIR_STR) = sys.argv +XML_DIR = pathlib.Path(XML_DIR_STR) + +# - + +HEADER = b""" +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// clang-format off + +#ifndef GLCONSTS_H_ +#define GLCONSTS_H_ + +/** + * GENERATED FILE, DO NOT MODIFY DIRECTLY. + * This is a file generated directly from the official OpenGL registry + * xml available http://www.opengl.org/registry/#specfiles. + * + * To generate this file, see tutorial in \'GLConsts.py\'. + */ +"""[ + 1: +] + +FOOTER = b""" +#endif // GLCONSTS_H_ + +// clang-format on +"""[ + 1: +] + +# - + + +def format_lib_constant(lib, name, value): + # lib would be 'GL', 'EGL', 'GLX' or 'WGL' + # name is the name of the const (example: MAX_TEXTURE_SIZE) + # value is the value of the const (example: 0xABCD) + + define = "#define LOCAL_" + lib + "_" + name + whitespace = 60 - len(define) + if whitespace < 0: + whitespace = whitespace % 8 + + return define + " " * whitespace + " " + value + + +class GLConst: + def __init__(self, lib, name, value, type): + self.lib = lib + self.name = name + self.value = value + self.type = type + + +class GLDatabase: + LIBS = ["GL", "EGL", "GLX", "WGL"] + + def __init__(self): + self.consts = {} + self.libs = set(GLDatabase.LIBS) + self.vendors = set(["EXT", "ATI"]) + # there is no vendor="EXT" and vendor="ATI" in gl.xml, + # so we manualy declare them + + def load_xml(self, xml_path): + tree = xml.etree.ElementTree.parse(xml_path) + root = tree.getroot() + + for enums in root.iter("enums"): + vendor = enums.get("vendor") + if not vendor: + # there some standart enums that do have the vendor attribute, + # so we fake them as ARB's enums + vendor = "ARB" + + if vendor not in self.vendors: + # we map this new vendor in the vendors set. + self.vendors.add(vendor) + + namespaceType = enums.get("type") + + for enum in enums: + if enum.tag != "enum": + # this is not an enum => we skip it + continue + + lib = enum.get("name").split("_")[0] + + if lib not in self.libs: + # unknown library => we skip it + continue + + name = enum.get("name")[len(lib) + 1 :] + value = enum.get("value") + type = enum.get("type") + + if not type: + # if no type specified, we get the namespace's default type + type = namespaceType + + self.consts[lib + "_" + name] = GLConst(lib, name, value, type) + + +# - + +db = GLDatabase() +db.load_xml(XML_DIR / "gl.xml") +db.load_xml(XML_DIR / "glx.xml") +db.load_xml(XML_DIR / "wgl.xml") +db.load_xml(XML_DIR / "egl.xml") + +# - + +lines: List[str] = [] # noqa: E999 (bug 1573737) + +keys = sorted(db.consts.keys()) + +for lib in db.LIBS: + lines.append("// " + lib) + + for k in keys: + const = db.consts[k] + + if const.lib != lib: + continue + + const_str = format_lib_constant(lib, const.name, const.value) + lines.append(const_str) + + lines.append("") + +# - + +b_lines: List[bytes] = [HEADER] + [x.encode() for x in lines] + [FOOTER] +b_data: bytes = b"\n".join(b_lines) + +dest = pathlib.Path("GLConsts.h") +dest.write_bytes(b_data) + +print(f"Wrote {len(b_data)} bytes.") # Some indication that we're successful. diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp new file mode 100644 index 0000000000..9036653af8 --- /dev/null +++ b/gfx/gl/GLContext.cpp @@ -0,0 +1,2652 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContext.h" + +#include <algorithm> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <regex> +#include <string> +#include <vector> +#ifdef MOZ_WIDGET_ANDROID +# include <sys/mman.h> +#endif +#if defined(XP_LINUX) && !defined(ANDROID) +// For MesaMemoryLeakWorkaround +# include <dlfcn.h> +# include <link.h> +#endif + +#include "GLBlitHelper.h" +#include "GLReadTexImageHelper.h" +#include "GLScreenBuffer.h" + +#include "gfxCrashReporterUtils.h" +#include "gfxEnv.h" +#include "gfxUtils.h" +#include "GLContextProvider.h" +#include "GLLibraryLoader.h" +#include "GLTextureImage.h" +#include "nsPrintfCString.h" +#include "nsThreadUtils.h" +#include "prenv.h" +#include "prlink.h" +#include "ScopedGLHelpers.h" +#include "SharedSurfaceGL.h" +#include "GfxTexturesReporter.h" +#include "gfx2DGlue.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_gl.h" +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/BuildConstants.h" +#include "mozilla/layers/TextureForwarder.h" // for LayersIPCChannel + +#include "OGLShaderProgram.h" // for ShaderProgramType + +#include "mozilla/DebugOnly.h" +#include "mozilla/Maybe.h" + +#ifdef XP_MACOSX +# include <CoreServices/CoreServices.h> +#endif + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/jni/Utils.h" +#endif + +namespace mozilla { +namespace gl { + +using namespace mozilla::gfx; +using namespace mozilla::layers; + +// Zero-initialized after init(). +MOZ_THREAD_LOCAL(const GLContext*) GLContext::sCurrentContext; + +// If adding defines, don't forget to undefine symbols. See #undef block below. +// clang-format off +#define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, {{ "gl" #x }} } +#define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, {{ "gl" #x, "gl" #x #y, "gl" #x #z }} } +#define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, {{ "gl" #x #y, "gl" #x #z }} } +#define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, {{ "gl" #x #y, "gl" #x #z, "gl" #x #w }} } +#define END_SYMBOLS { nullptr, {} } +// clang-format on + +// should match the order of GLExtensions, and be null-terminated. +static const char* const sExtensionNames[] = { + "NO_EXTENSION", + "GL_AMD_compressed_ATC_texture", + "GL_ANGLE_depth_texture", + "GL_ANGLE_framebuffer_blit", + "GL_ANGLE_framebuffer_multisample", + "GL_ANGLE_instanced_arrays", + "GL_ANGLE_multiview", + "GL_ANGLE_provoking_vertex", + "GL_ANGLE_texture_compression_dxt3", + "GL_ANGLE_texture_compression_dxt5", + "GL_ANGLE_timer_query", + "GL_APPLE_client_storage", + "GL_APPLE_fence", + "GL_APPLE_framebuffer_multisample", + "GL_APPLE_sync", + "GL_APPLE_texture_range", + "GL_APPLE_vertex_array_object", + "GL_ARB_ES2_compatibility", + "GL_ARB_ES3_compatibility", + "GL_ARB_color_buffer_float", + "GL_ARB_compatibility", + "GL_ARB_copy_buffer", + "GL_ARB_depth_texture", + "GL_ARB_draw_buffers", + "GL_ARB_draw_instanced", + "GL_ARB_framebuffer_object", + "GL_ARB_framebuffer_sRGB", + "GL_ARB_geometry_shader4", + "GL_ARB_half_float_pixel", + "GL_ARB_instanced_arrays", + "GL_ARB_internalformat_query", + "GL_ARB_invalidate_subdata", + "GL_ARB_map_buffer_range", + "GL_ARB_occlusion_query2", + "GL_ARB_pixel_buffer_object", + "GL_ARB_provoking_vertex", + "GL_ARB_robust_buffer_access_behavior", + "GL_ARB_robustness", + "GL_ARB_sampler_objects", + "GL_ARB_seamless_cube_map", + "GL_ARB_shader_texture_lod", + "GL_ARB_sync", + "GL_ARB_texture_compression", + "GL_ARB_texture_compression_bptc", + "GL_ARB_texture_compression_rgtc", + "GL_ARB_texture_float", + "GL_ARB_texture_non_power_of_two", + "GL_ARB_texture_rectangle", + "GL_ARB_texture_rg", + "GL_ARB_texture_storage", + "GL_ARB_texture_swizzle", + "GL_ARB_timer_query", + "GL_ARB_transform_feedback2", + "GL_ARB_uniform_buffer_object", + "GL_ARB_vertex_array_object", + "GL_CHROMIUM_color_buffer_float_rgb", + "GL_CHROMIUM_color_buffer_float_rgba", + "GL_EXT_bgra", + "GL_EXT_blend_minmax", + "GL_EXT_color_buffer_float", + "GL_EXT_color_buffer_half_float", + "GL_EXT_copy_texture", + "GL_EXT_disjoint_timer_query", + "GL_EXT_draw_buffers", + "GL_EXT_draw_buffers2", + "GL_EXT_draw_instanced", + "GL_EXT_float_blend", + "GL_EXT_frag_depth", + "GL_EXT_framebuffer_blit", + "GL_EXT_framebuffer_multisample", + "GL_EXT_framebuffer_object", + "GL_EXT_framebuffer_sRGB", + "GL_EXT_gpu_shader4", + "GL_EXT_map_buffer_range", + "GL_EXT_multisampled_render_to_texture", + "GL_EXT_occlusion_query_boolean", + "GL_EXT_packed_depth_stencil", + "GL_EXT_provoking_vertex", + "GL_EXT_read_format_bgra", + "GL_EXT_robustness", + "GL_EXT_sRGB", + "GL_EXT_sRGB_write_control", + "GL_EXT_shader_texture_lod", + "GL_EXT_texture_compression_bptc", + "GL_EXT_texture_compression_dxt1", + "GL_EXT_texture_compression_rgtc", + "GL_EXT_texture_compression_s3tc", + "GL_EXT_texture_compression_s3tc_srgb", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_format_BGRA8888", + "GL_EXT_texture_norm16", + "GL_EXT_texture_sRGB", + "GL_EXT_texture_storage", + "GL_EXT_timer_query", + "GL_EXT_transform_feedback", + "GL_EXT_unpack_subimage", + "GL_IMG_read_format", + "GL_IMG_texture_compression_pvrtc", + "GL_IMG_texture_npot", + "GL_KHR_debug", + "GL_KHR_parallel_shader_compile", + "GL_KHR_robust_buffer_access_behavior", + "GL_KHR_robustness", + "GL_KHR_texture_compression_astc_hdr", + "GL_KHR_texture_compression_astc_ldr", + "GL_NV_draw_instanced", + "GL_NV_fence", + "GL_NV_framebuffer_blit", + "GL_NV_geometry_program4", + "GL_NV_half_float", + "GL_NV_instanced_arrays", + "GL_NV_primitive_restart", + "GL_NV_texture_barrier", + "GL_NV_transform_feedback", + "GL_NV_transform_feedback2", + "GL_OES_EGL_image", + "GL_OES_EGL_image_external", + "GL_OES_EGL_sync", + "GL_OES_compressed_ETC1_RGB8_texture", + "GL_OES_depth24", + "GL_OES_depth32", + "GL_OES_depth_texture", + "GL_OES_draw_buffers_indexed", + "GL_OES_element_index_uint", + "GL_OES_fbo_render_mipmap", + "GL_OES_framebuffer_object", + "GL_OES_packed_depth_stencil", + "GL_OES_rgb8_rgba8", + "GL_OES_standard_derivatives", + "GL_OES_stencil8", + "GL_OES_texture_3D", + "GL_OES_texture_float", + "GL_OES_texture_float_linear", + "GL_OES_texture_half_float", + "GL_OES_texture_half_float_linear", + "GL_OES_texture_npot", + "GL_OES_vertex_array_object", + "GL_OVR_multiview2"}; + +static bool ShouldUseTLSIsCurrent(bool useTLSIsCurrent) { + if (StaticPrefs::gl_use_tls_is_current() == 0) { + return useTLSIsCurrent; + } + + return StaticPrefs::gl_use_tls_is_current() > 0; +} + +static bool ParseVersion(const std::string& versionStr, + uint32_t* const out_major, uint32_t* const out_minor) { + static const std::regex kVersionRegex("([0-9]+)\\.([0-9]+)"); + std::smatch match; + if (!std::regex_search(versionStr, match, kVersionRegex)) return false; + + const auto& majorStr = match.str(1); + const auto& minorStr = match.str(2); + *out_major = atoi(majorStr.c_str()); + *out_minor = atoi(minorStr.c_str()); + return true; +} + +/*static*/ +uint8_t GLContext::ChooseDebugFlags(const CreateContextFlags createFlags) { + uint8_t debugFlags = 0; + +#ifdef MOZ_GL_DEBUG_BUILD + if (gfxEnv::MOZ_GL_DEBUG()) { + debugFlags |= GLContext::DebugFlagEnabled; + } + + // Enables extra verbose output, informing of the start and finish of every GL + // call. Useful e.g. to record information to investigate graphics system + // crashes/lockups + if (gfxEnv::MOZ_GL_DEBUG_VERBOSE()) { + debugFlags |= GLContext::DebugFlagTrace; + } + + // Aborts on GL error. Can be useful to debug quicker code that is known not + // to generate any GL error in principle. + bool abortOnError = false; + + if (createFlags & CreateContextFlags::NO_VALIDATION) { + abortOnError = true; + + const auto& env = gfxEnv::MOZ_GL_DEBUG_ABORT_ON_ERROR(); + if (env.as_str == "0") { + abortOnError = false; + } + } + + if (abortOnError) { + debugFlags |= GLContext::DebugFlagAbortOnError; + } +#endif + + return debugFlags; +} + +GLContext::GLContext(const GLContextDesc& desc, GLContext* sharedContext, + bool useTLSIsCurrent) + : mDesc(desc), + mUseTLSIsCurrent(ShouldUseTLSIsCurrent(useTLSIsCurrent)), + mDebugFlags(ChooseDebugFlags(mDesc.flags)), + mSharedContext(sharedContext), + mOwningThreadId(Some(PlatformThread::CurrentId())), + mWorkAroundDriverBugs( + StaticPrefs::gfx_work_around_driver_bugs_AtStartup()) {} + +GLContext::~GLContext() { + NS_ASSERTION( + IsDestroyed(), + "GLContext implementation must call MarkDestroyed in destructor!"); +#ifdef MOZ_GL_DEBUG_BUILD + if (mSharedContext) { + GLContext* tip = mSharedContext; + while (tip->mSharedContext) tip = tip->mSharedContext; + tip->SharedContextDestroyed(this); + tip->ReportOutstandingNames(); + } else { + ReportOutstandingNames(); + } +#endif + // Ensure we clear sCurrentContext if we were the last context set and avoid + // the memory getting reused. + if (sCurrentContext.init() && sCurrentContext.get() == this) { + sCurrentContext.set(nullptr); + } +} + +/*static*/ +void GLContext::InvalidateCurrentContext() { + if (sCurrentContext.init()) { + sCurrentContext.set(nullptr); + } +} + +/*static*/ +void GLContext::StaticDebugCallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar* message, + const GLvoid* userParam) { + GLContext* gl = (GLContext*)userParam; + gl->DebugCallback(source, type, id, severity, length, message); +} + +bool GLContext::Init() { + MOZ_RELEASE_ASSERT(!mSymbols.fBindFramebuffer, + "GFX: GLContext::Init should only be called once."); + + ScopedGfxFeatureReporter reporter("GL Context"); + + if (!InitImpl()) { + // If initialization fails, zero the symbols to avoid hard-to-understand + // bugs. + mSymbols = {}; + NS_WARNING("GLContext::InitWithPrefix failed!"); + return false; + } + + reporter.SetSuccessful(); + return true; +} + +static bool LoadSymbolsWithDesc(const SymbolLoader& loader, + const SymLoadStruct* list, const char* desc) { + const auto warnOnFailure = bool(desc); + if (loader.LoadSymbols(list, warnOnFailure)) return true; + + ClearSymbols(list); + + if (desc) { + const nsPrintfCString err("Failed to load symbols for %s.", desc); + NS_ERROR(err.BeginReading()); + } + return false; +} + +bool GLContext::LoadExtSymbols(const SymbolLoader& loader, + const SymLoadStruct* list, GLExtensions ext) { + const char* extName = sExtensionNames[size_t(ext)]; + if (!LoadSymbolsWithDesc(loader, list, extName)) { + MarkExtensionUnsupported(ext); + return false; + } + return true; +}; + +bool GLContext::LoadFeatureSymbols(const SymbolLoader& loader, + const SymLoadStruct* list, + GLFeature feature) { + const char* featureName = GetFeatureName(feature); + if (!LoadSymbolsWithDesc(loader, list, featureName)) { + MarkUnsupported(feature); + return false; + } + return true; +}; + +bool GLContext::InitImpl() { + if (!MakeCurrent(true)) return false; + + const auto loader = GetSymbolLoader(); + if (!loader) return false; + + const auto fnLoadSymbols = [&](const SymLoadStruct* const list, + const char* const desc) { + return LoadSymbolsWithDesc(*loader, list, desc); + }; + + // clang-format off + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fActiveTexture, {{ "glActiveTexture", "glActiveTextureARB" }} }, + { (PRFuncPtr*) &mSymbols.fAttachShader, {{ "glAttachShader", "glAttachShaderARB" }} }, + { (PRFuncPtr*) &mSymbols.fBindAttribLocation, {{ "glBindAttribLocation", "glBindAttribLocationARB" }} }, + { (PRFuncPtr*) &mSymbols.fBindBuffer, {{ "glBindBuffer", "glBindBufferARB" }} }, + { (PRFuncPtr*) &mSymbols.fBindTexture, {{ "glBindTexture", "glBindTextureARB" }} }, + { (PRFuncPtr*) &mSymbols.fBlendColor, {{ "glBlendColor" }} }, + { (PRFuncPtr*) &mSymbols.fBlendEquation, {{ "glBlendEquation" }} }, + { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, {{ "glBlendEquationSeparate", "glBlendEquationSeparateEXT" }} }, + { (PRFuncPtr*) &mSymbols.fBlendFunc, {{ "glBlendFunc" }} }, + { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, {{ "glBlendFuncSeparate", "glBlendFuncSeparateEXT" }} }, + { (PRFuncPtr*) &mSymbols.fBufferData, {{ "glBufferData" }} }, + { (PRFuncPtr*) &mSymbols.fBufferSubData, {{ "glBufferSubData" }} }, + { (PRFuncPtr*) &mSymbols.fClear, {{ "glClear" }} }, + { (PRFuncPtr*) &mSymbols.fClearColor, {{ "glClearColor" }} }, + { (PRFuncPtr*) &mSymbols.fClearStencil, {{ "glClearStencil" }} }, + { (PRFuncPtr*) &mSymbols.fColorMask, {{ "glColorMask" }} }, + { (PRFuncPtr*) &mSymbols.fCompressedTexImage2D, {{ "glCompressedTexImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage2D, {{ "glCompressedTexSubImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fCullFace, {{ "glCullFace" }} }, + { (PRFuncPtr*) &mSymbols.fDetachShader, {{ "glDetachShader", "glDetachShaderARB" }} }, + { (PRFuncPtr*) &mSymbols.fDepthFunc, {{ "glDepthFunc" }} }, + { (PRFuncPtr*) &mSymbols.fDepthMask, {{ "glDepthMask" }} }, + { (PRFuncPtr*) &mSymbols.fDisable, {{ "glDisable" }} }, + { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, {{ "glDisableVertexAttribArray", "glDisableVertexAttribArrayARB" }} }, + { (PRFuncPtr*) &mSymbols.fDrawArrays, {{ "glDrawArrays" }} }, + { (PRFuncPtr*) &mSymbols.fDrawElements, {{ "glDrawElements" }} }, + { (PRFuncPtr*) &mSymbols.fEnable, {{ "glEnable" }} }, + { (PRFuncPtr*) &mSymbols.fEnableVertexAttribArray, {{ "glEnableVertexAttribArray", "glEnableVertexAttribArrayARB" }} }, + { (PRFuncPtr*) &mSymbols.fFinish, {{ "glFinish" }} }, + { (PRFuncPtr*) &mSymbols.fFlush, {{ "glFlush" }} }, + { (PRFuncPtr*) &mSymbols.fFrontFace, {{ "glFrontFace" }} }, + { (PRFuncPtr*) &mSymbols.fGetActiveAttrib, {{ "glGetActiveAttrib", "glGetActiveAttribARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetActiveUniform, {{ "glGetActiveUniform", "glGetActiveUniformARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetAttachedShaders, {{ "glGetAttachedShaders", "glGetAttachedShadersARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetAttribLocation, {{ "glGetAttribLocation", "glGetAttribLocationARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetIntegerv, {{ "glGetIntegerv" }} }, + { (PRFuncPtr*) &mSymbols.fGetFloatv, {{ "glGetFloatv" }} }, + { (PRFuncPtr*) &mSymbols.fGetBooleanv, {{ "glGetBooleanv" }} }, + { (PRFuncPtr*) &mSymbols.fGetBufferParameteriv, {{ "glGetBufferParameteriv", "glGetBufferParameterivARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetError, {{ "glGetError" }} }, + { (PRFuncPtr*) &mSymbols.fGetProgramiv, {{ "glGetProgramiv", "glGetProgramivARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetProgramInfoLog, {{ "glGetProgramInfoLog", "glGetProgramInfoLogARB" }} }, + { (PRFuncPtr*) &mSymbols.fTexParameteri, {{ "glTexParameteri" }} }, + { (PRFuncPtr*) &mSymbols.fTexParameteriv, {{ "glTexParameteriv" }} }, + { (PRFuncPtr*) &mSymbols.fTexParameterf, {{ "glTexParameterf" }} }, + { (PRFuncPtr*) &mSymbols.fGetString, {{ "glGetString" }} }, + { (PRFuncPtr*) &mSymbols.fGetTexParameterfv, {{ "glGetTexParameterfv" }} }, + { (PRFuncPtr*) &mSymbols.fGetTexParameteriv, {{ "glGetTexParameteriv" }} }, + { (PRFuncPtr*) &mSymbols.fGetUniformfv, {{ "glGetUniformfv", "glGetUniformfvARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetUniformiv, {{ "glGetUniformiv", "glGetUniformivARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetUniformLocation, {{ "glGetUniformLocation", "glGetUniformLocationARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetVertexAttribfv, {{ "glGetVertexAttribfv", "glGetVertexAttribfvARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetVertexAttribiv, {{ "glGetVertexAttribiv", "glGetVertexAttribivARB" }} }, + { (PRFuncPtr*) &mSymbols.fGetVertexAttribPointerv, {{ "glGetVertexAttribPointerv" }} }, + { (PRFuncPtr*) &mSymbols.fHint, {{ "glHint" }} }, + { (PRFuncPtr*) &mSymbols.fIsBuffer, {{ "glIsBuffer", "glIsBufferARB" }} }, + { (PRFuncPtr*) &mSymbols.fIsEnabled, {{ "glIsEnabled" }} }, + { (PRFuncPtr*) &mSymbols.fIsProgram, {{ "glIsProgram", "glIsProgramARB" }} }, + { (PRFuncPtr*) &mSymbols.fIsShader, {{ "glIsShader", "glIsShaderARB" }} }, + { (PRFuncPtr*) &mSymbols.fIsTexture, {{ "glIsTexture", "glIsTextureARB" }} }, + { (PRFuncPtr*) &mSymbols.fLineWidth, {{ "glLineWidth" }} }, + { (PRFuncPtr*) &mSymbols.fLinkProgram, {{ "glLinkProgram", "glLinkProgramARB" }} }, + { (PRFuncPtr*) &mSymbols.fPixelStorei, {{ "glPixelStorei" }} }, + { (PRFuncPtr*) &mSymbols.fPolygonOffset, {{ "glPolygonOffset" }} }, + { (PRFuncPtr*) &mSymbols.fReadPixels, {{ "glReadPixels" }} }, + { (PRFuncPtr*) &mSymbols.fSampleCoverage, {{ "glSampleCoverage" }} }, + { (PRFuncPtr*) &mSymbols.fScissor, {{ "glScissor" }} }, + { (PRFuncPtr*) &mSymbols.fStencilFunc, {{ "glStencilFunc" }} }, + { (PRFuncPtr*) &mSymbols.fStencilFuncSeparate, {{ "glStencilFuncSeparate", "glStencilFuncSeparateEXT" }} }, + { (PRFuncPtr*) &mSymbols.fStencilMask, {{ "glStencilMask" }} }, + { (PRFuncPtr*) &mSymbols.fStencilMaskSeparate, {{ "glStencilMaskSeparate", "glStencilMaskSeparateEXT" }} }, + { (PRFuncPtr*) &mSymbols.fStencilOp, {{ "glStencilOp" }} }, + { (PRFuncPtr*) &mSymbols.fStencilOpSeparate, {{ "glStencilOpSeparate", "glStencilOpSeparateEXT" }} }, + { (PRFuncPtr*) &mSymbols.fTexImage2D, {{ "glTexImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fTexSubImage2D, {{ "glTexSubImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1f, {{ "glUniform1f" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1fv, {{ "glUniform1fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1i, {{ "glUniform1i" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1iv, {{ "glUniform1iv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2f, {{ "glUniform2f" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2fv, {{ "glUniform2fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2i, {{ "glUniform2i" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2iv, {{ "glUniform2iv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3f, {{ "glUniform3f" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3fv, {{ "glUniform3fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3i, {{ "glUniform3i" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3iv, {{ "glUniform3iv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4f, {{ "glUniform4f" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4fv, {{ "glUniform4fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4i, {{ "glUniform4i" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4iv, {{ "glUniform4iv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix2fv, {{ "glUniformMatrix2fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix3fv, {{ "glUniformMatrix3fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix4fv, {{ "glUniformMatrix4fv" }} }, + { (PRFuncPtr*) &mSymbols.fUseProgram, {{ "glUseProgram" }} }, + { (PRFuncPtr*) &mSymbols.fValidateProgram, {{ "glValidateProgram" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, {{ "glVertexAttribPointer" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib1f, {{ "glVertexAttrib1f" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib2f, {{ "glVertexAttrib2f" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib3f, {{ "glVertexAttrib3f" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib4f, {{ "glVertexAttrib4f" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib1fv, {{ "glVertexAttrib1fv" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib2fv, {{ "glVertexAttrib2fv" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib3fv, {{ "glVertexAttrib3fv" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttrib4fv, {{ "glVertexAttrib4fv" }} }, + { (PRFuncPtr*) &mSymbols.fViewport, {{ "glViewport" }} }, + { (PRFuncPtr*) &mSymbols.fCompileShader, {{ "glCompileShader" }} }, + { (PRFuncPtr*) &mSymbols.fCopyTexImage2D, {{ "glCopyTexImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fCopyTexSubImage2D, {{ "glCopyTexSubImage2D" }} }, + { (PRFuncPtr*) &mSymbols.fGetShaderiv, {{ "glGetShaderiv" }} }, + { (PRFuncPtr*) &mSymbols.fGetShaderInfoLog, {{ "glGetShaderInfoLog" }} }, + { (PRFuncPtr*) &mSymbols.fGetShaderSource, {{ "glGetShaderSource" }} }, + { (PRFuncPtr*) &mSymbols.fShaderSource, {{ "glShaderSource" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, {{ "glVertexAttribPointer" }} }, + + { (PRFuncPtr*) &mSymbols.fGenBuffers, {{ "glGenBuffers", "glGenBuffersARB" }} }, + { (PRFuncPtr*) &mSymbols.fGenTextures, {{ "glGenTextures" }} }, + { (PRFuncPtr*) &mSymbols.fCreateProgram, {{ "glCreateProgram", "glCreateProgramARB" }} }, + { (PRFuncPtr*) &mSymbols.fCreateShader, {{ "glCreateShader", "glCreateShaderARB" }} }, + + { (PRFuncPtr*) &mSymbols.fDeleteBuffers, {{ "glDeleteBuffers", "glDeleteBuffersARB" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteTextures, {{ "glDeleteTextures", "glDeleteTexturesARB" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteProgram, {{ "glDeleteProgram", "glDeleteProgramARB" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteShader, {{ "glDeleteShader", "glDeleteShaderARB" }} }, + + END_SYMBOLS + }; + // clang-format on + + if (!fnLoadSymbols(coreSymbols, "GL")) return false; + + { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fGetGraphicsResetStatus, + {{"glGetGraphicsResetStatus", "glGetGraphicsResetStatusARB", + "glGetGraphicsResetStatusKHR", "glGetGraphicsResetStatusEXT"}}}, + END_SYMBOLS}; + (void)fnLoadSymbols(symbols, nullptr); + + // We need to call the fGetError symbol directly here because if there is an + // unflushed reset status, we don't want to mark the context as lost. That + // would prevent us from recovering. + auto err = mSymbols.fGetError(); + if (err == LOCAL_GL_CONTEXT_LOST) { + MOZ_ASSERT(mSymbols.fGetGraphicsResetStatus); + const auto status = fGetGraphicsResetStatus(); + if (status) { + printf_stderr("Unflushed glGetGraphicsResetStatus: 0x%04x\n", status); + } + err = fGetError(); + MOZ_ASSERT(!err); + } + if (err) { + MOZ_ASSERT(false); + return false; + } + } + + //////////////// + + const auto* const versionRawStr = (const char*)fGetString(LOCAL_GL_VERSION); + if (!versionRawStr || !*versionRawStr) { + // This can happen with Pernosco. + NS_WARNING("Empty GL version string"); + return false; + } + + const std::string versionStr = versionRawStr; + if (versionStr.find("OpenGL ES") == 0) { + mProfile = ContextProfile::OpenGLES; + } + + uint32_t majorVer, minorVer; + if (!ParseVersion(versionStr, &majorVer, &minorVer)) { + MOZ_ASSERT(false, "Failed to parse GL_VERSION"); + return false; + } + MOZ_ASSERT(majorVer < 10); + MOZ_ASSERT(minorVer < 10); + mVersion = majorVer * 100 + minorVer * 10; + if (mVersion < 200) return false; + + //// + + const auto glslVersionStr = + (const char*)fGetString(LOCAL_GL_SHADING_LANGUAGE_VERSION); + if (!glslVersionStr) { + // This happens on the Android emulators. We'll just return 100 + mShadingLanguageVersion = 100; + } else if (ParseVersion(glslVersionStr, &majorVer, &minorVer)) { + MOZ_ASSERT(majorVer < 10); + MOZ_ASSERT(minorVer < 100); + mShadingLanguageVersion = majorVer * 100 + minorVer; + } else { + MOZ_ASSERT(false, "Failed to parse GL_SHADING_LANGUAGE_VERSION"); + return false; + } + + if (ShouldSpew()) { + printf_stderr("GL version detected: %u\n", mVersion); + printf_stderr("GLSL version detected: %u\n", mShadingLanguageVersion); + printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR)); + printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER)); + } + + //////////////// + + // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2. + if (mProfile == ContextProfile::OpenGLES) { + const SymLoadStruct symbols[] = {CORE_SYMBOL(GetShaderPrecisionFormat), + CORE_SYMBOL(ClearDepthf), + CORE_SYMBOL(DepthRangef), END_SYMBOLS}; + + if (!fnLoadSymbols(symbols, "OpenGL ES")) return false; + } else { + const SymLoadStruct symbols[] = { + CORE_SYMBOL(ClearDepth), CORE_SYMBOL(DepthRange), + CORE_SYMBOL(ReadBuffer), CORE_SYMBOL(MapBuffer), + CORE_SYMBOL(UnmapBuffer), CORE_SYMBOL(PointParameterf), + CORE_SYMBOL(DrawBuffer), + // The following functions are only used by Skia/GL in desktop mode. + // Other parts of Gecko should avoid using these + CORE_SYMBOL(DrawBuffers), CORE_SYMBOL(ClientActiveTexture), + CORE_SYMBOL(DisableClientState), CORE_SYMBOL(EnableClientState), + CORE_SYMBOL(LoadIdentity), CORE_SYMBOL(LoadMatrixf), + CORE_SYMBOL(MatrixMode), CORE_SYMBOL(PolygonMode), CORE_SYMBOL(TexGeni), + CORE_SYMBOL(TexGenf), CORE_SYMBOL(TexGenfv), CORE_SYMBOL(VertexPointer), + END_SYMBOLS}; + + if (!fnLoadSymbols(symbols, "Desktop OpenGL")) return false; + } + + //////////////// + + const char* glVendorString = (const char*)fGetString(LOCAL_GL_VENDOR); + const char* glRendererString = (const char*)fGetString(LOCAL_GL_RENDERER); + if (!glVendorString || !glRendererString) return false; + + // The order of these strings must match up with the order of the enum + // defined in GLContext.h for vendor IDs. + const char* vendorMatchStrings[size_t(GLVendor::Other) + 1] = { + "Intel", "NVIDIA", "ATI", "Qualcomm", "Imagination", + "nouveau", "Vivante", "VMware, Inc.", "ARM", "Unknown"}; + + mVendor = GLVendor::Other; + for (size_t i = 0; i < size_t(GLVendor::Other); ++i) { + if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) { + mVendor = GLVendor(i); + break; + } + } + + // The order of these strings must match up with the order of the enum + // defined in GLContext.h for renderer IDs. + const char* rendererMatchStrings[size_t(GLRenderer::Other) + 1] = { + "Adreno 200", + "Adreno 205", + "Adreno (TM) 200", + "Adreno (TM) 205", + "Adreno (TM) 305", + "Adreno (TM) 320", + "Adreno (TM) 330", + "Adreno (TM) 420", + "Mali-400 MP", + "Mali-450 MP", + "Mali-T", + "PowerVR SGX 530", + "PowerVR SGX 540", + "PowerVR SGX 544MP", + "NVIDIA Tegra", + "Android Emulator", + "Gallium 0.4 on llvmpipe", + "Intel HD Graphics 3000 OpenGL Engine", + "Microsoft Basic Render Driver", + "Samsung Xclipse", + "Unknown"}; + + mRenderer = GLRenderer::Other; + for (size_t i = 0; i < size_t(GLRenderer::Other); ++i) { + if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) { + mRenderer = GLRenderer(i); + break; + } + } + + { + const auto versionStr = (const char*)fGetString(LOCAL_GL_VERSION); + if (strstr(versionStr, "Mesa")) { + mIsMesa = true; + } + } + + const auto Once = []() { + static bool did = false; + if (did) return false; + did = true; + return true; + }; + + bool printRenderer = ShouldSpew(); + printRenderer |= (kIsDebug && Once()); + if (printRenderer) { + printf_stderr("GL_VENDOR: %s\n", glVendorString); + printf_stderr("mVendor: %s\n", vendorMatchStrings[size_t(mVendor)]); + printf_stderr("GL_RENDERER: %s\n", glRendererString); + printf_stderr("mRenderer: %s\n", rendererMatchStrings[size_t(mRenderer)]); + printf_stderr("mIsMesa: %i\n", int(mIsMesa)); + } + + //////////////// + + if (mVersion >= 300) { // Both GL3 and ES3. + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fGetStringi, {{"glGetStringi"}}}, END_SYMBOLS}; + + if (!fnLoadSymbols(symbols, "GetStringi")) { + MOZ_RELEASE_ASSERT(false, "GFX: GetStringi is required!"); + return false; + } + } + + InitExtensions(); + if (mProfile != ContextProfile::OpenGLES) { + if (mVersion >= 310 && !IsExtensionSupported(ARB_compatibility)) { + mProfile = ContextProfile::OpenGLCore; + } else { + mProfile = ContextProfile::OpenGLCompatibility; + } + } + MOZ_ASSERT(mProfile != ContextProfile::Unknown); + + if (ShouldSpew()) { + const char* profileStr = ""; + if (mProfile == ContextProfile::OpenGLES) { + profileStr = " es"; + } else if (mProfile == ContextProfile::OpenGLCore) { + profileStr = " core"; + } + printf_stderr("Detected profile: %u%s\n", mVersion, profileStr); + } + + InitFeatures(); + + //// + + // Disable extensions with partial or incorrect support. + if (WorkAroundDriverBugs()) { + if (Renderer() == GLRenderer::AdrenoTM320) { + MarkUnsupported(GLFeature::standard_derivatives); + } + + if (Renderer() == GLRenderer::AndroidEmulator) { + // Bug 1665300 + mSymbols.fGetGraphicsResetStatus = 0; + } + + if (Vendor() == GLVendor::Vivante) { + // bug 958256 + MarkUnsupported(GLFeature::standard_derivatives); + } + + if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) { + // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer) + // multisampling hardcodes blending with the default blendfunc, which + // breaks WebGL. + MarkUnsupported(GLFeature::framebuffer_multisample); + } + + if (IsMesa()) { + // DrawElementsInstanced hangs the driver. + MarkUnsupported(GLFeature::robust_buffer_access_behavior); + } + + if (Renderer() == GLRenderer::SamsungXclipse) { + MarkUnsupported(GLFeature::invalidate_framebuffer); + } + } + + if (IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) { + MOZ_ASSERT( + (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer), + "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer" + " being available!"); + } + + //////////////////////////////////////////////////////////////////////////// + + const auto fnLoadForFeature = [&](const SymLoadStruct* list, + GLFeature feature) { + return this->LoadFeatureSymbols(*loader, list, feature); + }; + + // Check for ARB_framebuffer_objects + if (IsSupported(GLFeature::framebuffer_object)) { + // https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt + const SymLoadStruct symbols[] = { + CORE_SYMBOL(IsRenderbuffer), + CORE_SYMBOL(BindRenderbuffer), + CORE_SYMBOL(DeleteRenderbuffers), + CORE_SYMBOL(GenRenderbuffers), + CORE_SYMBOL(RenderbufferStorage), + CORE_SYMBOL(RenderbufferStorageMultisample), + CORE_SYMBOL(GetRenderbufferParameteriv), + CORE_SYMBOL(IsFramebuffer), + CORE_SYMBOL(BindFramebuffer), + CORE_SYMBOL(DeleteFramebuffers), + CORE_SYMBOL(GenFramebuffers), + CORE_SYMBOL(CheckFramebufferStatus), + CORE_SYMBOL(FramebufferTexture2D), + CORE_SYMBOL(FramebufferTextureLayer), + CORE_SYMBOL(FramebufferRenderbuffer), + CORE_SYMBOL(GetFramebufferAttachmentParameteriv), + CORE_SYMBOL(BlitFramebuffer), + CORE_SYMBOL(GenerateMipmap), + END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::framebuffer_object); + } + + if (!IsSupported(GLFeature::framebuffer_object)) { + // Check for aux symbols based on extensions + if (IsSupported(GLFeature::framebuffer_object_EXT_OES)) { + const SymLoadStruct symbols[] = { + CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES), + CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES), + CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES), + CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES), + CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES), + CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES), + CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES), + CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES), + CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES), + CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES), + CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES), + CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES), + END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::framebuffer_object_EXT_OES); + } + + if (IsSupported(GLFeature::framebuffer_blit)) { + const SymLoadStruct symbols[] = { + EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV), END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::framebuffer_blit); + } + + if (IsSupported(GLFeature::framebuffer_multisample)) { + const SymLoadStruct symbols[] = { + EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT), + END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::framebuffer_multisample); + } + + if (IsExtensionSupported(GLContext::ARB_geometry_shader4) || + IsExtensionSupported(GLContext::NV_geometry_program4)) { + const SymLoadStruct symbols[] = { + EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT), END_SYMBOLS}; + if (!fnLoadSymbols(symbols, + "ARB_geometry_shader4/NV_geometry_program4")) { + MarkExtensionUnsupported(GLContext::ARB_geometry_shader4); + MarkExtensionUnsupported(GLContext::NV_geometry_program4); + } + } + } + + if (!IsSupported(GLFeature::framebuffer_object) && + !IsSupported(GLFeature::framebuffer_object_EXT_OES)) { + NS_ERROR("GLContext requires support for framebuffer objects."); + return false; + } + MOZ_RELEASE_ASSERT(mSymbols.fBindFramebuffer, + "GFX: mSymbols.fBindFramebuffer zero or not set."); + + //////////////// + + const auto err = fGetError(); + MOZ_RELEASE_ASSERT(!IsBadCallError(err)); + if (err) return false; + + LoadMoreSymbols(*loader); + + //////////////////////////////////////////////////////////////////////////// + + raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect); + raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect); + raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize); + raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); + raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); + + if (mWorkAroundDriverBugs) { + int maxTexSize = INT32_MAX; + int maxCubeSize = INT32_MAX; +#ifdef XP_MACOSX + // https://bugzilla.mozilla.org/show_bug.cgi?id=1544446 + // Mojave exposes 16k textures, but gives FRAMEBUFFER_UNSUPPORTED for any + // 16k*16k FB except rgba8 without depth/stencil. + // The max supported sizes changes based on involved formats. + // (RGBA32F more restrictive than RGBA16F) + maxTexSize = 8192; +#endif +#ifdef MOZ_X11 + if (mVendor == GLVendor::Nouveau) { + // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau. + maxCubeSize = 2048; + } else if (mVendor == GLVendor::Intel) { + // Bug 1199923. Driver seems to report a larger max size than + // actually supported. + maxTexSize = mMaxTextureSize / 2; + } + // Bug 1367570. Explicitly set vertex attributes [1,3] to opaque + // black because Nvidia doesn't do it for us. + if (mVendor == GLVendor::NVIDIA) { + for (size_t i = 1; i <= 3; ++i) { + mSymbols.fVertexAttrib4f(i, 0, 0, 0, 1); + } + } +#endif + if (Renderer() == GLRenderer::AdrenoTM420) { + // see bug 1194923. Calling glFlush before glDeleteFramebuffers + // prevents occasional driver crash. + mNeedsFlushBeforeDeleteFB = true; + } + + // - + + const auto fnLimit = [&](int* const driver, const int limit) { + if (*driver > limit) { + *driver = limit; + mNeedsTextureSizeChecks = true; + } + }; + + fnLimit(&mMaxTextureSize, maxTexSize); + fnLimit(&mMaxRenderbufferSize, maxTexSize); + + maxCubeSize = std::min(maxCubeSize, maxTexSize); + fnLimit(&mMaxCubeMapTextureSize, maxCubeSize); + } + + if (IsSupported(GLFeature::framebuffer_multisample)) { + fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples); + } + + mMaxTexOrRbSize = std::min(mMaxTextureSize, mMaxRenderbufferSize); + + //////////////////////////////////////////////////////////////////////////// + + // We're ready for final setup. + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); + MOZ_GL_ASSERT(this, IsCurrent()); + + if (ShouldSpew() && IsExtensionSupported(KHR_debug)) { + fEnable(LOCAL_GL_DEBUG_OUTPUT); + fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS); + fDebugMessageCallback(&StaticDebugCallback, (void*)this); + fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE, + LOCAL_GL_DONT_CARE, 0, nullptr, true); + } + + return true; +} + +void GLContext::LoadMoreSymbols(const SymbolLoader& loader) { + const auto fnLoadForExt = [&](const SymLoadStruct* list, GLExtensions ext) { + return this->LoadExtSymbols(loader, list, ext); + }; + + const auto fnLoadForFeature = [&](const SymLoadStruct* list, + GLFeature feature) { + return this->LoadFeatureSymbols(loader, list, feature); + }; + + const auto fnLoadFeatureByCore = [&](const SymLoadStruct* coreList, + const SymLoadStruct* extList, + GLFeature feature) { + const bool useCore = this->IsFeatureProvidedByCoreSymbols(feature); + const auto list = useCore ? coreList : extList; + return fnLoadForFeature(list, feature); + }; + + if (IsSupported(GLFeature::robustness)) { + const auto resetStrategy = + GetIntAs<GLuint>(LOCAL_GL_RESET_NOTIFICATION_STRATEGY); + if (resetStrategy != LOCAL_GL_LOSE_CONTEXT_ON_RESET) { + NS_WARNING( + "Robustness supported, strategy is not LOSE_CONTEXT_ON_RESET!"); + if (ShouldSpew()) { + const bool isDisabled = + (resetStrategy == LOCAL_GL_NO_RESET_NOTIFICATION); + printf_stderr("Strategy: %s (0x%04x)", + (isDisabled ? "disabled" : "unrecognized"), + resetStrategy); + } + MarkUnsupported(GLFeature::robustness); + } + } + + if (IsSupported(GLFeature::sync)) { + const SymLoadStruct symbols[] = { + CORE_SYMBOL(FenceSync), CORE_SYMBOL(IsSync), + CORE_SYMBOL(DeleteSync), CORE_SYMBOL(ClientWaitSync), + CORE_SYMBOL(WaitSync), CORE_SYMBOL(GetInteger64v), + CORE_SYMBOL(GetSynciv), END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::sync); + } + + if (IsExtensionSupported(OES_EGL_image)) { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fEGLImageTargetTexture2D, + {{"glEGLImageTargetTexture2DOES"}}}, + {(PRFuncPtr*)&mSymbols.fEGLImageTargetRenderbufferStorage, + {{"glEGLImageTargetRenderbufferStorageOES"}}}, + END_SYMBOLS}; + fnLoadForExt(symbols, OES_EGL_image); + } + + if (IsExtensionSupported(APPLE_texture_range)) { + const SymLoadStruct symbols[] = {CORE_SYMBOL(TextureRangeAPPLE), + END_SYMBOLS}; + fnLoadForExt(symbols, APPLE_texture_range); + } + + if (IsExtensionSupported(APPLE_fence)) { + const SymLoadStruct symbols[] = {CORE_SYMBOL(FinishObjectAPPLE), + CORE_SYMBOL(TestObjectAPPLE), END_SYMBOLS}; + fnLoadForExt(symbols, APPLE_fence); + } + + // clang-format off + + if (IsSupported(GLFeature::vertex_array_object)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fIsVertexArray, {{ "glIsVertexArray" }} }, + { (PRFuncPtr*) &mSymbols.fGenVertexArrays, {{ "glGenVertexArrays" }} }, + { (PRFuncPtr*) &mSymbols.fBindVertexArray, {{ "glBindVertexArray" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, {{ "glDeleteVertexArrays" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fIsVertexArray, {{ "glIsVertexArrayARB", "glIsVertexArrayOES", "glIsVertexArrayAPPLE" }} }, + { (PRFuncPtr*) &mSymbols.fGenVertexArrays, {{ "glGenVertexArraysARB", "glGenVertexArraysOES", "glGenVertexArraysAPPLE" }} }, + { (PRFuncPtr*) &mSymbols.fBindVertexArray, {{ "glBindVertexArrayARB", "glBindVertexArrayOES", "glBindVertexArrayAPPLE" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, {{ "glDeleteVertexArraysARB", "glDeleteVertexArraysOES", "glDeleteVertexArraysAPPLE" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::vertex_array_object); + } + + if (IsSupported(GLFeature::draw_instanced)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, {{ "glDrawArraysInstanced" }} }, + { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, {{ "glDrawElementsInstanced" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, {{ "glDrawArraysInstancedARB", "glDrawArraysInstancedEXT", "glDrawArraysInstancedNV", "glDrawArraysInstancedANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, {{ "glDrawElementsInstancedARB", "glDrawElementsInstancedEXT", "glDrawElementsInstancedNV", "glDrawElementsInstancedANGLE" }} + }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_instanced); + } + + if (IsSupported(GLFeature::instanced_arrays)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, {{ "glVertexAttribDivisor" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, {{ "glVertexAttribDivisorARB", "glVertexAttribDivisorNV", "glVertexAttribDivisorANGLE" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::instanced_arrays); + } + + if (IsSupported(GLFeature::texture_storage)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fTexStorage2D, {{ "glTexStorage2D" }} }, + { (PRFuncPtr*) &mSymbols.fTexStorage3D, {{ "glTexStorage3D" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fTexStorage2D, {{ "glTexStorage2DEXT" }} }, + { (PRFuncPtr*) &mSymbols.fTexStorage3D, {{ "glTexStorage3DEXT" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_storage); + } + + if (IsSupported(GLFeature::sampler_objects)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fGenSamplers, {{ "glGenSamplers" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteSamplers, {{ "glDeleteSamplers" }} }, + { (PRFuncPtr*) &mSymbols.fIsSampler, {{ "glIsSampler" }} }, + { (PRFuncPtr*) &mSymbols.fBindSampler, {{ "glBindSampler" }} }, + { (PRFuncPtr*) &mSymbols.fSamplerParameteri, {{ "glSamplerParameteri" }} }, + { (PRFuncPtr*) &mSymbols.fSamplerParameteriv, {{ "glSamplerParameteriv" }} }, + { (PRFuncPtr*) &mSymbols.fSamplerParameterf, {{ "glSamplerParameterf" }} }, + { (PRFuncPtr*) &mSymbols.fSamplerParameterfv, {{ "glSamplerParameterfv" }} }, + { (PRFuncPtr*) &mSymbols.fGetSamplerParameteriv, {{ "glGetSamplerParameteriv" }} }, + { (PRFuncPtr*) &mSymbols.fGetSamplerParameterfv, {{ "glGetSamplerParameterfv" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::sampler_objects); + } + + // ARB_transform_feedback2/NV_transform_feedback2 is a + // superset of EXT_transform_feedback/NV_transform_feedback + // and adds glPauseTransformFeedback & + // glResumeTransformFeedback, which are required for WebGL2. + if (IsSupported(GLFeature::transform_feedback2)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBindBufferBase, {{ "glBindBufferBase" }} }, + { (PRFuncPtr*) &mSymbols.fBindBufferRange, {{ "glBindBufferRange" }} }, + { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, {{ "glGenTransformFeedbacks" }} }, + { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, {{ "glBindTransformFeedback" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, {{ "glDeleteTransformFeedbacks" }} }, + { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, {{ "glIsTransformFeedback" }} }, + { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, {{ "glBeginTransformFeedback" }} }, + { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, {{ "glEndTransformFeedback" }} }, + { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, {{ "glTransformFeedbackVaryings" }} }, + { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, {{ "glGetTransformFeedbackVarying" }} }, + { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, {{ "glPauseTransformFeedback" }} }, + { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, {{ "glResumeTransformFeedback" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBindBufferBase, {{ "glBindBufferBaseEXT", "glBindBufferBaseNV" }} }, + { (PRFuncPtr*) &mSymbols.fBindBufferRange, {{ "glBindBufferRangeEXT", "glBindBufferRangeNV" }} }, + { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, {{ "glGenTransformFeedbacksNV" }} }, + { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, {{ "glBindTransformFeedbackNV" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, {{ "glDeleteTransformFeedbacksNV" }} }, + { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, {{ "glIsTransformFeedbackNV" }} }, + { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, {{ "glBeginTransformFeedbackEXT", "glBeginTransformFeedbackNV" }} }, + { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, {{ "glEndTransformFeedbackEXT", "glEndTransformFeedbackNV" }} }, + { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, {{ "glTransformFeedbackVaryingsEXT", "glTransformFeedbackVaryingsNV" }} }, + { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, {{ "glGetTransformFeedbackVaryingEXT", "glGetTransformFeedbackVaryingNV" }} }, + { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, {{ "glPauseTransformFeedbackNV" }} }, + { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, {{ "glResumeTransformFeedbackNV" }} }, + END_SYMBOLS + }; + if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::transform_feedback2)) { + // Also mark bind_buffer_offset as unsupported. + MarkUnsupported(GLFeature::bind_buffer_offset); + } + } + + if (IsSupported(GLFeature::bind_buffer_offset)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBindBufferOffset, {{ "glBindBufferOffset" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBindBufferOffset, + {{ "glBindBufferOffsetEXT", "glBindBufferOffsetNV" }} + }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::bind_buffer_offset); + } + + if (IsSupported(GLFeature::query_counter)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fQueryCounter, {{ "glQueryCounter" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fQueryCounter, {{ "glQueryCounterEXT", "glQueryCounterANGLE" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_counter); + } + + if (IsSupported(GLFeature::query_objects)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBeginQuery, {{ "glBeginQuery" }} }, + { (PRFuncPtr*) &mSymbols.fGenQueries, {{ "glGenQueries" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteQueries, {{ "glDeleteQueries" }} }, + { (PRFuncPtr*) &mSymbols.fEndQuery, {{ "glEndQuery" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryiv, {{ "glGetQueryiv" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, {{ "glGetQueryObjectuiv" }} }, + { (PRFuncPtr*) &mSymbols.fIsQuery, {{ "glIsQuery" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBeginQuery, {{ "glBeginQueryEXT", "glBeginQueryANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fGenQueries, {{ "glGenQueriesEXT", "glGenQueriesANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteQueries, {{ "glDeleteQueriesEXT", "glDeleteQueriesANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fEndQuery, {{ "glEndQueryEXT", "glEndQueryANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryiv, {{ "glGetQueryivEXT", "glGetQueryivANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, {{ "glGetQueryObjectuivEXT", "glGetQueryObjectuivANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fIsQuery, {{ "glIsQueryEXT", "glIsQueryANGLE" }} }, + END_SYMBOLS + }; + if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_objects)) { + MarkUnsupported(GLFeature::get_query_object_i64v); + MarkUnsupported(GLFeature::get_query_object_iv); + MarkUnsupported(GLFeature::occlusion_query); + MarkUnsupported(GLFeature::occlusion_query_boolean); + MarkUnsupported(GLFeature::occlusion_query2); + } + } + + if (IsSupported(GLFeature::get_query_object_i64v)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, {{ "glGetQueryObjecti64v" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, {{ "glGetQueryObjectui64v" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, {{ "glGetQueryObjecti64vEXT", "glGetQueryObjecti64vANGLE" }} }, + { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, {{ "glGetQueryObjectui64vEXT", "glGetQueryObjectui64vANGLE" }} }, + END_SYMBOLS + }; + if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_i64v)) { + MarkUnsupported(GLFeature::query_counter); + } + } + + if (IsSupported(GLFeature::get_query_object_iv)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, {{ "glGetQueryObjectiv" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, {{ "glGetQueryObjectivEXT", "glGetQueryObjectivANGLE" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_iv); + } + + if (IsSupported(GLFeature::clear_buffers)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fClearBufferfi, {{ "glClearBufferfi", }} }, + { (PRFuncPtr*) &mSymbols.fClearBufferfv, {{ "glClearBufferfv", }} }, + { (PRFuncPtr*) &mSymbols.fClearBufferiv, {{ "glClearBufferiv", }} }, + { (PRFuncPtr*) &mSymbols.fClearBufferuiv, {{ "glClearBufferuiv" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::clear_buffers); + } + + if (IsSupported(GLFeature::copy_buffer)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fCopyBufferSubData, {{ "glCopyBufferSubData" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::copy_buffer); + } + + if (IsSupported(GLFeature::draw_buffers)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fDrawBuffers, {{ "glDrawBuffers" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fDrawBuffers, {{ "glDrawBuffersARB", "glDrawBuffersEXT" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_buffers); + } + + if (IsSupported(GLFeature::draw_buffers_indexed)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBlendEquationSeparatei, {{ "glBlendEquationSeparatei" }} }, + { (PRFuncPtr*) &mSymbols.fBlendFuncSeparatei, {{ "glBlendFuncSeparatei" }} }, + { (PRFuncPtr*) &mSymbols.fColorMaski, {{ "glColorMaski" }} }, + { (PRFuncPtr*) &mSymbols.fDisablei, {{ "glDisablei" }} }, + { (PRFuncPtr*) &mSymbols.fEnablei, {{ "glEnablei" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBlendEquationSeparatei, {{ "glBlendEquationSeparateiOES" }} }, + { (PRFuncPtr*) &mSymbols.fBlendFuncSeparatei, {{ "glBlendFuncSeparateiOES" }} }, + { (PRFuncPtr*) &mSymbols.fColorMaski, {{ "glColorMaskiOES" }} }, + { (PRFuncPtr*) &mSymbols.fDisablei, {{ "glDisableiOES" }} }, + { (PRFuncPtr*) &mSymbols.fEnablei, {{ "glEnableiOES" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_buffers_indexed); + } + + if (IsSupported(GLFeature::get_integer_indexed)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, {{ "glGetIntegeri_v" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] ={ + { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, {{ "glGetIntegerIndexedvEXT" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_integer_indexed); + } + + if (IsSupported(GLFeature::get_integer64_indexed)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fGetInteger64i_v, {{ "glGetInteger64i_v" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::get_integer64_indexed); + } + + if (IsSupported(GLFeature::gpu_shader4)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fGetVertexAttribIiv, {{ "glGetVertexAttribIiv", "glGetVertexAttribIivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fGetVertexAttribIuiv, {{ "glGetVertexAttribIuiv", "glGetVertexAttribIuivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribI4i, {{ "glVertexAttribI4i", "glVertexAttribI4iEXT" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribI4iv, {{ "glVertexAttribI4iv", "glVertexAttribI4ivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribI4ui, {{ "glVertexAttribI4ui", "glVertexAttribI4uiEXT" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribI4uiv, {{ "glVertexAttribI4uiv", "glVertexAttribI4uivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fVertexAttribIPointer, {{ "glVertexAttribIPointer", "glVertexAttribIPointerEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1ui, {{ "glUniform1ui", "glUniform1uiEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2ui, {{ "glUniform2ui", "glUniform2uiEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3ui, {{ "glUniform3ui", "glUniform3uiEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4ui, {{ "glUniform4ui", "glUniform4uiEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform1uiv, {{ "glUniform1uiv", "glUniform1uivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform2uiv, {{ "glUniform2uiv", "glUniform2uivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform3uiv, {{ "glUniform3uiv", "glUniform3uivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fUniform4uiv, {{ "glUniform4uiv", "glUniform4uivEXT" }} }, + { (PRFuncPtr*) &mSymbols.fGetFragDataLocation, {{ "glGetFragDataLocation", "glGetFragDataLocationEXT" }} }, + { (PRFuncPtr*) &mSymbols.fGetUniformuiv, {{ "glGetUniformuiv", "glGetUniformuivEXT" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::gpu_shader4); + } + + if (IsSupported(GLFeature::map_buffer_range)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fMapBufferRange, {{ "glMapBufferRange" }} }, + { (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, {{ "glFlushMappedBufferRange" }} }, + { (PRFuncPtr*) &mSymbols.fUnmapBuffer, {{ "glUnmapBuffer" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::map_buffer_range); + } + + if (IsSupported(GLFeature::texture_3D)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fTexImage3D, {{ "glTexImage3D" }} }, + { (PRFuncPtr*) &mSymbols.fTexSubImage3D, {{ "glTexSubImage3D" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fTexImage3D, {{ "glTexImage3DOES" }} }, + { (PRFuncPtr*) &mSymbols.fTexSubImage3D, {{ "glTexSubImage3DOES" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D); + } + + if (IsSupported(GLFeature::texture_3D_compressed)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, {{ "glCompressedTexImage3D" }} }, + { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, {{ "glCompressedTexSubImage3D" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, {{ "glCompressedTexImage3DARB", "glCompressedTexImage3DOES" }} }, + { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, {{ "glCompressedTexSubImage3DARB", "glCompressedTexSubImage3DOES" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_compressed); + } + + if (IsSupported(GLFeature::texture_3D_copy)) { + const SymLoadStruct coreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, {{ "glCopyTexSubImage3D" }} }, + END_SYMBOLS + }; + const SymLoadStruct extSymbols[] = { + { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, {{ "glCopyTexSubImage3DEXT", "glCopyTexSubImage3DOES" }} }, + END_SYMBOLS + }; + fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_copy); + } + + if (IsSupported(GLFeature::uniform_buffer_object)) { + // Note: Don't query for glGetActiveUniformName because it is not + // supported by GL ES 3. + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fGetUniformIndices, {{ "glGetUniformIndices" }} }, + { (PRFuncPtr*) &mSymbols.fGetActiveUniformsiv, {{ "glGetActiveUniformsiv" }} }, + { (PRFuncPtr*) &mSymbols.fGetUniformBlockIndex, {{ "glGetUniformBlockIndex" }} }, + { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockiv, {{ "glGetActiveUniformBlockiv" }} }, + { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockName, {{ "glGetActiveUniformBlockName" }} }, + { (PRFuncPtr*) &mSymbols.fUniformBlockBinding, {{ "glUniformBlockBinding" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::uniform_buffer_object); + } + + if (IsSupported(GLFeature::uniform_matrix_nonsquare)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fUniformMatrix2x3fv, {{ "glUniformMatrix2x3fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix2x4fv, {{ "glUniformMatrix2x4fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix3x2fv, {{ "glUniformMatrix3x2fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix3x4fv, {{ "glUniformMatrix3x4fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix4x2fv, {{ "glUniformMatrix4x2fv" }} }, + { (PRFuncPtr*) &mSymbols.fUniformMatrix4x3fv, {{ "glUniformMatrix4x3fv" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::uniform_matrix_nonsquare); + } + + if (IsSupported(GLFeature::internalformat_query)) { + const SymLoadStruct symbols[] = { + CORE_SYMBOL(GetInternalformativ), + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::internalformat_query); + } + + if (IsSupported(GLFeature::invalidate_framebuffer)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fInvalidateFramebuffer, {{ "glInvalidateFramebuffer" }} }, + { (PRFuncPtr*) &mSymbols.fInvalidateSubFramebuffer, {{ "glInvalidateSubFramebuffer" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::invalidate_framebuffer); + } + + if (IsSupported(GLFeature::multiview)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fFramebufferTextureMultiview, {{ + "glFramebufferTextureMultiviewOVR", + "glFramebufferTextureMultiviewLayeredANGLE" + }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::multiview); + } + + if (IsSupported(GLFeature::prim_restart)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fPrimitiveRestartIndex, {{ "glPrimitiveRestartIndex", "glPrimitiveRestartIndexNV" }} }, + END_SYMBOLS + }; + fnLoadForFeature(symbols, GLFeature::prim_restart); + } + + if (IsExtensionSupported(KHR_debug)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fDebugMessageControl, {{ "glDebugMessageControl", "glDebugMessageControlKHR", }} }, + { (PRFuncPtr*) &mSymbols.fDebugMessageInsert, {{ "glDebugMessageInsert", "glDebugMessageInsertKHR", }} }, + { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, {{ "glDebugMessageCallback", "glDebugMessageCallbackKHR" }} }, + { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog, {{ "glGetDebugMessageLog", "glGetDebugMessageLogKHR", }} }, + { (PRFuncPtr*) &mSymbols.fGetPointerv, {{ "glGetPointerv", "glGetPointervKHR", }} }, + { (PRFuncPtr*) &mSymbols.fPushDebugGroup, {{ "glPushDebugGroup", "glPushDebugGroupKHR", }} }, + { (PRFuncPtr*) &mSymbols.fPopDebugGroup, {{ "glPopDebugGroup", "glPopDebugGroupKHR", }} }, + { (PRFuncPtr*) &mSymbols.fObjectLabel, {{ "glObjectLabel", "glObjectLabelKHR", }} }, + { (PRFuncPtr*) &mSymbols.fGetObjectLabel, {{ "glGetObjectLabel", "glGetObjectLabelKHR", }} }, + { (PRFuncPtr*) &mSymbols.fObjectPtrLabel, {{ "glObjectPtrLabel", "glObjectPtrLabelKHR", }} }, + { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel, {{ "glGetObjectPtrLabel", "glGetObjectPtrLabelKHR", }} }, + END_SYMBOLS + }; + fnLoadForExt(symbols, KHR_debug); + } + + if (IsExtensionSupported(NV_fence)) { + const SymLoadStruct symbols[] = { + { (PRFuncPtr*) &mSymbols.fGenFences, {{ "glGenFencesNV" }} }, + { (PRFuncPtr*) &mSymbols.fDeleteFences, {{ "glDeleteFencesNV" }} }, + { (PRFuncPtr*) &mSymbols.fSetFence, {{ "glSetFenceNV" }} }, + { (PRFuncPtr*) &mSymbols.fTestFence, {{ "glTestFenceNV" }} }, + { (PRFuncPtr*) &mSymbols.fFinishFence, {{ "glFinishFenceNV" }} }, + { (PRFuncPtr*) &mSymbols.fIsFence, {{ "glIsFenceNV" }} }, + { (PRFuncPtr*) &mSymbols.fGetFenceiv, {{ "glGetFenceivNV" }} }, + END_SYMBOLS + }; + fnLoadForExt(symbols, NV_fence); + } + + // clang-format on + + if (IsExtensionSupported(NV_texture_barrier)) { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fTextureBarrier, {{"glTextureBarrierNV"}}}, + END_SYMBOLS}; + fnLoadForExt(symbols, NV_texture_barrier); + } + + if (IsSupported(GLFeature::read_buffer)) { + const SymLoadStruct symbols[] = {CORE_SYMBOL(ReadBuffer), END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::read_buffer); + } + + if (IsExtensionSupported(APPLE_framebuffer_multisample)) { + const SymLoadStruct symbols[] = { + CORE_SYMBOL(ResolveMultisampleFramebufferAPPLE), END_SYMBOLS}; + fnLoadForExt(symbols, APPLE_framebuffer_multisample); + } + + if (IsSupported(GLFeature::provoking_vertex)) { + const SymLoadStruct symbols[] = {{(PRFuncPtr*)&mSymbols.fProvokingVertex, + {{ + "glProvokingVertex", + "glProvokingVertexANGLE", + "glProvokingVertexEXT", + }}}, + END_SYMBOLS}; + fnLoadForFeature(symbols, GLFeature::provoking_vertex); + } + + // Load developer symbols, don't fail if we can't find them. + const SymLoadStruct devSymbols[] = {CORE_SYMBOL(GetTexImage), + CORE_SYMBOL(GetTexLevelParameteriv), + END_SYMBOLS}; + const bool warnOnFailures = ShouldSpew(); + (void)loader.LoadSymbols(devSymbols, warnOnFailures); +} + +#undef CORE_SYMBOL +#undef CORE_EXT_SYMBOL2 +#undef EXT_SYMBOL2 +#undef EXT_SYMBOL3 +#undef END_SYMBOLS + +void GLContext::DebugCallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar* message) { + nsAutoCString sourceStr; + switch (source) { + case LOCAL_GL_DEBUG_SOURCE_API: + sourceStr = "SOURCE_API"_ns; + break; + case LOCAL_GL_DEBUG_SOURCE_WINDOW_SYSTEM: + sourceStr = "SOURCE_WINDOW_SYSTEM"_ns; + break; + case LOCAL_GL_DEBUG_SOURCE_SHADER_COMPILER: + sourceStr = "SOURCE_SHADER_COMPILER"_ns; + break; + case LOCAL_GL_DEBUG_SOURCE_THIRD_PARTY: + sourceStr = "SOURCE_THIRD_PARTY"_ns; + break; + case LOCAL_GL_DEBUG_SOURCE_APPLICATION: + sourceStr = "SOURCE_APPLICATION"_ns; + break; + case LOCAL_GL_DEBUG_SOURCE_OTHER: + sourceStr = "SOURCE_OTHER"_ns; + break; + default: + sourceStr = nsPrintfCString("<source 0x%04x>", source); + break; + } + + nsAutoCString typeStr; + switch (type) { + case LOCAL_GL_DEBUG_TYPE_ERROR: + typeStr = "TYPE_ERROR"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + typeStr = "TYPE_DEPRECATED_BEHAVIOR"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + typeStr = "TYPE_UNDEFINED_BEHAVIOR"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_PORTABILITY: + typeStr = "TYPE_PORTABILITY"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_PERFORMANCE: + typeStr = "TYPE_PERFORMANCE"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_OTHER: + typeStr = "TYPE_OTHER"_ns; + break; + case LOCAL_GL_DEBUG_TYPE_MARKER: + typeStr = "TYPE_MARKER"_ns; + break; + default: + typeStr = nsPrintfCString("<type 0x%04x>", type); + break; + } + + nsAutoCString sevStr; + switch (severity) { + case LOCAL_GL_DEBUG_SEVERITY_HIGH: + sevStr = "SEVERITY_HIGH"_ns; + break; + case LOCAL_GL_DEBUG_SEVERITY_MEDIUM: + sevStr = "SEVERITY_MEDIUM"_ns; + break; + case LOCAL_GL_DEBUG_SEVERITY_LOW: + sevStr = "SEVERITY_LOW"_ns; + break; + case LOCAL_GL_DEBUG_SEVERITY_NOTIFICATION: + sevStr = "SEVERITY_NOTIFICATION"_ns; + break; + default: + sevStr = nsPrintfCString("<severity 0x%04x>", severity); + break; + } + + printf_stderr("[KHR_debug: 0x%" PRIxPTR "] ID %u: %s, %s, %s:\n %s\n", + (uintptr_t)this, id, sourceStr.BeginReading(), + typeStr.BeginReading(), sevStr.BeginReading(), message); +} + +void GLContext::InitExtensions() { + MOZ_GL_ASSERT(this, IsCurrent()); + + std::vector<nsCString> driverExtensionList; + + [&]() { + if (mSymbols.fGetStringi) { + GLuint count = 0; + if (GetPotentialInteger(LOCAL_GL_NUM_EXTENSIONS, (GLint*)&count)) { + for (GLuint i = 0; i < count; i++) { + // This is UTF-8. + const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i); + + // We CANNOT use nsDependentCString here, because the spec doesn't + // guarantee that the pointers returned are different, only that their + // contents are. On Flame, each of these index string queries returns + // the same address. + driverExtensionList.push_back(nsCString(rawExt)); + } + return; + } + } + + const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS); + if (rawExts) { + nsDependentCString exts(rawExts); + SplitByChar(exts, ' ', &driverExtensionList); + } + }(); + const auto err = fGetError(); + MOZ_ALWAYS_TRUE(!IsBadCallError(err)); + + const bool shouldDumpExts = ShouldDumpExts(); + if (shouldDumpExts) { + printf_stderr("%i GL driver extensions: (*: recognized)\n", + (uint32_t)driverExtensionList.size()); + } + + MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sExtensionNames, + &mAvailableExtensions); + + if (WorkAroundDriverBugs()) { + if (Vendor() == GLVendor::Qualcomm) { + // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do + // support it. + MarkExtensionSupported(OES_EGL_sync); + } + + if (Vendor() == GLVendor::ATI) { + // ATI drivers say this extension exists, but we can't + // actually find the EGLImageTargetRenderbufferStorageOES + // extension function pointer in the drivers. + MarkExtensionUnsupported(OES_EGL_image); + } + + if (Vendor() == GLVendor::Imagination && Renderer() == GLRenderer::SGX540) { + // Bug 980048 + MarkExtensionUnsupported(OES_EGL_sync); + } + + if (Vendor() == GLVendor::ARM && (Renderer() == GLRenderer::Mali400MP || + Renderer() == GLRenderer::Mali450MP)) { + // Bug 1264505 + MarkExtensionUnsupported(OES_EGL_image_external); + } + + if (Renderer() == GLRenderer::AndroidEmulator) { + // the Android emulator, which we use to run B2G reftests on, + // doesn't expose the OES_rgb8_rgba8 extension, but it seems to + // support it (tautologically, as it only runs on desktop GL). + MarkExtensionSupported(OES_rgb8_rgba8); + } + + if (Vendor() == GLVendor::VMware && + Renderer() == GLRenderer::GalliumLlvmpipe) { + // The llvmpipe driver that is used on linux try servers appears to have + // buggy support for s3tc/dxt1 compressed textures. + // See Bug 975824. + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + MarkExtensionUnsupported(EXT_texture_compression_dxt1); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); + } + +#ifdef XP_MACOSX + // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD + // 3000 appears to be buggy WRT updating sub-images of S3TC + // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 + // and Intel HD 5000/Iris that I tested. + // Bug 1124996: Appears to be the same on OSX Yosemite (10.10) + if (Renderer() == GLRenderer::IntelHD3000) { + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + } + + // OSX supports EXT_texture_sRGB in Legacy contexts, but not in Core + // contexts. Though EXT_texture_sRGB was included into GL2.1, it *excludes* + // the interactions with s3tc. Strictly speaking, you must advertize support + // for EXT_texture_sRGB in order to allow for srgb+s3tc on desktop GL. The + // omission of EXT_texture_sRGB in OSX Core contexts appears to be a bug. + MarkExtensionSupported(EXT_texture_sRGB); +#endif + } + + if (shouldDumpExts) { + printf_stderr("\nActivated extensions:\n"); + + for (size_t i = 0; i < mAvailableExtensions.size(); i++) { + if (!mAvailableExtensions[i]) continue; + + const char* ext = sExtensionNames[i]; + printf_stderr("[%i] %s\n", (uint32_t)i, ext); + } + } +} + +void GLContext::PlatformStartup() { + RegisterStrongMemoryReporter(new GfxTexturesReporter()); +} + +// Common code for checking for both GL extensions and GLX extensions. +bool GLContext::ListHasExtension(const GLubyte* extensions, + const char* extension) { + // fix bug 612572 - we were crashing as we were calling this function with + // extensions==null + if (extensions == nullptr || extension == nullptr) return false; + + const GLubyte* start; + GLubyte* where; + GLubyte* terminator; + + /* Extension names should not have spaces. */ + where = (GLubyte*)strchr(extension, ' '); + if (where || *extension == '\0') return false; + + /* + * It takes a bit of care to be fool-proof about parsing the + * OpenGL extensions string. Don't be fooled by sub-strings, + * etc. + */ + start = extensions; + for (;;) { + where = (GLubyte*)strstr((const char*)start, extension); + if (!where) { + break; + } + terminator = where + strlen(extension); + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + return true; + } + } + start = terminator; + } + return false; +} + +bool GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) { + MOZ_ASSERT(fb); + + ScopedBindFramebuffer autoFB(this, fb); + MOZ_GL_ASSERT(this, fIsFramebuffer(fb)); + + GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (pStatus) *pStatus = status; + + return status == LOCAL_GL_FRAMEBUFFER_COMPLETE; +} + +void GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB, + GLuint depthRB, GLuint stencilRB, GLuint fb, + GLenum target) { + MOZ_ASSERT(fb); + MOZ_ASSERT(!(colorTex && colorRB)); + + ScopedBindFramebuffer autoFB(this, fb); + MOZ_GL_ASSERT(this, fIsFramebuffer(fb)); // It only counts after being bound. + + if (colorTex) { + MOZ_GL_ASSERT(this, fIsTexture(colorTex)); + MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || + target == LOCAL_GL_TEXTURE_RECTANGLE_ARB); + fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + target, colorTex, 0); + } else if (colorRB) { + // On the Android 4.3 emulator, IsRenderbuffer may return false incorrectly. + MOZ_GL_ASSERT(this, fIsRenderbuffer(colorRB) || + Renderer() == GLRenderer::AndroidEmulator); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, colorRB); + } + + if (depthRB) { + MOZ_GL_ASSERT(this, fIsRenderbuffer(depthRB) || + Renderer() == GLRenderer::AndroidEmulator); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, depthRB); + } + + if (stencilRB) { + MOZ_GL_ASSERT(this, fIsRenderbuffer(stencilRB) || + Renderer() == GLRenderer::AndroidEmulator); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, stencilRB); + } +} + +bool GLContext::AssembleOffscreenFBs(const GLuint colorMSRB, + const GLuint depthRB, + const GLuint stencilRB, + const GLuint texture, GLuint* drawFB_out, + GLuint* readFB_out) { + if (!colorMSRB && !texture) { + MOZ_ASSERT(!depthRB && !stencilRB); + + if (drawFB_out) *drawFB_out = 0; + if (readFB_out) *readFB_out = 0; + + return true; + } + + ScopedBindFramebuffer autoFB(this); + + GLuint drawFB = 0; + GLuint readFB = 0; + + if (texture) { + readFB = 0; + fGenFramebuffers(1, &readFB); + BindFB(readFB); + fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_TEXTURE_2D, texture, 0); + } + + if (colorMSRB) { + drawFB = 0; + fGenFramebuffers(1, &drawFB); + BindFB(drawFB); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, colorMSRB); + } else { + drawFB = readFB; + } + MOZ_ASSERT(GetIntAs<GLuint>(LOCAL_GL_FRAMEBUFFER_BINDING) == drawFB); + + if (depthRB) { + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, depthRB); + } + + if (stencilRB) { + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, stencilRB); + } + + // We should be all resized. Check for framebuffer completeness. + GLenum status; + bool isComplete = true; + + if (!IsFramebufferComplete(drawFB, &status)) { + NS_WARNING("DrawFBO: Incomplete"); +#ifdef MOZ_GL_DEBUG_BUILD + if (ShouldSpew()) { + printf_stderr("Framebuffer status: %X\n", status); + } +#endif + isComplete = false; + } + + if (!IsFramebufferComplete(readFB, &status)) { + NS_WARNING("ReadFBO: Incomplete"); +#ifdef MOZ_GL_DEBUG_BUILD + if (ShouldSpew()) { + printf_stderr("Framebuffer status: %X\n", status); + } +#endif + isComplete = false; + } + + if (drawFB_out) { + *drawFB_out = drawFB; + } else if (drawFB) { + MOZ_CRASH("drawFB created when not requested!"); + } + + if (readFB_out) { + *readFB_out = readFB; + } else if (readFB) { + MOZ_CRASH("readFB created when not requested!"); + } + + return isComplete; +} + +void GLContext::MarkDestroyed() { + if (IsDestroyed()) return; + + OnMarkDestroyed(); + + // Null these before they're naturally nulled after dtor, as we want GLContext + // to still be alive in *their* dtors. + mBlitHelper = nullptr; + mReadTexImageHelper = nullptr; + + mContextLost = true; + mSymbols = {}; +} + +// - + +#ifdef MOZ_GL_DEBUG_BUILD +/* static */ +void GLContext::AssertNotPassingStackBufferToTheGL(const void* ptr) { + int somethingOnTheStack; + const void* someStackPtr = &somethingOnTheStack; + const int page_bits = 12; + intptr_t page = reinterpret_cast<uintptr_t>(ptr) >> page_bits; + intptr_t someStackPage = + reinterpret_cast<uintptr_t>(someStackPtr) >> page_bits; + uintptr_t pageDistance = std::abs(page - someStackPage); + + // Explanation for the "distance <= 1" check here as opposed to just + // an equality check. + // + // Here we assume that pages immediately adjacent to the someStackAddress + // page, are also stack pages. That allows to catch the case where the calling + // frame put a buffer on the stack, and we just crossed the page boundary. + // That is likely to happen, precisely, when using stack arrays. I hit that + // specifically with CompositorOGL::Initialize. + // + // In theory we could be unlucky and wrongly assert here. If that happens, + // it will only affect debug builds, and looking at stacks we'll be able to + // see that this assert is wrong and revert to the conservative and safe + // approach of only asserting when address and someStackAddress are + // on the same page. + bool isStackAddress = pageDistance <= 1; + MOZ_ASSERT(!isStackAddress, + "Please don't pass stack arrays to the GL. " + "Consider using HeapCopyOfStackArray. " + "See bug 1005658."); +} + +void GLContext::CreatedProgram(GLContext* aOrigin, GLuint aName) { + mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName)); +} + +void GLContext::CreatedShader(GLContext* aOrigin, GLuint aName) { + mTrackedShaders.AppendElement(NamedResource(aOrigin, aName)); +} + +void GLContext::CreatedBuffers(GLContext* aOrigin, GLsizei aCount, + GLuint* aNames) { + for (GLsizei i = 0; i < aCount; ++i) { + mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i])); + } +} + +void GLContext::CreatedQueries(GLContext* aOrigin, GLsizei aCount, + GLuint* aNames) { + for (GLsizei i = 0; i < aCount; ++i) { + mTrackedQueries.AppendElement(NamedResource(aOrigin, aNames[i])); + } +} + +void GLContext::CreatedTextures(GLContext* aOrigin, GLsizei aCount, + GLuint* aNames) { + for (GLsizei i = 0; i < aCount; ++i) { + mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i])); + } +} + +void GLContext::CreatedFramebuffers(GLContext* aOrigin, GLsizei aCount, + GLuint* aNames) { + for (GLsizei i = 0; i < aCount; ++i) { + mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i])); + } +} + +void GLContext::CreatedRenderbuffers(GLContext* aOrigin, GLsizei aCount, + GLuint* aNames) { + for (GLsizei i = 0; i < aCount; ++i) { + mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i])); + } +} + +static void RemoveNamesFromArray(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames, + nsTArray<GLContext::NamedResource>& aArray) { + for (GLsizei j = 0; j < aCount; ++j) { + GLuint name = aNames[j]; + // name 0 can be ignored + if (name == 0) continue; + + for (uint32_t i = 0; i < aArray.Length(); ++i) { + if (aArray[i].name == name) { + aArray.RemoveElementAt(i); + break; + } + } + } +} + +void GLContext::DeletedProgram(GLContext* aOrigin, GLuint aName) { + RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms); +} + +void GLContext::DeletedShader(GLContext* aOrigin, GLuint aName) { + RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders); +} + +void GLContext::DeletedBuffers(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames) { + RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers); +} + +void GLContext::DeletedQueries(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames) { + RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedQueries); +} + +void GLContext::DeletedTextures(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames) { + RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures); +} + +void GLContext::DeletedFramebuffers(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames) { + RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers); +} + +void GLContext::DeletedRenderbuffers(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames) { + RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers); +} + +static void MarkContextDestroyedInArray( + GLContext* aContext, nsTArray<GLContext::NamedResource>& aArray) { + for (uint32_t i = 0; i < aArray.Length(); ++i) { + if (aArray[i].origin == aContext) aArray[i].originDeleted = true; + } +} + +void GLContext::SharedContextDestroyed(GLContext* aChild) { + MarkContextDestroyedInArray(aChild, mTrackedPrograms); + MarkContextDestroyedInArray(aChild, mTrackedShaders); + MarkContextDestroyedInArray(aChild, mTrackedTextures); + MarkContextDestroyedInArray(aChild, mTrackedFramebuffers); + MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers); + MarkContextDestroyedInArray(aChild, mTrackedBuffers); + MarkContextDestroyedInArray(aChild, mTrackedQueries); +} + +static void ReportArrayContents( + const char* title, const nsTArray<GLContext::NamedResource>& aArray) { + if (aArray.Length() == 0) return; + + printf_stderr("%s:\n", title); + + nsTArray<GLContext::NamedResource> copy(aArray.Clone()); + copy.Sort(); + + GLContext* lastContext = nullptr; + for (uint32_t i = 0; i < copy.Length(); ++i) { + if (lastContext != copy[i].origin) { + if (lastContext) printf_stderr("\n"); + printf_stderr(" [%p - %s] ", copy[i].origin, + copy[i].originDeleted ? "deleted" : "live"); + lastContext = copy[i].origin; + } + printf_stderr("%d ", copy[i].name); + } + printf_stderr("\n"); +} + +void GLContext::ReportOutstandingNames() { + if (!ShouldSpew()) return; + + printf_stderr("== GLContext %p Outstanding ==\n", this); + + ReportArrayContents("Outstanding Textures", mTrackedTextures); + ReportArrayContents("Outstanding Buffers", mTrackedBuffers); + ReportArrayContents("Outstanding Queries", mTrackedQueries); + ReportArrayContents("Outstanding Programs", mTrackedPrograms); + ReportArrayContents("Outstanding Shaders", mTrackedShaders); + ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers); + ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers); +} + +#endif // ifdef MOZ_GL_DEBUG_BUILD + +bool GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const { + int32_t biggerDimension = std::max(aSize.width, aSize.height); + int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize); + return biggerDimension <= maxAllowed; +} + +bool GLContext::IsValidOwningThread() const { + if (!mOwningThreadId) return true; // Free for all! + return PlatformThread::CurrentId() == *mOwningThreadId; +} + +GLBlitHelper* GLContext::BlitHelper() { + if (!mBlitHelper) { + mBlitHelper.reset(new GLBlitHelper(this)); + } + + return mBlitHelper.get(); +} + +GLReadTexImageHelper* GLContext::ReadTexImageHelper() { + if (!mReadTexImageHelper) { + mReadTexImageHelper = MakeUnique<GLReadTexImageHelper>(this); + } + + return mReadTexImageHelper.get(); +} + +void GLContext::FlushIfHeavyGLCallsSinceLastFlush() { + if (!mHeavyGLCallsSinceLastFlush) { + return; + } + if (MakeCurrent()) { + fFlush(); + } +} + +/*static*/ +bool GLContext::ShouldDumpExts() { return gfxEnv::MOZ_GL_DUMP_EXTS(); } + +bool DoesStringMatch(const char* aString, const char* aWantedString) { + if (!aString || !aWantedString) return false; + + const char* occurrence = strstr(aString, aWantedString); + + // aWanted not found + if (!occurrence) return false; + + // aWantedString preceded by alpha character + if (occurrence != aString && isalpha(*(occurrence - 1))) return false; + + // aWantedVendor followed by alpha character + const char* afterOccurrence = occurrence + strlen(aWantedString); + if (isalpha(*afterOccurrence)) return false; + + return true; +} + +/*static*/ +bool GLContext::ShouldSpew() { return gfxEnv::MOZ_GL_SPEW(); } + +void SplitByChar(const nsACString& str, const char delim, + std::vector<nsCString>* const out) { + uint32_t start = 0; + while (true) { + int32_t end = str.FindChar(' ', start); + if (end == -1) break; + + uint32_t len = (uint32_t)end - start; + nsDependentCSubstring substr(str, start, len); + out->push_back(nsCString(substr)); + + start = end + 1; + } + + nsDependentCSubstring substr(str, start); + out->push_back(nsCString(substr)); +} + +void GLContext::fCopyTexImage2D(GLenum target, GLint level, + GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border) { + if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { + // pass wrong values to cause the GL to generate GL_INVALID_VALUE. + // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. + level = -1; + width = -1; + height = -1; + border = -1; + } + + BeforeGLReadCall(); + raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, + border); + AfterGLReadCall(); +} + +void GLContext::fGetIntegerv(const GLenum pname, GLint* const params) const { + const auto AssertBinding = [&](const char* const name, const GLenum binding, + const GLuint expected) { + if (MOZ_LIKELY(!mDebugFlags)) return; + GLuint actual = 0; + raw_fGetIntegerv(binding, (GLint*)&actual); + if (actual != expected) { + gfxCriticalError() << "Misprediction: " << name << " expected " + << expected << ", was " << actual; + } + }; + + switch (pname) { + case LOCAL_GL_MAX_TEXTURE_SIZE: + MOZ_ASSERT(mMaxTextureSize > 0); + *params = mMaxTextureSize; + return; + + case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: + MOZ_ASSERT(mMaxCubeMapTextureSize > 0); + *params = mMaxCubeMapTextureSize; + return; + + case LOCAL_GL_MAX_RENDERBUFFER_SIZE: + MOZ_ASSERT(mMaxRenderbufferSize > 0); + *params = mMaxRenderbufferSize; + return; + + case LOCAL_GL_VIEWPORT: + for (size_t i = 0; i < 4; i++) { + params[i] = mViewportRect[i]; + } + return; + + case LOCAL_GL_SCISSOR_BOX: + for (size_t i = 0; i < 4; i++) { + params[i] = mScissorRect[i]; + } + return; + + case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING: + if (mElideDuplicateBindFramebuffers) { + static_assert(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING == + LOCAL_GL_FRAMEBUFFER_BINDING); + AssertBinding("GL_DRAW_FRAMEBUFFER_BINDING", + LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, mCachedDrawFb); + *params = static_cast<GLint>(mCachedDrawFb); + return; + } + break; + + case LOCAL_GL_READ_FRAMEBUFFER_BINDING: + if (mElideDuplicateBindFramebuffers) { + if (IsSupported(GLFeature::framebuffer_blit)) { + AssertBinding("GL_READ_FRAMEBUFFER_BINDING", + LOCAL_GL_READ_FRAMEBUFFER_BINDING, mCachedReadFb); + } + *params = static_cast<GLint>(mCachedReadFb); + return; + } + break; + + default: + break; + } + raw_fGetIntegerv(pname, params); +} + +void GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) { + BeforeGLReadCall(); + raw_fReadPixels(x, y, width, height, format, type, pixels); + AfterGLReadCall(); + + // Check if GL is giving back 1.0 alpha for + // RGBA reads to RGBA images from no-alpha buffers. +#ifdef XP_MACOSX + if (WorkAroundDriverBugs() && Vendor() == gl::GLVendor::NVIDIA && + format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE && + !IsCoreProfile() && width && height) { + GLint alphaBits = 0; + fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits); + if (!alphaBits) { + const uint32_t alphaMask = 0xff000000; + + uint32_t* itr = (uint32_t*)pixels; + uint32_t testPixel = *itr; + if ((testPixel & alphaMask) != alphaMask) { + // We need to set the alpha channel to 1.0 manually. + uint32_t* itrEnd = + itr + width * height; // Stride is guaranteed to be width*4. + + for (; itr != itrEnd; itr++) { + *itr |= alphaMask; + } + } + } + } +#endif +} + +void GLContext::fDeleteFramebuffers(GLsizei n, const GLuint* names) { + // Avoid crash by flushing before glDeleteFramebuffers. See bug 1194923. + if (mNeedsFlushBeforeDeleteFB) { + fFlush(); + } + + if (n == 1 && *names == 0) { + // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228. + } else { + raw_fDeleteFramebuffers(n, names); + } + TRACKING_CONTEXT(DeletedFramebuffers(this, n, names)); +} + +#ifdef MOZ_WIDGET_ANDROID +/** + * Conservatively estimate whether there is enough available + * contiguous virtual address space to map a newly allocated texture. + */ +static bool WillTextureMapSucceed(GLsizei width, GLsizei height, GLenum format, + GLenum type) { + bool willSucceed = false; + // Some drivers leave large gaps between textures, so require + // there to be double the actual size of the texture available. + size_t size = width * height * GetBytesPerTexel(format, type) * 2; + + void* p = mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p != MAP_FAILED) { + willSucceed = true; + munmap(p, size); + } + + return willSucceed; +} +#endif // MOZ_WIDGET_ANDROID + +void GLContext::fTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid* pixels) { + if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { + // pass wrong values to cause the GL to generate GL_INVALID_VALUE. + // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. + level = -1; + width = -1; + height = -1; + border = -1; + } +#if MOZ_WIDGET_ANDROID + if (mTextureAllocCrashesOnMapFailure) { + // We have no way of knowing whether this texture already has + // storage allocated for it, and therefore whether this check + // is necessary. We must therefore assume it does not and + // always perform the check. + if (!WillTextureMapSucceed(width, height, internalformat, type)) { + return; + } + } +#endif + raw_fTexImage2D(target, level, internalformat, width, height, border, format, + type, pixels); +} + +UniquePtr<Texture> CreateTexture(GLContext& gl, const gfx::IntSize& size) { + const GLenum target = LOCAL_GL_TEXTURE_2D; + const GLenum format = LOCAL_GL_RGBA; + + auto tex = MakeUnique<Texture>(gl); + ScopedBindTexture autoTex(&gl, tex->name, target); + + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + + gl.fTexImage2D(target, 0, format, size.width, size.height, 0, format, + LOCAL_GL_UNSIGNED_BYTE, nullptr); + + return tex; +} + +uint32_t GetBytesPerTexel(GLenum format, GLenum type) { + // If there is no defined format or type, we're not taking up any memory + if (!format || !type) { + return 0; + } + + if (format == LOCAL_GL_DEPTH_COMPONENT) { + if (type == LOCAL_GL_UNSIGNED_SHORT) + return 2; + else if (type == LOCAL_GL_UNSIGNED_INT) + return 4; + } else if (format == LOCAL_GL_DEPTH_STENCIL) { + if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT) return 4; + } + + if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT || + type == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) { + uint32_t multiplier = type == LOCAL_GL_UNSIGNED_BYTE ? 1 : 4; + switch (format) { + case LOCAL_GL_ALPHA: + case LOCAL_GL_LUMINANCE: + case LOCAL_GL_R8: + return 1 * multiplier; + case LOCAL_GL_LUMINANCE_ALPHA: + case LOCAL_GL_R16: + return 2 * multiplier; + case LOCAL_GL_RGB: + return 3 * multiplier; + case LOCAL_GL_RGBA: + case LOCAL_GL_BGRA_EXT: + return 4 * multiplier; + default: + break; + } + } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 || + type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 || + type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 || + type == LOCAL_GL_UNSIGNED_SHORT) { + return 2; + } + + gfxCriticalError() << "Unknown texture type " << type << " or format " + << format; + return 0; +} + +void GLContext::ResetTLSCurrentContext() { + if (sCurrentContext.init()) { + sCurrentContext.set(nullptr); + } +} + +bool GLContext::MakeCurrent(bool aForce) const { + if (MOZ_UNLIKELY(IsContextLost())) return false; + + if (MOZ_LIKELY(!aForce)) { + bool isCurrent; + if (mUseTLSIsCurrent && sCurrentContext.init()) { + isCurrent = (sCurrentContext.get() == this); + } else { + isCurrent = IsCurrentImpl(); + } + if (MOZ_LIKELY(isCurrent)) { + MOZ_ASSERT(IsCurrentImpl() || + MakeCurrentImpl()); // Might have lost context. + return true; + } + } + if (!IsValidOwningThread()) { + gfxCriticalError() << "MakeCurrent called on a thread other than the" + << " creating thread!"; + if (gfxEnv::MOZ_GL_RELEASE_ASSERT_CONTEXT_OWNERSHIP()) { + MOZ_CRASH("MOZ_GL_RELEASE_ASSERT_CONTEXT_OWNERSHIP"); + } + } + if (!MakeCurrentImpl()) return false; + + if (sCurrentContext.init()) { + sCurrentContext.set(this); + } + return true; +} + +void GLContext::ResetSyncCallCount(const char* resetReason) const { + if (ShouldSpew()) { + printf_stderr("On %s, mSyncGLCallCount = %" PRIu64 "\n", resetReason, + mSyncGLCallCount); + } + + mSyncGLCallCount = 0; +} + +// - + +bool CheckContextLost(const GLContext* const gl) { + return gl->CheckContextLost(); +} + +// - + +GLenum GLContext::GetError() const { + if (mContextLost) return LOCAL_GL_CONTEXT_LOST; + + if (mImplicitMakeCurrent) { + (void)MakeCurrent(); + } + + const auto fnGetError = [&]() { + const auto ret = mSymbols.fGetError(); + if (ret == LOCAL_GL_CONTEXT_LOST) { + OnContextLostError(); + mTopError = ret; // Promote to top! + } + return ret; + }; + + auto ret = fnGetError(); + + { + auto flushedErr = ret; + uint32_t i = 1; + while (flushedErr && !mContextLost) { + if (i == 100) { + gfxCriticalError() << "Flushing glGetError still " + << gfx::hexa(flushedErr) << " after " << i + << " calls."; + break; + } + flushedErr = fnGetError(); + i += 1; + } + } + + if (mTopError) { + ret = mTopError; + mTopError = 0; + } + + if (mDebugFlags & DebugFlagTrace) { + const auto errStr = GLErrorToString(ret); + printf_stderr("[gl:%p] GetError() -> %s\n", this, errStr.c_str()); + } + return ret; +} + +GLenum GLContext::fGetGraphicsResetStatus() const { + OnSyncCall(); + + GLenum ret = 0; + if (mSymbols.fGetGraphicsResetStatus) { + if (mImplicitMakeCurrent) { + (void)MakeCurrent(); + } + ret = mSymbols.fGetGraphicsResetStatus(); + } else { + if (!MakeCurrent(true)) { + ret = LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB; + } + } + + if (mDebugFlags & DebugFlagTrace) { + printf_stderr("[gl:%p] GetGraphicsResetStatus() -> 0x%04x\n", this, ret); + } + + return ret; +} + +void GLContext::OnContextLostError() const { + if (mDebugFlags & DebugFlagTrace) { + printf_stderr("[gl:%p] CONTEXT_LOST\n", this); + } + mContextLost = true; +} + +// -- + +/*static*/ std::string GLContext::GLErrorToString(const GLenum err) { + switch (err) { + case LOCAL_GL_NO_ERROR: + return "GL_NO_ERROR"; + case LOCAL_GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case LOCAL_GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case LOCAL_GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case LOCAL_GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; + case LOCAL_GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; + case LOCAL_GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + case LOCAL_GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; + case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + case LOCAL_GL_CONTEXT_LOST: + return "GL_CONTEXT_LOST"; + } + + const nsPrintfCString hex("<enum 0x%04x>", err); + return hex.BeginReading(); +} + +// -- + +void GLContext::BeforeGLCall_Debug(const char* const funcName) const { + MOZ_ASSERT(mDebugFlags); + + if (mDebugFlags & DebugFlagTrace) { + printf_stderr("[gl:%p] > %s\n", this, funcName); + } + + MOZ_ASSERT(!mDebugErrorScope); + mDebugErrorScope.reset(new LocalErrorScope(*this)); +} + +void GLContext::AfterGLCall_Debug(const char* const funcName) const { + MOZ_ASSERT(mDebugFlags); + + // calling fFinish() immediately after every GL call makes sure that if this + // GL command crashes, the stack trace will actually point to it. Otherwise, + // OpenGL being an asynchronous API, stack traces tend to be meaningless + mSymbols.fFinish(); + + const auto err = mDebugErrorScope->GetError(); + mDebugErrorScope = nullptr; + if (!mTopError) { + mTopError = err; + } + + if (mDebugFlags & DebugFlagTrace) { + printf_stderr("[gl:%p] < %s [%s]\n", this, funcName, + GLErrorToString(err).c_str()); + } + + if (err && !mLocalErrorScopeStack.size()) { + const auto errStr = GLErrorToString(err); + const auto text = nsPrintfCString("%s: Generated unexpected %s error", + funcName, errStr.c_str()); + printf_stderr("[gl:%p] %s.\n", this, text.BeginReading()); + + const bool abortOnError = mDebugFlags & DebugFlagAbortOnError; + if (abortOnError && err != LOCAL_GL_CONTEXT_LOST) { + gfxCriticalErrorOnce() << text.BeginReading(); + MOZ_CRASH( + "Aborting... (Run with MOZ_GL_DEBUG_ABORT_ON_ERROR=0 to disable)"); + } + } +} + +/*static*/ +void GLContext::OnImplicitMakeCurrentFailure(const char* const funcName) { + gfxCriticalError() << "Ignoring call to " << funcName << " with failed" + << " mImplicitMakeCurrent."; +} + +bool GLContext::CreateOffscreenDefaultFb(const gfx::IntSize& size) { + mOffscreenDefaultFb = MozFramebuffer::Create(this, size, 0, true); + return bool(mOffscreenDefaultFb); +} + +// Some of Mesa's drivers allocate heap memory when loaded and don't +// free it when unloaded; this causes Leak Sanitizer to detect leaks and +// fail to unwind the stack, so suppressions don't work. This +// workaround leaks a reference to the driver library so that it's never +// unloaded. Because the leak isn't significant for real usage, only +// ASan runs in CI, this is applied only to the software renderer. +// +// See bug 1702394 for more details. +void MesaMemoryLeakWorkaround() { +#if defined(XP_LINUX) && !defined(ANDROID) + Maybe<nsAutoCString> foundPath; + + dl_iterate_phdr( + [](dl_phdr_info* info, size_t size, void* data) { + auto& foundPath = *reinterpret_cast<Maybe<nsAutoCString>*>(data); + nsDependentCString thisPath(info->dlpi_name); + if (StringEndsWith(thisPath, "/swrast_dri.so"_ns)) { + foundPath.emplace(thisPath); + return 1; + } + return 0; + }, + &foundPath); + + if (foundPath) { + // Deliberately leak to prevent unload + Unused << dlopen(foundPath->get(), RTLD_LAZY); + } +#endif // XP_LINUX but not ANDROID +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h new file mode 100644 index 0000000000..eea26024ae --- /dev/null +++ b/gfx/gl/GLContext.h @@ -0,0 +1,3883 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXT_H_ +#define GLCONTEXT_H_ + +#include <bitset> +#include <stdint.h> +#include <stdio.h> +#include <stack> +#include <vector> + +#ifdef DEBUG +# include <string.h> +#endif + +#ifdef GetClassName +# undef GetClassName +#endif + +// Define MOZ_GL_DEBUG_BUILD unconditionally to enable GL debugging in opt +// builds. +#ifdef DEBUG +# define MOZ_GL_DEBUG_BUILD 1 +#endif + +#include "mozilla/IntegerRange.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/ThreadLocal.h" + +#include "MozFramebuffer.h" +#include "nsTArray.h" +#include "GLConsts.h" +#include "GLDefs.h" +#include "GLTypes.h" +#include "nsRegionFwd.h" +#include "nsString.h" +#include "GLContextTypes.h" +#include "GLContextSymbols.h" +#include "base/platform_thread.h" // for PlatformThreadId +#include "mozilla/GenericRefCounted.h" +#include "mozilla/WeakPtr.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/ProfilerLabels.h" +#endif + +namespace mozilla { + +namespace gl { +class GLBlitHelper; +class GLLibraryEGL; +class GLReadTexImageHelper; +class SharedSurface; +class SymbolLoader; +struct SymLoadStruct; +} // namespace gl + +namespace layers { +class ColorTextureLayerProgram; +} // namespace layers + +namespace widget { +class CompositorWidget; +} // namespace widget +} // namespace mozilla + +namespace mozilla { +namespace gl { + +enum class GLFeature { + bind_buffer_offset, + blend_minmax, + clear_buffers, + copy_buffer, + depth_texture, + draw_buffers, + draw_buffers_indexed, + draw_instanced, + element_index_uint, + ES2_compatibility, + ES3_compatibility, + EXT_color_buffer_float, + frag_color_float, + frag_depth, + framebuffer_blit, + framebuffer_multisample, + framebuffer_object, + framebuffer_object_EXT_OES, + get_integer_indexed, + get_integer64_indexed, + get_query_object_i64v, + get_query_object_iv, + gpu_shader4, + instanced_arrays, + instanced_non_arrays, + internalformat_query, + invalidate_framebuffer, + map_buffer_range, + multiview, + occlusion_query, + occlusion_query_boolean, + occlusion_query2, + packed_depth_stencil, + prim_restart, + prim_restart_fixed, + provoking_vertex, + query_counter, + query_objects, + query_time_elapsed, + read_buffer, + renderbuffer_color_float, + renderbuffer_color_half_float, + robust_buffer_access_behavior, + robustness, + sRGB, + sampler_objects, + seamless_cube_map_opt_in, + shader_texture_lod, + split_framebuffer, + standard_derivatives, + sync, + texture_3D, + texture_3D_compressed, + texture_3D_copy, + texture_compression_bptc, + texture_compression_rgtc, + texture_float, + texture_float_linear, + texture_half_float, + texture_half_float_linear, + texture_non_power_of_two, + texture_norm16, + texture_rg, + texture_storage, + texture_swizzle, + transform_feedback2, + uniform_buffer_object, + uniform_matrix_nonsquare, + vertex_array_object, + EnumMax +}; + +enum class ContextProfile : uint8_t { + Unknown = 0, + OpenGLCore, + OpenGLCompatibility, + OpenGLES +}; + +enum class GLRenderer { + Adreno200, + Adreno205, + AdrenoTM200, + AdrenoTM205, + AdrenoTM305, + AdrenoTM320, + AdrenoTM330, + AdrenoTM420, + Mali400MP, + Mali450MP, + MaliT, + SGX530, + SGX540, + SGX544MP, + Tegra, + AndroidEmulator, + GalliumLlvmpipe, + IntelHD3000, + MicrosoftBasicRenderDriver, + SamsungXclipse, + Other +}; + +class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { + public: + static MOZ_THREAD_LOCAL(const GLContext*) sCurrentContext; + + static void InvalidateCurrentContext(); + + const GLContextDesc mDesc; + + bool mImplicitMakeCurrent = false; + bool mUseTLSIsCurrent; + + static void ResetTLSCurrentContext(); + + class TlsScope final { + const WeakPtr<GLContext> mGL; + const bool mWasTlsOk; + + public: + explicit TlsScope(GLContext* const gl, bool invalidate = false) + : mGL(gl), mWasTlsOk(gl && gl->mUseTLSIsCurrent) { + if (mGL) { + if (invalidate) { + InvalidateCurrentContext(); + } + mGL->mUseTLSIsCurrent = true; + } + } + + ~TlsScope() { + if (mGL) { + mGL->mUseTLSIsCurrent = mWasTlsOk; + } + } + }; + + // ----------------------------------------------------------------------------- + // basic getters + public: + /** + * Returns true if the context is using ANGLE. This should only be overridden + * for an ANGLE implementation. + */ + virtual bool IsANGLE() const { return false; } + + /** + * Returns true if the context is using WARP. This should only be overridden + * for an ANGLE implementation. + */ + virtual bool IsWARP() const { return false; } + + virtual void GetWSIInfo(nsCString* const out) const = 0; + + /** + * Return true if we are running on a OpenGL core profile context + */ + inline bool IsCoreProfile() const { + MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); + + return mProfile == ContextProfile::OpenGLCore; + } + + /** + * Return true if we are running on a OpenGL compatibility profile context + * (legacy profile 2.1 on Max OS X) + */ + inline bool IsCompatibilityProfile() const { + MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); + + return mProfile == ContextProfile::OpenGLCompatibility; + } + + inline bool IsGLES() const { + MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); + + return mProfile == ContextProfile::OpenGLES; + } + + inline bool IsAtLeast(ContextProfile profile, unsigned int version) const { + MOZ_ASSERT(profile != ContextProfile::Unknown, + "IsAtLeast: bad <profile> parameter"); + MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); + MOZ_ASSERT(mVersion != 0, "unknown context version"); + + if (version > mVersion) { + return false; + } + + return profile == mProfile; + } + + /** + * Return the version of the context. + * Example : + * If this a OpenGL 2.1, that will return 210 + */ + inline uint32_t Version() const { return mVersion; } + + inline uint32_t ShadingLanguageVersion() const { + return mShadingLanguageVersion; + } + + GLVendor Vendor() const { return mVendor; } + GLRenderer Renderer() const { return mRenderer; } + bool IsMesa() const { return mIsMesa; } + + bool IsContextLost() const { return mContextLost; } + + bool CheckContextLost() const { + mTopError = GetError(); + return IsContextLost(); + } + + bool HasPBOState() const { return (!IsGLES() || Version() >= 300); } + + /** + * If this context is double-buffered, returns TRUE. + */ + virtual bool IsDoubleBuffered() const { return false; } + + virtual GLContextType GetContextType() const = 0; + + virtual bool IsCurrentImpl() const = 0; + virtual bool MakeCurrentImpl() const = 0; + + bool IsCurrent() const { + if (mImplicitMakeCurrent) return MakeCurrent(); + + return IsCurrentImpl(); + } + + bool MakeCurrent(bool aForce = false) const; + + /** + * Get the default framebuffer for this context. + */ + UniquePtr<MozFramebuffer> mOffscreenDefaultFb; + + bool CreateOffscreenDefaultFb(const gfx::IntSize& size); + + virtual GLuint GetDefaultFramebuffer() { + if (mOffscreenDefaultFb) { + return mOffscreenDefaultFb->mFB; + } + return 0; + } + + /** + * mVersion store the OpenGL's version, multiplied by 100. For example, if + * the context is an OpenGL 2.1 context, mVersion value will be 210. + */ + uint32_t mVersion = 0; + ContextProfile mProfile = ContextProfile::Unknown; + + uint32_t mShadingLanguageVersion = 0; + + GLVendor mVendor = GLVendor::Other; + GLRenderer mRenderer = GLRenderer::Other; + bool mIsMesa = false; + + // ----------------------------------------------------------------------------- + // Extensions management + /** + * This mechanism is designed to know if an extension is supported. In the + * long term, we would like to only use the extension group queries XXX_* to + * have full compatibility with context version and profiles (especialy the + * core that officialy don't bring any extensions). + */ + + /** + * Known GL extensions that can be queried by + * IsExtensionSupported. The results of this are cached, and as + * such it's safe to use this even in performance critical code. + * If you add to this array, remember to add to the string names + * in GLContext.cpp. + */ + enum GLExtensions { + Extension_None = 0, + AMD_compressed_ATC_texture, + ANGLE_depth_texture, + ANGLE_framebuffer_blit, + ANGLE_framebuffer_multisample, + ANGLE_instanced_arrays, + ANGLE_multiview, + ANGLE_provoking_vertex, + ANGLE_texture_compression_dxt3, + ANGLE_texture_compression_dxt5, + ANGLE_timer_query, + APPLE_client_storage, + APPLE_fence, + APPLE_framebuffer_multisample, + APPLE_sync, + APPLE_texture_range, + APPLE_vertex_array_object, + ARB_ES2_compatibility, + ARB_ES3_compatibility, + ARB_color_buffer_float, + ARB_compatibility, + ARB_copy_buffer, + ARB_depth_texture, + ARB_draw_buffers, + ARB_draw_instanced, + ARB_framebuffer_object, + ARB_framebuffer_sRGB, + ARB_geometry_shader4, + ARB_half_float_pixel, + ARB_instanced_arrays, + ARB_internalformat_query, + ARB_invalidate_subdata, + ARB_map_buffer_range, + ARB_occlusion_query2, + ARB_pixel_buffer_object, + ARB_provoking_vertex, + ARB_robust_buffer_access_behavior, + ARB_robustness, + ARB_sampler_objects, + ARB_seamless_cube_map, + ARB_shader_texture_lod, + ARB_sync, + ARB_texture_compression, + ARB_texture_compression_bptc, + ARB_texture_compression_rgtc, + ARB_texture_float, + ARB_texture_non_power_of_two, + ARB_texture_rectangle, + ARB_texture_rg, + ARB_texture_storage, + ARB_texture_swizzle, + ARB_timer_query, + ARB_transform_feedback2, + ARB_uniform_buffer_object, + ARB_vertex_array_object, + CHROMIUM_color_buffer_float_rgb, + CHROMIUM_color_buffer_float_rgba, + EXT_bgra, + EXT_blend_minmax, + EXT_color_buffer_float, + EXT_color_buffer_half_float, + EXT_copy_texture, + EXT_disjoint_timer_query, + EXT_draw_buffers, + EXT_draw_buffers2, + EXT_draw_instanced, + EXT_float_blend, + EXT_frag_depth, + EXT_framebuffer_blit, + EXT_framebuffer_multisample, + EXT_framebuffer_object, + EXT_framebuffer_sRGB, + EXT_gpu_shader4, + EXT_map_buffer_range, + EXT_multisampled_render_to_texture, + EXT_occlusion_query_boolean, + EXT_packed_depth_stencil, + EXT_provoking_vertex, + EXT_read_format_bgra, + EXT_robustness, + EXT_sRGB, + EXT_sRGB_write_control, + EXT_shader_texture_lod, + EXT_texture_compression_bptc, + EXT_texture_compression_dxt1, + EXT_texture_compression_rgtc, + EXT_texture_compression_s3tc, + EXT_texture_compression_s3tc_srgb, + EXT_texture_filter_anisotropic, + EXT_texture_format_BGRA8888, + EXT_texture_norm16, + EXT_texture_sRGB, + EXT_texture_storage, + EXT_timer_query, + EXT_transform_feedback, + EXT_unpack_subimage, + IMG_read_format, + IMG_texture_compression_pvrtc, + IMG_texture_npot, + KHR_debug, + KHR_parallel_shader_compile, + KHR_robust_buffer_access_behavior, + KHR_robustness, + KHR_texture_compression_astc_hdr, + KHR_texture_compression_astc_ldr, + NV_draw_instanced, + NV_fence, + NV_framebuffer_blit, + NV_geometry_program4, + NV_half_float, + NV_instanced_arrays, + NV_primitive_restart, + NV_texture_barrier, + NV_transform_feedback, + NV_transform_feedback2, + OES_EGL_image, + OES_EGL_image_external, + OES_EGL_sync, + OES_compressed_ETC1_RGB8_texture, + OES_depth24, + OES_depth32, + OES_depth_texture, + OES_draw_buffers_indexed, + OES_element_index_uint, + OES_fbo_render_mipmap, + OES_framebuffer_object, + OES_packed_depth_stencil, + OES_rgb8_rgba8, + OES_standard_derivatives, + OES_stencil8, + OES_texture_3D, + OES_texture_float, + OES_texture_float_linear, + OES_texture_half_float, + OES_texture_half_float_linear, + OES_texture_npot, + OES_vertex_array_object, + OVR_multiview2, + Extensions_Max, + Extensions_End + }; + + bool IsExtensionSupported(GLExtensions aKnownExtension) const { + return mAvailableExtensions[aKnownExtension]; + } + + protected: + void MarkExtensionUnsupported(GLExtensions aKnownExtension) { + mAvailableExtensions[aKnownExtension] = 0; + } + + void MarkExtensionSupported(GLExtensions aKnownExtension) { + mAvailableExtensions[aKnownExtension] = 1; + } + + std::bitset<Extensions_Max> mAvailableExtensions; + + // ----------------------------------------------------------------------------- + // Feature queries + /* + * This mecahnism introduces a new way to check if a OpenGL feature is + * supported, regardless of whether it is supported by an extension or + * natively by the context version/profile + */ + public: + bool IsSupported(GLFeature feature) const { + return mAvailableFeatures[size_t(feature)]; + } + + static const char* GetFeatureName(GLFeature feature); + + private: + std::bitset<size_t(GLFeature::EnumMax)> mAvailableFeatures; + + /** + * Init features regarding OpenGL extension and context version and profile + */ + void InitFeatures(); + + /** + * Mark the feature and associated extensions as unsupported + */ + void MarkUnsupported(GLFeature feature); + + /** + * Is this feature supported using the core (unsuffixed) symbols? + */ + bool IsFeatureProvidedByCoreSymbols(GLFeature feature); + + // ----------------------------------------------------------------------------- + // Error handling + + private: + mutable bool mContextLost = false; + mutable GLenum mTopError = 0; + + protected: + void OnContextLostError() const; + + public: + static std::string GLErrorToString(GLenum aError); + + static bool IsBadCallError(const GLenum err) { + return !(err == 0 || err == LOCAL_GL_CONTEXT_LOST); + } + + class LocalErrorScope; + + private: + mutable std::stack<const LocalErrorScope*> mLocalErrorScopeStack; + mutable UniquePtr<LocalErrorScope> mDebugErrorScope; + + //////////////////////////////////// + // Use this safer option. + + public: + class LocalErrorScope { + const GLContext& mGL; + GLenum mOldTop; + bool mHasBeenChecked; + + public: + explicit LocalErrorScope(const GLContext& gl) + : mGL(gl), mHasBeenChecked(false) { + mGL.mLocalErrorScopeStack.push(this); + mOldTop = mGL.GetError(); + } + + /// Never returns CONTEXT_LOST. + GLenum GetError() { + MOZ_ASSERT(!mHasBeenChecked); + mHasBeenChecked = true; + + const auto ret = mGL.GetError(); + if (ret == LOCAL_GL_CONTEXT_LOST) return 0; + return ret; + } + + ~LocalErrorScope() { + MOZ_ASSERT(mHasBeenChecked); + + MOZ_ASSERT(!IsBadCallError(mGL.GetError())); + + MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this); + mGL.mLocalErrorScopeStack.pop(); + + mGL.mTopError = mOldTop; + } + }; + + // - + + bool GetPotentialInteger(GLenum pname, GLint* param) { + LocalErrorScope localError(*this); + + fGetIntegerv(pname, param); + + GLenum err = localError.GetError(); + MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_INVALID_ENUM); + return err == LOCAL_GL_NO_ERROR; + } + + void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message); + + private: + static void GLAPIENTRY StaticDebugCallback(GLenum source, GLenum type, + GLuint id, GLenum severity, + GLsizei length, + const GLchar* message, + const GLvoid* userParam); + + // ----------------------------------------------------------------------------- + // Debugging implementation + private: +#ifndef MOZ_FUNCTION_NAME +# ifdef __GNUC__ +# define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ +# elif defined(_MSC_VER) +# define MOZ_FUNCTION_NAME __FUNCTION__ +# else +# define MOZ_FUNCTION_NAME \ + __func__ // defined in C99, supported in various C++ compilers. Just raw + // function name. +# endif +#endif + +#ifdef MOZ_WIDGET_ANDROID +// Record the name of the GL call for better hang stacks on Android. +# define ANDROID_ONLY_PROFILER_LABEL AUTO_PROFILER_LABEL(__func__, GRAPHICS); +#else +# define ANDROID_ONLY_PROFILER_LABEL +#endif + +#define BEFORE_GL_CALL \ + ANDROID_ONLY_PROFILER_LABEL \ + if (MOZ_LIKELY(BeforeGLCall(MOZ_FUNCTION_NAME))) { \ + do { \ + } while (0) + +#define AFTER_GL_CALL \ + AfterGLCall(MOZ_FUNCTION_NAME); \ + } \ + do { \ + } while (0) + + void BeforeGLCall_Debug(const char* funcName) const; + void AfterGLCall_Debug(const char* funcName) const; + static void OnImplicitMakeCurrentFailure(const char* funcName); + + bool BeforeGLCall(const char* const funcName) const { + if (mImplicitMakeCurrent) { + if (MOZ_UNLIKELY(!MakeCurrent())) { + if (!mContextLost) { + OnImplicitMakeCurrentFailure(funcName); + } + return false; + } + } + MOZ_GL_ASSERT(this, IsCurrentImpl()); + + if (MOZ_UNLIKELY(mDebugFlags)) { + BeforeGLCall_Debug(funcName); + } + return true; + } + + void AfterGLCall(const char* const funcName) const { + if (MOZ_UNLIKELY(mDebugFlags)) { + AfterGLCall_Debug(funcName); + } + } + + GLContext* TrackingContext() { + GLContext* tip = this; + while (tip->mSharedContext) tip = tip->mSharedContext; + return tip; + } + + static void AssertNotPassingStackBufferToTheGL(const void* ptr); + +#ifdef MOZ_GL_DEBUG_BUILD + +# define TRACKING_CONTEXT(a) \ + do { \ + TrackingContext()->a; \ + } while (0) + +# define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ + AssertNotPassingStackBufferToTheGL(ptr) + +# define ASSERT_SYMBOL_PRESENT(func) \ + do { \ + MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, \ + "Mismatched symbol check."); \ + if (MOZ_UNLIKELY(!mSymbols.func)) { \ + printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", \ + #func); \ + MOZ_CRASH("GFX: Uninitialized GL function"); \ + } \ + } while (0) + +#else // ifdef MOZ_GL_DEBUG_BUILD + +# define TRACKING_CONTEXT(a) \ + do { \ + } while (0) +# define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ + do { \ + } while (0) +# define ASSERT_SYMBOL_PRESENT(func) \ + do { \ + } while (0) + +#endif // ifdef MOZ_GL_DEBUG_BUILD + + // Do whatever setup is necessary to draw to our offscreen FBO, if it's + // bound. + void BeforeGLDrawCall() {} + + // Do whatever tear-down is necessary after drawing to our offscreen FBO, + // if it's bound. + void AfterGLDrawCall() { mHeavyGLCallsSinceLastFlush = true; } + + // Do whatever setup is necessary to read from our offscreen FBO, if it's + // bound. + void BeforeGLReadCall() {} + + // Do whatever tear-down is necessary after reading from our offscreen FBO, + // if it's bound. + void AfterGLReadCall() {} + + public: + void OnSyncCall() const { mSyncGLCallCount++; } + + uint64_t GetSyncCallCount() const { return mSyncGLCallCount; } + + void ResetSyncCallCount(const char* resetReason) const; + + // ----------------------------------------------------------------------------- + // GL official entry points + public: + // We smash all errors together, so you never have to loop on this. We + // guarantee that immediately after this call, there are no errors left. + // Always returns the top-most error, except if followed by CONTEXT_LOST, then + // return that instead. + GLenum GetError() const; + + GLenum fGetError() { return GetError(); } + + GLenum fGetGraphicsResetStatus() const; + + // - + + void fActiveTexture(GLenum texture) { + BEFORE_GL_CALL; + mSymbols.fActiveTexture(texture); + AFTER_GL_CALL; + } + + void fAttachShader(GLuint program, GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fAttachShader(program, shader); + AFTER_GL_CALL; + } + + void fBeginQuery(GLenum target, GLuint id) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBeginQuery); + mSymbols.fBeginQuery(target, id); + AFTER_GL_CALL; + } + + void fBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fBindAttribLocation(program, index, name); + AFTER_GL_CALL; + } + + void fBindBuffer(GLenum target, GLuint buffer) { + BEFORE_GL_CALL; + mSymbols.fBindBuffer(target, buffer); + AFTER_GL_CALL; + } + + void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum* attachments) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer); + mSymbols.fInvalidateFramebuffer(target, numAttachments, attachments); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum* attachments, GLint x, GLint y, + GLsizei width, GLsizei height) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer); + mSymbols.fInvalidateSubFramebuffer(target, numAttachments, attachments, x, + y, width, height); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fBindTexture(GLenum target, GLuint texture) { + BEFORE_GL_CALL; + mSymbols.fBindTexture(target, texture); + AFTER_GL_CALL; + } + + void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + BEFORE_GL_CALL; + mSymbols.fBlendColor(red, green, blue, alpha); + AFTER_GL_CALL; + } + + void fBlendEquation(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fBlendEquation(mode); + AFTER_GL_CALL; + } + + void fBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { + BEFORE_GL_CALL; + mSymbols.fBlendEquationSeparate(modeRGB, modeAlpha); + AFTER_GL_CALL; + } + + void fBlendFunc(GLenum sfactor, GLenum dfactor) { + BEFORE_GL_CALL; + mSymbols.fBlendFunc(sfactor, dfactor); + AFTER_GL_CALL; + } + + void fBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorAlpha, GLenum dfactorAlpha) { + BEFORE_GL_CALL; + mSymbols.fBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, + dfactorAlpha); + AFTER_GL_CALL; + } + + private: + void raw_fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, + GLenum usage) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); + BEFORE_GL_CALL; + mSymbols.fBufferData(target, size, data, usage); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + public: + void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, + GLenum usage) { + raw_fBufferData(target, size, data, usage); + + // bug 744888 + if (WorkAroundDriverBugs() && !data && Vendor() == GLVendor::NVIDIA) { + UniquePtr<char[]> buf = MakeUnique<char[]>(1); + buf[0] = 0; + fBufferSubData(target, size - 1, 1, buf.get()); + } + } + + void fBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, + const GLvoid* data) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); + BEFORE_GL_CALL; + mSymbols.fBufferSubData(target, offset, size, data); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + private: + void raw_fClear(GLbitfield mask) { + BEFORE_GL_CALL; + mSymbols.fClear(mask); + AFTER_GL_CALL; + } + + public: + void fClear(GLbitfield mask) { + BeforeGLDrawCall(); + raw_fClear(mask); + AfterGLDrawCall(); + } + + void fClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, + GLint stencil) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferfi(buffer, drawbuffer, depth, stencil); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferfv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferiv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferuiv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { + BEFORE_GL_CALL; + mSymbols.fClearColor(r, g, b, a); + AFTER_GL_CALL; + } + + void fClearStencil(GLint s) { + BEFORE_GL_CALL; + mSymbols.fClearStencil(s); + AFTER_GL_CALL; + } + + void fClientActiveTexture(GLenum texture) { + BEFORE_GL_CALL; + mSymbols.fClientActiveTexture(texture); + AFTER_GL_CALL; + } + + void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, + realGLboolean alpha) { + BEFORE_GL_CALL; + mSymbols.fColorMask(red, green, blue, alpha); + AFTER_GL_CALL; + } + + void fCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fCompressedTexImage2D(target, level, internalformat, width, height, + border, imageSize, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, + height, format, imageSize, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + + void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height) { + BeforeGLReadCall(); + raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, + height); + AfterGLReadCall(); + } + + void fCullFace(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fCullFace(mode); + AFTER_GL_CALL; + } + + void fDebugMessageCallback(GLDEBUGPROC callback, const GLvoid* userParam) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageCallback); + mSymbols.fDebugMessageCallback(callback, userParam); + AFTER_GL_CALL; + } + + void fDebugMessageControl(GLenum source, GLenum type, GLenum severity, + GLsizei count, const GLuint* ids, + realGLboolean enabled) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageControl); + mSymbols.fDebugMessageControl(source, type, severity, count, ids, enabled); + AFTER_GL_CALL; + } + + void fDebugMessageInsert(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* buf) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageInsert); + mSymbols.fDebugMessageInsert(source, type, id, severity, length, buf); + AFTER_GL_CALL; + } + + void fDetachShader(GLuint program, GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fDetachShader(program, shader); + AFTER_GL_CALL; + } + + void fDepthFunc(GLenum func) { + BEFORE_GL_CALL; + mSymbols.fDepthFunc(func); + AFTER_GL_CALL; + } + + void fDepthMask(realGLboolean flag) { + BEFORE_GL_CALL; + mSymbols.fDepthMask(flag); + AFTER_GL_CALL; + } + + void fDisable(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fDisable(capability); + AFTER_GL_CALL; + } + + void fDisableClientState(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fDisableClientState(capability); + AFTER_GL_CALL; + } + + void fDisableVertexAttribArray(GLuint index) { + BEFORE_GL_CALL; + mSymbols.fDisableVertexAttribArray(index); + AFTER_GL_CALL; + } + + void fDrawBuffer(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fDrawBuffer(mode); + AFTER_GL_CALL; + } + + private: + void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) { + BEFORE_GL_CALL; + mSymbols.fDrawArrays(mode, first, count); + AFTER_GL_CALL; + } + + void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices) { + BEFORE_GL_CALL; + mSymbols.fDrawElements(mode, count, type, indices); + AFTER_GL_CALL; + } + + public: + void fDrawArrays(GLenum mode, GLint first, GLsizei count) { + BeforeGLDrawCall(); + raw_fDrawArrays(mode, first, count); + AfterGLDrawCall(); + } + + void fDrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices) { + BeforeGLDrawCall(); + raw_fDrawElements(mode, count, type, indices); + AfterGLDrawCall(); + } + + void fEnable(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fEnable(capability); + AFTER_GL_CALL; + } + + void fEnableClientState(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fEnableClientState(capability); + AFTER_GL_CALL; + } + + void fEnableVertexAttribArray(GLuint index) { + BEFORE_GL_CALL; + mSymbols.fEnableVertexAttribArray(index); + AFTER_GL_CALL; + } + + void fEndQuery(GLenum target) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fEndQuery); + mSymbols.fEndQuery(target); + AFTER_GL_CALL; + } + + void fFinish() { + BEFORE_GL_CALL; + mSymbols.fFinish(); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = false; + } + + void fFlush() { + BEFORE_GL_CALL; + mSymbols.fFlush(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = false; + } + + void fFrontFace(GLenum face) { + BEFORE_GL_CALL; + mSymbols.fFrontFace(face); + AFTER_GL_CALL; + } + + void fGetActiveAttrib(GLuint program, GLuint index, GLsizei maxLength, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fGetActiveAttrib(program, index, maxLength, length, size, type, + name); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetActiveUniform(GLuint program, GLuint index, GLsizei maxLength, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fGetActiveUniform(program, index, maxLength, length, size, type, + name); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, + GLuint* shaders) { + BEFORE_GL_CALL; + mSymbols.fGetAttachedShaders(program, maxCount, count, shaders); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLint fGetAttribLocation(GLuint program, const GLchar* name) { + GLint retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fGetAttribLocation(program, name); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + private: + void raw_fGetIntegerv(GLenum pname, GLint* params) const { + BEFORE_GL_CALL; + mSymbols.fGetIntegerv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + public: + void fGetIntegerv(GLenum pname, GLint* params) const; + + template <typename T> + void GetInt(const GLenum pname, T* const params) const { + static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); + fGetIntegerv(pname, reinterpret_cast<GLint*>(params)); + } + + void GetUIntegerv(GLenum pname, GLuint* params) const { + GetInt(pname, params); + } + + template <typename T> + T GetIntAs(GLenum pname) const { + static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); + T ret = 0; + fGetIntegerv(pname, (GLint*)&ret); + return ret; + } + + void fGetFloatv(GLenum pname, GLfloat* params) const { + BEFORE_GL_CALL; + mSymbols.fGetFloatv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetBooleanv(GLenum pname, realGLboolean* params) const { + BEFORE_GL_CALL; + mSymbols.fGetBooleanv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetBufferParameteriv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLuint fGetDebugMessageLog(GLuint count, GLsizei bufsize, GLenum* sources, + GLenum* types, GLuint* ids, GLenum* severities, + GLsizei* lengths, GLchar* messageLog) { + GLuint ret = 0; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetDebugMessageLog); + ret = mSymbols.fGetDebugMessageLog(count, bufsize, sources, types, ids, + severities, lengths, messageLog); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fGetPointerv(GLenum pname, GLvoid** params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetPointerv); + mSymbols.fGetPointerv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, + GLsizei* length, GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetObjectLabel); + mSymbols.fGetObjectLabel(identifier, name, bufSize, length, label); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetObjectPtrLabel(const GLvoid* ptr, GLsizei bufSize, GLsizei* length, + GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetObjectPtrLabel); + mSymbols.fGetObjectPtrLabel(ptr, bufSize, length, label); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGenerateMipmap(GLenum target) { + BEFORE_GL_CALL; + mSymbols.fGenerateMipmap(target); + AFTER_GL_CALL; + } + + void fGetProgramiv(GLuint program, GLenum pname, GLint* param) { + BEFORE_GL_CALL; + mSymbols.fGetProgramiv(program, pname, param); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, + GLchar* infoLog) { + BEFORE_GL_CALL; + mSymbols.fGetProgramInfoLog(program, bufSize, length, infoLog); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fTexParameteri(GLenum target, GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fTexParameteri(target, pname, param); + AFTER_GL_CALL; + } + + void fTexParameteriv(GLenum target, GLenum pname, const GLint* params) { + BEFORE_GL_CALL; + mSymbols.fTexParameteriv(target, pname, params); + AFTER_GL_CALL; + } + + void fTexParameterf(GLenum target, GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fTexParameterf(target, pname, param); + AFTER_GL_CALL; + } + + const GLubyte* fGetString(GLenum name) { + const GLubyte* result = nullptr; + BEFORE_GL_CALL; + result = mSymbols.fGetString(name); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, + GLvoid* img) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetTexImage); + mSymbols.fGetTexImage(target, level, format, type, img); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, + GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv); + mSymbols.fGetTexLevelParameteriv(target, level, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fGetTexParameterfv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetTexParameteriv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformfv(GLuint program, GLint location, GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fGetUniformfv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformiv(GLuint program, GLint location, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetUniformiv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformuiv(GLuint program, GLint location, GLuint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetUniformuiv); + mSymbols.fGetUniformuiv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLint fGetUniformLocation(GLuint programObj, const GLchar* name) { + GLint retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fGetUniformLocation(programObj, name); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + void fGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribfv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetVertexAttribiv(GLuint index, GLenum pname, GLint* retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribiv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribPointerv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fHint(GLenum target, GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fHint(target, mode); + AFTER_GL_CALL; + } + + realGLboolean fIsBuffer(GLuint buffer) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsBuffer(buffer); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsEnabled(GLenum capability) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsEnabled(capability); + AFTER_GL_CALL; + return retval; + } + + void SetEnabled(const GLenum cap, const bool val) { + if (val) { + fEnable(cap); + } else { + fDisable(cap); + } + } + + bool PushEnabled(const GLenum cap, const bool newVal) { + const bool oldVal = fIsEnabled(cap); + if (oldVal != newVal) { + SetEnabled(cap, newVal); + } + return oldVal; + } + + realGLboolean fIsProgram(GLuint program) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsProgram(program); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsShader(GLuint shader) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsShader(shader); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsTexture(GLuint texture) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsTexture(texture); + AFTER_GL_CALL; + return retval; + } + + void fLineWidth(GLfloat width) { + BEFORE_GL_CALL; + mSymbols.fLineWidth(width); + AFTER_GL_CALL; + } + + void fLinkProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fLinkProgram(program); + AFTER_GL_CALL; + } + + void fObjectLabel(GLenum identifier, GLuint name, GLsizei length, + const GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fObjectLabel); + mSymbols.fObjectLabel(identifier, name, length, label); + AFTER_GL_CALL; + } + + void fObjectPtrLabel(const GLvoid* ptr, GLsizei length, const GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fObjectPtrLabel); + mSymbols.fObjectPtrLabel(ptr, length, label); + AFTER_GL_CALL; + } + + void fLoadIdentity() { + BEFORE_GL_CALL; + mSymbols.fLoadIdentity(); + AFTER_GL_CALL; + } + + void fLoadMatrixf(const GLfloat* matrix) { + BEFORE_GL_CALL; + mSymbols.fLoadMatrixf(matrix); + AFTER_GL_CALL; + } + + void fMatrixMode(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fMatrixMode(mode); + AFTER_GL_CALL; + } + + void fPixelStorei(GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fPixelStorei(pname, param); + AFTER_GL_CALL; + } + + void fTextureRangeAPPLE(GLenum target, GLsizei length, GLvoid* pointer) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pointer); + BEFORE_GL_CALL; + mSymbols.fTextureRangeAPPLE(target, length, pointer); + AFTER_GL_CALL; + } + + void fPointParameterf(GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fPointParameterf(pname, param); + AFTER_GL_CALL; + } + + void fPolygonMode(GLenum face, GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fPolygonMode(face, mode); + AFTER_GL_CALL; + } + + void fPolygonOffset(GLfloat factor, GLfloat bias) { + BEFORE_GL_CALL; + mSymbols.fPolygonOffset(factor, bias); + AFTER_GL_CALL; + } + + void fPopDebugGroup() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPopDebugGroup); + mSymbols.fPopDebugGroup(); + AFTER_GL_CALL; + } + + void fPushDebugGroup(GLenum source, GLuint id, GLsizei length, + const GLchar* message) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPushDebugGroup); + mSymbols.fPushDebugGroup(source, id, length, message); + AFTER_GL_CALL; + } + + void fReadBuffer(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fReadBuffer(mode); + AFTER_GL_CALL; + } + + void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) { + BEFORE_GL_CALL; + mSymbols.fReadPixels(x, y, width, height, format, type, pixels); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels); + + public: + void fSampleCoverage(GLclampf value, realGLboolean invert) { + BEFORE_GL_CALL; + mSymbols.fSampleCoverage(value, invert); + AFTER_GL_CALL; + } + + void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) { + if (mScissorRect[0] == x && mScissorRect[1] == y && + mScissorRect[2] == width && mScissorRect[3] == height) { + return; + } + mScissorRect[0] = x; + mScissorRect[1] = y; + mScissorRect[2] = width; + mScissorRect[3] = height; + BEFORE_GL_CALL; + mSymbols.fScissor(x, y, width, height); + AFTER_GL_CALL; + } + + void fStencilFunc(GLenum func, GLint reference, GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilFunc(func, reference, mask); + AFTER_GL_CALL; + } + + void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint reference, + GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilFuncSeparate(frontfunc, backfunc, reference, mask); + AFTER_GL_CALL; + } + + void fStencilMask(GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilMask(mask); + AFTER_GL_CALL; + } + + void fStencilMaskSeparate(GLenum face, GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilMaskSeparate(face, mask); + AFTER_GL_CALL; + } + + void fStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { + BEFORE_GL_CALL; + mSymbols.fStencilOp(fail, zfail, zpass); + AFTER_GL_CALL; + } + + void fStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, + GLenum dppass) { + BEFORE_GL_CALL; + mSymbols.fStencilOpSeparate(face, sfail, dpfail, dppass); + AFTER_GL_CALL; + } + + void fTexGeni(GLenum coord, GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fTexGeni(coord, pname, param); + AFTER_GL_CALL; + } + + void fTexGenf(GLenum coord, GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fTexGenf(coord, pname, param); + AFTER_GL_CALL; + } + + void fTexGenfv(GLenum coord, GLenum pname, const GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fTexGenfv(coord, pname, params); + AFTER_GL_CALL; + } + + private: + void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fTexImage2D(target, level, internalformat, width, height, border, + format, type, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + public: + void fTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, GLenum format, + GLenum type, const GLvoid* pixels); + + void fTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fUniform1f(GLint location, GLfloat v0) { + BEFORE_GL_CALL; + mSymbols.fUniform1f(location, v0); + AFTER_GL_CALL; + } + + void fUniform1fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform1fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform1i(GLint location, GLint v0) { + BEFORE_GL_CALL; + mSymbols.fUniform1i(location, v0); + AFTER_GL_CALL; + } + + void fUniform1iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform1iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform2f(GLint location, GLfloat v0, GLfloat v1) { + BEFORE_GL_CALL; + mSymbols.fUniform2f(location, v0, v1); + AFTER_GL_CALL; + } + + void fUniform2fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform2fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform2i(GLint location, GLint v0, GLint v1) { + BEFORE_GL_CALL; + mSymbols.fUniform2i(location, v0, v1); + AFTER_GL_CALL; + } + + void fUniform2iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform2iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + BEFORE_GL_CALL; + mSymbols.fUniform3f(location, v0, v1, v2); + AFTER_GL_CALL; + } + + void fUniform3fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform3fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform3i(GLint location, GLint v0, GLint v1, GLint v2) { + BEFORE_GL_CALL; + mSymbols.fUniform3i(location, v0, v1, v2); + AFTER_GL_CALL; + } + + void fUniform3iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform3iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, + GLfloat v3) { + BEFORE_GL_CALL; + mSymbols.fUniform4f(location, v0, v1, v2, v3); + AFTER_GL_CALL; + } + + void fUniform4fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform4fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + BEFORE_GL_CALL; + mSymbols.fUniform4i(location, v0, v1, v2, v3); + AFTER_GL_CALL; + } + + void fUniform4iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform4iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2x3fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix2x3fv); + mSymbols.fUniformMatrix2x3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2x4fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix2x4fv); + mSymbols.fUniformMatrix2x4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3x2fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix3x2fv); + mSymbols.fUniformMatrix3x2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3x4fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix3x4fv); + mSymbols.fUniformMatrix3x4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4x2fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix4x2fv); + mSymbols.fUniformMatrix4x2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4x3fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix4x3fv); + mSymbols.fUniformMatrix4x3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUseProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fUseProgram(program); + AFTER_GL_CALL; + } + + void fValidateProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fValidateProgram(program); + AFTER_GL_CALL; + } + + void fVertexAttribPointer(GLuint index, GLint size, GLenum type, + realGLboolean normalized, GLsizei stride, + const GLvoid* pointer) { + BEFORE_GL_CALL; + mSymbols.fVertexAttribPointer(index, size, type, normalized, stride, + pointer); + AFTER_GL_CALL; + } + + void fVertexAttrib1f(GLuint index, GLfloat x) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib1f(index, x); + AFTER_GL_CALL; + } + + void fVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib2f(index, x, y); + AFTER_GL_CALL; + } + + void fVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib3f(index, x, y, z); + AFTER_GL_CALL; + } + + void fVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, + GLfloat w) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib4f(index, x, y, z, w); + AFTER_GL_CALL; + } + + void fVertexAttrib1fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib1fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib2fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib2fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib3fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib3fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib4fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib4fv(index, v); + AFTER_GL_CALL; + } + + void fVertexPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid* pointer) { + BEFORE_GL_CALL; + mSymbols.fVertexPointer(size, type, stride, pointer); + AFTER_GL_CALL; + } + + void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + if (mViewportRect[0] == x && mViewportRect[1] == y && + mViewportRect[2] == width && mViewportRect[3] == height) { + return; + } + mViewportRect[0] = x; + mViewportRect[1] = y; + mViewportRect[2] = width; + mViewportRect[3] = height; + BEFORE_GL_CALL; + mSymbols.fViewport(x, y, width, height); + AFTER_GL_CALL; + } + + void fCompileShader(GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fCompileShader(shader); + AFTER_GL_CALL; + } + + private: + friend class SharedSurface_IOSurface; + + void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) { + BEFORE_GL_CALL; + mSymbols.fCopyTexImage2D(target, level, internalformat, x, y, width, height, + border); + AFTER_GL_CALL; + } + + void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height) { + BEFORE_GL_CALL; + mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, + height); + AFTER_GL_CALL; + } + + public: + void fGetShaderiv(GLuint shader, GLenum pname, GLint* param) { + BEFORE_GL_CALL; + mSymbols.fGetShaderiv(shader, pname, param); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, + GLchar* infoLog) { + BEFORE_GL_CALL; + mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog); + OnSyncCall(); + AFTER_GL_CALL; + } + + private: + void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + MOZ_ASSERT(IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat); + mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, + precision); + OnSyncCall(); + AFTER_GL_CALL; + } + + public: + void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + if (IsGLES()) { + raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, + precision); + } else { + // Fall back to automatic values because almost all desktop hardware + // supports the OpenGL standard precisions. + GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, + precision); + } + } + + void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, + GLchar* source) { + BEFORE_GL_CALL; + mSymbols.fGetShaderSource(obj, maxLength, length, source); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, + const GLint* lengths) { + BEFORE_GL_CALL; + mSymbols.fShaderSource(shader, count, strings, lengths); + AFTER_GL_CALL; + } + + private: + mutable GLuint mCachedDrawFb = 0; + mutable GLuint mCachedReadFb = 0; + + public: + bool mElideDuplicateBindFramebuffers = false; + + void fBindFramebuffer(const GLenum target, const GLuint fb) const { + if (mElideDuplicateBindFramebuffers) { + MOZ_ASSERT(mCachedDrawFb == + GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING)); + MOZ_ASSERT(mCachedReadFb == + GetIntAs<GLuint>(LOCAL_GL_READ_FRAMEBUFFER_BINDING)); + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + if (mCachedDrawFb == fb && mCachedReadFb == fb) return; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + if (mCachedDrawFb == fb) return; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + if (mCachedReadFb == fb) return; + break; + } + } + + BEFORE_GL_CALL; + mSymbols.fBindFramebuffer(target, fb); + AFTER_GL_CALL; + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + mCachedDrawFb = fb; + mCachedReadFb = fb; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + mCachedDrawFb = fb; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + mCachedReadFb = fb; + break; + } + } + + void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { + BEFORE_GL_CALL; + mSymbols.fBindRenderbuffer(target, renderbuffer); + AFTER_GL_CALL; + } + + GLenum fCheckFramebufferStatus(GLenum target) { + GLenum retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fCheckFramebufferStatus(target); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, + GLenum renderbufferTarget, + GLuint renderbuffer) { + BEFORE_GL_CALL; + mSymbols.fFramebufferRenderbuffer(target, attachmentPoint, + renderbufferTarget, renderbuffer); + AFTER_GL_CALL; + } + + void fFramebufferTexture2D(GLenum target, GLenum attachmentPoint, + GLenum textureTarget, GLuint texture, + GLint level) { + BEFORE_GL_CALL; + mSymbols.fFramebufferTexture2D(target, attachmentPoint, textureTarget, + texture, level); + AFTER_GL_CALL; + } + + void fFramebufferTextureLayer(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fFramebufferTextureLayer); + mSymbols.fFramebufferTextureLayer(target, attachment, texture, level, + layer); + AFTER_GL_CALL; + } + + void fGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, + GLenum pname, GLint* value) { + BEFORE_GL_CALL; + mSymbols.fGetFramebufferAttachmentParameteriv(target, attachment, pname, + value); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* value) { + BEFORE_GL_CALL; + mSymbols.fGetRenderbufferParameteriv(target, pname, value); + OnSyncCall(); + AFTER_GL_CALL; + } + + realGLboolean fIsFramebuffer(GLuint framebuffer) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsFramebuffer(framebuffer); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + public: + realGLboolean fIsRenderbuffer(GLuint renderbuffer) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsRenderbuffer(renderbuffer); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + void fRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, + GLsizei height) { + BEFORE_GL_CALL; + mSymbols.fRenderbufferStorage(target, internalFormat, width, height); + AFTER_GL_CALL; + } + + private: + void raw_fDepthRange(GLclampf a, GLclampf b) { + MOZ_ASSERT(!IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDepthRange); + mSymbols.fDepthRange(a, b); + AFTER_GL_CALL; + } + + void raw_fDepthRangef(GLclampf a, GLclampf b) { + MOZ_ASSERT(IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDepthRangef); + mSymbols.fDepthRangef(a, b); + AFTER_GL_CALL; + } + + void raw_fClearDepth(GLclampf v) { + MOZ_ASSERT(!IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fClearDepth); + mSymbols.fClearDepth(v); + AFTER_GL_CALL; + } + + void raw_fClearDepthf(GLclampf v) { + MOZ_ASSERT(IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fClearDepthf); + mSymbols.fClearDepthf(v); + AFTER_GL_CALL; + } + + public: + void fDepthRange(GLclampf a, GLclampf b) { + if (IsGLES()) { + raw_fDepthRangef(a, b); + } else { + raw_fDepthRange(a, b); + } + } + + void fClearDepth(GLclampf v) { + if (IsGLES()) { + raw_fClearDepthf(v); + } else { + raw_fClearDepth(v); + } + } + + void* fMapBuffer(GLenum target, GLenum access) { + void* ret = nullptr; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fMapBuffer); + ret = mSymbols.fMapBuffer(target, access); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + realGLboolean fUnmapBuffer(GLenum target) { + realGLboolean ret = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUnmapBuffer); + ret = mSymbols.fUnmapBuffer(target); + AFTER_GL_CALL; + return ret; + } + + private: + GLuint raw_fCreateProgram() { + GLuint ret = 0; + BEFORE_GL_CALL; + ret = mSymbols.fCreateProgram(); + AFTER_GL_CALL; + return ret; + } + + GLuint raw_fCreateShader(GLenum t) { + GLuint ret = 0; + BEFORE_GL_CALL; + ret = mSymbols.fCreateShader(t); + AFTER_GL_CALL; + return ret; + } + + void raw_fGenBuffers(GLsizei n, GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fGenBuffers(n, names); + OnSyncCall(); + AFTER_GL_CALL; + } + + void raw_fGenFramebuffers(GLsizei n, GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fGenFramebuffers(n, names); + OnSyncCall(); + AFTER_GL_CALL; + } + + void raw_fGenRenderbuffers(GLsizei n, GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fGenRenderbuffers(n, names); + OnSyncCall(); + AFTER_GL_CALL; + } + + void raw_fGenTextures(GLsizei n, GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fGenTextures(n, names); + OnSyncCall(); + AFTER_GL_CALL; + } + + public: + GLuint fCreateProgram() { + GLuint ret = raw_fCreateProgram(); + TRACKING_CONTEXT(CreatedProgram(this, ret)); + return ret; + } + + GLuint fCreateShader(GLenum t) { + GLuint ret = raw_fCreateShader(t); + TRACKING_CONTEXT(CreatedShader(this, ret)); + return ret; + } + + void fGenBuffers(GLsizei n, GLuint* names) { + raw_fGenBuffers(n, names); + TRACKING_CONTEXT(CreatedBuffers(this, n, names)); + } + + void fGenFramebuffers(GLsizei n, GLuint* names) { + raw_fGenFramebuffers(n, names); + TRACKING_CONTEXT(CreatedFramebuffers(this, n, names)); + } + + void fGenRenderbuffers(GLsizei n, GLuint* names) { + raw_fGenRenderbuffers(n, names); + TRACKING_CONTEXT(CreatedRenderbuffers(this, n, names)); + } + + void fGenTextures(GLsizei n, GLuint* names) { + raw_fGenTextures(n, names); + TRACKING_CONTEXT(CreatedTextures(this, n, names)); + } + + private: + void raw_fDeleteProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fDeleteProgram(program); + AFTER_GL_CALL; + } + + void raw_fDeleteShader(GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fDeleteShader(shader); + AFTER_GL_CALL; + } + + void raw_fDeleteBuffers(GLsizei n, const GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fDeleteBuffers(n, names); + AFTER_GL_CALL; + } + + void raw_fDeleteFramebuffers(GLsizei n, const GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fDeleteFramebuffers(n, names); + AFTER_GL_CALL; + + for (const auto i : IntegerRange(n)) { + const auto fb = names[i]; + if (mCachedDrawFb == fb) { + mCachedDrawFb = 0; + } + if (mCachedReadFb == fb) { + mCachedReadFb = 0; + } + } + } + + void raw_fDeleteRenderbuffers(GLsizei n, const GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fDeleteRenderbuffers(n, names); + AFTER_GL_CALL; + } + + void raw_fDeleteTextures(GLsizei n, const GLuint* names) { + BEFORE_GL_CALL; + mSymbols.fDeleteTextures(n, names); + AFTER_GL_CALL; + } + + public: + void fDeleteProgram(GLuint program) { + raw_fDeleteProgram(program); + TRACKING_CONTEXT(DeletedProgram(this, program)); + } + + void fDeleteShader(GLuint shader) { + raw_fDeleteShader(shader); + TRACKING_CONTEXT(DeletedShader(this, shader)); + } + + void fDeleteBuffers(GLsizei n, const GLuint* names) { + raw_fDeleteBuffers(n, names); + TRACKING_CONTEXT(DeletedBuffers(this, n, names)); + } + + void fDeleteFramebuffers(GLsizei n, const GLuint* names); + + void fDeleteRenderbuffers(GLsizei n, const GLuint* names) { + raw_fDeleteRenderbuffers(n, names); + TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names)); + } + + void fDeleteTextures(GLsizei n, const GLuint* names) { +#ifdef XP_MACOSX + // On the Mac the call to fDeleteTextures() triggers a flush. But it + // happens at the wrong time, which can lead to crashes. To work around + // this we call fFlush() explicitly ourselves, before the call to + // fDeleteTextures(). This fixes bug 1666293. + fFlush(); +#endif + raw_fDeleteTextures(n, names); + TRACKING_CONTEXT(DeletedTextures(this, n, names)); + } + + // ----------------------------------------------------------------------------- + // Extension ARB_sync (GL) + public: + GLsync fFenceSync(GLenum condition, GLbitfield flags) { + GLsync ret = 0; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fFenceSync); + ret = mSymbols.fFenceSync(condition, flags); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + realGLboolean fIsSync(GLsync sync) { + realGLboolean ret = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fIsSync); + ret = mSymbols.fIsSync(sync); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fDeleteSync(GLsync sync) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDeleteSync); + mSymbols.fDeleteSync(sync); + AFTER_GL_CALL; + } + + GLenum fClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { + GLenum ret = 0; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fClientWaitSync); + ret = mSymbols.fClientWaitSync(sync, flags, timeout); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fWaitSync); + mSymbols.fWaitSync(sync, flags, timeout); + AFTER_GL_CALL; + } + + void fGetInteger64v(GLenum pname, GLint64* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetInteger64v); + mSymbols.fGetInteger64v(pname, params); + AFTER_GL_CALL; + } + + void fGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, + GLint* values) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetSynciv); + mSymbols.fGetSynciv(sync, pname, bufSize, length, values); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Extension OES_EGL_image (GLES) + public: + void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D); + mSymbols.fEGLImageTargetTexture2D(target, image); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage); + mSymbols.fEGLImageTargetRenderbufferStorage(target, image); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_bind_buffer_offset + public: + void fBindBufferOffset(GLenum target, GLuint index, GLuint buffer, + GLintptr offset) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindBufferOffset); + mSymbols.fBindBufferOffset(target, index, buffer, offset); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_draw_buffers + public: + void fDrawBuffers(GLsizei n, const GLenum* bufs) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDrawBuffers); + mSymbols.fDrawBuffers(n, bufs); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_draw_instanced + public: + void fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, + GLsizei primcount) { + BeforeGLDrawCall(); + raw_fDrawArraysInstanced(mode, first, count, primcount); + AfterGLDrawCall(); + } + + void fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount) { + BeforeGLDrawCall(); + raw_fDrawElementsInstanced(mode, count, type, indices, primcount); + AfterGLDrawCall(); + } + + private: + void raw_fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, + GLsizei primcount) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDrawArraysInstanced); + mSymbols.fDrawArraysInstanced(mode, first, count, primcount); + AFTER_GL_CALL; + } + + void raw_fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDrawElementsInstanced); + mSymbols.fDrawElementsInstanced(mode, count, type, indices, primcount); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_framebuffer_blit + public: + // Draw/Read + void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { + BeforeGLDrawCall(); + BeforeGLReadCall(); + raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); + AfterGLReadCall(); + AfterGLDrawCall(); + } + + private: + void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBlitFramebuffer); + mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, + dstY1, mask, filter); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_framebuffer_multisample + public: + void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, GLsizei width, + GLsizei height) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample); + mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, + width, height); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // GL 3.0, GL ES 3.0 & EXT_gpu_shader4 + public: + void fGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) { + ASSERT_SYMBOL_PRESENT(fGetVertexAttribIiv); + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribIiv(index, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) { + ASSERT_SYMBOL_PRESENT(fGetVertexAttribIuiv); + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribIuiv(index, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribI4i); + mSymbols.fVertexAttribI4i(index, x, y, z, w); + AFTER_GL_CALL; + } + + void fVertexAttribI4iv(GLuint index, const GLint* v) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribI4iv); + mSymbols.fVertexAttribI4iv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribI4ui); + mSymbols.fVertexAttribI4ui(index, x, y, z, w); + AFTER_GL_CALL; + } + + void fVertexAttribI4uiv(GLuint index, const GLuint* v) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribI4uiv); + mSymbols.fVertexAttribI4uiv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttribIPointer(GLuint index, GLint size, GLenum type, + GLsizei stride, const GLvoid* offset) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribIPointer); + mSymbols.fVertexAttribIPointer(index, size, type, stride, offset); + AFTER_GL_CALL; + } + + void fUniform1ui(GLint location, GLuint v0) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform1ui); + mSymbols.fUniform1ui(location, v0); + AFTER_GL_CALL; + } + + void fUniform2ui(GLint location, GLuint v0, GLuint v1) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform2ui); + mSymbols.fUniform2ui(location, v0, v1); + AFTER_GL_CALL; + } + + void fUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform3ui); + mSymbols.fUniform3ui(location, v0, v1, v2); + AFTER_GL_CALL; + } + + void fUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform4ui); + mSymbols.fUniform4ui(location, v0, v1, v2, v3); + AFTER_GL_CALL; + } + + void fUniform1uiv(GLint location, GLsizei count, const GLuint* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform1uiv); + mSymbols.fUniform1uiv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform2uiv(GLint location, GLsizei count, const GLuint* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform2uiv); + mSymbols.fUniform2uiv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform3uiv(GLint location, GLsizei count, const GLuint* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform3uiv); + mSymbols.fUniform3uiv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform4uiv(GLint location, GLsizei count, const GLuint* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniform4uiv); + mSymbols.fUniform4uiv(location, count, value); + AFTER_GL_CALL; + } + + GLint fGetFragDataLocation(GLuint program, const GLchar* name) { + GLint result = 0; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetFragDataLocation); + result = mSymbols.fGetFragDataLocation(program, name); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + // ----------------------------------------------------------------------------- + // Package XXX_instanced_arrays + public: + void fVertexAttribDivisor(GLuint index, GLuint divisor) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fVertexAttribDivisor); + mSymbols.fVertexAttribDivisor(index, divisor); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Feature internalformat_query + public: + void fGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, + GLsizei bufSize, GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetInternalformativ); + mSymbols.fGetInternalformativ(target, internalformat, pname, bufSize, + params); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_query_counter + /** + * XXX_query_counter: + * - depends on XXX_query_objects + * - provide all followed entry points + * - provide GL_TIMESTAMP + */ + public: + void fQueryCounter(GLuint id, GLenum target) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fQueryCounter); + mSymbols.fQueryCounter(id, target); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_query_objects + /** + * XXX_query_objects: + * - provide all followed entry points + * + * XXX_occlusion_query2: + * - depends on XXX_query_objects + * - provide ANY_SAMPLES_PASSED + * + * XXX_occlusion_query_boolean: + * - depends on XXX_occlusion_query2 + * - provide ANY_SAMPLES_PASSED_CONSERVATIVE + */ + public: + void fDeleteQueries(GLsizei n, const GLuint* names) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDeleteQueries); + mSymbols.fDeleteQueries(n, names); + AFTER_GL_CALL; + TRACKING_CONTEXT(DeletedQueries(this, n, names)); + } + + void fGenQueries(GLsizei n, GLuint* names) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGenQueries); + mSymbols.fGenQueries(n, names); + AFTER_GL_CALL; + TRACKING_CONTEXT(CreatedQueries(this, n, names)); + } + + void fGetQueryiv(GLenum target, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetQueryiv); + mSymbols.fGetQueryiv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetQueryObjectuiv); + mSymbols.fGetQueryObjectuiv(id, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + realGLboolean fIsQuery(GLuint query) { + realGLboolean retval = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fIsQuery); + retval = mSymbols.fIsQuery(query); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + // ----------------------------------------------------------------------------- + // Package XXX_get_query_object_i64v + /** + * XXX_get_query_object_i64v: + * - depends on XXX_query_objects + * - provide the followed entry point + */ + public: + void fGetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetQueryObjecti64v); + mSymbols.fGetQueryObjecti64v(id, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetQueryObjectui64v); + mSymbols.fGetQueryObjectui64v(id, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_get_query_object_iv + /** + * XXX_get_query_object_iv: + * - depends on XXX_query_objects + * - provide the followed entry point + * + * XXX_occlusion_query: + * - depends on XXX_get_query_object_iv + * - provide LOCAL_GL_SAMPLES_PASSED + */ + public: + void fGetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetQueryObjectiv); + mSymbols.fGetQueryObjectiv(id, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // GL 4.0, GL ES 3.0, ARB_transform_feedback2, NV_transform_feedback2 + public: + void fBindBufferBase(GLenum target, GLuint index, GLuint buffer) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindBufferBase); + mSymbols.fBindBufferBase(target, index, buffer); + AFTER_GL_CALL; + } + + void fBindBufferRange(GLenum target, GLuint index, GLuint buffer, + GLintptr offset, GLsizeiptr size) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindBufferRange); + mSymbols.fBindBufferRange(target, index, buffer, offset, size); + AFTER_GL_CALL; + } + + void fGenTransformFeedbacks(GLsizei n, GLuint* ids) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGenTransformFeedbacks); + mSymbols.fGenTransformFeedbacks(n, ids); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDeleteTransformFeedbacks); + mSymbols.fDeleteTransformFeedbacks(n, ids); + AFTER_GL_CALL; + } + + realGLboolean fIsTransformFeedback(GLuint id) { + realGLboolean result = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fIsTransformFeedback); + result = mSymbols.fIsTransformFeedback(id); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + void fBindTransformFeedback(GLenum target, GLuint id) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindTransformFeedback); + mSymbols.fBindTransformFeedback(target, id); + AFTER_GL_CALL; + } + + void fBeginTransformFeedback(GLenum primitiveMode) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBeginTransformFeedback); + mSymbols.fBeginTransformFeedback(primitiveMode); + AFTER_GL_CALL; + } + + void fEndTransformFeedback() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fEndTransformFeedback); + mSymbols.fEndTransformFeedback(); + AFTER_GL_CALL; + } + + void fTransformFeedbackVaryings(GLuint program, GLsizei count, + const GLchar* const* varyings, + GLenum bufferMode) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTransformFeedbackVaryings); + mSymbols.fTransformFeedbackVaryings(program, count, varyings, bufferMode); + AFTER_GL_CALL; + } + + void fGetTransformFeedbackVarying(GLuint program, GLuint index, + GLsizei bufSize, GLsizei* length, + GLsizei* size, GLenum* type, GLchar* name) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetTransformFeedbackVarying); + mSymbols.fGetTransformFeedbackVarying(program, index, bufSize, length, size, + type, name); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fPauseTransformFeedback() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPauseTransformFeedback); + mSymbols.fPauseTransformFeedback(); + AFTER_GL_CALL; + } + + void fResumeTransformFeedback() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fResumeTransformFeedback); + mSymbols.fResumeTransformFeedback(); + AFTER_GL_CALL; + } + + void fGetIntegeri_v(GLenum param, GLuint index, GLint* values) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetIntegeri_v); + mSymbols.fGetIntegeri_v(param, index, values); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetInteger64i_v(GLenum target, GLuint index, GLint64* data) { + ASSERT_SYMBOL_PRESENT(fGetInteger64i_v); + BEFORE_GL_CALL; + mSymbols.fGetInteger64i_v(target, index, data); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Package XXX_vertex_array_object + public: + void fBindVertexArray(GLuint array) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindVertexArray); + mSymbols.fBindVertexArray(array); + AFTER_GL_CALL; + } + + void fDeleteVertexArrays(GLsizei n, const GLuint* arrays) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDeleteVertexArrays); + mSymbols.fDeleteVertexArrays(n, arrays); + AFTER_GL_CALL; + } + + void fGenVertexArrays(GLsizei n, GLuint* arrays) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGenVertexArrays); + mSymbols.fGenVertexArrays(n, arrays); + AFTER_GL_CALL; + } + + realGLboolean fIsVertexArray(GLuint array) { + realGLboolean ret = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fIsVertexArray); + ret = mSymbols.fIsVertexArray(array); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + // ----------------------------------------------------------------------------- + // Extension NV_fence + public: + void fGenFences(GLsizei n, GLuint* fences) { + ASSERT_SYMBOL_PRESENT(fGenFences); + BEFORE_GL_CALL; + mSymbols.fGenFences(n, fences); + AFTER_GL_CALL; + } + + void fDeleteFences(GLsizei n, const GLuint* fences) { + ASSERT_SYMBOL_PRESENT(fDeleteFences); + BEFORE_GL_CALL; + mSymbols.fDeleteFences(n, fences); + AFTER_GL_CALL; + } + + void fSetFence(GLuint fence, GLenum condition) { + ASSERT_SYMBOL_PRESENT(fSetFence); + BEFORE_GL_CALL; + mSymbols.fSetFence(fence, condition); + AFTER_GL_CALL; + } + + realGLboolean fTestFence(GLuint fence) { + realGLboolean ret = false; + ASSERT_SYMBOL_PRESENT(fTestFence); + BEFORE_GL_CALL; + ret = mSymbols.fTestFence(fence); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fFinishFence(GLuint fence) { + ASSERT_SYMBOL_PRESENT(fFinishFence); + BEFORE_GL_CALL; + mSymbols.fFinishFence(fence); + OnSyncCall(); + AFTER_GL_CALL; + } + + realGLboolean fIsFence(GLuint fence) { + realGLboolean ret = false; + ASSERT_SYMBOL_PRESENT(fIsFence); + BEFORE_GL_CALL; + ret = mSymbols.fIsFence(fence); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fGetFenceiv(GLuint fence, GLenum pname, GLint* params) { + ASSERT_SYMBOL_PRESENT(fGetFenceiv); + BEFORE_GL_CALL; + mSymbols.fGetFenceiv(fence, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Extension NV_texture_barrier + public: + void fTextureBarrier() { + ASSERT_SYMBOL_PRESENT(fTextureBarrier); + BEFORE_GL_CALL; + mSymbols.fTextureBarrier(); + AFTER_GL_CALL; + } + + // Core GL & Extension ARB_copy_buffer + public: + void fCopyBufferSubData(GLenum readtarget, GLenum writetarget, + GLintptr readoffset, GLintptr writeoffset, + GLsizeiptr size) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fCopyBufferSubData); + mSymbols.fCopyBufferSubData(readtarget, writetarget, readoffset, + writeoffset, size); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Core GL & Extension ARB_map_buffer_range + public: + void* fMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access) { + void* data = nullptr; + ASSERT_SYMBOL_PRESENT(fMapBufferRange); + BEFORE_GL_CALL; + data = mSymbols.fMapBufferRange(target, offset, length, access); + OnSyncCall(); + AFTER_GL_CALL; + return data; + } + + void fFlushMappedBufferRange(GLenum target, GLintptr offset, + GLsizeiptr length) { + ASSERT_SYMBOL_PRESENT(fFlushMappedBufferRange); + BEFORE_GL_CALL; + mSymbols.fFlushMappedBufferRange(target, offset, length); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Core GL & Extension ARB_sampler_objects + public: + void fGenSamplers(GLsizei count, GLuint* samplers) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGenSamplers); + mSymbols.fGenSamplers(count, samplers); + AFTER_GL_CALL; + } + + void fDeleteSamplers(GLsizei count, const GLuint* samplers) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDeleteSamplers); + mSymbols.fDeleteSamplers(count, samplers); + AFTER_GL_CALL; + } + + realGLboolean fIsSampler(GLuint sampler) { + realGLboolean result = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fIsSampler); + result = mSymbols.fIsSampler(sampler); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + void fBindSampler(GLuint unit, GLuint sampler) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBindSampler); + mSymbols.fBindSampler(unit, sampler); + AFTER_GL_CALL; + } + + void fSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fSamplerParameteri); + mSymbols.fSamplerParameteri(sampler, pname, param); + AFTER_GL_CALL; + } + + void fSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fSamplerParameteriv); + mSymbols.fSamplerParameteriv(sampler, pname, param); + AFTER_GL_CALL; + } + + void fSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fSamplerParameterf); + mSymbols.fSamplerParameterf(sampler, pname, param); + AFTER_GL_CALL; + } + + void fSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fSamplerParameterfv); + mSymbols.fSamplerParameterfv(sampler, pname, param); + AFTER_GL_CALL; + } + + void fGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetSamplerParameteriv); + mSymbols.fGetSamplerParameteriv(sampler, pname, params); + AFTER_GL_CALL; + } + + void fGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetSamplerParameterfv); + mSymbols.fGetSamplerParameterfv(sampler, pname, params); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Core GL & Extension ARB_uniform_buffer_object + public: + void fGetUniformIndices(GLuint program, GLsizei uniformCount, + const GLchar* const* uniformNames, + GLuint* uniformIndices) { + ASSERT_SYMBOL_PRESENT(fGetUniformIndices); + BEFORE_GL_CALL; + mSymbols.fGetUniformIndices(program, uniformCount, uniformNames, + uniformIndices); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetActiveUniformsiv(GLuint program, GLsizei uniformCount, + const GLuint* uniformIndices, GLenum pname, + GLint* params) { + ASSERT_SYMBOL_PRESENT(fGetActiveUniformsiv); + BEFORE_GL_CALL; + mSymbols.fGetActiveUniformsiv(program, uniformCount, uniformIndices, pname, + params); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLuint fGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) { + GLuint result = 0; + ASSERT_SYMBOL_PRESENT(fGetUniformBlockIndex); + BEFORE_GL_CALL; + result = mSymbols.fGetUniformBlockIndex(program, uniformBlockName); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + void fGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, + GLenum pname, GLint* params) { + ASSERT_SYMBOL_PRESENT(fGetActiveUniformBlockiv); + BEFORE_GL_CALL; + mSymbols.fGetActiveUniformBlockiv(program, uniformBlockIndex, pname, + params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, + GLsizei bufSize, GLsizei* length, + GLchar* uniformBlockName) { + ASSERT_SYMBOL_PRESENT(fGetActiveUniformBlockName); + BEFORE_GL_CALL; + mSymbols.fGetActiveUniformBlockName(program, uniformBlockIndex, bufSize, + length, uniformBlockName); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding) { + ASSERT_SYMBOL_PRESENT(fUniformBlockBinding); + BEFORE_GL_CALL; + mSymbols.fUniformBlockBinding(program, uniformBlockIndex, + uniformBlockBinding); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // Core GL 4.2, GL ES 3.0 & Extension ARB_texture_storage/EXT_texture_storage + void fTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTexStorage2D); + mSymbols.fTexStorage2D(target, levels, internalformat, width, height); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTexStorage3D); + mSymbols.fTexStorage3D(target, levels, internalformat, width, height, + depth); + OnSyncCall(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // 3D Textures + void fTexImage3D(GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLenum format, GLenum type, const GLvoid* data) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTexImage3D); + mSymbols.fTexImage3D(target, level, internalFormat, width, height, depth, + border, format, type, data); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, + GLsizei depth, GLenum format, GLenum type, + const GLvoid* pixels) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTexSubImage3D); + mSymbols.fTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, + height, depth, format, type, pixels); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height) { + BeforeGLReadCall(); + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fCopyTexSubImage3D); + mSymbols.fCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, + width, height); + AFTER_GL_CALL; + AfterGLReadCall(); + } + + void fCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLsizei imageSize, + const GLvoid* data) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fCompressedTexImage3D); + mSymbols.fCompressedTexImage3D(target, level, internalformat, width, height, + depth, border, imageSize, data); + AFTER_GL_CALL; + } + + void fCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const GLvoid* data) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fCompressedTexSubImage3D); + mSymbols.fCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, + width, height, depth, format, imageSize, + data); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // GL3+, ES3+ + + const GLubyte* fGetStringi(GLenum name, GLuint index) { + const GLubyte* ret = nullptr; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetStringi); + ret = mSymbols.fGetStringi(name, index); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + // ----------------------------------------------------------------------------- + // APPLE_framebuffer_multisample + + void fResolveMultisampleFramebufferAPPLE() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE); + mSymbols.fResolveMultisampleFramebufferAPPLE(); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // APPLE_fence + + void fFinishObjectAPPLE(GLenum object, GLint name) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fFinishObjectAPPLE); + mSymbols.fFinishObjectAPPLE(object, name); + AFTER_GL_CALL; + } + + realGLboolean fTestObjectAPPLE(GLenum object, GLint name) { + realGLboolean ret = false; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fTestObjectAPPLE); + ret = mSymbols.fTestObjectAPPLE(object, name); + AFTER_GL_CALL; + return ret; + } + + // ----------------------------------------------------------------------------- + // prim_restart + + void fPrimitiveRestartIndex(GLuint index) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPrimitiveRestartIndex); + mSymbols.fPrimitiveRestartIndex(index); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- + // multiview + + void fFramebufferTextureMultiview(GLenum target, GLenum attachment, + GLuint texture, GLint level, + GLint baseViewIndex, + GLsizei numViews) const { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fFramebufferTextureMultiview); + mSymbols.fFramebufferTextureMultiview(target, attachment, texture, level, + baseViewIndex, numViews); + AFTER_GL_CALL; + } + + // - + // draw_buffers_indexed + + void fBlendEquationSeparatei(GLuint i, GLenum modeRGB, + GLenum modeAlpha) const { + BEFORE_GL_CALL; + mSymbols.fBlendEquationSeparatei(i, modeRGB, modeAlpha); + AFTER_GL_CALL; + } + + void fBlendFuncSeparatei(GLuint i, GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorAlpha, GLenum dfactorAlpha) const { + BEFORE_GL_CALL; + mSymbols.fBlendFuncSeparatei(i, sfactorRGB, dfactorRGB, sfactorAlpha, + dfactorAlpha); + AFTER_GL_CALL; + } + + void fColorMaski(GLuint i, realGLboolean red, realGLboolean green, + realGLboolean blue, realGLboolean alpha) const { + BEFORE_GL_CALL; + mSymbols.fColorMaski(i, red, green, blue, alpha); + AFTER_GL_CALL; + } + + void fDisablei(GLenum capability, GLuint i) const { + BEFORE_GL_CALL; + mSymbols.fDisablei(capability, i); + AFTER_GL_CALL; + } + + void fEnablei(GLenum capability, GLuint i) const { + BEFORE_GL_CALL; + mSymbols.fEnablei(capability, i); + AFTER_GL_CALL; + } + + // - + + void fProvokingVertex(GLenum mode) const { + BEFORE_GL_CALL; + mSymbols.fProvokingVertex(mode); + AFTER_GL_CALL; + } + + // - + +#undef BEFORE_GL_CALL +#undef AFTER_GL_CALL +#undef ASSERT_SYMBOL_PRESENT +// #undef TRACKING_CONTEXT // Needed in GLContext.cpp +#undef ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL + + // ----------------------------------------------------------------------------- + // Constructor + protected: + explicit GLContext(const GLContextDesc&, GLContext* sharedContext = nullptr, + bool canUseTLSIsCurrent = false); + + // ----------------------------------------------------------------------------- + // Destructor + public: + virtual ~GLContext(); + + // Mark this context as destroyed. This will nullptr out all + // the GL function pointers! + void MarkDestroyed(); + + protected: + virtual void OnMarkDestroyed() {} + + // ----------------------------------------------------------------------------- + // Everything that isn't standard GL APIs + protected: + typedef gfx::SurfaceFormat SurfaceFormat; + + public: + virtual void ReleaseSurface() {} + + bool IsDestroyed() const { + // MarkDestroyed will mark all these as null. + return mContextLost && mSymbols.fUseProgram == nullptr; + } + + GLContext* GetSharedContext() { return mSharedContext; } + + /** + * Returns true if the thread on which this context was created is the + * currently executing thread. + */ + bool IsValidOwningThread() const; + + static void PlatformStartup(); + + public: + /** + * If this context wraps a double-buffered target, swap the back + * and front buffers. It should be assumed that after a swap, the + * contents of the new back buffer are undefined. + */ + virtual bool SwapBuffers() { return false; } + + /** + * Stores a damage region (in origin bottom left coordinates), which + * makes the next SwapBuffers call do eglSwapBuffersWithDamage if supported. + * + * Note that even if only part of the context is damaged, the entire buffer + * needs to be filled with up-to-date contents. This region is only a hint + * telling the system compositor which parts of the buffer were updated. + */ + virtual void SetDamage(const nsIntRegion& aDamageRegion) {} + + /** + * Get the buffer age. If it returns 0, that indicates the buffer state is + * unknown and the entire frame should be redrawn. + */ + virtual GLint GetBufferAge() const { return 0; } + + /** + * Defines a two-dimensional texture image for context target surface + */ + virtual bool BindTexImage() { return false; } + /* + * Releases a color buffer that is being used as a texture + */ + virtual bool ReleaseTexImage() { return false; } + + virtual Maybe<SymbolLoader> GetSymbolLoader() const = 0; + + void BindFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); + MOZ_GL_ASSERT(this, !fb || fIsFramebuffer(fb)); + } + + void BindDrawFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); + } + + void BindReadFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); + } + + GLuint GetDrawFB() const { + return GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT); + } + + GLuint GetReadFB() const { + auto bindEnum = LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT; + if (!IsSupported(GLFeature::split_framebuffer)) { + bindEnum = LOCAL_GL_FRAMEBUFFER_BINDING; + } + return GetIntAs<GLuint>(bindEnum); + } + + GLuint GetFB() const { + const auto ret = GetDrawFB(); + MOZ_ASSERT(ret == GetReadFB()); + return ret; + } + + private: + void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + switch (precisiontype) { + case LOCAL_GL_LOW_FLOAT: + case LOCAL_GL_MEDIUM_FLOAT: + case LOCAL_GL_HIGH_FLOAT: + // Assume IEEE 754 precision + range[0] = 127; + range[1] = 127; + *precision = 23; + break; + case LOCAL_GL_LOW_INT: + case LOCAL_GL_MEDIUM_INT: + case LOCAL_GL_HIGH_INT: + // Some (most) hardware only supports single-precision floating-point + // numbers, which can accurately represent integers up to +/-16777216 + range[0] = 24; + range[1] = 24; + *precision = 0; + break; + } + } + + public: + virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; } + + virtual GLenum GetPreferredEGLImageTextureTarget() const { +#ifdef MOZ_WIDGET_GTK + return LOCAL_GL_TEXTURE_2D; +#else + return IsExtensionSupported(OES_EGL_image_external) + ? LOCAL_GL_TEXTURE_EXTERNAL + : LOCAL_GL_TEXTURE_2D; +#endif + } + + virtual bool RenewSurface(widget::CompositorWidget* aWidget) { return false; } + + // Shared code for GL extensions and GLX extensions. + static bool ListHasExtension(const GLubyte* extensions, + const char* extension); + + public: + enum { + DebugFlagEnabled = 1 << 0, + DebugFlagTrace = 1 << 1, + DebugFlagAbortOnError = 1 << 2 + }; + + const uint8_t mDebugFlags; + static uint8_t ChooseDebugFlags(CreateContextFlags createFlags); + + protected: + RefPtr<GLContext> mSharedContext; + + public: + // The thread id which this context was created. + Maybe<PlatformThreadId> mOwningThreadId; + + protected: + GLContextSymbols mSymbols = {}; + + UniquePtr<GLBlitHelper> mBlitHelper; + UniquePtr<GLReadTexImageHelper> mReadTexImageHelper; + + public: + GLBlitHelper* BlitHelper(); + GLReadTexImageHelper* ReadTexImageHelper(); + + // Assumes shares are created by all sharing with the same global context. + bool SharesWith(const GLContext* other) const { + MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext); + MOZ_ASSERT(!other->mSharedContext || + !other->mSharedContext->mSharedContext); + MOZ_ASSERT(!this->mSharedContext || !other->mSharedContext || + this->mSharedContext == other->mSharedContext); + + const GLContext* thisShared = + this->mSharedContext ? this->mSharedContext : this; + const GLContext* otherShared = + other->mSharedContext ? other->mSharedContext : other; + + return thisShared == otherShared; + } + + bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); + + // Does not check completeness. + void AttachBuffersToFB(GLuint colorTex, GLuint colorRB, GLuint depthRB, + GLuint stencilRB, GLuint fb, + GLenum target = LOCAL_GL_TEXTURE_2D); + + // Passing null is fine if the value you'd get is 0. + bool AssembleOffscreenFBs(const GLuint colorMSRB, const GLuint depthRB, + const GLuint stencilRB, const GLuint texture, + GLuint* drawFB, GLuint* readFB); + + protected: + SharedSurface* mLockedSurface = nullptr; + + public: + void LockSurface(SharedSurface* surf) { mLockedSurface = surf; } + + void UnlockSurface(SharedSurface* surf) { + MOZ_ASSERT(mLockedSurface == surf); + mLockedSurface = nullptr; + } + + SharedSurface* GetLockedSurface() const { return mLockedSurface; } + + bool IsOffscreen() const { return mDesc.isOffscreen; } + + bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } + + bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; + + virtual bool Init(); + + private: + bool InitImpl(); + void LoadMoreSymbols(const SymbolLoader& loader); + bool LoadExtSymbols(const SymbolLoader& loader, const SymLoadStruct* list, + GLExtensions ext); + bool LoadFeatureSymbols(const SymbolLoader& loader, const SymLoadStruct* list, + GLFeature feature); + + protected: + void InitExtensions(); + + GLint mViewportRect[4] = {}; + GLint mScissorRect[4] = {}; + + uint32_t mMaxTexOrRbSize = 0; + GLint mMaxTextureSize = 0; + GLint mMaxCubeMapTextureSize = 0; + GLint mMaxRenderbufferSize = 0; + GLint mMaxViewportDims[2] = {}; + GLsizei mMaxSamples = 0; + bool mNeedsTextureSizeChecks = false; + bool mNeedsFlushBeforeDeleteFB = false; + bool mTextureAllocCrashesOnMapFailure = false; + const bool mWorkAroundDriverBugs; + mutable uint64_t mSyncGLCallCount = 0; + + bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, + GLsizei height) const { + if (mNeedsTextureSizeChecks) { + // some drivers incorrectly handle some large texture sizes that are below + // the max texture size that they report. So we check ourselves against + // our own values (mMax[CubeMap]TextureSize). see bug 737182 for Mac Intel + // 2D textures see bug 684882 for Mac Intel cube map textures see bug + // 814716 for Mesa Nouveau + GLsizei maxSize = + target == LOCAL_GL_TEXTURE_CUBE_MAP || + (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && + target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) + ? mMaxCubeMapTextureSize + : mMaxTextureSize; + return width <= maxSize && height <= maxSize; + } + return true; + } + + public: + auto MaxSamples() const { return uint32_t(mMaxSamples); } + auto MaxTextureSize() const { return uint32_t(mMaxTextureSize); } + auto MaxRenderbufferSize() const { return uint32_t(mMaxRenderbufferSize); } + auto MaxTexOrRbSize() const { return mMaxTexOrRbSize; } + +#ifdef MOZ_GL_DEBUG_BUILD + void CreatedProgram(GLContext* aOrigin, GLuint aName); + void CreatedShader(GLContext* aOrigin, GLuint aName); + void CreatedBuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); + void CreatedQueries(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); + void CreatedTextures(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); + void CreatedFramebuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); + void CreatedRenderbuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); + void DeletedProgram(GLContext* aOrigin, GLuint aName); + void DeletedShader(GLContext* aOrigin, GLuint aName); + void DeletedBuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); + void DeletedQueries(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); + void DeletedTextures(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames); + void DeletedFramebuffers(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames); + void DeletedRenderbuffers(GLContext* aOrigin, GLsizei aCount, + const GLuint* aNames); + + void SharedContextDestroyed(GLContext* aChild); + void ReportOutstandingNames(); + + struct NamedResource { + NamedResource() : origin(nullptr), name(0), originDeleted(false) {} + + NamedResource(GLContext* aOrigin, GLuint aName) + : origin(aOrigin), name(aName), originDeleted(false) {} + + GLContext* origin; + GLuint name; + bool originDeleted; + + // for sorting + bool operator<(const NamedResource& aOther) const { + if (intptr_t(origin) < intptr_t(aOther.origin)) return true; + if (name < aOther.name) return true; + return false; + } + bool operator==(const NamedResource& aOther) const { + return origin == aOther.origin && name == aOther.name && + originDeleted == aOther.originDeleted; + } + }; + + nsTArray<NamedResource> mTrackedPrograms; + nsTArray<NamedResource> mTrackedShaders; + nsTArray<NamedResource> mTrackedTextures; + nsTArray<NamedResource> mTrackedFramebuffers; + nsTArray<NamedResource> mTrackedRenderbuffers; + nsTArray<NamedResource> mTrackedBuffers; + nsTArray<NamedResource> mTrackedQueries; +#endif + + protected: + bool mHeavyGLCallsSinceLastFlush = false; + + public: + void FlushIfHeavyGLCallsSinceLastFlush(); + static bool ShouldSpew(); + static bool ShouldDumpExts(); + + // -- + + void TexParams_SetClampNoMips(GLenum target = LOCAL_GL_TEXTURE_2D) { + fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); + fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); + } + + // -- + + GLuint CreateFramebuffer() { + GLuint x = 0; + fGenFramebuffers(1, &x); + return x; + } + GLuint CreateRenderbuffer() { + GLuint x = 0; + fGenRenderbuffers(1, &x); + return x; + } + GLuint CreateTexture() { + GLuint x = 0; + fGenTextures(1, &x); + return x; + } + + void DeleteFramebuffer(const GLuint x) { fDeleteFramebuffers(1, &x); } + void DeleteRenderbuffer(const GLuint x) { fDeleteRenderbuffers(1, &x); } + void DeleteTexture(const GLuint x) { fDeleteTextures(1, &x); } +}; + +bool DoesStringMatch(const char* aString, const char* aWantedString); + +void SplitByChar(const nsACString& str, const char delim, + std::vector<nsCString>* const out); + +template <size_t N> +bool MarkBitfieldByString(const nsACString& str, + const char* const (&markStrList)[N], + std::bitset<N>* const out_markList) { + for (size_t i = 0; i < N; i++) { + if (str.Equals(markStrList[i])) { + (*out_markList)[i] = 1; + return true; + } + } + return false; +} + +template <size_t N> +void MarkBitfieldByStrings(const std::vector<nsCString>& strList, + bool dumpStrings, + const char* const (&markStrList)[N], + std::bitset<N>* const out_markList) { + for (auto itr = strList.begin(); itr != strList.end(); ++itr) { + const nsACString& str = *itr; + const bool wasMarked = MarkBitfieldByString(str, markStrList, out_markList); + if (dumpStrings) + printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : ""); + } +} + +// - + +class Renderbuffer final { + public: + const WeakPtr<GLContext> weakGl; + const GLuint name; + + private: + static GLuint Create(GLContext& gl) { + GLuint ret = 0; + gl.fGenRenderbuffers(1, &ret); + return ret; + } + + public: + explicit Renderbuffer(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} + + ~Renderbuffer() { + const RefPtr<GLContext> gl = weakGl.get(); + if (!gl || !gl->MakeCurrent()) return; + gl->fDeleteRenderbuffers(1, &name); + } +}; + +// - + +class Texture final { + public: + const WeakPtr<GLContext> weakGl; + const GLuint name; + + private: + static GLuint Create(GLContext& gl) { + GLuint ret = 0; + gl.fGenTextures(1, &ret); + return ret; + } + + public: + explicit Texture(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} + + ~Texture() { + const RefPtr<GLContext> gl = weakGl.get(); + if (!gl || !gl->MakeCurrent()) return; + gl->fDeleteTextures(1, &name); + } +}; + +/** + * Helper function that creates a 2D texture aSize.width x aSize.height with + * storage type specified by aFormats. Returns GL texture object id. + * + * See mozilla::gl::CreateTexture. + */ +UniquePtr<Texture> CreateTexture(GLContext&, const gfx::IntSize& size); + +/** + * Helper function that calculates the number of bytes required per + * texel for a texture from its format and type. + */ +uint32_t GetBytesPerTexel(GLenum format, GLenum type); + +void MesaMemoryLeakWorkaround(); + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* GLCONTEXT_H_ */ diff --git a/gfx/gl/GLContextCGL.h b/gfx/gl/GLContextCGL.h new file mode 100644 index 0000000000..b065df4554 --- /dev/null +++ b/gfx/gl/GLContextCGL.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTCGL_H_ +#define GLCONTEXTCGL_H_ + +#include "GLContext.h" + +#include "OpenGL/OpenGL.h" + +#ifdef __OBJC__ +# include <AppKit/NSOpenGL.h> +#else +typedef void NSOpenGLContext; +#endif + +#include <CoreGraphics/CGDisplayConfiguration.h> + +#include "mozilla/Atomics.h" + +class nsIWidget; + +namespace mozilla { +namespace gl { + +class GLContextCGL : public GLContext { + friend class GLContextProviderCGL; + + NSOpenGLContext* mContext; + + mozilla::Atomic<bool> mActiveGPUSwitchMayHaveOccurred; + + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, override) + GLContextCGL(const GLContextDesc&, NSOpenGLContext* context); + + ~GLContextCGL(); + + virtual GLContextType GetContextType() const override { + return GLContextType::CGL; + } + + static GLContextCGL* Cast(GLContext* gl) { + MOZ_ASSERT(gl->GetContextType() == GLContextType::CGL); + return static_cast<GLContextCGL*>(gl); + } + + NSOpenGLContext* GetNSOpenGLContext() const { return mContext; } + CGLContextObj GetCGLContext() const; + + // Can be called on any thread + static void DisplayReconfigurationCallback(CGDirectDisplayID aDisplay, + CGDisplayChangeSummaryFlags aFlags, + void* aUserInfo); + + // Call at the beginning of a frame, on contexts that should stay on the + // active GPU. This method will migrate the context to the new active GPU, if + // the active GPU has changed since the last call. + void MigrateToActiveGPU(); + + virtual bool MakeCurrentImpl() const override; + + virtual bool IsCurrentImpl() const override; + + virtual GLenum GetPreferredARGB32Format() const override; + + virtual bool SwapBuffers() override; + + virtual void GetWSIInfo(nsCString* const out) const override; + + Maybe<SymbolLoader> GetSymbolLoader() const override; +}; + +} // namespace gl +} // namespace mozilla + +#endif // GLCONTEXTCGL_H_ diff --git a/gfx/gl/GLContextEAGL.h b/gfx/gl/GLContextEAGL.h new file mode 100644 index 0000000000..6e137e7b70 --- /dev/null +++ b/gfx/gl/GLContextEAGL.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTEAGL_H_ +#define GLCONTEXTEAGL_H_ + +#include "GLContext.h" + +#include <CoreGraphics/CoreGraphics.h> +#include <OpenGLES/EAGL.h> + +namespace mozilla { +namespace gl { + +class GLContextEAGL : public GLContext { + friend class GLContextProviderEAGL; + + EAGLContext* const mContext; + + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override) + GLContextEAGL(const GLContextDesc&, EAGLContext* context, + GLContext* sharedContext, ContextProfile profile); + + ~GLContextEAGL(); + + virtual GLContextType GetContextType() const override { + return GLContextType::EAGL; + } + + static GLContextEAGL* Cast(GLContext* gl) { + MOZ_ASSERT(gl->GetContextType() == GLContextType::EAGL); + return static_cast<GLContextEAGL*>(gl); + } + + bool AttachToWindow(nsIWidget* aWidget); + + EAGLContext* GetEAGLContext() const { return mContext; } + + virtual bool MakeCurrentImpl() const override; + + virtual bool IsCurrentImpl() const override; + + Maybe<SymbolLoader> GetSymbolLoader() const override; + + virtual bool IsDoubleBuffered() const override; + + virtual bool SwapBuffers() override; + + virtual void GetWSIInfo(nsCString* const out) const override; + + virtual GLuint GetDefaultFramebuffer() override { return mBackbufferFB; } + + virtual bool RenewSurface(widget::CompositorWidget*) override { + // FIXME: should use the passed widget instead of the existing one. + return RecreateRB(); + } + + private: + GLuint mBackbufferRB = 0; + GLuint mBackbufferFB = 0; + + void* mLayer = nullptr; + + bool RecreateRB(); +}; + +} // namespace gl +} // namespace mozilla + +#endif // GLCONTEXTEAGL_H_ diff --git a/gfx/gl/GLContextEGL.h b/gfx/gl/GLContextEGL.h new file mode 100644 index 0000000000..5a88f4a2a2 --- /dev/null +++ b/gfx/gl/GLContextEGL.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTEGL_H_ +#define GLCONTEXTEGL_H_ + +#include "GLContext.h" +#include "GLLibraryEGL.h" +#include "nsRegion.h" +#include <memory> + +namespace mozilla { +namespace layers { +class SurfaceTextureImage; +} // namespace layers +namespace widget { +class CompositorWidget; +} // namespace widget +namespace gl { + +inline std::shared_ptr<EglDisplay> DefaultEglDisplay( + nsACString* const out_failureId) { + const auto lib = GLLibraryEGL::Get(out_failureId); + if (!lib) { + return nullptr; + } + return lib->DefaultDisplay(out_failureId); +} + +// - + +class GLContextEGL final : public GLContext { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEGL, override) + + static RefPtr<GLContextEGL> CreateGLContext( + std::shared_ptr<EglDisplay>, const GLContextDesc&, + EGLConfig surfaceConfig, EGLSurface surface, const bool useGles, + EGLConfig contextConfig, nsACString* const out_failureId); + + private: + GLContextEGL(std::shared_ptr<EglDisplay>, const GLContextDesc&, + EGLConfig surfaceConfig, EGLSurface surface, EGLContext context); + ~GLContextEGL(); + + public: + virtual GLContextType GetContextType() const override { + return GLContextType::EGL; + } + + static GLContextEGL* Cast(GLContext* gl) { + MOZ_ASSERT(gl->GetContextType() == GLContextType::EGL); + return static_cast<GLContextEGL*>(gl); + } + + bool Init() override; + + virtual bool IsDoubleBuffered() const override { return mIsDoubleBuffered; } + + void SetIsDoubleBuffered(bool aIsDB) { mIsDoubleBuffered = aIsDB; } + + virtual bool IsANGLE() const override { return mEgl->mLib->IsANGLE(); } + virtual bool IsWARP() const override { return mEgl->mIsWARP; } + + virtual bool BindTexImage() override; + + virtual bool ReleaseTexImage() override; + + void SetEGLSurfaceOverride(EGLSurface surf); + EGLSurface GetEGLSurfaceOverride() { return mSurfaceOverride; } + + virtual bool MakeCurrentImpl() const override; + + virtual bool IsCurrentImpl() const override; + + virtual bool RenewSurface(widget::CompositorWidget* aWidget) override; + + virtual void ReleaseSurface() override; + + Maybe<SymbolLoader> GetSymbolLoader() const override; + + virtual bool SwapBuffers() override; + + virtual void SetDamage(const nsIntRegion& aDamageRegion) override; + + GLint GetBufferAge() const override; + + virtual void GetWSIInfo(nsCString* const out) const override; + + EGLSurface GetEGLSurface() const { return mSurface; } + + bool HasExtBufferAge() const; + bool HasKhrPartialUpdate() const; + + bool BindTex2DOffscreen(GLContext* aOffscreen); + void UnbindTex2DOffscreen(GLContext* aOffscreen); + void BindOffscreenFramebuffer(); + + void Destroy(); + + static RefPtr<GLContextEGL> CreateWithoutSurface( + std::shared_ptr<EglDisplay>, const GLContextCreateDesc&, + nsACString* const out_FailureId); + static RefPtr<GLContextEGL> CreateEGLSurfacelessContext( + const std::shared_ptr<EglDisplay> display, + const GLContextCreateDesc& desc, nsACString* const out_failureId); + + static EGLSurface CreateEGLSurfaceForCompositorWidget( + widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig); + + static void DestroySurface(EglDisplay&, const EGLSurface aSurface); + +#ifdef MOZ_X11 + static bool FindVisual(int* const out_visualId); +#endif + + protected: + friend class GLContextProviderEGL; + friend class GLContextEGLFactory; + + virtual void OnMarkDestroyed() override; + + public: + const std::shared_ptr<EglDisplay> mEgl; + const EGLConfig mSurfaceConfig; + const EGLContext mContext; + + protected: + EGLSurface mSurface; + const EGLSurface mFallbackSurface; + + EGLSurface mSurfaceOverride = EGL_NO_SURFACE; + bool mBound = false; + + bool mIsPBuffer = false; + bool mIsDoubleBuffered = false; + bool mCanBindToTexture = false; + bool mShareWithEGLImage = false; + bool mOwnsContext = true; + + nsIntRegion mDamageRegion; + + static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo( + EglDisplay&, EGLConfig, EGLenum bindToTextureFormat, + gfx::IntSize& pbsize); + +#ifdef MOZ_WAYLAND + static EGLSurface CreateWaylandOffscreenSurface(EglDisplay&, EGLConfig, + gfx::IntSize& pbsize); +#endif + + public: + EGLSurface CreateCompatibleSurface(void* aWindow) const; +}; + +bool CreateConfig(EglDisplay&, EGLConfig* aConfig, int32_t aDepth, + bool aEnableDepthBuffer, bool aUseGles, + bool aAllowFallback = true); + +} // namespace gl +} // namespace mozilla + +#endif // GLCONTEXTEGL_H_ diff --git a/gfx/gl/GLContextFeatures.cpp b/gfx/gl/GLContextFeatures.cpp new file mode 100644 index 0000000000..b66e6b6bbf --- /dev/null +++ b/gfx/gl/GLContextFeatures.cpp @@ -0,0 +1,642 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContext.h" +#include "nsPrintfCString.h" + +namespace mozilla { +namespace gl { + +const size_t kMAX_EXTENSION_GROUP_SIZE = 5; + +enum class GLVersion : uint32_t { + NONE = 0, // Feature is not supported natively by GL + GL1_2 = 120, + GL1_3 = 130, + GL2 = 200, + GL2_1 = 210, + GL3 = 300, + GL3_1 = 310, + GL3_2 = 320, + GL3_3 = 330, + GL4 = 400, + GL4_1 = 410, + GL4_2 = 420, + GL4_3 = 430, +}; + +enum class GLESVersion : uint32_t { + NONE = 0, // Feature is not support natively by GL ES + ES2 = 200, + ES3 = 300, + ES3_1 = 310, + ES3_2 = 320, +}; + +// ARB_ES2_compatibility is natively supported in OpenGL 4.1. +static const GLVersion kGLCoreVersionForES2Compat = GLVersion::GL4_1; + +// ARB_ES3_compatibility is natively supported in OpenGL 4.3. +static const GLVersion kGLCoreVersionForES3Compat = GLVersion::GL4_3; + +struct FeatureInfo { + const char* mName; + + /* The (desktop) OpenGL version that provides this feature */ + GLVersion mOpenGLVersion; + + /* The OpenGL ES version that provides this feature */ + GLESVersion mOpenGLESVersion; + + /* If there is an ARB extension, and its function symbols are + * not decorated with an ARB suffix, then its extension ID should go + * here, and NOT in mExtensions. For example, ARB_vertex_array_object + * functions do not have an ARB suffix, because it is an extension that + * was created to match core GL functionality and will never differ. + * Some ARB extensions do have a suffix, if they were created before + * a core version of the functionality existed. + * + * If there is no such ARB extension, pass 0 (GLContext::Extension_None) + */ + GLContext::GLExtensions mARBExtensionWithoutARBSuffix; + + /* Extensions that also provide this feature */ + GLContext::GLExtensions mExtensions[kMAX_EXTENSION_GROUP_SIZE]; +}; + +static const FeatureInfo sFeatureInfoArr[] = { + {"bind_buffer_offset", + GLVersion::NONE, + GLESVersion::NONE, + GLContext::Extension_None, + { + + GLContext::EXT_transform_feedback, GLContext::NV_transform_feedback2, + GLContext::Extensions_End}}, + {"blend_minmax", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_blend_minmax, GLContext::Extensions_End}}, + {"clear_buffers", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::Extensions_End}}, + {"copy_buffer", + GLVersion::GL3_1, + GLESVersion::ES3, + GLContext::ARB_copy_buffer, + {GLContext::Extensions_End}}, + {"depth_texture", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_depth_texture, GLContext::OES_depth_texture, + // Intentionally avoid putting ANGLE_depth_texture here, + // it does not offer quite the same functionality. + GLContext::Extensions_End}}, + {"draw_buffers", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_draw_buffers, GLContext::EXT_draw_buffers, + GLContext::Extensions_End}}, + {"draw_buffers_indexed", + GLVersion::GL3, + GLESVersion::ES3_2, + GLContext::Extension_None, + {GLContext::OES_draw_buffers_indexed, GLContext::Extensions_End}}, + {"draw_instanced", + GLVersion::GL3_1, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_draw_instanced, GLContext::EXT_draw_instanced, + GLContext::NV_draw_instanced, GLContext::ANGLE_instanced_arrays, + GLContext::Extensions_End}}, + {"element_index_uint", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::OES_element_index_uint, GLContext::Extensions_End}}, + {"ES2_compatibility", + kGLCoreVersionForES2Compat, + GLESVersion::ES2, // OpenGL ES version + GLContext::ARB_ES2_compatibility, // no suffix on ARB extension + {GLContext::Extensions_End}}, + {"ES3_compatibility", + kGLCoreVersionForES3Compat, + GLESVersion::ES3, // OpenGL ES version + GLContext::ARB_ES3_compatibility, // no suffix on ARB extension + {GLContext::Extensions_End}}, + {"EXT_color_buffer_float", + GLVersion::GL3, + GLESVersion::ES3_2, + GLContext::Extension_None, + {GLContext::EXT_color_buffer_float, GLContext::Extensions_End}}, + {// Removes clamping for float color outputs from frag shaders. + "frag_color_float", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_color_buffer_float, GLContext::EXT_color_buffer_float, + GLContext::EXT_color_buffer_half_float, + GLContext::CHROMIUM_color_buffer_float_rgba, GLContext::Extensions_End}}, + {"frag_depth", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_frag_depth, GLContext::Extensions_End}}, + {// Check for just the blit framebuffer blit part of + // ARB_framebuffer_object + "framebuffer_blit", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_framebuffer_object, + {GLContext::ANGLE_framebuffer_blit, GLContext::EXT_framebuffer_blit, + GLContext::NV_framebuffer_blit, GLContext::Extensions_End}}, + {// Check for just the multisample renderbuffer part of + // ARB_framebuffer_object + "framebuffer_multisample", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_framebuffer_object, + {GLContext::ANGLE_framebuffer_multisample, + GLContext::APPLE_framebuffer_multisample, + GLContext::EXT_framebuffer_multisample, + GLContext::EXT_multisampled_render_to_texture, + GLContext::Extensions_End}}, + {// ARB_framebuffer_object support + "framebuffer_object", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_framebuffer_object, + {GLContext::Extensions_End}}, + {// EXT_framebuffer_object/OES_framebuffer_object support + "framebuffer_object_EXT_OES", + GLVersion::GL3, + GLESVersion::ES2, + GLContext::Extension_None, + {GLContext::EXT_framebuffer_object, GLContext::OES_framebuffer_object, + GLContext::Extensions_End}}, + {"get_integer_indexed", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_draw_buffers2, GLContext::Extensions_End}}, + {"get_integer64_indexed", + GLVersion::GL3_2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::Extensions_End}}, + {"get_query_object_i64v", + GLVersion::GL3_3, + GLESVersion::NONE, + GLContext::ARB_timer_query, + {GLContext::ANGLE_timer_query, GLContext::EXT_disjoint_timer_query, + GLContext::EXT_timer_query, GLContext::Extensions_End}}, + { + "get_query_object_iv", + GLVersion::GL2, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::Extensions_End} + /* + * XXX_get_query_object_iv only provide GetQueryObjectiv provided by + * ARB_occlusion_query (added by OpenGL 2.0). + */ + }, + {"gpu_shader4", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_gpu_shader4, GLContext::Extensions_End}}, + {"instanced_arrays", + GLVersion::GL3_3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_instanced_arrays, GLContext::NV_instanced_arrays, + GLContext::ANGLE_instanced_arrays, GLContext::Extensions_End}}, + { + "instanced_non_arrays", + GLVersion::GL3_3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_instanced_arrays, GLContext::Extensions_End} + /* This is an expanded version of `instanced_arrays` that allows for all + * enabled active attrib arrays to have non-zero divisors. + * ANGLE_instanced_arrays and NV_instanced_arrays forbid this, but GLES3 + * has no such restriction. + */ + }, + {"internalformat_query", + GLVersion::GL4_2, + GLESVersion::ES3, + GLContext::ARB_internalformat_query, + {GLContext::Extensions_End}}, + {"invalidate_framebuffer", + GLVersion::GL4_3, + GLESVersion::ES3, + GLContext::ARB_invalidate_subdata, + {GLContext::Extensions_End}}, + {"map_buffer_range", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_map_buffer_range, + {GLContext::EXT_map_buffer_range, GLContext::Extensions_End}}, + {"multiview", + GLVersion::NONE, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ANGLE_multiview, GLContext::OVR_multiview2, + GLContext::Extensions_End}}, + { + "occlusion_query", + GLVersion::GL2, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::Extensions_End} + // XXX_occlusion_query depend on ARB_occlusion_query (added in + // OpenGL 2.0) + }, + { + "occlusion_query_boolean", + kGLCoreVersionForES3Compat, + GLESVersion::ES3, + GLContext::ARB_ES3_compatibility, + {GLContext::EXT_occlusion_query_boolean, GLContext::Extensions_End} + /* + * XXX_occlusion_query_boolean provide ANY_SAMPLES_PASSED_CONSERVATIVE, + * but EXT_occlusion_query_boolean is only a OpenGL ES extension. But + * it is supported on desktop if ARB_ES3_compatibility because + * EXT_occlusion_query_boolean (added in OpenGL ES 3.0). + */ + }, + { + "occlusion_query2", + GLVersion::GL3_3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_occlusion_query2, GLContext::ARB_ES3_compatibility, + GLContext::EXT_occlusion_query_boolean, GLContext::Extensions_End} + /* + * XXX_occlusion_query2 (add in OpenGL 3.3) provide ANY_SAMPLES_PASSED, + * which is provided by ARB_occlusion_query2, + * EXT_occlusion_query_boolean (added in OpenGL ES 3.0) and + * ARB_ES3_compatibility + */ + }, + {"packed_depth_stencil", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_packed_depth_stencil, GLContext::OES_packed_depth_stencil, + GLContext::Extensions_End}}, + {"prim_restart", + GLVersion::GL3_1, + GLESVersion::NONE, + GLContext::Extension_None, + {// GLContext::NV_primitive_restart, // Has different enum values. + GLContext::Extensions_End}}, + {"prim_restart_fixed", + kGLCoreVersionForES3Compat, + GLESVersion::ES3, + GLContext::ARB_ES3_compatibility, + {GLContext::Extensions_End}}, + {"provoking_vertex", + GLVersion::GL3_2, + GLESVersion::NONE, + GLContext::ARB_provoking_vertex, + {GLContext::ANGLE_provoking_vertex, GLContext::EXT_provoking_vertex, + GLContext::Extensions_End}}, + {"query_counter", + GLVersion::GL3_3, + GLESVersion::NONE, + GLContext::ARB_timer_query, + {GLContext::ANGLE_timer_query, GLContext::EXT_disjoint_timer_query, + // EXT_timer_query does NOT support GL_TIMESTAMP retrieval with + // QueryCounter. + GLContext::Extensions_End}}, + { + "query_objects", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ANGLE_timer_query, GLContext::EXT_disjoint_timer_query, + GLContext::EXT_occlusion_query_boolean, GLContext::Extensions_End} + /* + * XXX_query_objects only provide entry points commonly supported by + * ARB_occlusion_query (added in OpenGL 2.0), + * EXT_occlusion_query_boolean (added in OpenGL ES 3.0), and + * ARB_timer_query (added in OpenGL 3.3) + */ + }, + {"query_time_elapsed", + GLVersion::GL3_3, + GLESVersion::NONE, + GLContext::ARB_timer_query, + {GLContext::ANGLE_timer_query, GLContext::EXT_disjoint_timer_query, + GLContext::EXT_timer_query, GLContext::Extensions_End}}, + {"read_buffer", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::Extensions_End}}, + {"renderbuffer_color_float", + GLVersion::GL3, + GLESVersion::ES3_2, + GLContext::Extension_None, + {GLContext::ARB_texture_float, GLContext::EXT_color_buffer_float, + GLContext::CHROMIUM_color_buffer_float_rgba, GLContext::Extensions_End}}, + {"renderbuffer_color_half_float", + GLVersion::GL3, + GLESVersion::ES3_2, + GLContext::Extension_None, + {GLContext::ARB_texture_float, GLContext::EXT_color_buffer_float, + GLContext::EXT_color_buffer_half_float, GLContext::Extensions_End}}, + {"robust_buffer_access_behavior", + GLVersion::NONE, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ARB_robust_buffer_access_behavior, + GLContext::KHR_robust_buffer_access_behavior, GLContext::Extensions_End}}, + {"robustness", + GLVersion::NONE, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ARB_robustness, GLContext::EXT_robustness, + GLContext::KHR_robustness, GLContext::Extensions_End}}, + {"sRGB", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_framebuffer_sRGB, + {GLContext::EXT_sRGB, GLContext::EXT_framebuffer_sRGB, + GLContext::Extensions_End}}, + {"sampler_objects", + GLVersion::GL3_3, + GLESVersion::ES3, + GLContext::ARB_sampler_objects, + {GLContext::Extensions_End}}, + {"seamless_cube_map_opt_in", + GLVersion::GL3_2, + GLESVersion::NONE, + GLContext::ARB_seamless_cube_map, + {GLContext::Extensions_End}}, + {"shader_texture_lod", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_shader_texture_lod, GLContext::EXT_shader_texture_lod, + GLContext::Extensions_End}}, + {// Do we have separate DRAW and READ framebuffer bind points? + "split_framebuffer", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_framebuffer_object, + {GLContext::ANGLE_framebuffer_blit, + GLContext::APPLE_framebuffer_multisample, GLContext::EXT_framebuffer_blit, + GLContext::NV_framebuffer_blit, GLContext::Extensions_End}}, + {"standard_derivatives", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::OES_standard_derivatives, GLContext::Extensions_End}}, + {"sync", + GLVersion::GL3_2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_sync, GLContext::APPLE_sync, GLContext::Extensions_End}}, + {"texture_3D", + GLVersion::GL1_2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::OES_texture_3D, GLContext::Extensions_End}}, + {"texture_3D_compressed", + GLVersion::GL1_3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_texture_compression, GLContext::OES_texture_3D, + GLContext::Extensions_End}}, + {"texture_3D_copy", + GLVersion::GL1_2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::EXT_copy_texture, GLContext::OES_texture_3D, + GLContext::Extensions_End}}, + {"texture_compression_bptc", + GLVersion::GL4_2, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ARB_texture_compression_bptc, + GLContext::EXT_texture_compression_bptc, GLContext::Extensions_End}}, + {"texture_compression_rgtc", + GLVersion::GL3, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ARB_texture_compression_rgtc, + GLContext::EXT_texture_compression_rgtc, GLContext::Extensions_End}}, + {"texture_float", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_texture_float, GLContext::OES_texture_float, + GLContext::Extensions_End}}, + {"texture_float_linear", + GLVersion::GL3_1, + GLESVersion::NONE, + GLContext::Extension_None, + {GLContext::ARB_texture_float, GLContext::OES_texture_float_linear, + GLContext::Extensions_End}}, + { + "texture_half_float", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_half_float_pixel, GLContext::ARB_texture_float, + GLContext::NV_half_float, GLContext::Extensions_End} + /** + * We are not including OES_texture_half_float in this feature, because: + * GL_HALF_FLOAT = 0x140B + * GL_HALF_FLOAT_ARB = 0x140B == GL_HALF_FLOAT + * GL_HALF_FLOAT_NV = 0x140B == GL_HALF_FLOAT + * GL_HALF_FLOAT_OES = 0x8D61 != GL_HALF_FLOAT + * WebGL handles this specifically with an OES_texture_half_float check. + */ + }, + {"texture_half_float_linear", + GLVersion::GL3_1, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_half_float_pixel, GLContext::ARB_texture_float, + GLContext::NV_half_float, GLContext::OES_texture_half_float_linear, + GLContext::Extensions_End}}, + {"texture_non_power_of_two", + GLVersion::GL2, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::ARB_texture_non_power_of_two, GLContext::OES_texture_npot, + GLContext::Extensions_End}}, + {"texture_norm16", + GLVersion::GL3_1, + GLESVersion::ES3_1, + GLContext::EXT_texture_norm16, + {GLContext::Extensions_End}}, + {"texture_rg", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_texture_rg, + {GLContext::Extensions_End}}, + {"texture_storage", + GLVersion::GL4_2, + GLESVersion::ES3, + GLContext::ARB_texture_storage, + {/* + * Not including GL_EXT_texture_storage here because it + * doesn't guarantee glTexStorage3D, which is required for + * WebGL 2. + */ + GLContext::Extensions_End}}, + {"texture_swizzle", + GLVersion::GL3_3, + GLESVersion::ES3, + GLContext::ARB_texture_swizzle, + {GLContext::Extensions_End}}, + {"transform_feedback2", + GLVersion::GL4, + GLESVersion::ES3, + GLContext::ARB_transform_feedback2, + {GLContext::NV_transform_feedback2, GLContext::Extensions_End}}, + {"uniform_buffer_object", + GLVersion::GL3_1, + GLESVersion::ES3, + GLContext::ARB_uniform_buffer_object, + {GLContext::Extensions_End}}, + {"uniform_matrix_nonsquare", + GLVersion::GL2_1, + GLESVersion::ES3, + GLContext::Extension_None, + {GLContext::Extensions_End}}, + {"vertex_array_object", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::ARB_vertex_array_object, // ARB extension + {GLContext::OES_vertex_array_object, GLContext::APPLE_vertex_array_object, + GLContext::Extensions_End}}}; + +static inline const FeatureInfo& GetFeatureInfo(GLFeature feature) { + static_assert(MOZ_ARRAY_LENGTH(sFeatureInfoArr) == size_t(GLFeature::EnumMax), + "Mismatched lengths for sFeatureInfoInfos and GLFeature enums"); + + MOZ_ASSERT(feature < GLFeature::EnumMax, + "GLContext::GetFeatureInfoInfo : unknown <feature>"); + + return sFeatureInfoArr[size_t(feature)]; +} + +static inline uint32_t ProfileVersionForFeature(GLFeature feature, + ContextProfile profile) { + MOZ_ASSERT(profile != ContextProfile::Unknown, + "GLContext::ProfileVersionForFeature : unknown <profile>"); + + const FeatureInfo& featureInfo = GetFeatureInfo(feature); + + if (profile == ContextProfile::OpenGLES) + return (uint32_t)featureInfo.mOpenGLESVersion; + + return (uint32_t)featureInfo.mOpenGLVersion; +} + +static bool IsFeaturePartOfProfileVersion(GLFeature feature, + ContextProfile profile, + unsigned int version) { + unsigned int profileVersion = ProfileVersionForFeature(feature, profile); + + /** + * if `profileVersion` is zero, it means that no version of the profile + * added support for the feature. + */ + return profileVersion && version >= profileVersion; +} + +bool GLContext::IsFeatureProvidedByCoreSymbols(GLFeature feature) { + if (IsFeaturePartOfProfileVersion(feature, mProfile, mVersion)) return true; + + if (IsExtensionSupported( + GetFeatureInfo(feature).mARBExtensionWithoutARBSuffix)) + return true; + + return false; +} + +const char* GLContext::GetFeatureName(GLFeature feature) { + return GetFeatureInfo(feature).mName; +} + +void GLContext::InitFeatures() { + for (size_t featureId = 0; featureId < size_t(GLFeature::EnumMax); + featureId++) { + GLFeature feature = GLFeature(featureId); + + if (IsFeaturePartOfProfileVersion(feature, mProfile, mVersion)) { + mAvailableFeatures[featureId] = true; + continue; + } + + mAvailableFeatures[featureId] = false; + + const FeatureInfo& featureInfo = GetFeatureInfo(feature); + + if (IsExtensionSupported(featureInfo.mARBExtensionWithoutARBSuffix)) { + mAvailableFeatures[featureId] = true; + continue; + } + + for (size_t j = 0; true; j++) { + MOZ_ASSERT(j < kMAX_EXTENSION_GROUP_SIZE, + "kMAX_EXTENSION_GROUP_SIZE too small"); + + if (featureInfo.mExtensions[j] == GLContext::Extensions_End) break; + + if (IsExtensionSupported(featureInfo.mExtensions[j])) { + mAvailableFeatures[featureId] = true; + break; + } + } + } + + if (ShouldDumpExts()) { + for (size_t featureId = 0; featureId < size_t(GLFeature::EnumMax); + featureId++) { + GLFeature feature = GLFeature(featureId); + printf_stderr("[%s] Feature::%s\n", + IsSupported(feature) ? "enabled" : "disabled", + GetFeatureName(feature)); + } + } +} + +void GLContext::MarkUnsupported(GLFeature feature) { + mAvailableFeatures[size_t(feature)] = false; + + const FeatureInfo& featureInfo = GetFeatureInfo(feature); + + for (size_t i = 0; true; i++) { + MOZ_ASSERT(i < kMAX_EXTENSION_GROUP_SIZE, + "kMAX_EXTENSION_GROUP_SIZE too small"); + + if (featureInfo.mExtensions[i] == GLContext::Extensions_End) break; + + MarkExtensionUnsupported(featureInfo.mExtensions[i]); + } + + MOZ_ASSERT(!IsSupported(feature), "GLContext::MarkUnsupported has failed!"); + + NS_WARNING( + nsPrintfCString("%s marked as unsupported", GetFeatureName(feature)) + .get()); +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContextGLX.h b/gfx/gl/GLContextGLX.h new file mode 100644 index 0000000000..b6f6e9a959 --- /dev/null +++ b/gfx/gl/GLContextGLX.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTGLX_H_ +#define GLCONTEXTGLX_H_ + +#include "GLContext.h" +#include "GLXLibrary.h" +#include "mozilla/X11Util.h" + +namespace mozilla { +namespace gl { + +class GLContextGLX : public GLContext { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX, override) + static already_AddRefed<GLContextGLX> CreateGLContext( + const GLContextDesc&, std::shared_ptr<gfx::XlibDisplay> display, + GLXDrawable drawable, GLXFBConfig cfg, Drawable ownedPixmap = X11None); + + static bool FindVisual(Display* display, int screen, int* const out_visualId); + + // Finds a GLXFBConfig compatible with the provided window. + static bool FindFBConfigForWindow( + Display* display, int screen, Window window, + GLXFBConfig* const out_config, int* const out_visid, bool aWebRender); + + virtual ~GLContextGLX(); + + GLContextType GetContextType() const override { return GLContextType::GLX; } + + static GLContextGLX* Cast(GLContext* gl) { + MOZ_ASSERT(gl->GetContextType() == GLContextType::GLX); + return static_cast<GLContextGLX*>(gl); + } + + bool Init() override; + + bool MakeCurrentImpl() const override; + + bool IsCurrentImpl() const override; + + Maybe<SymbolLoader> GetSymbolLoader() const override; + + bool IsDoubleBuffered() const override; + + bool SwapBuffers() override; + + GLint GetBufferAge() const override; + + void GetWSIInfo(nsCString* const out) const override; + + // Overrides the current GLXDrawable backing the context and makes the + // context current. + bool OverrideDrawable(GLXDrawable drawable); + + // Undoes the effect of a drawable override. + bool RestoreDrawable(); + + private: + friend class GLContextProviderGLX; + + GLContextGLX(const GLContextDesc&, std::shared_ptr<gfx::XlibDisplay> aDisplay, + GLXDrawable aDrawable, GLXContext aContext, bool aDoubleBuffered, + Drawable aOwnedPixmap = X11None); + + const GLXContext mContext; + const std::shared_ptr<gfx::XlibDisplay> mDisplay; + const GLXDrawable mDrawable; + // The X pixmap associated with the GLX pixmap. If this is provided, then this + // class assumes responsibility for freeing both. Otherwise, the user of this + // class is responsibility for freeing the drawables. + const Drawable mOwnedPixmap; + const bool mDoubleBuffered; + + GLXLibrary* const mGLX; + + const bool mOwnsContext = true; +}; + +} // namespace gl +} // namespace mozilla + +#endif // GLCONTEXTGLX_H_ diff --git a/gfx/gl/GLContextProvider.h b/gfx/gl/GLContextProvider.h new file mode 100644 index 0000000000..c63f1ada0b --- /dev/null +++ b/gfx/gl/GLContextProvider.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTPROVIDER_H_ +#define GLCONTEXTPROVIDER_H_ + +#include "mozilla/AlreadyAddRefed.h" + +#include "GLContextTypes.h" +#include "SurfaceTypes.h" + +#include "nsSize.h" // for gfx::IntSize (needed by GLContextProviderImpl.h below) +#include "nsStringFwd.h" // needed by GLContextProviderImpl.h below + +class nsIWidget; + +namespace mozilla { +namespace widget { +class CompositorWidget; +} +namespace gl { + +#define IN_GL_CONTEXT_PROVIDER_H + +// Null is always there +#define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull +#include "GLContextProviderImpl.h" +#undef GL_CONTEXT_PROVIDER_NAME + +#ifdef XP_WIN +# define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL +# define DEFAULT_IMPL WGL +#endif + +#ifdef XP_MACOSX +# define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL +#endif + +#define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL +#include "GLContextProviderImpl.h" +#undef GL_CONTEXT_PROVIDER_NAME + +#if defined(MOZ_WIDGET_GTK) +# ifdef MOZ_X11 +# define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# endif +# define GL_CONTEXT_PROVIDER_NAME GLContextProviderLinux +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderLinux +#endif + +#ifndef GL_CONTEXT_PROVIDER_DEFAULT +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL +#endif + +#if defined(MOZ_WIDGET_UIKIT) +# define GL_CONTEXT_PROVIDER_NAME GLContextProviderEAGL +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# ifndef GL_CONTEXT_PROVIDER_DEFAULT +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEAGL +# endif +#endif + +#ifdef MOZ_GL_PROVIDER +# define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER +# include "GLContextProviderImpl.h" +# undef GL_CONTEXT_PROVIDER_NAME +# define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER +#endif + +#ifdef GL_CONTEXT_PROVIDER_DEFAULT +typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; +#else +typedef GLContextProviderNull GLContextProvider; +#endif + +#undef IN_GL_CONTEXT_PROVIDER_H + +} // namespace gl +} // namespace mozilla + +#endif diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm new file mode 100644 index 0000000000..2e205c1434 --- /dev/null +++ b/gfx/gl/GLContextProviderCGL.mm @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContextProvider.h" +#include "GLContextCGL.h" +#include "GLLibraryLoader.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include <OpenGL/gl.h> +#include "gfxFailure.h" +#include "mozilla/IntegerRange.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_gl.h" +#include "mozilla/StaticPrefs_layout.h" +#include "prenv.h" +#include "prlink.h" +#include "mozilla/ProfilerLabels.h" +#include "MozFramebuffer.h" +#include "mozilla/layers/CompositorOptions.h" +#include "mozilla/widget/CompositorWidget.h" +#include "ScopedGLHelpers.h" + +#include <OpenGL/OpenGL.h> + +namespace mozilla { +namespace gl { + +using namespace mozilla::gfx; +using namespace mozilla::widget; + +class CGLLibrary { + public: + bool EnsureInitialized() { + if (mInitialized) { + return true; + } + if (!mOGLLibrary) { + mOGLLibrary = + PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL"); + if (!mOGLLibrary) { + NS_WARNING("Couldn't load OpenGL Framework."); + return false; + } + } + + mInitialized = true; + return true; + } + + const auto& Library() const { return mOGLLibrary; } + + private: + bool mInitialized = false; + PRLibrary* mOGLLibrary = nullptr; +}; + +CGLLibrary sCGLLibrary; + +GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context) + : GLContext(desc), mContext(context) { + CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback, + this); +} + +GLContextCGL::~GLContextCGL() { + MarkDestroyed(); + + CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback, this); + + if (mContext) { + if ([NSOpenGLContext currentContext] == mContext) { + // Clear the current context before releasing. If we don't do + // this, the next time we call [NSOpenGLContext currentContext], + // "invalid context" will be printed to the console. + [NSOpenGLContext clearCurrentContext]; + } + [mContext release]; + } +} + +CGLContextObj GLContextCGL::GetCGLContext() const { + return static_cast<CGLContextObj>([mContext CGLContextObj]); +} + +bool GLContextCGL::MakeCurrentImpl() const { + if (mContext) { + GLContext::ResetTLSCurrentContext(); + + [mContext makeCurrentContext]; + MOZ_ASSERT(IsCurrentImpl()); + // Use non-blocking swap in "ASAP mode". + // ASAP mode means that rendering is iterated as fast as possible. + // ASAP mode is entered when layout.frame_rate=0 (requires restart). + // If swapInt is 1, then glSwapBuffers will block and wait for a vblank + // signal. When we're iterating as fast as possible, however, we want a + // non-blocking glSwapBuffers, which will happen when swapInt==0. + GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1; + [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + } + return true; +} + +bool GLContextCGL::IsCurrentImpl() const { + return [NSOpenGLContext currentContext] == mContext; +} + +/* static */ void GLContextCGL::DisplayReconfigurationCallback( + CGDirectDisplayID aDisplay, CGDisplayChangeSummaryFlags aFlags, + void* aUserInfo) { + if (aFlags & kCGDisplaySetModeFlag) { + static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred = + true; + } +} + +static NSOpenGLContext* CreateWithFormat( + const NSOpenGLPixelFormatAttribute* attribs) { + NSOpenGLPixelFormat* format = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + if (!format) { + NS_WARNING("Failed to create NSOpenGLPixelFormat."); + return nullptr; + } + + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format + shareContext:nullptr]; + + [format release]; + + return context; +} + +// Get the "OpenGL display mask" for a fresh context. The return value of this +// function depends on the time at which this function is called. +// In practice, on a Macbook Pro with an integrated and a discrete GPU, this +// function returns the display mask for the GPU that currently drives the +// internal display. +// +// Quick reference of the concepts involved in the code below: +// GPU switch: On Mac devices with an integrated and a discrete GPU, a GPU +// switch changes which +// GPU drives the internal display. Both GPUs are still usable at all times. +// (When the integrated GPU is driving the internal display, using the +// discrete GPU can incur a longer warm-up cost.) +// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL +// renderer. There's one +// for the integrated GPU, one for each discrete GPU, and one for the Apple +// software renderer. The list of virtual screens is +// per-NSOpenGLPixelFormat; it is filtered down to only the renderers that +// support the requirements from the pixel format attributes. Indexes into +// this list (such as currentVirtualScreen) cannot be used interchangably +// across different NSOpenGLPixelFormat instances. +// Display mask: A bitset per GL renderer. Different renderers have disjoint +// display masks. The +// Apple software renderer has all bits zeroed. For each CGDirectDisplayID, +// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the +// display mask. +// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive +// this screen) pair. The +// current CGDirectDisplayID for an NSScreen object can be obtained using +// [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] +// unsignedIntValue]; it changes depending on which GPU is currently driving +// the screen. +static CGOpenGLDisplayMask GetFreshContextDisplayMask() { + NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers, + 0}; + NSOpenGLPixelFormat* pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + MOZ_RELEASE_ASSERT(pixelFormat); + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:nullptr]; + GLint displayMask = 0; + [pixelFormat getValues:&displayMask + forAttribute:NSOpenGLPFAScreenMask + forVirtualScreen:[context currentVirtualScreen]]; + [pixelFormat release]; + [context release]; + return static_cast<CGOpenGLDisplayMask>(displayMask); +} + +static bool IsSameGPU(CGOpenGLDisplayMask mask1, CGOpenGLDisplayMask mask2) { + if ((mask1 & mask2) != 0) { + return true; + } + // Both masks can be zero, when using the Apple software renderer. + return !mask1 && !mask2; +} + +void GLContextCGL::MigrateToActiveGPU() { + if (!mActiveGPUSwitchMayHaveOccurred.compareExchange(true, false)) { + return; + } + + CGOpenGLDisplayMask newPreferredDisplayMask = GetFreshContextDisplayMask(); + NSOpenGLPixelFormat* pixelFormat = [mContext pixelFormat]; + GLint currentVirtualScreen = [mContext currentVirtualScreen]; + GLint currentDisplayMask = 0; + [pixelFormat getValues:¤tDisplayMask + forAttribute:NSOpenGLPFAScreenMask + forVirtualScreen:currentVirtualScreen]; + if (IsSameGPU(currentDisplayMask, newPreferredDisplayMask)) { + // No "virtual screen" change needed. + return; + } + + // Find the "virtual screen" with a display mask that matches + // newPreferredDisplayMask, if available, and switch the context over to it. + // This code was inspired by equivalent functionality in -[NSOpenGLContext + // update] which only kicks in for contexts that present via a CAOpenGLLayer. + for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) { + GLint displayMask = 0; + [pixelFormat getValues:&displayMask + forAttribute:NSOpenGLPFAScreenMask + forVirtualScreen:i]; + if (IsSameGPU(displayMask, newPreferredDisplayMask)) { + CGLSetVirtualScreen([mContext CGLContextObj], i); + return; + } + } +} + +GLenum GLContextCGL::GetPreferredARGB32Format() const { return LOCAL_GL_BGRA; } + +bool GLContextCGL::SwapBuffers() { + AUTO_PROFILER_LABEL("GLContextCGL::SwapBuffers", GRAPHICS); + + // We do not have a default framebuffer. Just do a flush. + // Flushing is necessary if we want our IOSurfaces to have the correct + // content once they're picked up by the WindowServer from our CALayers. + fFlush(); + + return true; +} + +void GLContextCGL::GetWSIInfo(nsCString* const out) const { + out->AppendLiteral("CGL"); +} + +Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const { + const auto& lib = sCGLLibrary.Library(); + return Some(SymbolLoader(*lib)); +} + +already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER; + if (aForceAccelerated) { + flags |= CreateContextFlags::FORBID_SOFTWARE; + } + if (!aHardwareWebRender) { + flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE; + } + nsCString failureUnused; + return CreateHeadless({flags}, &failureUnused); +} + +static RefPtr<GLContextCGL> CreateOffscreenFBOContext( + GLContextCreateDesc desc) { + if (!sCGLLibrary.EnsureInitialized()) { + return nullptr; + } + + NSOpenGLContext* context = nullptr; + + std::vector<NSOpenGLPixelFormatAttribute> attribs; + auto& flags = desc.flags; + + if (!StaticPrefs::gl_allow_high_power()) { + flags &= ~CreateContextFlags::HIGH_POWER; + } + if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER || + !(flags & CreateContextFlags::HIGH_POWER)) { + // This is really poorly named on Apple's part, but "AllowOfflineRenderers" + // means that we want to allow running on the iGPU instead of requiring the + // dGPU. + attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); + } + + if (flags & CreateContextFlags::FORBID_SOFTWARE) { + if (flags & CreateContextFlags::FORBID_HARDWARE) { + NS_WARNING("Both !hardware and !software."); + return nullptr; + } + attribs.push_back(NSOpenGLPFAAccelerated); + } + if (flags & CreateContextFlags::FORBID_HARDWARE) { + /* NSOpenGLPFARendererID: + * > OpenGL renderers that match the specified ID are preferred. + * > Constants to select specific renderers are provided in the + * > GLRenderers.h header of the OpenGL framework. + * > Of note is kCGLRendererGenericID which selects the Apple software + * > renderer. + * > The other constants select renderers for specific hardware vendors. + */ + attribs.push_back(NSOpenGLPFARendererID); + attribs.push_back(kCGLRendererGenericID); + } + + if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) { + auto coreAttribs = attribs; + coreAttribs.push_back(NSOpenGLPFAOpenGLProfile); + coreAttribs.push_back(NSOpenGLProfileVersion3_2Core); + coreAttribs.push_back(0); + context = CreateWithFormat(coreAttribs.data()); + } + + if (!context) { + attribs.push_back(0); + context = CreateWithFormat(attribs.data()); + } + + if (!context) { + NS_WARNING("Failed to create NSOpenGLContext."); + return nullptr; + } + + RefPtr<GLContextCGL> glContext = new GLContextCGL({desc, true}, context); + + if (flags & CreateContextFlags::PREFER_MULTITHREADED) { + CGLEnable(glContext->GetCGLContext(), kCGLCEMPEngine); + } + return glContext; +} + +already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless( + const GLContextCreateDesc& desc, nsACString* const out_failureId) { + auto gl = CreateOffscreenFBOContext(desc); + if (!gl) { + *out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns; + return nullptr; + } + + if (!gl->Init()) { + *out_failureId = "FEATURE_FAILURE_CGL_INIT"_ns; + NS_WARNING("Failed during Init."); + return nullptr; + } + + return gl.forget(); +} + +static RefPtr<GLContext> gGlobalContext; + +GLContext* GLContextProviderCGL::GetGlobalContext() { + static bool triedToCreateContext = false; + if (!triedToCreateContext) { + triedToCreateContext = true; + + MOZ_RELEASE_ASSERT(!gGlobalContext); + nsCString discardFailureId; + RefPtr<GLContext> temp = CreateHeadless({}, &discardFailureId); + gGlobalContext = temp; + + if (!gGlobalContext) { + NS_WARNING("Couldn't init gGlobalContext."); + } + } + + return gGlobalContext; +} + +void GLContextProviderCGL::Shutdown() { gGlobalContext = nullptr; } + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContextProviderEAGL.mm b/gfx/gl/GLContextProviderEAGL.mm new file mode 100644 index 0000000000..6e27498028 --- /dev/null +++ b/gfx/gl/GLContextProviderEAGL.mm @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContextProvider.h" +#include "GLContextEAGL.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include "gfxFailure.h" +#include "prenv.h" +#include "mozilla/Preferences.h" +#include "mozilla/ProfilerLabels.h" +#include "mozilla/layers/CompositorOptions.h" +#include "mozilla/widget/CompositorWidget.h" + +#import <UIKit/UIKit.h> + +namespace mozilla { +namespace gl { + +using namespace mozilla::widget; + +GLContextEAGL::GLContextEAGL(const GLContextDesc& desc, EAGLContext* context, + GLContext* sharedContext) + : GLContext(desc, sharedContext), mContext(context) {} + +GLContextEAGL::~GLContextEAGL() { + MakeCurrent(); + + if (mBackbufferFB) { + fDeleteFramebuffers(1, &mBackbufferFB); + } + + if (mBackbufferRB) { + fDeleteRenderbuffers(1, &mBackbufferRB); + } + + MarkDestroyed(); + + if (mLayer) { + mLayer = nil; + } + + if (mContext) { + [EAGLContext setCurrentContext:nil]; + [mContext release]; + } +} + +bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) { + // This should only be called once + MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB); + + UIView* view = + reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET)); + + if (!view) { + MOZ_CRASH("no view!"); + } + + mLayer = [view layer]; + + fGenFramebuffers(1, &mBackbufferFB); + return RecreateRB(); +} + +bool GLContextEAGL::RecreateRB() { + MakeCurrent(); + + CAEAGLLayer* layer = (CAEAGLLayer*)mLayer; + + if (mBackbufferRB) { + // It doesn't seem to be enough to just call renderbufferStorage: below, + // we apparently have to recreate the RB. + fDeleteRenderbuffers(1, &mBackbufferRB); + mBackbufferRB = 0; + } + + fGenRenderbuffers(1, &mBackbufferRB); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB); + + [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer]; + + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, mBackbufferRB); + + return LOCAL_GL_FRAMEBUFFER_COMPLETE == + fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); +} + +bool GLContextEAGL::MakeCurrentImpl() const { + if (mContext) { + GLContext::ResetTLSCurrentContext(); + + if (![EAGLContext setCurrentContext:mContext]) { + return false; + } + } + return true; +} + +bool GLContextEAGL::IsCurrentImpl() const { + return [EAGLContext currentContext] == mContext; +} + +static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) { + PRLibrary* lib = nullptr; + const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &leakedLibRef); + if (lib) { + PR_UnloadLibrary(lib); + } + return ret; +} + +Maybe<SymbolLoader> GLContextEAGL::GetSymbolLoader() const { + return Some(SymbolLoader(&GetLoadedProcAddress)); +} + +bool GLContextEAGL::IsDoubleBuffered() const { return true; } + +bool GLContextEAGL::SwapBuffers() { + AUTO_PROFILER_LABEL("GLContextEAGL::SwapBuffers", GRAPHICS); + + [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER]; + return true; +} + +void GLContextEAGL::GetWSIInfo(nsCString* const out) const { + out->AppendLiteral("EAGL"); +} + +static GLContextEAGL* GetGlobalContextEAGL() { + return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext()); +} + +static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc, + GLContextEAGL* sharedContext) { + EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, + kEAGLRenderingAPIOpenGLES2}; + + // Try to create a GLES3 context if we can, otherwise fall back to GLES2 + EAGLContext* context = nullptr; + for (EAGLRenderingAPI api : apis) { + if (sharedContext) { + context = [[EAGLContext alloc] + initWithAPI:api + sharegroup:sharedContext->GetEAGLContext().sharegroup]; + } else { + context = [[EAGLContext alloc] initWithAPI:api]; + } + + if (context) { + break; + } + } + + if (!context) { + return nullptr; + } + + RefPtr<GLContextEAGL> glContext = + new GLContextEAGL(desc, context, sharedContext); + if (!glContext->Init()) { + glContext = nullptr; + return nullptr; + } + + return glContext; +} + +already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + if (!aCompositorWidget) { + MOZ_ASSERT(false); + return nullptr; + } + + const GLContextDesc desc = {}; + auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL()); + if (!glContext) { + return nullptr; + } + + if (!GLContextEAGL::Cast(glContext)->AttachToWindow( + aCompositorWidget->RealWidget())) { + return nullptr; + } + + return glContext.forget(); +} + +already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless( + const GLContextCreateDesc& createDesc, nsACString* const out_failureId) { + auto desc = GLContextDesc{createDesc}; + desc.isOffcreen = true; + return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget(); +} + +static RefPtr<GLContext> gGlobalContext; + +GLContext* GLContextProviderEAGL::GetGlobalContext() { + static bool triedToCreateContext = false; + if (!triedToCreateContext) { + triedToCreateContext = true; + + MOZ_RELEASE_ASSERT(!gGlobalContext, + "GFX: Global GL context already initialized."); + RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE); + gGlobalContext = temp; + + if (!gGlobalContext) { + MOZ_CRASH("Failed to create global context"); + } + } + + return gGlobalContext; +} + +void GLContextProviderEAGL::Shutdown() { gGlobalContext = nullptr; } + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp new file mode 100644 index 0000000000..cb47e285a5 --- /dev/null +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -0,0 +1,1261 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZ_WIDGET_GTK) +# define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_EGL_WINDOW)) +# define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \ + (aWidget->AsGTK()->GetEGLNativeWindow()) +#elif defined(MOZ_WIDGET_ANDROID) +# define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->GetNativeData(NS_JAVA_SURFACE)) +# define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \ + (aWidget->AsAndroid()->GetEGLNativeWindow()) +#elif defined(XP_WIN) +# define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) +# define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->AsWindows()->GetHwnd()) +#else +# define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) +# define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \ + ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData( \ + NS_NATIVE_WINDOW)) +#endif + +#if defined(XP_UNIX) +# ifdef MOZ_WIDGET_ANDROID +# include <android/native_window.h> +# include <android/native_window_jni.h> +# include "mozilla/widget/AndroidCompositorWidget.h" +# endif + +# define GLES2_LIB "libGLESv2.so" +# define GLES2_LIB2 "libGLESv2.so.2" + +#elif defined(XP_WIN) +# include "mozilla/widget/WinCompositorWidget.h" +# include "nsIFile.h" + +# define GLES2_LIB "libGLESv2.dll" + +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif + +# include <windows.h> +#else +# error "Platform not recognized" +#endif + +#include "gfxCrashReporterUtils.h" +#include "gfxFailure.h" +#include "gfxPlatform.h" +#include "gfxUtils.h" +#include "GLBlitHelper.h" +#include "GLContextEGL.h" +#include "GLContextProvider.h" +#include "GLLibraryEGL.h" +#include "GLLibraryLoader.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Preferences.h" +#include "mozilla/Services.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/gfx/BuildConstants.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/CompositorOptions.h" +#include "mozilla/widget/CompositorWidget.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include "nsThreadUtils.h" +#include "ScopedGLHelpers.h" + +#if defined(MOZ_WIDGET_GTK) +# include "mozilla/widget/GtkCompositorWidget.h" +# if defined(MOZ_WAYLAND) +# include <gdk/gdkwayland.h> +# include <wayland-egl.h> +# include "mozilla/WidgetUtilsGtk.h" +# include "mozilla/widget/nsWaylandDisplay.h" +# endif +#endif + +struct wl_egl_window; + +using namespace mozilla::gfx; + +namespace mozilla { +namespace gl { + +using namespace mozilla::widget; + +#if defined(MOZ_WAYLAND) +class WaylandOffscreenGLSurface { + public: + WaylandOffscreenGLSurface(struct wl_surface* aWaylandSurface, + struct wl_egl_window* aEGLWindow); + ~WaylandOffscreenGLSurface(); + + private: + struct wl_surface* mWaylandSurface = nullptr; + struct wl_egl_window* mEGLWindow = nullptr; +}; + +static nsTHashMap<nsPtrHashKey<void>, WaylandOffscreenGLSurface*> + sWaylandOffscreenGLSurfaces; + +void DeleteWaylandOffscreenGLSurface(EGLSurface surface) { + auto entry = sWaylandOffscreenGLSurfaces.Lookup(surface); + if (entry) { + delete entry.Data(); + entry.Remove(); + } +} +#endif + +static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig, + const bool aEnableDepthBuffer, + const bool aUseGles); + +// append three zeros at the end of attribs list to work around +// EGL implementation bugs that iterate until they find 0, instead of +// EGL_NONE. See bug 948406. +#define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \ + LOCAL_EGL_NONE, 0, 0, 0 + +static EGLint kTerminationAttribs[] = { + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS}; + +static int next_power_of_two(int v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + return v; +} + +static bool is_power_of_two(int v) { + NS_ASSERTION(v >= 0, "bad value"); + + if (v == 0) return true; + + return (v & (v - 1)) == 0; +} + +static EGLSurface CreateFallbackSurface(EglDisplay& egl, + const EGLConfig& config) { + if (egl.IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) { + // We don't need a PBuffer surface in this case + return EGL_NO_SURFACE; + } + + std::vector<EGLint> pbattrs; + pbattrs.push_back(LOCAL_EGL_WIDTH); + pbattrs.push_back(1); + pbattrs.push_back(LOCAL_EGL_HEIGHT); + pbattrs.push_back(1); + + for (const auto& cur : kTerminationAttribs) { + pbattrs.push_back(cur); + } + + EGLSurface surface = egl.fCreatePbufferSurface(config, pbattrs.data()); + if (!surface) { + MOZ_CRASH("Failed to create fallback EGLSurface"); + } + + return surface; +} + +static EGLSurface CreateSurfaceFromNativeWindow( + EglDisplay& egl, const EGLNativeWindowType window, const EGLConfig config) { + MOZ_ASSERT(window); + EGLSurface newSurface = EGL_NO_SURFACE; + +#ifdef MOZ_WIDGET_ANDROID + JNIEnv* const env = jni::GetEnvForThread(); + ANativeWindow* const nativeWindow = + ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window)); + if (!nativeWindow) { + gfxCriticalNote << "Failed to obtain native window from Surface"; + return EGL_NO_SURFACE; + } + const auto& display = egl.mLib->fGetDisplay(EGL_DEFAULT_DISPLAY); + newSurface = egl.mLib->fCreateWindowSurface(display, config, nativeWindow, 0); + ANativeWindow_release(nativeWindow); +#else + newSurface = egl.fCreateWindowSurface(config, window, 0); +#endif + if (!newSurface) { + const auto err = egl.mLib->fGetError(); + gfxCriticalNote << "Failed to create EGLSurface!: " << gfx::hexa(err); + } + return newSurface; +} + +/* GLContextEGLFactory class was added as a friend of GLContextEGL + * so that it could access GLContextEGL::CreateGLContext. This was + * done so that a new function would not need to be added to the shared + * GLContextProvider interface. + */ +class GLContextEGLFactory { + public: + static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow, + bool aHardwareWebRender); + static already_AddRefed<GLContext> CreateImpl(EGLNativeWindowType aWindow, + bool aHardwareWebRender, + bool aUseGles); + + private: + GLContextEGLFactory() = default; + ~GLContextEGLFactory() = default; +}; + +already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl( + EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) { + nsCString failureId; + const auto lib = GLLibraryEGL::Get(&failureId); + if (!lib) { + gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get(); + return nullptr; + } + const auto egl = lib->CreateDisplay(true, &failureId); + if (!egl) { + gfxCriticalNote << "Failed[3] to create EGL library display: " + << failureId.get(); + return nullptr; + } + + bool doubleBuffered = true; + + EGLConfig config; + if (aHardwareWebRender && egl->mLib->IsANGLE()) { + // Force enable alpha channel to make sure ANGLE use correct framebuffer + // formart + const int bpp = 32; + if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) { + gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!"; + return nullptr; + } + } else if (kIsLinux) { + const int bpp = 32; + if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) { + gfxCriticalNote << "Failed to create EGLConfig for WebRender!"; + return nullptr; + } + } else { + if (!CreateConfigScreen(*egl, &config, + /* aEnableDepthBuffer */ false, aUseGles)) { + gfxCriticalNote << "Failed to create EGLConfig!"; + return nullptr; + } + } + + EGLSurface surface = EGL_NO_SURFACE; + if (aWindow) { + surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config); + if (!surface) { + return nullptr; + } + } + + CreateContextFlags flags = CreateContextFlags::NONE; + if (aHardwareWebRender && + StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) { + flags |= CreateContextFlags::PREFER_ROBUSTNESS; + } + if (aHardwareWebRender && aUseGles) { + flags |= CreateContextFlags::PREFER_ES3; + } + if (!aHardwareWebRender) { + flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE; + } + + const auto desc = GLContextDesc{{flags}, false}; + RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext( + egl, desc, config, surface, aUseGles, config, &failureId); + if (!gl) { + const auto err = egl->mLib->fGetError(); + gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err); + GLContextEGL::DestroySurface(*egl, surface); + return nullptr; + } + + gl->MakeCurrent(); + gl->SetIsDoubleBuffered(doubleBuffered); + +#ifdef MOZ_WIDGET_GTK + if (surface) { + const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0; + egl->fSwapInterval(interval); + } +#endif + if (aHardwareWebRender && egl->mLib->IsANGLE()) { + MOZ_ASSERT(doubleBuffered); + const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0; + egl->fSwapInterval(interval); + } + return gl.forget(); +} + +already_AddRefed<GLContext> GLContextEGLFactory::Create( + EGLNativeWindowType aWindow, bool aHardwareWebRender) { + bool preferGles; +#if defined(MOZ_WIDGET_ANDROID) + preferGles = true; +#else + preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup(); +#endif // defined(MOZ_WIDGET_ANDROID) + + RefPtr<GLContext> glContext = + CreateImpl(aWindow, aHardwareWebRender, preferGles); +#if !defined(MOZ_WIDGET_ANDROID) + if (!glContext) { + glContext = CreateImpl(aWindow, aHardwareWebRender, !preferGles); + } +#endif // !defined(MOZ_WIDGET_ANDROID) + return glContext.forget(); +} + +/* static */ +EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget( + widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig) { + nsCString discardFailureId; + const auto egl = DefaultEglDisplay(&discardFailureId); + if (!egl) { + gfxCriticalNote << "Failed to load EGL library 6!"; + return EGL_NO_SURFACE; + } + + MOZ_ASSERT(aCompositorWidget); +#ifdef MOZ_WAYLAND + // RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks + // to SW rendering or claims itself as paused. + // In case we're missing valid native window because aCompositorWidget hidden, + // just create a fallback EGLSurface. + // Actual EGLSurface will be created by widget code later when + // aCompositorWidget becomes visible. + if (widget::GdkIsWaylandDisplay() && aCompositorWidget->IsHidden()) { + mozilla::gfx::IntSize pbSize(16, 16); + return CreateWaylandOffscreenSurface(*egl, aConfig, pbSize); + } +#endif + EGLNativeWindowType window = + GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget); + if (!window) { + gfxCriticalNote << "window is null"; + return EGL_NO_SURFACE; + } + + return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig); +} + +GLContextEGL::GLContextEGL(const std::shared_ptr<EglDisplay> egl, + const GLContextDesc& desc, EGLConfig surfaceConfig, + EGLSurface surface, EGLContext context) + : GLContext(desc, nullptr, false), + mEgl(egl), + mSurfaceConfig(surfaceConfig), + mContext(context), + mSurface(surface), + mFallbackSurface(CreateFallbackSurface(*mEgl, mSurfaceConfig)) { +#ifdef DEBUG + printf_stderr("Initializing context %p surface %p on display %p\n", mContext, + mSurface, mEgl->mDisplay); +#endif +} + +void GLContextEGL::OnMarkDestroyed() { + if (mSurfaceOverride != EGL_NO_SURFACE) { + SetEGLSurfaceOverride(EGL_NO_SURFACE); + } +} + +GLContextEGL::~GLContextEGL() { + MarkDestroyed(); + + // Wrapped context should not destroy eglContext/Surface + if (!mOwnsContext) { + return; + } + +#ifdef DEBUG + printf_stderr("Destroying context %p surface %p on display %p\n", mContext, + mSurface, mEgl->mDisplay); +#endif + + mEgl->fDestroyContext(mContext); + + DestroySurface(*mEgl, mSurface); + DestroySurface(*mEgl, mFallbackSurface); +} + +bool GLContextEGL::Init() { + if (!GLContext::Init()) return false; + + bool current = MakeCurrent(); + if (!current) { + gfx::LogFailure("Couldn't get device attachments for device."_ns); + return false; + } + + mShareWithEGLImage = + mEgl->HasKHRImageBase() && + mEgl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) && + IsExtensionSupported(OES_EGL_image); + + return true; +} + +bool GLContextEGL::BindTexImage() { + if (!mSurface) return false; + + if (mBound && !ReleaseTexImage()) return false; + + EGLBoolean success = + mEgl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER); + if (success == LOCAL_EGL_FALSE) return false; + + mBound = true; + return true; +} + +bool GLContextEGL::ReleaseTexImage() { + if (!mBound) return true; + + if (!mSurface) return false; + + EGLBoolean success; + success = mEgl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER); + if (success == LOCAL_EGL_FALSE) return false; + + mBound = false; + return true; +} + +void GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) { + mSurfaceOverride = surf; + DebugOnly<bool> ok = MakeCurrent(true); + MOZ_ASSERT(ok); +} + +bool GLContextEGL::MakeCurrentImpl() const { + EGLSurface surface = + (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride : mSurface; + if (!surface) { + surface = mFallbackSurface; + } + + const bool succeeded = mEgl->fMakeCurrent(surface, surface, mContext); + if (!succeeded) { + const auto eglError = mEgl->mLib->fGetError(); + if (eglError == LOCAL_EGL_CONTEXT_LOST) { + OnContextLostError(); + } else { + NS_WARNING("Failed to make GL context current!"); +#ifdef DEBUG + printf_stderr("EGL Error: 0x%04x\n", eglError); +#endif + } + } + + return succeeded; +} + +bool GLContextEGL::IsCurrentImpl() const { + return mEgl->mLib->fGetCurrentContext() == mContext; +} + +bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) { + if (!mOwnsContext) { + return false; + } + // unconditionally release the surface and create a new one. Don't try to + // optimize this away. If we get here, then by definition we know that we want + // to get a new surface. + ReleaseSurface(); + MOZ_ASSERT(aWidget); + + EGLNativeWindowType nativeWindow = + GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget); +#ifdef MOZ_WAYLAND + // In case we're missing native window on Wayland CompositorWidget is hidden. + // Don't create a fallback EGL surface but fails here. + // We need to repeat RenewSurface() when native window is available + // (CompositorWidget becomes visible). + if (GdkIsWaylandDisplay()) { + NS_WARNING("Failed to get native window"); + return false; + } +#endif + if (nativeWindow) { + mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow, + mSurfaceConfig); + if (!mSurface) { + NS_WARNING("Failed to create EGLSurface from native window"); + return false; + } + } + const bool ok = MakeCurrent(true); + MOZ_ASSERT(ok); +#ifdef MOZ_WIDGET_GTK + if (mSurface) { + const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0; + mEgl->fSwapInterval(interval); + } +#endif + return ok; +} + +void GLContextEGL::ReleaseSurface() { + if (mOwnsContext) { + DestroySurface(*mEgl, mSurface); + } + if (mSurface == mSurfaceOverride) { + mSurfaceOverride = EGL_NO_SURFACE; + } + mSurface = EGL_NO_SURFACE; +} + +Maybe<SymbolLoader> GLContextEGL::GetSymbolLoader() const { + return mEgl->mLib->GetSymbolLoader(); +} + +bool GLContextEGL::SwapBuffers() { + EGLSurface surface = + mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface; + if (surface) { + if ((mEgl->IsExtensionSupported( + EGLExtension::EXT_swap_buffers_with_damage) || + mEgl->IsExtensionSupported( + EGLExtension::KHR_swap_buffers_with_damage))) { + std::vector<EGLint> rects; + for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) { + const IntRect& r = iter.Get(); + rects.push_back(r.X()); + rects.push_back(r.Y()); + rects.push_back(r.Width()); + rects.push_back(r.Height()); + } + mDamageRegion.SetEmpty(); + return mEgl->fSwapBuffersWithDamage(surface, rects.data(), + rects.size() / 4); + } + return mEgl->fSwapBuffers(surface); + } else { + return false; + } +} + +void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) { + mDamageRegion = aDamageRegion; +} + +void GLContextEGL::GetWSIInfo(nsCString* const out) const { + out->AppendLiteral("EGL_VENDOR: "); + out->Append( + (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VENDOR)); + + out->AppendLiteral("\nEGL_VERSION: "); + out->Append( + (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VERSION)); + + out->AppendLiteral("\nEGL_EXTENSIONS: "); + out->Append((const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, + LOCAL_EGL_EXTENSIONS)); + +#ifndef ANDROID // This query will crash some old android. + out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): "); + out->Append( + (const char*)mEgl->mLib->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS)); +#endif +} + +bool GLContextEGL::HasExtBufferAge() const { + return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age); +} + +bool GLContextEGL::HasKhrPartialUpdate() const { + return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update); +} + +GLint GLContextEGL::GetBufferAge() const { + EGLSurface surface = + mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface; + + if (surface && (HasExtBufferAge() || HasKhrPartialUpdate())) { + EGLint result; + mEgl->fQuerySurface(surface, LOCAL_EGL_BUFFER_AGE_EXT, &result); + return result; + } + + return 0; +} + +#define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000 + +RefPtr<GLContextEGL> GLContextEGL::CreateGLContext( + const std::shared_ptr<EglDisplay> egl, const GLContextDesc& desc, + EGLConfig surfaceConfig, EGLSurface surface, const bool useGles, + EGLConfig contextConfig, nsACString* const out_failureId) { + const auto& flags = desc.flags; + + std::vector<EGLint> required_attribs; + + if (useGles) { + // TODO: This fBindAPI could be more thread-safe + if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) { + *out_failureId = "FEATURE_FAILURE_EGL_ES"_ns; + NS_WARNING("Failed to bind API to GLES!"); + return nullptr; + } + required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION); + if (flags & CreateContextFlags::PREFER_ES3) { + required_attribs.push_back(3); + } else { + required_attribs.push_back(2); + } + } else { + if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_API) == LOCAL_EGL_FALSE) { + *out_failureId = "FEATURE_FAILURE_EGL"_ns; + NS_WARNING("Failed to bind API to GL!"); + return nullptr; + } + if (flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE) { + required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK); + required_attribs.push_back( + LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION); + required_attribs.push_back(2); + } else { + // !REQUIRE_COMPAT_PROFILE means core profle. + required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK); + required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); + required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION); + required_attribs.push_back(3); + required_attribs.push_back(LOCAL_EGL_CONTEXT_MINOR_VERSION); + required_attribs.push_back(2); + } + } + + if ((flags & CreateContextFlags::PREFER_EXACT_VERSION) && + egl->mLib->IsANGLE()) { + required_attribs.push_back( + LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE); + required_attribs.push_back(LOCAL_EGL_FALSE); + } + + const auto debugFlags = GLContext::ChooseDebugFlags(flags); + if (!debugFlags && flags & CreateContextFlags::NO_VALIDATION && + egl->IsExtensionSupported(EGLExtension::KHR_create_context_no_error)) { + required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR); + required_attribs.push_back(LOCAL_EGL_TRUE); + } + + if (flags & CreateContextFlags::PROVOKING_VERTEX_DONT_CARE && + egl->IsExtensionSupported( + EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) { + required_attribs.push_back( + LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ); + required_attribs.push_back(LOCAL_EGL_TRUE); + } + + std::vector<EGLint> ext_robustness_attribs; + std::vector<EGLint> ext_rbab_attribs; // RBAB: Robust Buffer Access Behavior + std::vector<EGLint> khr_robustness_attribs; + std::vector<EGLint> khr_rbab_attribs; // RBAB: Robust Buffer Access Behavior + if (flags & CreateContextFlags::PREFER_ROBUSTNESS) { + std::vector<EGLint> base_robustness_attribs = required_attribs; + if (egl->IsExtensionSupported( + EGLExtension::NV_robustness_video_memory_purge)) { + base_robustness_attribs.push_back( + LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV); + base_robustness_attribs.push_back(LOCAL_EGL_TRUE); + } + + if (egl->IsExtensionSupported( + EGLExtension::EXT_create_context_robustness)) { + ext_robustness_attribs = base_robustness_attribs; + ext_robustness_attribs.push_back( + LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT); + ext_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT); + + if (gfxVars::AllowEglRbab()) { + ext_rbab_attribs = ext_robustness_attribs; + ext_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT); + ext_rbab_attribs.push_back(LOCAL_EGL_TRUE); + } + } + + if (egl->IsExtensionSupported(EGLExtension::KHR_create_context)) { + khr_robustness_attribs = base_robustness_attribs; + khr_robustness_attribs.push_back( + LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR); + khr_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR); + + khr_rbab_attribs = khr_robustness_attribs; + khr_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR); + khr_rbab_attribs.push_back( + LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR); + } + } + + const auto fnCreate = [&](const std::vector<EGLint>& attribs) { + auto terminated_attribs = attribs; + + for (const auto& cur : kTerminationAttribs) { + terminated_attribs.push_back(cur); + } + + return egl->fCreateContext(contextConfig, EGL_NO_CONTEXT, + terminated_attribs.data()); + }; + + EGLContext context; + do { + if (!khr_rbab_attribs.empty()) { + context = fnCreate(khr_rbab_attribs); + if (context) break; + NS_WARNING("Failed to create EGLContext with khr_rbab_attribs"); + } + + if (!ext_rbab_attribs.empty()) { + context = fnCreate(ext_rbab_attribs); + if (context) break; + NS_WARNING("Failed to create EGLContext with ext_rbab_attribs"); + } + + if (!khr_robustness_attribs.empty()) { + context = fnCreate(khr_robustness_attribs); + if (context) break; + NS_WARNING("Failed to create EGLContext with khr_robustness_attribs"); + } + + if (!ext_robustness_attribs.empty()) { + context = fnCreate(ext_robustness_attribs); + if (context) break; + NS_WARNING("Failed to create EGLContext with ext_robustness_attribs"); + } + + context = fnCreate(required_attribs); + if (context) break; + NS_WARNING("Failed to create EGLContext with required_attribs"); + + *out_failureId = "FEATURE_FAILURE_EGL_CREATE"_ns; + return nullptr; + } while (false); + MOZ_ASSERT(context); + + RefPtr<GLContextEGL> glContext = + new GLContextEGL(egl, desc, surfaceConfig, surface, context); + if (!glContext->Init()) { + *out_failureId = "FEATURE_FAILURE_EGL_INIT"_ns; + return nullptr; + } + + if (GLContext::ShouldSpew()) { + printf_stderr("new GLContextEGL %p on EGLDisplay %p\n", glContext.get(), + egl->mDisplay); + } + + return glContext; +} + +// static +EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo( + EglDisplay& egl, EGLConfig config, EGLenum bindToTextureFormat, + mozilla::gfx::IntSize& pbsize) { + nsTArray<EGLint> pbattrs(16); + EGLSurface surface = nullptr; + +TRY_AGAIN_POWER_OF_TWO: + pbattrs.Clear(); + pbattrs.AppendElement(LOCAL_EGL_WIDTH); + pbattrs.AppendElement(pbsize.width); + pbattrs.AppendElement(LOCAL_EGL_HEIGHT); + pbattrs.AppendElement(pbsize.height); + + if (bindToTextureFormat != LOCAL_EGL_NONE) { + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET); + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D); + + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT); + pbattrs.AppendElement(bindToTextureFormat); + } + + for (const auto& cur : kTerminationAttribs) { + pbattrs.AppendElement(cur); + } + + surface = egl.fCreatePbufferSurface(config, &pbattrs[0]); + if (!surface) { + if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) { + if (!is_power_of_two(pbsize.width)) + pbsize.width = next_power_of_two(pbsize.width); + if (!is_power_of_two(pbsize.height)) + pbsize.height = next_power_of_two(pbsize.height); + + NS_WARNING("Failed to create pbuffer, trying power of two dims"); + goto TRY_AGAIN_POWER_OF_TWO; + } + + NS_WARNING("Failed to create pbuffer surface"); + return nullptr; + } + + return surface; +} + +#if defined(MOZ_WAYLAND) +WaylandOffscreenGLSurface::WaylandOffscreenGLSurface( + struct wl_surface* aWaylandSurface, struct wl_egl_window* aEGLWindow) + : mWaylandSurface(aWaylandSurface), mEGLWindow(aEGLWindow) {} + +WaylandOffscreenGLSurface::~WaylandOffscreenGLSurface() { + if (mEGLWindow) { + wl_egl_window_destroy(mEGLWindow); + } + if (mWaylandSurface) { + wl_surface_destroy(mWaylandSurface); + } +} + +// static +EGLSurface GLContextEGL::CreateWaylandOffscreenSurface( + EglDisplay& egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) { + wl_egl_window* eglwindow = nullptr; + + struct wl_compositor* compositor = + gdk_wayland_display_get_wl_compositor(gdk_display_get_default()); + struct wl_surface* wlsurface = wl_compositor_create_surface(compositor); + eglwindow = wl_egl_window_create(wlsurface, pbsize.width, pbsize.height); + if (!eglwindow) return nullptr; + + const auto surface = egl.fCreateWindowSurface( + config, reinterpret_cast<EGLNativeWindowType>(eglwindow), 0); + if (surface) { + MOZ_DIAGNOSTIC_ASSERT(!sWaylandOffscreenGLSurfaces.Contains(surface)); + sWaylandOffscreenGLSurfaces.LookupOrInsert( + surface, new WaylandOffscreenGLSurface(wlsurface, eglwindow)); + } + return surface; +} +#endif + +static const EGLint kEGLConfigAttribsRGB16[] = { + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, + LOCAL_EGL_RED_SIZE, 5, + LOCAL_EGL_GREEN_SIZE, 6, + LOCAL_EGL_BLUE_SIZE, 5, + LOCAL_EGL_ALPHA_SIZE, 0}; + +static const EGLint kEGLConfigAttribsRGB24[] = { + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, + LOCAL_EGL_RED_SIZE, 8, + LOCAL_EGL_GREEN_SIZE, 8, + LOCAL_EGL_BLUE_SIZE, 8, + LOCAL_EGL_ALPHA_SIZE, 0}; + +static const EGLint kEGLConfigAttribsRGBA32[] = { + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, + LOCAL_EGL_RED_SIZE, 8, + LOCAL_EGL_GREEN_SIZE, 8, + LOCAL_EGL_BLUE_SIZE, 8, + LOCAL_EGL_ALPHA_SIZE, 8}; + +bool CreateConfig(EglDisplay& aEgl, EGLConfig* aConfig, int32_t aDepth, + bool aEnableDepthBuffer, bool aUseGles, bool aAllowFallback) { + EGLConfig configs[64]; + std::vector<EGLint> attribs; + EGLint ncfg = ArrayLength(configs); + + switch (aDepth) { + case 16: + for (const auto& cur : kEGLConfigAttribsRGB16) { + attribs.push_back(cur); + } + break; + case 24: + for (const auto& cur : kEGLConfigAttribsRGB24) { + attribs.push_back(cur); + } + break; + case 32: + for (const auto& cur : kEGLConfigAttribsRGBA32) { + attribs.push_back(cur); + } + break; + default: + NS_ERROR("Unknown pixel depth"); + return false; + } + + if (aUseGles) { + attribs.push_back(LOCAL_EGL_RENDERABLE_TYPE); + attribs.push_back(LOCAL_EGL_OPENGL_ES2_BIT); + } + for (const auto& cur : kTerminationAttribs) { + attribs.push_back(cur); + } + + if (!aEgl.fChooseConfig(attribs.data(), configs, ncfg, &ncfg) || ncfg < 1) { + return false; + } + + Maybe<EGLConfig> fallbackConfig; + + for (int j = 0; j < ncfg; ++j) { + EGLConfig config = configs[j]; + EGLint r, g, b, a; + if (aEgl.fGetConfigAttrib(config, LOCAL_EGL_RED_SIZE, &r) && + aEgl.fGetConfigAttrib(config, LOCAL_EGL_GREEN_SIZE, &g) && + aEgl.fGetConfigAttrib(config, LOCAL_EGL_BLUE_SIZE, &b) && + aEgl.fGetConfigAttrib(config, LOCAL_EGL_ALPHA_SIZE, &a) && + ((aDepth == 16 && r == 5 && g == 6 && b == 5) || + (aDepth == 24 && r == 8 && g == 8 && b == 8) || + (aDepth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) { + EGLint z; + if (aEnableDepthBuffer) { + if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_DEPTH_SIZE, &z) || + z != 24) { + continue; + } + } +#ifdef MOZ_X11 + if (GdkIsX11Display()) { + int configVisualID; + if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, + &configVisualID)) { + continue; + } + + XVisualInfo visual_info_template, *visual_info; + int num_visuals; + + visual_info_template.visualid = configVisualID; + visual_info = + XGetVisualInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), + VisualIDMask, &visual_info_template, &num_visuals); + + if (!visual_info || visual_info->depth != aDepth) { + if (aAllowFallback && !fallbackConfig) { + fallbackConfig = Some(config); + } + continue; + } + } +#endif + *aConfig = config; + return true; + } + } + + if (kIsLinux && fallbackConfig) { + *aConfig = fallbackConfig.value(); + return true; + } + + return false; +} + +// Return true if a suitable EGLConfig was found and pass it out +// through aConfig. Return false otherwise. +// +// NB: It's entirely legal for the returned EGLConfig to be valid yet +// have the value null. +static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig, + const bool aEnableDepthBuffer, + const bool aUseGles) { + int32_t depth = gfxVars::ScreenDepth(); + if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles)) { + return true; + } +#ifdef MOZ_WIDGET_ANDROID + // Bug 736005 + // Android doesn't always support 16 bit so also try 24 bit + if (depth == 16) { + return CreateConfig(egl, aConfig, 24, aEnableDepthBuffer, aUseGles); + } + // Bug 970096 + // Some devices that have 24 bit screens only support 16 bit OpenGL? + if (depth == 24) { + return CreateConfig(egl, aConfig, 16, aEnableDepthBuffer, aUseGles); + } +#endif + return false; +} + +already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool /*aForceAccelerated*/) { + EGLNativeWindowType window = nullptr; + if (aCompositorWidget) { + window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget); + } + return GLContextEGLFactory::Create(window, aHardwareWebRender); +} + +EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) const { + MOZ_ASSERT(aWindow); + MOZ_RELEASE_ASSERT(mSurfaceConfig != EGL_NO_CONFIG); + + // NOTE: aWindow is an ANativeWindow + EGLSurface surface = mEgl->fCreateWindowSurface( + mSurfaceConfig, reinterpret_cast<EGLNativeWindowType>(aWindow), nullptr); + if (!surface) { + gfxCriticalError() << "CreateCompatibleSurface failed: " + << hexa(GetError()); + } + return surface; +} + +static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) { + out->AppendElement(LOCAL_EGL_SURFACE_TYPE); +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + // Wayland on desktop does not support PBuffer or FBO. + // We create a dummy wl_egl_window instead. + out->AppendElement(LOCAL_EGL_WINDOW_BIT); + } else +#endif + { + out->AppendElement(LOCAL_EGL_PBUFFER_BIT); + } + + if (useGles) { + out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); + if (es3) { + out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR); + } else { + out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT); + } + } + + out->AppendElement(LOCAL_EGL_RED_SIZE); + out->AppendElement(8); + + out->AppendElement(LOCAL_EGL_GREEN_SIZE); + out->AppendElement(8); + + out->AppendElement(LOCAL_EGL_BLUE_SIZE); + out->AppendElement(8); + + out->AppendElement(LOCAL_EGL_ALPHA_SIZE); + out->AppendElement(8); + + out->AppendElement(LOCAL_EGL_DEPTH_SIZE); + out->AppendElement(0); + + out->AppendElement(LOCAL_EGL_STENCIL_SIZE); + out->AppendElement(0); + + // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS + out->AppendElement(LOCAL_EGL_NONE); + out->AppendElement(0); + + out->AppendElement(0); + out->AppendElement(0); +} + +/* +/// Useful for debugging, but normally unused. +static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) { + EGLint bits = 0; + egl->fGetConfigAttrib(config, attrib, &bits); + MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS); + + return bits; +} +*/ + +static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc, + const bool useGles) { + nsTArray<EGLint> configAttribList; + FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles, + &configAttribList); + + const EGLint* configAttribs = configAttribList.Elements(); + + // The sorting dictated by the spec for eglChooseConfig reasonably assures + // that a reasonable 'best' config is on top. + const EGLint kMaxConfigs = 1; + EGLConfig configs[kMaxConfigs]; + EGLint foundConfigs = 0; + if (!egl.fChooseConfig(configAttribs, configs, kMaxConfigs, &foundConfigs) || + foundConfigs == 0) { + return EGL_NO_CONFIG; + } + + EGLConfig config = configs[0]; + return config; +} + +#ifdef MOZ_X11 +/* static */ +bool GLContextEGL::FindVisual(int* const out_visualId) { + nsCString discardFailureId; + const auto egl = DefaultEglDisplay(&discardFailureId); + if (!egl) { + gfxCriticalNote + << "GLContextEGL::FindVisual(): Failed to load EGL library!"; + return false; + } + + EGLConfig config; + const int bpp = 32; + if (!CreateConfig(*egl, &config, bpp, /* aEnableDepthBuffer */ false, + /* aUseGles */ false, /* aAllowFallback */ false)) { + // We are on a buggy driver. Do not return a visual so a fallback path can + // be used. See https://gitlab.freedesktop.org/mesa/mesa/-/issues/149 + return false; + } + if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) { + return true; + } + return false; +} +#endif + +/*static*/ +RefPtr<GLContextEGL> GLContextEGL::CreateWithoutSurface( + const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc, + nsACString* const out_failureId) { + const auto WithUseGles = [&](const bool useGles) -> RefPtr<GLContextEGL> { +#ifdef MOZ_WIDGET_GTK + // First try creating a context with no config and no surface, this is what + // we really want, and seems to be the only way to make selecting software + // Mesa init properly when it's not the first device. + if (egl->IsExtensionSupported(EGLExtension::KHR_no_config_context) && + egl->IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) { + // These extensions have been supported by mesa and nvidia drivers + // since 2014 or earlier, this is the preferred code path + auto fullDesc = GLContextDesc{desc}; + fullDesc.isOffscreen = true; + RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext( + egl, fullDesc, EGL_NO_CONFIG, EGL_NO_SURFACE, useGles, EGL_NO_CONFIG, + out_failureId); + if (gl) { + return gl; + } + NS_WARNING( + "Failed to create GLContext with no config and no surface, will try " + "ChooseConfig"); + } +#endif + + const EGLConfig surfaceConfig = ChooseConfig(*egl, desc, useGles); + if (surfaceConfig == EGL_NO_CONFIG) { + *out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns; + NS_WARNING("Failed to find a compatible config."); + return nullptr; + } + + if (GLContext::ShouldSpew()) { + egl->DumpEGLConfig(surfaceConfig); + } + const EGLConfig contextConfig = + egl->IsExtensionSupported(EGLExtension::KHR_no_config_context) + ? nullptr + : surfaceConfig; + + auto dummySize = mozilla::gfx::IntSize{16, 16}; + EGLSurface surface = nullptr; +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + surface = GLContextEGL::CreateWaylandOffscreenSurface(*egl, surfaceConfig, + dummySize); + } else +#endif + { + surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo( + *egl, surfaceConfig, LOCAL_EGL_NONE, dummySize); + } + if (!surface) { + *out_failureId = "FEATURE_FAILURE_EGL_POT"_ns; + NS_WARNING("Failed to create PBuffer for context!"); + return nullptr; + } + + auto fullDesc = GLContextDesc{desc}; + fullDesc.isOffscreen = true; + RefPtr<GLContextEGL> gl = + GLContextEGL::CreateGLContext(egl, fullDesc, surfaceConfig, surface, + useGles, contextConfig, out_failureId); + if (!gl) { + NS_WARNING("Failed to create GLContext from PBuffer"); + egl->fDestroySurface(surface); +#if defined(MOZ_WAYLAND) + DeleteWaylandOffscreenGLSurface(surface); +#endif + return nullptr; + } + + return gl; + }; + + bool preferGles; +#if defined(MOZ_WIDGET_ANDROID) + preferGles = true; +#else + preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup(); +#endif // defined(MOZ_WIDGET_ANDROID) + RefPtr<GLContextEGL> gl = WithUseGles(preferGles); +#if !defined(MOZ_WIDGET_ANDROID) + if (!gl) { + gl = WithUseGles(!preferGles); + } +#endif // !defined(MOZ_WIDGET_ANDROID) + return gl; +} + +/*static*/ +void GLContextEGL::DestroySurface(EglDisplay& aEgl, const EGLSurface aSurface) { + if (aSurface != EGL_NO_SURFACE) { + if (!aEgl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + const EGLint err = aEgl.mLib->fGetError(); + gfxCriticalNote << "Error in eglMakeCurrent: " << gfx::hexa(err); + } + if (!aEgl.fDestroySurface(aSurface)) { + const EGLint err = aEgl.mLib->fGetError(); + gfxCriticalNote << "Error in eglDestroySurface: " << gfx::hexa(err); + } +#if defined(MOZ_WAYLAND) + DeleteWaylandOffscreenGLSurface(aSurface); +#endif + } +} + +/*static*/ +already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless( + const GLContextCreateDesc& desc, nsACString* const out_failureId) { + const auto display = DefaultEglDisplay(out_failureId); + if (!display) { + return nullptr; + } + auto ret = GLContextEGL::CreateWithoutSurface(display, desc, out_failureId); + return ret.forget(); +} + +// Don't want a global context on Android as 1) share groups across 2 threads +// fail on many Tegra drivers (bug 759225) and 2) some mobile devices have a +// very strict limit on global number of GL contexts (bug 754257) and 3) each +// EGL context eats 750k on B2G (bug 813783) +/*static*/ +GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; } + +// - + +/*static*/ void GLContextProviderEGL::Shutdown() { GLLibraryEGL::Shutdown(); } + +} /* namespace gl */ +} /* namespace mozilla */ + +#undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp new file mode 100644 index 0000000000..cdc5e7ce1a --- /dev/null +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -0,0 +1,908 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZ_WIDGET_GTK +# include <gdk/gdk.h> +# include <gdk/gdkx.h> +# define GET_NATIVE_WINDOW(aWidget) \ + GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW)) +#endif + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "X11UndefineNone.h" + +#include "mozilla/MathAlgorithms.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/layers/CompositorOptions.h" +#include "mozilla/Range.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Sprintf.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_layout.h" +#include "mozilla/widget/CompositorWidget.h" +#include "mozilla/widget/GtkCompositorWidget.h" +#include "mozilla/Unused.h" + +#include "prenv.h" +#include "GLContextProvider.h" +#include "GLLibraryLoader.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include "GLXLibrary.h" +#include "gfxContext.h" +#include "gfxEnv.h" +#include "gfxPlatform.h" +#include "GLContextGLX.h" +#include "gfxUtils.h" +#include "gfx2DGlue.h" +#include "GLScreenBuffer.h" + +#include "gfxCrashReporterUtils.h" + +#ifdef MOZ_WIDGET_GTK +# include "gfxPlatformGtk.h" +#endif + +namespace mozilla::gl { + +using namespace mozilla::gfx; +using namespace mozilla::widget; + +GLXLibrary sGLXLibrary; + +static inline bool HasExtension(const char* aExtensions, + const char* aRequiredExtension) { + return GLContext::ListHasExtension( + reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); +} + +bool GLXLibrary::EnsureInitialized(Display* aDisplay) { + if (mInitialized) { + return true; + } + + // Don't repeatedly try to initialize. + if (mTriedInitializing) { + return false; + } + mTriedInitializing = true; + + MOZ_ASSERT(aDisplay); + if (!aDisplay) { + return false; + } + + // Force enabling s3 texture compression. (Bug 774134) + PR_SetEnv("force_s3tc_enable=true"); + + if (!mOGLLibrary) { + // see e.g. bug 608526: it is intrinsically interesting to know whether we + // have dynamically linked to libGL.so.1 because at least the NVIDIA + // implementation requires an executable stack, which causes mprotect calls, + // which trigger glibc bug + // http://sourceware.org/bugzilla/show_bug.cgi?id=12225 + const char* libGLfilename = "libGL.so.1"; +#if defined(__OpenBSD__) || defined(__NetBSD__) + libGLfilename = "libGL.so"; +#endif + + const bool forceFeatureReport = false; + ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); + mOGLLibrary = PR_LoadLibrary(libGLfilename); + if (!mOGLLibrary) { + NS_WARNING("Couldn't load OpenGL shared library."); + return false; + } + reporter.SetSuccessful(); + } + + if (gfxEnv::MOZ_GLX_DEBUG()) { + mDebug = true; + } + +#define SYMBOL(X) \ + { \ + (PRFuncPtr*)&mSymbols.f##X, { \ + { "glX" #X } \ + } \ + } +#define END_OF_SYMBOLS \ + { \ + nullptr, {} \ + } + + const SymLoadStruct symbols[] = { + /* functions that were in GLX 1.0 */ + SYMBOL(DestroyContext), + SYMBOL(MakeCurrent), + SYMBOL(SwapBuffers), + SYMBOL(QueryVersion), + SYMBOL(GetConfig), + SYMBOL(GetCurrentContext), + SYMBOL(WaitGL), + SYMBOL(WaitX), + + /* functions introduced in GLX 1.1 */ + SYMBOL(QueryExtensionsString), + SYMBOL(GetClientString), + SYMBOL(QueryServerString), + + /* functions introduced in GLX 1.3 */ + SYMBOL(ChooseFBConfig), + SYMBOL(ChooseVisual), + SYMBOL(GetFBConfigAttrib), + SYMBOL(GetFBConfigs), + SYMBOL(CreatePixmap), + SYMBOL(DestroyPixmap), + SYMBOL(CreateNewContext), + + // Core in GLX 1.4, ARB extension before. + {(PRFuncPtr*)&mSymbols.fGetProcAddress, + {{"glXGetProcAddress", "glXGetProcAddressARB"}}}, + END_OF_SYMBOLS}; + + { + const SymbolLoader libLoader(*mOGLLibrary); + if (!libLoader.LoadSymbols(symbols)) { + NS_WARNING("Couldn't load required GLX symbols."); + return false; + } + } + const SymbolLoader pfnLoader(mSymbols.fGetProcAddress); + + int screen = DefaultScreen(aDisplay); + + { + int major, minor; + if (!fQueryVersion(aDisplay, &major, &minor) || major != 1 || minor < 3) { + NS_ERROR("GLX version older than 1.3. (released in 1998)"); + return false; + } + } + + const SymLoadStruct symbols_createcontext[] = { + SYMBOL(CreateContextAttribsARB), END_OF_SYMBOLS}; + + const SymLoadStruct symbols_videosync[] = { + SYMBOL(GetVideoSyncSGI), SYMBOL(WaitVideoSyncSGI), END_OF_SYMBOLS}; + + const SymLoadStruct symbols_swapcontrol[] = {SYMBOL(SwapIntervalEXT), + END_OF_SYMBOLS}; + + const SymLoadStruct symbols_querydrawable[] = {SYMBOL(QueryDrawable), + END_OF_SYMBOLS}; + + const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) { + if (pfnLoader.LoadSymbols(symbols)) return true; + + ClearSymbols(symbols); + return false; + }; + + const char* clientVendor = fGetClientString(aDisplay, LOCAL_GLX_VENDOR); + const char* serverVendor = + fQueryServerString(aDisplay, screen, LOCAL_GLX_VENDOR); + const char* extensionsStr = fQueryExtensionsString(aDisplay, screen); + + if (HasExtension(extensionsStr, "GLX_ARB_create_context") && + HasExtension(extensionsStr, "GLX_ARB_create_context_profile") && + fnLoadSymbols(symbols_createcontext)) { + mHasCreateContextAttribs = true; + } + + if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness")) { + mHasRobustness = true; + } + + if (HasExtension(extensionsStr, "GLX_NV_robustness_video_memory_purge")) { + mHasVideoMemoryPurge = true; + } + + if (HasExtension(extensionsStr, "GLX_SGI_video_sync") && + fnLoadSymbols(symbols_videosync)) { + mHasVideoSync = true; + } + + if (!HasExtension(extensionsStr, "GLX_EXT_swap_control") || + !fnLoadSymbols(symbols_swapcontrol)) { + NS_WARNING( + "GLX_swap_control unsupported, ASAP mode may still block on buffer " + "swaps."); + } + + if (HasExtension(extensionsStr, "GLX_EXT_buffer_age") && + fnLoadSymbols(symbols_querydrawable)) { + mHasBufferAge = true; + } + + mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); + mIsNVIDIA = + serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation"); + mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); + + mInitialized = true; + + // This needs to be after `fQueryServerString` is called so that the + // driver is loaded. + MesaMemoryLeakWorkaround(); + + return true; +} + +bool GLXLibrary::SupportsVideoSync(Display* aDisplay) { + if (!EnsureInitialized(aDisplay)) { + return false; + } + + return mHasVideoSync; +} + +static int (*sOldErrorHandler)(Display*, XErrorEvent*); +static XErrorEvent sErrorEvent = {}; + +static int GLXErrorHandler(Display* display, XErrorEvent* ev) { + if (!sErrorEvent.error_code) { + sErrorEvent = *ev; + } + return 0; +} + +GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary& glx, + const char* const funcName, + Display* aDisplay) + : mGlx(glx), mFuncName(funcName), mDisplay(aDisplay) { + if (mGlx.mDebug) { + sOldErrorHandler = XSetErrorHandler(GLXErrorHandler); + } +} + +GLXLibrary::WrapperScope::~WrapperScope() { + if (mGlx.mDebug) { + if (mDisplay) { + FinishX(mDisplay); + } + if (sErrorEvent.error_code) { + char buffer[100] = {}; + if (mDisplay) { + XGetErrorText(mDisplay, sErrorEvent.error_code, buffer, sizeof(buffer)); + } else { + SprintfLiteral(buffer, "%d", sErrorEvent.error_code); + } + printf_stderr("X ERROR after %s: %s (%i) - Request: %i.%i, Serial: %lu", + mFuncName, buffer, sErrorEvent.error_code, + sErrorEvent.request_code, sErrorEvent.minor_code, + sErrorEvent.serial); + MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent"); + } + const auto was = XSetErrorHandler(sOldErrorHandler); + if (was != GLXErrorHandler) { + NS_WARNING("Concurrent XSetErrorHandlers"); + } + } +} + +// Returns the GTK display if available; otherwise, if a display was +// previously opened by this method and is still open, returns a +// reference to it; otherwise, opens a new connection. (The non-GTK +// cases are similar to what we do for EGL.) +std::shared_ptr<XlibDisplay> GLXLibrary::GetDisplay() { + std::shared_ptr<XlibDisplay> display; + +#ifdef MOZ_WIDGET_GTK + static const bool kHaveGtk = !!gdk_display_get_default(); + if (kHaveGtk) { + display = XlibDisplay::Borrow(DefaultXDisplay()); + } +#endif + if (display) { + return display; + } + + auto ownDisplay = mOwnDisplay.Lock(); + display = ownDisplay->lock(); + if (display) { + return display; + } + + display = XlibDisplay::Open(nullptr); + if (NS_WARN_IF(!display)) { + return nullptr; + } + *ownDisplay = display; + return display; +} + +already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext( + const GLContextDesc& desc, std::shared_ptr<XlibDisplay> display, + GLXDrawable drawable, GLXFBConfig cfg, Drawable ownedPixmap) { + GLXLibrary& glx = sGLXLibrary; + + int isDoubleBuffered = 0; + int err = glx.fGetFBConfigAttrib(*display, cfg, LOCAL_GLX_DOUBLEBUFFER, + &isDoubleBuffered); + if (LOCAL_GLX_BAD_ATTRIBUTE != err) { + if (ShouldSpew()) { + printf("[GLX] FBConfig is %sdouble-buffered\n", + isDoubleBuffered ? "" : "not "); + } + } + + if (!glx.HasCreateContextAttribs()) { + NS_WARNING("Cannot create GLContextGLX without glxCreateContextAttribs"); + return nullptr; + } + + // - + + const auto CreateWithAttribs = + [&](const std::vector<int>& attribs) -> RefPtr<GLContextGLX> { + auto terminated = attribs; + terminated.push_back(0); + + const auto glxContext = glx.fCreateContextAttribs( + *display, cfg, nullptr, X11True, terminated.data()); + if (!glxContext) return nullptr; + const RefPtr<GLContextGLX> ret = new GLContextGLX( + desc, display, drawable, glxContext, isDoubleBuffered, ownedPixmap); + + if (!ret->Init()) return nullptr; + + return ret; + }; + + // - + + RefPtr<GLContextGLX> glContext; + + std::vector<int> attribs; + attribs.insert(attribs.end(), { + LOCAL_GLX_RENDER_TYPE, + LOCAL_GLX_RGBA_TYPE, + }); + if (glx.HasVideoMemoryPurge()) { + attribs.insert(attribs.end(), + { + LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, + LOCAL_GL_TRUE, + }); + } + const bool useCore = + !(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE); + if (useCore) { + attribs.insert(attribs.end(), { + LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB, + 3, + LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB, + 2, + LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB, + LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + }); + } + + if (glx.HasRobustness()) { + auto withRobustness = attribs; + withRobustness.insert(withRobustness.end(), + { + LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB, + }); + + { + auto withRBAB = withRobustness; + withRBAB.insert(withRBAB.end(), + { + LOCAL_GLX_CONTEXT_FLAGS_ARB, + LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, + }); + if (!glContext) { + glContext = CreateWithAttribs(withRBAB); + if (!glContext) { + NS_WARNING("Failed to create+init GLContextGLX with RBAB"); + } + } + } + + if (!glContext) { + glContext = CreateWithAttribs(withRobustness); + if (!glContext) { + NS_WARNING("Failed to create+init GLContextGLX with Robustness"); + } + } + } + + if (!glContext) { + glContext = CreateWithAttribs(attribs); + if (!glContext) { + NS_WARNING("Failed to create+init GLContextGLX with required attribs"); + } + } + + return glContext.forget(); +} + +GLContextGLX::~GLContextGLX() { + MarkDestroyed(); + + // Wrapped context should not destroy glxContext/Surface + if (!mOwnsContext) { + return; + } + + // see bug 659842 comment 76 + bool success = mGLX->fMakeCurrent(*mDisplay, X11None, nullptr); + if (!success) { + NS_WARNING( + "glXMakeCurrent failed to release GL context before we call " + "glXDestroyContext!"); + } + + mGLX->fDestroyContext(*mDisplay, mContext); + + // If we own the enclosed X pixmap, then free it after we free the enclosing + // GLX pixmap. + if (mOwnedPixmap) { + mGLX->fDestroyPixmap(*mDisplay, mDrawable); + XFreePixmap(*mDisplay, mOwnedPixmap); + } +} + +bool GLContextGLX::Init() { + if (!GLContext::Init()) { + return false; + } + + // EXT_framebuffer_object is not supported on Core contexts + // so we'll also check for ARB_framebuffer_object + if (!IsExtensionSupported(EXT_framebuffer_object) && + !IsSupported(GLFeature::framebuffer_object)) + return false; + + return true; +} + +bool GLContextGLX::MakeCurrentImpl() const { + if (mGLX->IsMesa()) { + // Read into the event queue to ensure that Mesa receives a + // DRI2InvalidateBuffers event before drawing. See bug 1280653. + Unused << XPending(*mDisplay); + } + + const bool succeeded = mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext); + if (!succeeded) { + NS_WARNING("Failed to make GL context current!"); + } + + if (!IsOffscreen() && mGLX->SupportsSwapControl()) { + // Many GLX implementations default to blocking until the next + // VBlank when calling glXSwapBuffers. We want to run unthrottled + // in ASAP mode. See bug 1280744. + const bool swapInterval = gfxVars::SwapIntervalGLX(); + const bool isASAP = (StaticPrefs::layout_frame_rate() == 0); + const int interval = (swapInterval && !isASAP) ? 1 : 0; + mGLX->fSwapInterval(*mDisplay, mDrawable, interval); + } + return succeeded; +} + +bool GLContextGLX::IsCurrentImpl() const { + return mGLX->fGetCurrentContext() == mContext; +} + +Maybe<SymbolLoader> GLContextGLX::GetSymbolLoader() const { + const auto pfn = sGLXLibrary.GetGetProcAddress(); + return Some(SymbolLoader(pfn)); +} + +bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered; } + +bool GLContextGLX::SwapBuffers() { + if (!mDoubleBuffered) return false; + mGLX->fSwapBuffers(*mDisplay, mDrawable); + return true; +} + +GLint GLContextGLX::GetBufferAge() const { + if (!sGLXLibrary.SupportsBufferAge()) { + return 0; + } + + GLuint result = 0; + mGLX->fQueryDrawable(*mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT, + &result); + if (result > INT32_MAX) { + // If the result can't fit, just assume the buffer cannot be reused. + return 0; + } + return result; +} + +void GLContextGLX::GetWSIInfo(nsCString* const out) const { + int screen = DefaultScreen(mDisplay->get()); + + int majorVersion, minorVersion; + sGLXLibrary.fQueryVersion(*mDisplay, &majorVersion, &minorVersion); + + out->Append(nsPrintfCString("GLX %u.%u", majorVersion, minorVersion)); + + out->AppendLiteral("\nGLX_VENDOR(client): "); + out->Append(sGLXLibrary.fGetClientString(*mDisplay, LOCAL_GLX_VENDOR)); + + out->AppendLiteral("\nGLX_VENDOR(server): "); + out->Append( + sGLXLibrary.fQueryServerString(*mDisplay, screen, LOCAL_GLX_VENDOR)); + + out->AppendLiteral("\nExtensions: "); + out->Append(sGLXLibrary.fQueryExtensionsString(*mDisplay, screen)); +} + +bool GLContextGLX::OverrideDrawable(GLXDrawable drawable) { + return mGLX->fMakeCurrent(*mDisplay, drawable, mContext); +} + +bool GLContextGLX::RestoreDrawable() { + return mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext); +} + +GLContextGLX::GLContextGLX(const GLContextDesc& desc, + std::shared_ptr<XlibDisplay> aDisplay, + GLXDrawable aDrawable, GLXContext aContext, + bool aDoubleBuffered, Drawable aOwnedPixmap) + : GLContext(desc, nullptr), + mContext(aContext), + mDisplay(aDisplay), + mDrawable(aDrawable), + mOwnedPixmap(aOwnedPixmap), + mDoubleBuffered(aDoubleBuffered), + mGLX(&sGLXLibrary) {} + +static bool AreCompatibleVisuals(Visual* one, Visual* two) { + if (one->c_class != two->c_class) { + return false; + } + + if (one->red_mask != two->red_mask || one->green_mask != two->green_mask || + one->blue_mask != two->blue_mask) { + return false; + } + + if (one->bits_per_rgb != two->bits_per_rgb) { + return false; + } + + return true; +} + +already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow, + bool aHardwareWebRender, + bool aForceAccelerated) { + if (!sGLXLibrary.EnsureInitialized(aXDisplay)) { + return nullptr; + } + + // Currently, we take whatever Visual the window already has, and + // try to create an fbconfig for that visual. This isn't + // necessarily what we want in the long run; an fbconfig may not + // be available for the existing visual, or if it is, the GL + // performance might be suboptimal. But using the existing visual + // is a relatively safe intermediate step. + + if (!aXDisplay) { + NS_ERROR("X Display required for GLX Context provider"); + return nullptr; + } + + if (!aXWindow) { + NS_ERROR("X window required for GLX Context provider"); + return nullptr; + } + + int xscreen = DefaultScreen(aXDisplay); + + GLXFBConfig config; + int visid; + if (!GLContextGLX::FindFBConfigForWindow(aXDisplay, xscreen, aXWindow, + &config, &visid, + aHardwareWebRender)) { + return nullptr; + } + + CreateContextFlags flags; + if (aHardwareWebRender) { + flags = CreateContextFlags::NONE; // WR needs GL3.2+ + } else { + flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE; + } + return GLContextGLX::CreateGLContext( + {{flags}, false}, XlibDisplay::Borrow(aXDisplay), aXWindow, config); +} + +already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + if (!aCompositorWidget) { + MOZ_ASSERT(false); + return nullptr; + } + GtkCompositorWidget* compWidget = aCompositorWidget->AsGTK(); + MOZ_ASSERT(compWidget); + + return CreateForWidget(DefaultXDisplay(), compWidget->XWindow(), + aHardwareWebRender, aForceAccelerated); +} + +static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen, + GLXFBConfig* const out_config, int* const out_visid) { + const int attribs[] = { + LOCAL_GLX_RENDER_TYPE, + LOCAL_GLX_RGBA_BIT, + LOCAL_GLX_DRAWABLE_TYPE, + LOCAL_GLX_PIXMAP_BIT, + LOCAL_GLX_X_RENDERABLE, + X11True, + LOCAL_GLX_RED_SIZE, + 8, + LOCAL_GLX_GREEN_SIZE, + 8, + LOCAL_GLX_BLUE_SIZE, + 8, + LOCAL_GLX_ALPHA_SIZE, + 8, + LOCAL_GLX_DEPTH_SIZE, + 0, + LOCAL_GLX_STENCIL_SIZE, + 0, + 0, + }; + + int numConfigs = 0; + const auto scopedConfigArr = glx->fChooseFBConfig(display, screen, attribs, &numConfigs); + const auto freeConfigList = MakeScopeExit([&]() { + if (scopedConfigArr) { + XFree(scopedConfigArr); + } + }); + if (!scopedConfigArr || !numConfigs) return false; + + // Issues with glxChooseFBConfig selection and sorting: + // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't + // request + // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24. + // * DEPTH_SIZE is sorted largest first, including for `0` inputs. + // * STENCIL_SIZE is smallest first, but it might return `8` even though we + // ask for + // `0`. + + // For now, we don't care about these. We *will* care when we do XPixmap + // sharing. + + for (int i = 0; i < numConfigs; ++i) { + GLXFBConfig curConfig = scopedConfigArr[i]; + + int visid; + if (glx->fGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID, + &visid) != Success) { + continue; + } + + if (!visid) continue; + + *out_config = curConfig; + *out_visid = visid; + return true; + } + + return false; +} + +bool GLContextGLX::FindVisual(Display* display, int screen, + int* const out_visualId) { + if (!sGLXLibrary.EnsureInitialized(display)) { + return false; + } + + XVisualInfo visualTemplate; + visualTemplate.screen = screen; + + // Get all visuals of screen + + int visualsLen = 0; + XVisualInfo* xVisuals = + XGetVisualInfo(display, VisualScreenMask, &visualTemplate, &visualsLen); + if (!xVisuals) { + return false; + } + const Range<XVisualInfo> visualInfos(xVisuals, visualsLen); + auto cleanupVisuals = MakeScopeExit([&] { XFree(xVisuals); }); + + // Get default visual info + + Visual* defaultVisual = DefaultVisual(display, screen); + const auto defaultVisualInfo = [&]() -> const XVisualInfo* { + for (const auto& cur : visualInfos) { + if (cur.visual == defaultVisual) { + return &cur; + } + } + return nullptr; + }(); + if (!defaultVisualInfo) { + MOZ_ASSERT(false); + return false; + } + + const int bpp = 32; + + for (auto& cur : visualInfos) { + const auto fnConfigMatches = [&](const int pname, const int expected) { + int actual; + if (sGLXLibrary.fGetConfig(display, &cur, pname, &actual)) { + return false; + } + return actual == expected; + }; + + // Check if visual is compatible. + if (cur.depth != bpp || cur.c_class != defaultVisualInfo->c_class) { + continue; + } + + // Check if visual is compatible to GL requests. + if (fnConfigMatches(LOCAL_GLX_USE_GL, 1) && + fnConfigMatches(LOCAL_GLX_DOUBLEBUFFER, 1) && + fnConfigMatches(LOCAL_GLX_RED_SIZE, 8) && + fnConfigMatches(LOCAL_GLX_GREEN_SIZE, 8) && + fnConfigMatches(LOCAL_GLX_BLUE_SIZE, 8) && + fnConfigMatches(LOCAL_GLX_ALPHA_SIZE, 8)) { + *out_visualId = cur.visualid; + return true; + } + } + + return false; +} + +bool GLContextGLX::FindFBConfigForWindow( + Display* display, int screen, Window window, + GLXFBConfig* const out_config, int* const out_visid, bool aWebRender) { + // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so + // we could probably do this first and replace the glXGetFBConfigs + // with glXChooseConfigs. Docs are sparklingly clear as always. + XWindowAttributes windowAttrs; + if (!XGetWindowAttributes(display, window, &windowAttrs)) { + NS_WARNING("[GLX] XGetWindowAttributes() failed"); + return false; + } + + GLXFBConfig* cfgs = nullptr; + const auto freeConfigList = MakeScopeExit([&]() { + if (cfgs) { + XFree(cfgs); + } + }); + int numConfigs; + const int webrenderAttribs[] = {LOCAL_GLX_ALPHA_SIZE, + windowAttrs.depth == 32 ? 8 : 0, + LOCAL_GLX_DOUBLEBUFFER, X11True, 0}; + + if (aWebRender) { + cfgs = sGLXLibrary.fChooseFBConfig(display, screen, webrenderAttribs, + &numConfigs); + } else { + cfgs = sGLXLibrary.fGetFBConfigs(display, screen, &numConfigs); + } + + if (!cfgs) { + NS_WARNING("[GLX] glXGetFBConfigs() failed"); + return false; + } + NS_ASSERTION(numConfigs > 0, "No FBConfigs found!"); + + const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual); +#ifdef DEBUG + printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID); +#endif + + for (int i = 0; i < numConfigs; i++) { + int visid = X11None; + sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, + &visid); + if (visid) { + // WebRender compatible GLX visual is configured + // at nsWindow::Create() by GLContextGLX::FindVisual(), + // just reuse it here. + if (windowVisualID == static_cast<VisualID>(visid)) { + *out_config = cfgs[i]; + *out_visid = visid; + return true; + } + } + } + + // We don't have a frame buffer visual which matches the GLX visual + // from GLContextGLX::FindVisual(). Let's try to find a near one and hope + // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there. + for (int i = 0; i < numConfigs; i++) { + int visid = X11None; + sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, + &visid); + if (visid) { + int depth; + Visual* visual; + FindVisualAndDepth(display, visid, &visual, &depth); + if (depth == windowAttrs.depth && + AreCompatibleVisuals(windowAttrs.visual, visual)) { + *out_config = cfgs[i]; + *out_visid = visid; + return true; + } + } + } + + NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual"); + return false; +} + +static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext( + const GLContextCreateDesc& desc, const IntSize& size, + nsACString* const out_failureId) { + GLXLibrary* glx = &sGLXLibrary; + auto display = glx->GetDisplay(); + + if (!display || !glx->EnsureInitialized(*display)) return nullptr; + + int screen = DefaultScreen(display->get()); + + GLXFBConfig config; + int visid; + if (!ChooseConfig(glx, *display, screen, &config, &visid)) { + NS_WARNING("Failed to find a compatible config."); + return nullptr; + } + + Visual* visual; + int depth; + FindVisualAndDepth(*display, visid, &visual, &depth); + + gfx::IntSize dummySize(16, 16); + const auto drawable = + XCreatePixmap(*display, DefaultRootWindow(display->get()), + dummySize.width, dummySize.height, depth); + if (!drawable) { + return nullptr; + } + + // Handle slightly different signature between glXCreatePixmap and + // its pre-GLX-1.3 extension equivalent (though given the ABI, we + // might not need to). + const auto pixmap = glx->fCreatePixmap(*display, config, drawable, nullptr); + if (pixmap == 0) { + XFreePixmap(*display, drawable); + return nullptr; + } + + auto fullDesc = GLContextDesc{desc}; + fullDesc.isOffscreen = true; + return GLContextGLX::CreateGLContext(fullDesc, display, pixmap, config, + drawable); +} + +/*static*/ +already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless( + const GLContextCreateDesc& desc, nsACString* const out_failureId) { + IntSize dummySize = IntSize(16, 16); + return CreateOffscreenPixmapContext(desc, dummySize, out_failureId); +} + +/*static*/ +GLContext* GLContextProviderGLX::GetGlobalContext() { + // Context sharing not supported. + return nullptr; +} + +/*static*/ +void GLContextProviderGLX::Shutdown() {} + +} // namespace mozilla::gl diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h new file mode 100644 index 0000000000..e7aaeeaa62 --- /dev/null +++ b/gfx/gl/GLContextProviderImpl.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef IN_GL_CONTEXT_PROVIDER_H +# error GLContextProviderImpl.h must only be included from GLContextProvider.h +#endif + +#ifndef GL_CONTEXT_PROVIDER_NAME +# error GL_CONTEXT_PROVIDER_NAME not defined +#endif +#if defined(MOZ_WIDGET_ANDROID) +# include "GLTypes.h" // for EGLSurface and EGLConfig +#endif // defined(MOZ_WIDGET_ANDROID) + +class GL_CONTEXT_PROVIDER_NAME { + public: + /** + * Create a context that renders to the surface of the widget represented by + * the compositor widget that is passed in. The context is always created + * with an RGB pixel format, with no alpha, depth or stencil. + * If any of those features are needed, either use a framebuffer, or + * use CreateOffscreen. + * + * This context will attempt to share resources with all other window + * contexts. As such, it's critical that resources allocated that are not + * needed by other contexts be deleted before the context is destroyed. + * + * The GetSharedContext() method will return non-null if sharing + * was successful. + * + * Note: a context created for a widget /must not/ hold a strong + * reference to the widget; otherwise a cycle can be created through + * a GL layer manager. + * + * @param aCompositorWidget Widget whose surface to create a context for + * @param aForceAccelerated true if only accelerated contexts are allowed + * + * @return Context to use for the window + */ + static already_AddRefed<GLContext> CreateForCompositorWidget( + mozilla::widget::CompositorWidget* aCompositorWidget, + bool aHardwareWebRender, bool aForceAccelerated); + + /// Just create a context. We'll add offscreen stuff ourselves. + static already_AddRefed<GLContext> CreateHeadless( + const GLContextCreateDesc&, nsACString* const out_failureId); + + /** + * Get a pointer to the global context, creating it if it doesn't exist. + */ + static GLContext* GetGlobalContext(); + + /** + * Free any resources held by this Context Provider. + */ + static void Shutdown(); +}; diff --git a/gfx/gl/GLContextProviderLinux.cpp b/gfx/gl/GLContextProviderLinux.cpp new file mode 100644 index 0000000000..7205449387 --- /dev/null +++ b/gfx/gl/GLContextProviderLinux.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "prenv.h" + +#include "GLContextProvider.h" +#include "mozilla/gfx/gfxVars.h" + +namespace mozilla::gl { + +using namespace mozilla::gfx; +using namespace mozilla::widget; + +#ifdef MOZ_X11 +static class GLContextProviderGLX sGLContextProviderGLX; +#endif +static class GLContextProviderEGL sGLContextProviderEGL; + +already_AddRefed<GLContext> GLContextProviderLinux::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + if (gfxVars::UseEGL()) { + return sGLContextProviderEGL.CreateForCompositorWidget( + aCompositorWidget, aHardwareWebRender, aForceAccelerated); +#ifdef MOZ_X11 + } else { + return sGLContextProviderGLX.CreateForCompositorWidget( + aCompositorWidget, aHardwareWebRender, aForceAccelerated); +#endif + } +} + +/*static*/ +already_AddRefed<GLContext> GLContextProviderLinux::CreateHeadless( + const GLContextCreateDesc& desc, nsACString* const out_failureId) { + if (gfxVars::UseEGL()) { + return sGLContextProviderEGL.CreateHeadless(desc, out_failureId); +#ifdef MOZ_X11 + } else { + return sGLContextProviderGLX.CreateHeadless(desc, out_failureId); +#endif + } +} + +/*static*/ +GLContext* GLContextProviderLinux::GetGlobalContext() { + if (gfxVars::UseEGL()) { + return sGLContextProviderEGL.GetGlobalContext(); +#ifdef MOZ_X11 + } else { + return sGLContextProviderGLX.GetGlobalContext(); +#endif + } +} + +/*static*/ +void GLContextProviderLinux::Shutdown() { + if (gfxVars::UseEGL()) { + sGLContextProviderEGL.Shutdown(); +#ifdef MOZ_X11 + } else { + sGLContextProviderGLX.Shutdown(); +#endif + } +} + +} // namespace mozilla::gl diff --git a/gfx/gl/GLContextProviderNull.cpp b/gfx/gl/GLContextProviderNull.cpp new file mode 100644 index 0000000000..558abed19f --- /dev/null +++ b/gfx/gl/GLContextProviderNull.cpp @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContextProvider.h" + +namespace mozilla { +namespace gl { + +using namespace mozilla::widget; + +already_AddRefed<GLContext> GLContextProviderNull::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + return nullptr; +} + +already_AddRefed<GLContext> GLContextProviderNull::CreateHeadless( + const GLContextCreateDesc&, nsACString* const out_failureId) { + *out_failureId = "FEATURE_FAILURE_NULL"_ns; + return nullptr; +} + +GLContext* GLContextProviderNull::GetGlobalContext() { return nullptr; } + +void GLContextProviderNull::Shutdown() {} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp new file mode 100644 index 0000000000..9786e31307 --- /dev/null +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -0,0 +1,529 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContextProvider.h" +#include "GLContextWGL.h" +#include "GLLibraryLoader.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include "gfxPlatform.h" +#include "gfxWindowsSurface.h" + +#include "gfxCrashReporterUtils.h" + +#include "prenv.h" + +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/Preferences.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/StaticPrefs_gl.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/layers/CompositorOptions.h" +#include "mozilla/widget/CompositorWidget.h" +#include "mozilla/widget/WinCompositorWidget.h" + +namespace mozilla { +namespace gl { + +using namespace mozilla::gfx; +using namespace mozilla::widget; + +WGLLibrary sWGLLib; + +/* +ScopedWindow::~ScopedWindow() +{ + if (mDC) { + MOZ_ALWAYS_TRUE( ReleaseDC(mDC) ); + } + if (mWindow) { + MOZ_ALWAYS_TRUE( DestroyWindow(mWindow) ); + } +} +*/ +static HWND CreateDummyWindow() { + WNDCLASSW wc{}; + if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) { + wc = {}; + wc.style = CS_OWNDC; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpfnWndProc = DefWindowProc; + wc.lpszClassName = L"GLContextWGLClass"; + if (!RegisterClassW(&wc)) { + NS_WARNING("Failed to register GLContextWGLClass?!"); + // er. failed to register our class? + return nullptr; + } + } + + return CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, 0, 0, 1, 1, + nullptr, nullptr, GetModuleHandle(nullptr), nullptr); +} + +static inline bool HasExtension(const char* aExtensions, + const char* aRequiredExtension) { + return GLContext::ListHasExtension( + reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); +} + +SymbolLoader WGLLibrary::GetSymbolLoader() const { + auto ret = SymbolLoader(*mOGLLibrary); + ret.mPfn = SymbolLoader::GetProcAddressT(mSymbols.fGetProcAddress); + return ret; +} + +bool WGLLibrary::EnsureInitialized() { + if (mInitialized) return true; + + mozilla::ScopedGfxFeatureReporter reporter("WGL"); + + std::wstring libGLFilename = L"Opengl32.dll"; + // SU_SPIES_DIRECTORY is for AMD CodeXL/gDEBugger + if (_wgetenv(L"SU_SPIES_DIRECTORY")) { + libGLFilename = + std::wstring(_wgetenv(L"SU_SPIES_DIRECTORY")) + L"\\opengl32.dll"; + } + + if (!mOGLLibrary) { + mOGLLibrary = LoadLibraryWithFlags(libGLFilename.c_str()); + if (!mOGLLibrary) { + NS_WARNING("Couldn't load OpenGL library."); + return false; + } + } + +#define SYMBOL(X) \ + { \ + (PRFuncPtr*)&mSymbols.f##X, { \ + { "wgl" #X } \ + } \ + } +#define END_OF_SYMBOLS \ + { \ + nullptr, {} \ + } + + { + const auto loader = SymbolLoader(*mOGLLibrary); + const SymLoadStruct earlySymbols[] = {SYMBOL(CreateContext), + SYMBOL(MakeCurrent), + SYMBOL(GetProcAddress), + SYMBOL(DeleteContext), + SYMBOL(GetCurrentContext), + SYMBOL(GetCurrentDC), + END_OF_SYMBOLS}; + + if (!loader.LoadSymbols(earlySymbols)) { + NS_WARNING( + "Couldn't find required entry points in OpenGL DLL (early init)"); + return false; + } + } + + mDummyWindow = CreateDummyWindow(); + MOZ_ASSERT(mDummyWindow); + if (!mDummyWindow) return false; + auto cleanup = MakeScopeExit([&]() { Reset(); }); + + mRootDc = GetDC(mDummyWindow); + MOZ_ASSERT(mRootDc); + if (!mRootDc) return false; + + // -- + + { + PIXELFORMATDESCRIPTOR pfd{}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + // pfd.iPixelType = PFD_TYPE_RGBA; + // pfd.cColorBits = 24; + // pfd.cRedBits = 8; + // pfd.cGreenBits = 8; + // pfd.cBlueBits = 8; + // pfd.cAlphaBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + + const auto pixelFormat = ChoosePixelFormat(mRootDc, &pfd); + MOZ_ASSERT(pixelFormat); + if (!pixelFormat) return false; + const bool setPixelFormatOk = SetPixelFormat(mRootDc, pixelFormat, nullptr); + MOZ_ASSERT(setPixelFormatOk); + if (!setPixelFormatOk) return false; + } + + // -- + + // create rendering context + mDummyGlrc = mSymbols.fCreateContext(mRootDc); + if (!mDummyGlrc) return false; + + const auto curCtx = mSymbols.fGetCurrentContext(); + const auto curDC = mSymbols.fGetCurrentDC(); + + GLContext::ResetTLSCurrentContext(); + + if (!mSymbols.fMakeCurrent(mRootDc, mDummyGlrc)) { + NS_WARNING("wglMakeCurrent failed"); + return false; + } + const auto resetContext = MakeScopeExit([&]() { + GLContext::ResetTLSCurrentContext(); + mSymbols.fMakeCurrent(curDC, curCtx); + }); + + const auto loader = GetSymbolLoader(); + + // Now we can grab all the other symbols that we couldn't without having + // a context current. + // clang-format off + const SymLoadStruct reqExtSymbols[] = { + { (PRFuncPtr*)&mSymbols.fCreatePbuffer, {{ "wglCreatePbufferARB", "wglCreatePbufferEXT" }} }, + { (PRFuncPtr*)&mSymbols.fDestroyPbuffer, {{ "wglDestroyPbufferARB", "wglDestroyPbufferEXT" }} }, + { (PRFuncPtr*)&mSymbols.fGetPbufferDC, {{ "wglGetPbufferDCARB", "wglGetPbufferDCEXT" }} }, + { (PRFuncPtr*)&mSymbols.fReleasePbufferDC, {{ "wglReleasePbufferDCARB", "wglReleasePbufferDCEXT" }} }, + // { (PRFuncPtr*)&mSymbols.fBindTexImage, {{ "wglBindTexImageARB", "wglBindTexImageEXT" }} }, + // { (PRFuncPtr*)&mSymbols.fReleaseTexImage, {{ "wglReleaseTexImageARB", "wglReleaseTexImageEXT" }} }, + { (PRFuncPtr*)&mSymbols.fChoosePixelFormat, {{ "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT" }} }, + // { (PRFuncPtr*)&mSymbols.fGetPixelFormatAttribiv, {{ "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT" }} }, + SYMBOL(GetExtensionsStringARB), + END_OF_SYMBOLS + }; + // clang-format on + if (!loader.LoadSymbols(reqExtSymbols)) { + NS_WARNING("reqExtSymbols missing"); + return false; + } + + // -- + + const auto extString = mSymbols.fGetExtensionsStringARB(mRootDc); + MOZ_ASSERT(extString); + + // -- + + if (HasExtension(extString, "WGL_ARB_create_context")) { + const SymLoadStruct createContextSymbols[] = { + SYMBOL(CreateContextAttribsARB), END_OF_SYMBOLS}; + if (loader.LoadSymbols(createContextSymbols)) { + if (HasExtension(extString, "WGL_ARB_create_context_robustness")) { + mHasRobustness = true; + } + } else { + NS_ERROR( + "WGL_ARB_create_context announced without supplying its functions."); + ClearSymbols(createContextSymbols); + } + } + + // -- + + bool hasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2"); + if (gfxVars::DXInterop2Blocked() && + !StaticPrefs::gl_ignore_dx_interop2_blacklist()) { + hasDXInterop2 = false; + } + + if (hasDXInterop2) { + const SymLoadStruct dxInteropSymbols[] = { + SYMBOL(DXSetResourceShareHandleNV), + SYMBOL(DXOpenDeviceNV), + SYMBOL(DXCloseDeviceNV), + SYMBOL(DXRegisterObjectNV), + SYMBOL(DXUnregisterObjectNV), + SYMBOL(DXObjectAccessNV), + SYMBOL(DXLockObjectsNV), + SYMBOL(DXUnlockObjectsNV), + END_OF_SYMBOLS}; + if (!loader.LoadSymbols(dxInteropSymbols)) { + NS_ERROR( + "WGL_NV_DX_interop2 announceed without supplying its functions."); + ClearSymbols(dxInteropSymbols); + } + } + + // -- + + cleanup.release(); + + mInitialized = true; + + reporter.SetSuccessful(); + return true; +} + +#undef SYMBOL +#undef END_OF_SYMBOLS + +void WGLLibrary::Reset() { + if (mDummyGlrc) { + (void)mSymbols.fDeleteContext(mDummyGlrc); + mDummyGlrc = nullptr; + } + if (mRootDc) { + (void)ReleaseDC(mDummyWindow, mRootDc); + mRootDc = nullptr; + } + if (mDummyWindow) { + (void)DestroyWindow(mDummyWindow); + mDummyWindow = nullptr; + } +} + +GLContextWGL::GLContextWGL(const GLContextDesc& desc, HDC aDC, HGLRC aContext, + HWND aWindow) + : GLContext(desc, nullptr, false), + mDC(aDC), + mContext(aContext), + mWnd(aWindow), + mPBuffer(nullptr), + mPixelFormat(0) {} + +GLContextWGL::GLContextWGL(const GLContextDesc& desc, HANDLE aPbuffer, HDC aDC, + HGLRC aContext, int aPixelFormat) + : GLContext(desc, nullptr, false), + mDC(aDC), + mContext(aContext), + mWnd(nullptr), + mPBuffer(aPbuffer), + mPixelFormat(aPixelFormat) {} + +GLContextWGL::~GLContextWGL() { + MarkDestroyed(); + + (void)sWGLLib.mSymbols.fDeleteContext(mContext); + + if (mPBuffer) { + (void)sWGLLib.mSymbols.fReleasePbufferDC(mPBuffer, mDC); + (void)sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer); + } + if (mWnd) { + (void)ReleaseDC(mWnd, mDC); + DestroyWindow(mWnd); + } +} + +bool GLContextWGL::MakeCurrentImpl() const { + GLContext::ResetTLSCurrentContext(); + + const bool succeeded = sWGLLib.mSymbols.fMakeCurrent(mDC, mContext); + NS_ASSERTION(succeeded, "Failed to make GL context current!"); + return succeeded; +} + +bool GLContextWGL::IsCurrentImpl() const { + return sWGLLib.mSymbols.fGetCurrentContext() == mContext; +} + +bool GLContextWGL::SwapBuffers() { + if (!mIsDoubleBuffered) return false; + return ::SwapBuffers(mDC); +} + +void GLContextWGL::GetWSIInfo(nsCString* const out) const { + out->AppendLiteral("wglGetExtensionsString: "); + out->Append(sWGLLib.mSymbols.fGetExtensionsStringARB(mDC)); +} + +HGLRC +WGLLibrary::CreateContextWithFallback(const HDC dc, + const bool tryRobustBuffers) const { + if (mHasRobustness) { + if (tryRobustBuffers) { + const int attribs[] = {LOCAL_WGL_CONTEXT_FLAGS_ARB, + LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, + LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0}; + const auto context = + mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); + if (context) return context; + } + + const int attribs[] = {LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0}; + const auto context = + mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); + if (context) return context; + } + if (mSymbols.fCreateContextAttribsARB) { + const auto context = + mSymbols.fCreateContextAttribsARB(dc, nullptr, nullptr); + if (context) return context; + } + return mSymbols.fCreateContext(dc); +} + +static RefPtr<GLContext> CreateForWidget(const HWND window, + const bool isWebRender, + const bool requireAccelerated) { + auto& wgl = sWGLLib; + if (!wgl.EnsureInitialized()) return nullptr; + + const auto dc = GetDC(window); + if (!dc) return nullptr; + auto cleanupDc = MakeScopeExit([&]() { (void)ReleaseDC(window, dc); }); + + int chosenFormat; + UINT foundFormats = 0; + + if (!foundFormats) { + const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, + true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, + true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, + true, + LOCAL_WGL_ACCELERATION_ARB, + LOCAL_WGL_FULL_ACCELERATION_ARB, + 0}; + const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, + true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, + true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, + true, + LOCAL_WGL_DEPTH_BITS_ARB, + 24, + LOCAL_WGL_ACCELERATION_ARB, + LOCAL_WGL_FULL_ACCELERATION_ARB, + 0}; + const int* attribs; + if (isWebRender) { + attribs = kAttribsForWebRender; + } else { + attribs = kAttribs; + } + + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1, + &chosenFormat, &foundFormats)) { + foundFormats = 0; + } + } + if (!foundFormats) { + if (requireAccelerated) return nullptr; + + const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, + true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, + true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, + true, + 0}; + const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, + true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, + true, + LOCAL_WGL_DOUBLE_BUFFER_ARB, + true, + LOCAL_WGL_DEPTH_BITS_ARB, + 24, + 0}; + + const int* attribs; + if (isWebRender) { + attribs = kAttribsForWebRender; + } else { + attribs = kAttribs; + } + + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1, + &chosenFormat, &foundFormats)) { + foundFormats = 0; + } + } + if (!foundFormats) return nullptr; + + // We need to make sure we call SetPixelFormat -after- calling + // EnsureInitialized, otherwise it can load/unload the dll and + // wglCreateContext will fail. + + SetPixelFormat(dc, chosenFormat, nullptr); + const auto context = sWGLLib.CreateContextWithFallback(dc, false); + if (!context) return nullptr; + + const RefPtr<GLContextWGL> gl = new GLContextWGL({}, dc, context); + cleanupDc.release(); + gl->mIsDoubleBuffered = true; + if (!gl->Init()) return nullptr; + + return gl; +} + +already_AddRefed<GLContext> GLContextProviderWGL::CreateForCompositorWidget( + CompositorWidget* aCompositorWidget, bool aHardwareWebRender, + bool aForceAccelerated) { + if (!aCompositorWidget) { + MOZ_ASSERT(false); + return nullptr; + } + return CreateForWidget(aCompositorWidget->AsWindows()->GetHwnd(), + aHardwareWebRender, aForceAccelerated) + .forget(); +} + +/*static*/ +already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless( + const GLContextCreateDesc& desc, nsACString* const out_failureId) { + auto& wgl = sWGLLib; + if (!wgl.EnsureInitialized()) return nullptr; + + int chosenFormat; + UINT foundFormats = 0; + + if (!foundFormats) { + const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB, + true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, + true, + LOCAL_WGL_ACCELERATION_ARB, + LOCAL_WGL_FULL_ACCELERATION_ARB, + 0}; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) { + foundFormats = 0; + } + } + if (!foundFormats) { + const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB, true, + LOCAL_WGL_SUPPORT_OPENGL_ARB, true, 0}; + if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, + &chosenFormat, &foundFormats)) { + foundFormats = 0; + } + } + if (!foundFormats) return nullptr; + const int kPbufferAttribs[] = {0}; + const auto pbuffer = wgl.mSymbols.fCreatePbuffer(wgl.RootDc(), chosenFormat, + 1, 1, kPbufferAttribs); + if (!pbuffer) return nullptr; + auto cleanupPbuffer = + MakeScopeExit([&]() { (void)wgl.mSymbols.fDestroyPbuffer(pbuffer); }); + + const auto dc = wgl.mSymbols.fGetPbufferDC(pbuffer); + if (!dc) return nullptr; + auto cleanupDc = MakeScopeExit( + [&]() { (void)wgl.mSymbols.fReleasePbufferDC(pbuffer, dc); }); + + const auto context = wgl.CreateContextWithFallback(dc, true); + if (!context) return nullptr; + + const auto fullDesc = GLContextDesc{desc, true}; + const RefPtr<GLContextWGL> gl = + new GLContextWGL(fullDesc, pbuffer, dc, context, chosenFormat); + cleanupPbuffer.release(); + cleanupDc.release(); + if (!gl->Init()) return nullptr; + + return RefPtr<GLContext>(gl.get()).forget(); +} + +/*static*/ +GLContext* GLContextProviderWGL::GetGlobalContext() { return nullptr; } + +/*static*/ +void GLContextProviderWGL::Shutdown() {} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h new file mode 100644 index 0000000000..ac74f32e14 --- /dev/null +++ b/gfx/gl/GLContextSymbols.h @@ -0,0 +1,467 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTSYMBOLS_H_ +#define GLCONTEXTSYMBOLS_H_ + +#include "GLDefs.h" + +/* + * This file should only be included by GLContext.h, and should be + * autogenerated in the future. + */ + +#ifndef GLAPIENTRY +# ifdef XP_WIN +# define GLAPIENTRY __stdcall +# else +# define GLAPIENTRY +# endif +# define GLAPI +#endif + +namespace mozilla { +namespace gl { + +struct GLContextSymbols final { + void(GLAPIENTRY* fActiveTexture)(GLenum); + void(GLAPIENTRY* fAttachShader)(GLuint, GLuint); + void(GLAPIENTRY* fBeginQuery)(GLenum, GLuint); + void(GLAPIENTRY* fBindAttribLocation)(GLuint, GLuint, const GLchar*); + void(GLAPIENTRY* fBindBuffer)(GLenum, GLuint); + void(GLAPIENTRY* fBindTexture)(GLenum, GLuint); + void(GLAPIENTRY* fBindVertexArray)(GLuint); + void(GLAPIENTRY* fBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fBlendEquation)(GLenum); + void(GLAPIENTRY* fBlendEquationSeparate)(GLenum, GLenum); + void(GLAPIENTRY* fBlendFunc)(GLenum, GLenum); + void(GLAPIENTRY* fBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum); + void(GLAPIENTRY* fBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum); + void(GLAPIENTRY* fBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*); + + void(GLAPIENTRY* fClear)(GLbitfield); + void(GLAPIENTRY* fClearBufferfi)(GLenum, GLint, GLfloat, GLint); + void(GLAPIENTRY* fClearBufferfv)(GLenum, GLint, const GLfloat*); + void(GLAPIENTRY* fClearBufferiv)(GLenum, GLint, const GLint*); + void(GLAPIENTRY* fClearBufferuiv)(GLenum, GLint, const GLuint*); + void(GLAPIENTRY* fClearColor)(GLfloat, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fClearStencil)(GLint); + void(GLAPIENTRY* fColorMask)(realGLboolean, realGLboolean, realGLboolean, + realGLboolean); + void(GLAPIENTRY* fCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, + GLsizei, GLint, GLsizei, + const GLvoid*); + void(GLAPIENTRY* fCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, + GLsizei, GLsizei, GLenum, GLsizei, + const GLvoid*); + void(GLAPIENTRY* fCullFace)(GLenum); + void(GLAPIENTRY* fDetachShader)(GLuint, GLuint); + void(GLAPIENTRY* fDepthFunc)(GLenum); + void(GLAPIENTRY* fDepthMask)(realGLboolean); + void(GLAPIENTRY* fDisable)(GLenum); + void(GLAPIENTRY* fDisableVertexAttribArray)(GLuint); + void(GLAPIENTRY* fDrawArrays)(GLenum, GLint, GLsizei); + void(GLAPIENTRY* fDrawBuffer)(GLenum); + void(GLAPIENTRY* fDrawBuffers)(GLsizei, const GLenum*); + void(GLAPIENTRY* fDrawElements)(GLenum, GLsizei, GLenum, const GLvoid*); + void(GLAPIENTRY* fEnable)(GLenum); + void(GLAPIENTRY* fEnableVertexAttribArray)(GLuint); + void(GLAPIENTRY* fFinish)(void); + void(GLAPIENTRY* fEndQuery)(GLenum); + void(GLAPIENTRY* fFlush)(void); + void(GLAPIENTRY* fFrontFace)(GLenum); + void(GLAPIENTRY* fGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, + GLenum*, GLchar*); + void(GLAPIENTRY* fGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, + GLenum*, GLchar*); + void(GLAPIENTRY* fGetAttachedShaders)(GLuint, GLsizei, GLsizei*, GLuint*); + GLint(GLAPIENTRY* fGetAttribLocation)(GLuint, const GLchar*); + void(GLAPIENTRY* fGetIntegerv)(GLenum, GLint*); + void(GLAPIENTRY* fGetFloatv)(GLenum, GLfloat*); + void(GLAPIENTRY* fGetBooleanv)(GLenum, realGLboolean*); + void(GLAPIENTRY* fGetBufferParameteriv)(GLenum, GLenum, GLint*); + void(GLAPIENTRY* fGenerateMipmap)(GLenum); + GLenum(GLAPIENTRY* fGetError)(void); + void(GLAPIENTRY* fGetProgramiv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*); + void(GLAPIENTRY* fGetQueryiv)(GLenum, GLenum, GLint*); + void(GLAPIENTRY* fGetQueryObjectiv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetQueryObjectuiv)(GLuint, GLenum, GLuint*); + void(GLAPIENTRY* fGetQueryObjecti64v)(GLuint, GLenum, GLint64*); + void(GLAPIENTRY* fGetQueryObjectui64v)(GLuint, GLenum, GLuint64*); + void(GLAPIENTRY* fQueryCounter)(GLuint, GLenum); + void(GLAPIENTRY* fTexParameteri)(GLenum, GLenum, GLint); + void(GLAPIENTRY* fTexParameteriv)(GLenum, GLenum, const GLint*); + void(GLAPIENTRY* fTexParameterf)(GLenum, GLenum, GLfloat); + GLubyte*(GLAPIENTRY* fGetString)(GLenum); + void(GLAPIENTRY* fGetTexImage)(GLenum, GLint, GLenum, GLenum, GLvoid*); + void(GLAPIENTRY* fGetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint*); + void(GLAPIENTRY* fGetTexParameterfv)(GLenum, GLenum, GLfloat*); + void(GLAPIENTRY* fGetTexParameteriv)(GLenum, GLenum, GLint*); + void(GLAPIENTRY* fGetUniformfv)(GLuint, GLint, GLfloat*); + void(GLAPIENTRY* fGetUniformiv)(GLuint, GLint, GLint*); + void(GLAPIENTRY* fGetUniformuiv)(GLuint, GLint, GLuint*); + GLint(GLAPIENTRY* fGetUniformLocation)(GLuint, const GLchar*); + void(GLAPIENTRY* fGetVertexAttribfv)(GLuint, GLenum, GLfloat*); + void(GLAPIENTRY* fGetVertexAttribiv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetVertexAttribPointerv)(GLuint, GLenum, GLvoid**); + void(GLAPIENTRY* fHint)(GLenum, GLenum); + realGLboolean(GLAPIENTRY* fIsBuffer)(GLuint); + realGLboolean(GLAPIENTRY* fIsEnabled)(GLenum); + realGLboolean(GLAPIENTRY* fIsProgram)(GLuint); + realGLboolean(GLAPIENTRY* fIsQuery)(GLuint); + realGLboolean(GLAPIENTRY* fIsShader)(GLuint); + realGLboolean(GLAPIENTRY* fIsTexture)(GLuint); + void(GLAPIENTRY* fLineWidth)(GLfloat); + void(GLAPIENTRY* fLinkProgram)(GLuint); + void(GLAPIENTRY* fPixelStorei)(GLenum, GLint); + void(GLAPIENTRY* fPointParameterf)(GLenum, GLfloat); + void(GLAPIENTRY* fPolygonMode)(GLenum, GLenum); + void(GLAPIENTRY* fPolygonOffset)(GLfloat, GLfloat); + void(GLAPIENTRY* fReadBuffer)(GLenum); + void(GLAPIENTRY* fReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, + GLvoid*); + void(GLAPIENTRY* fSampleCoverage)(GLclampf, realGLboolean); + void(GLAPIENTRY* fStencilFunc)(GLenum, GLint, GLuint); + void(GLAPIENTRY* fStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint); + void(GLAPIENTRY* fStencilMask)(GLuint); + void(GLAPIENTRY* fStencilMaskSeparate)(GLenum, GLuint); + void(GLAPIENTRY* fStencilOp)(GLenum, GLenum, GLenum); + void(GLAPIENTRY* fStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum); + void(GLAPIENTRY* fTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, + GLenum, GLenum, const GLvoid*); + void(GLAPIENTRY* fTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, + GLsizei, GLenum, GLenum, const void*); + void(GLAPIENTRY* fTextureRangeAPPLE)(GLenum, GLsizei, GLvoid*); + void(GLAPIENTRY* fFinishObjectAPPLE)(GLenum, GLint); + realGLboolean(GLAPIENTRY* fTestObjectAPPLE)(GLenum, GLint); + void(GLAPIENTRY* fUniform1f)(GLint, GLfloat); + void(GLAPIENTRY* fUniform1fv)(GLint, GLsizei, const GLfloat*); + void(GLAPIENTRY* fUniform1i)(GLint, GLint); + void(GLAPIENTRY* fUniform1iv)(GLint, GLsizei, const GLint*); + void(GLAPIENTRY* fUniform2f)(GLint, GLfloat, GLfloat); + void(GLAPIENTRY* fUniform2fv)(GLint, GLsizei, const GLfloat*); + void(GLAPIENTRY* fUniform2i)(GLint, GLint, GLint); + void(GLAPIENTRY* fUniform2iv)(GLint, GLsizei, const GLint*); + void(GLAPIENTRY* fUniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fUniform3fv)(GLint, GLsizei, const GLfloat*); + void(GLAPIENTRY* fUniform3i)(GLint, GLint, GLint, GLint); + void(GLAPIENTRY* fUniform3iv)(GLint, GLsizei, const GLint*); + void(GLAPIENTRY* fUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fUniform4fv)(GLint, GLsizei, const GLfloat*); + void(GLAPIENTRY* fUniform4i)(GLint, GLint, GLint, GLint, GLint); + void(GLAPIENTRY* fUniform4iv)(GLint, GLsizei, const GLint*); + void(GLAPIENTRY* fUniformMatrix2fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix2x3fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix2x4fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix3fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix3x2fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix3x4fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix4fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix4x2fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + void(GLAPIENTRY* fUniformMatrix4x3fv)(GLint, GLsizei, realGLboolean, + const GLfloat*); + + void(GLAPIENTRY* fUseProgram)(GLuint); + void(GLAPIENTRY* fValidateProgram)(GLuint); + void(GLAPIENTRY* fVertexAttribPointer)(GLuint, GLint, GLenum, realGLboolean, + GLsizei, const GLvoid*); + void(GLAPIENTRY* fVertexAttrib1f)(GLuint, GLfloat); + void(GLAPIENTRY* fVertexAttrib2f)(GLuint, GLfloat, GLfloat); + void(GLAPIENTRY* fVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat); + void(GLAPIENTRY* fVertexAttrib1fv)(GLuint, const GLfloat*); + void(GLAPIENTRY* fVertexAttrib2fv)(GLuint, const GLfloat*); + void(GLAPIENTRY* fVertexAttrib3fv)(GLuint, const GLfloat*); + void(GLAPIENTRY* fVertexAttrib4fv)(GLuint, const GLfloat*); + void(GLAPIENTRY* fCompileShader)(GLuint); + void(GLAPIENTRY* fCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, + GLsizei, GLsizei, GLint); + void(GLAPIENTRY* fCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, + GLint, GLsizei, GLsizei); + void(GLAPIENTRY* fGetShaderiv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*); + void(GLAPIENTRY* fGetShaderPrecisionFormat)(GLenum, GLenum, GLint*, GLint*); + void(GLAPIENTRY* fGetShaderSource)(GLint, GLsizei, GLsizei*, GLchar*); + void(GLAPIENTRY* fShaderSource)(GLuint, GLsizei, const GLchar* const*, + const GLint*); + + void(GLAPIENTRY* fBindFramebuffer)(GLenum, GLuint); + void(GLAPIENTRY* fBindRenderbuffer)(GLenum, GLuint); + GLenum(GLAPIENTRY* fCheckFramebufferStatus)(GLenum); + void(GLAPIENTRY* fFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint); + void(GLAPIENTRY* fFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, + GLint); + void(GLAPIENTRY* fFramebufferTextureLayer)(GLenum, GLenum, GLuint, GLint, + GLint); + void(GLAPIENTRY* fGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, + GLint*); + void(GLAPIENTRY* fGetRenderbufferParameteriv)(GLenum, GLenum, GLint*); + realGLboolean(GLAPIENTRY* fIsFramebuffer)(GLuint); + realGLboolean(GLAPIENTRY* fIsRenderbuffer)(GLuint); + realGLboolean(GLAPIENTRY* fIsVertexArray)(GLuint); + void(GLAPIENTRY* fRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei); + + void(GLAPIENTRY* fInvalidateFramebuffer)(GLenum, GLsizei, const GLenum*); + void(GLAPIENTRY* fInvalidateSubFramebuffer)(GLenum, GLsizei, const GLenum*, + GLint, GLint, GLsizei, GLsizei); + + // These functions are only used by Skia/GL in desktop mode. + // Other parts of Gecko should avoid using these + void(GLAPIENTRY* fClientActiveTexture)(GLenum); + void(GLAPIENTRY* fDisableClientState)(GLenum); + void(GLAPIENTRY* fEnableClientState)(GLenum); + void(GLAPIENTRY* fLoadIdentity)(void); + void(GLAPIENTRY* fLoadMatrixd)(const GLdouble*); + void(GLAPIENTRY* fLoadMatrixf)(const GLfloat*); + void(GLAPIENTRY* fMatrixMode)(GLenum); + void(GLAPIENTRY* fTexGeni)(GLenum, GLenum, GLint); + void(GLAPIENTRY* fTexGenf)(GLenum, GLenum, GLfloat); + void(GLAPIENTRY* fTexGenfv)(GLenum, GLenum, const GLfloat*); + void(GLAPIENTRY* fVertexPointer)(GLint, GLenum, GLsizei, const GLvoid*); + + void(GLAPIENTRY* fBlitFramebuffer)(GLint, GLint, GLint, GLint, GLint, GLint, + GLint, GLint, GLbitfield, GLenum); + void(GLAPIENTRY* fRenderbufferStorageMultisample)(GLenum, GLsizei, GLenum, + GLsizei, GLsizei); + + /* These are different between GLES2 and desktop GL; we hide those + * differences, use the GL names, but the most limited data type. + */ + void(GLAPIENTRY* fDepthRangef)(GLclampf, GLclampf); + void(GLAPIENTRY* fClearDepthf)(GLclampf); + + void(GLAPIENTRY* fDepthRange)(GLclampd, GLclampd); + void(GLAPIENTRY* fClearDepth)(GLclampd); + + /* These are special because we end up tracking these so that we don't + * have to query the values from GL. + */ + + void(GLAPIENTRY* fViewport)(GLint, GLint, GLsizei, GLsizei); + void(GLAPIENTRY* fScissor)(GLint, GLint, GLsizei, GLsizei); + + /* These are special -- they create or delete GL resources that can live + * in a shared namespace. In DEBUG, we wrap these calls so that we can + * check when we have something that failed to do cleanup at the time the + * final context is destroyed. + */ + + GLuint(GLAPIENTRY* fCreateProgram)(); + GLuint(GLAPIENTRY* fCreateShader)(GLenum); + void(GLAPIENTRY* fGenBuffers)(GLsizei, GLuint*); + void(GLAPIENTRY* fGenQueries)(GLsizei, GLuint*); + void(GLAPIENTRY* fGenTextures)(GLsizei, GLuint*); + void(GLAPIENTRY* fGenFramebuffers)(GLsizei, GLuint*); + void(GLAPIENTRY* fGenRenderbuffers)(GLsizei, GLuint*); + void(GLAPIENTRY* fGenVertexArrays)(GLsizei, GLuint*); + + void(GLAPIENTRY* fDeleteProgram)(GLuint); + void(GLAPIENTRY* fDeleteShader)(GLuint); + void(GLAPIENTRY* fDeleteBuffers)(GLsizei, const GLuint*); + void(GLAPIENTRY* fDeleteQueries)(GLsizei, const GLuint*); + void(GLAPIENTRY* fDeleteTextures)(GLsizei, const GLuint*); + void(GLAPIENTRY* fDeleteFramebuffers)(GLsizei, const GLuint*); + void(GLAPIENTRY* fDeleteRenderbuffers)(GLsizei, const GLuint*); + void(GLAPIENTRY* fDeleteVertexArrays)(GLsizei, const GLuint*); + + void*(GLAPIENTRY* fMapBuffer)(GLenum, GLenum); + realGLboolean(GLAPIENTRY* fUnmapBuffer)(GLenum); + + // ARB_copy_buffer / OpenGL 3.1 / OpenGL ES 3.0 + void(GLAPIENTRY* fCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, + GLsizeiptr); + + GLenum(GLAPIENTRY* fGetGraphicsResetStatus)(); + + // ARB_sync + GLsync(GLAPIENTRY* fFenceSync)(GLenum, GLbitfield); + realGLboolean(GLAPIENTRY* fIsSync)(GLsync); + void(GLAPIENTRY* fDeleteSync)(GLsync); + GLenum(GLAPIENTRY* fClientWaitSync)(GLsync, GLbitfield, GLuint64); + void(GLAPIENTRY* fWaitSync)(GLsync, GLbitfield, GLuint64); + void(GLAPIENTRY* fGetInteger64v)(GLenum, GLint64*); + void(GLAPIENTRY* fGetSynciv)(GLsync, GLenum, GLsizei, GLsizei*, GLint*); + + // OES_egl_image + void(GLAPIENTRY* fEGLImageTargetTexture2D)(GLenum, GLeglImage); + void(GLAPIENTRY* fEGLImageTargetRenderbufferStorage)(GLenum, GLeglImage); + + // ARB_draw_instanced + void(GLAPIENTRY* fDrawArraysInstanced)(GLenum, GLint, GLsizei, GLsizei); + void(GLAPIENTRY* fDrawElementsInstanced)(GLenum, GLsizei, GLenum, + const GLvoid*, GLsizei); + + // ARB_instanced_array + void(GLAPIENTRY* fVertexAttribDivisor)(GLuint, GLuint); + + // ARB_internalformat_query + void(GLAPIENTRY* fGetInternalformativ)(GLenum, GLenum, GLenum, GLsizei, + GLint*); + + // ARB_transform_feedback2 / OpenGL 4.0 / OpenGL ES 3.0 + void(GLAPIENTRY* fBindBufferBase)(GLenum, GLuint, GLuint); + void(GLAPIENTRY* fBindBufferRange)(GLenum, GLuint, GLuint, GLintptr, + GLsizeiptr); + + void(GLAPIENTRY* fGenTransformFeedbacks)(GLsizei, GLuint*); + void(GLAPIENTRY* fDeleteTransformFeedbacks)(GLsizei, const GLuint*); + realGLboolean(GLAPIENTRY* fIsTransformFeedback)(GLuint); + void(GLAPIENTRY* fBindTransformFeedback)(GLenum, GLuint); + void(GLAPIENTRY* fTransformFeedbackVaryings)(GLuint, GLsizei, + const GLchar* const*, GLenum); + void(GLAPIENTRY* fGetTransformFeedbackVarying)(GLuint, GLuint, GLsizei, + GLsizei*, GLsizei*, GLenum*, + GLchar*); + void(GLAPIENTRY* fBeginTransformFeedback)(GLenum); + void(GLAPIENTRY* fEndTransformFeedback)(void); + void(GLAPIENTRY* fPauseTransformFeedback)(void); + void(GLAPIENTRY* fResumeTransformFeedback)(void); + + void(GLAPIENTRY* fGetIntegeri_v)(GLenum, GLuint, GLint*); + void(GLAPIENTRY* fGetInteger64i_v)(GLenum, GLuint, GLint64*); + + // EXT_transform_feedback only + void(GLAPIENTRY* fBindBufferOffset)(GLenum, GLuint, GLuint, GLintptr); + + // KHR_debug + void(GLAPIENTRY* fDebugMessageControl)(GLenum, GLenum, GLenum, GLsizei, + const GLuint*, realGLboolean); + void(GLAPIENTRY* fDebugMessageInsert)(GLenum, GLenum, GLuint, GLenum, GLsizei, + const GLchar*); + void(GLAPIENTRY* fDebugMessageCallback)(GLDEBUGPROC, const GLvoid*); + GLuint(GLAPIENTRY* fGetDebugMessageLog)(GLuint, GLsizei, GLenum*, GLenum*, + GLuint*, GLenum*, GLsizei*, GLchar*); + void(GLAPIENTRY* fGetPointerv)(GLenum, GLvoid**); + void(GLAPIENTRY* fPushDebugGroup)(GLenum, GLuint, GLsizei, const GLchar*); + void(GLAPIENTRY* fPopDebugGroup)(void); + void(GLAPIENTRY* fObjectLabel)(GLenum, GLuint, GLsizei, const GLchar*); + void(GLAPIENTRY* fGetObjectLabel)(GLenum, GLuint, GLsizei, GLsizei*, GLchar*); + void(GLAPIENTRY* fObjectPtrLabel)(const GLvoid*, GLsizei, const GLchar*); + void(GLAPIENTRY* fGetObjectPtrLabel)(const GLvoid*, GLsizei, GLsizei*, + GLchar*); + + // NV_fence + void(GLAPIENTRY* fGenFences)(GLsizei, GLuint*); + void(GLAPIENTRY* fDeleteFences)(GLsizei, const GLuint*); + void(GLAPIENTRY* fSetFence)(GLuint, GLenum); + realGLboolean(GLAPIENTRY* fTestFence)(GLuint); + void(GLAPIENTRY* fFinishFence)(GLuint); + realGLboolean(GLAPIENTRY* fIsFence)(GLuint); + void(GLAPIENTRY* fGetFenceiv)(GLuint, GLenum, GLint*); + + // map_buffer_range + void*(GLAPIENTRY* fMapBufferRange)(GLenum, GLintptr, GLsizeiptr, GLbitfield); + void(GLAPIENTRY* fFlushMappedBufferRange)(GLenum, GLintptr, GLsizeiptr); + + // sampler_object + void(GLAPIENTRY* fGenSamplers)(GLsizei, GLuint*); + void(GLAPIENTRY* fDeleteSamplers)(GLsizei, const GLuint*); + realGLboolean(GLAPIENTRY* fIsSampler)(GLuint); + void(GLAPIENTRY* fBindSampler)(GLuint, GLuint); + void(GLAPIENTRY* fSamplerParameteri)(GLuint, GLenum, GLint); + void(GLAPIENTRY* fSamplerParameteriv)(GLuint, GLenum, const GLint*); + void(GLAPIENTRY* fSamplerParameterf)(GLuint, GLenum, GLfloat); + void(GLAPIENTRY* fSamplerParameterfv)(GLuint, GLenum, const GLfloat*); + void(GLAPIENTRY* fGetSamplerParameteriv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetSamplerParameterfv)(GLuint, GLenum, GLfloat*); + + // texture_storage + void(GLAPIENTRY* fTexStorage2D)(GLenum, GLsizei, GLenum, GLsizei, GLsizei); + void(GLAPIENTRY* fTexStorage3D)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, + GLsizei); + + // uniform_buffer_object + void(GLAPIENTRY* fGetUniformIndices)(GLuint, GLsizei, const GLchar* const*, + GLuint*); + void(GLAPIENTRY* fGetActiveUniformsiv)(GLuint, GLsizei, const GLuint*, GLenum, + GLint*); + GLuint(GLAPIENTRY* fGetUniformBlockIndex)(GLuint, const GLchar*); + void(GLAPIENTRY* fGetActiveUniformBlockiv)(GLuint, GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetActiveUniformBlockName)(GLuint, GLuint, GLsizei, + GLsizei*, GLchar*); + void(GLAPIENTRY* fUniformBlockBinding)(GLuint, GLuint, GLuint); + + // EXT_gpu_shader4 + void(GLAPIENTRY* fGetVertexAttribIiv)(GLuint, GLenum, GLint*); + void(GLAPIENTRY* fGetVertexAttribIuiv)(GLuint, GLenum, GLuint*); + void(GLAPIENTRY* fVertexAttribI4i)(GLuint, GLint, GLint, GLint, GLint); + void(GLAPIENTRY* fVertexAttribI4iv)(GLuint, const GLint*); + void(GLAPIENTRY* fVertexAttribI4ui)(GLuint, GLuint, GLuint, GLuint, GLuint); + void(GLAPIENTRY* fVertexAttribI4uiv)(GLuint, const GLuint*); + void(GLAPIENTRY* fVertexAttribIPointer)(GLuint, GLint, GLenum, GLsizei, + const GLvoid*); + void(GLAPIENTRY* fUniform1ui)(GLint, GLuint); + void(GLAPIENTRY* fUniform2ui)(GLint, GLuint, GLuint); + void(GLAPIENTRY* fUniform3ui)(GLint, GLuint, GLuint, GLuint); + void(GLAPIENTRY* fUniform4ui)(GLint, GLuint, GLuint, GLuint, GLuint); + void(GLAPIENTRY* fUniform1uiv)(GLint, GLsizei, const GLuint*); + void(GLAPIENTRY* fUniform2uiv)(GLint, GLsizei, const GLuint*); + void(GLAPIENTRY* fUniform3uiv)(GLint, GLsizei, const GLuint*); + void(GLAPIENTRY* fUniform4uiv)(GLint, GLsizei, const GLuint*); + GLint(GLAPIENTRY* fGetFragDataLocation)(GLuint, const GLchar*); + + // 3D Textures + void(GLAPIENTRY* fTexImage3D)(GLenum, GLint, GLenum, GLenum, GLsizei, GLsizei, + GLint, GLenum, GLenum, const GLvoid*); + + void(GLAPIENTRY* fTexSubImage3D)(GLenum, GLint, GLint, GLint, GLint, GLsizei, + GLsizei, GLsizei, GLenum, GLenum, + const GLvoid*); + + void(GLAPIENTRY* fCopyTexSubImage3D)(GLenum, GLint, GLint, GLint, GLint, + GLint, GLint, GLsizei, GLsizei); + + void(GLAPIENTRY* fCompressedTexImage3D)(GLenum, GLint, GLenum, GLsizei, + GLsizei, GLsizei, GLint, GLsizei, + const GLvoid*); + + void(GLAPIENTRY* fCompressedTexSubImage3D)(GLenum, GLint, GLint, GLint, GLint, + GLsizei, GLsizei, GLsizei, GLenum, + GLsizei, const GLvoid*); + + // get_string_indexed + const GLubyte*(GLAPIENTRY* fGetStringi)(GLenum, GLuint); + + // APPLE_framebuffer_multisample + void(GLAPIENTRY* fResolveMultisampleFramebufferAPPLE)(void); + + // NV_texture_barrier + void(GLAPIENTRY* fTextureBarrier)(void); + + // NV_primitive_restart + void(GLAPIENTRY* fPrimitiveRestartIndex)(GLuint); + + // OVR_multiview2 + void(GLAPIENTRY* fFramebufferTextureMultiview)(GLenum target, + GLenum attachment, + GLuint texture, GLint level, + GLint baseViewIndex, + GLsizei numViews); + + // draw_buffers_indexed + void(GLAPIENTRY* fBlendEquationSeparatei)(GLuint, GLenum, GLenum); + void(GLAPIENTRY* fBlendFuncSeparatei)(GLuint, GLenum, GLenum, GLenum, GLenum); + void(GLAPIENTRY* fColorMaski)(GLuint, realGLboolean, realGLboolean, + realGLboolean, realGLboolean); + void(GLAPIENTRY* fDisablei)(GLenum, GLuint); + void(GLAPIENTRY* fEnablei)(GLenum, GLuint); + + // provoking_vertex + void(GLAPIENTRY* fProvokingVertex)(GLenum); +}; + +} // namespace gl +} // namespace mozilla + +#endif /* GLCONTEXTSYMBOLS_H_ */ diff --git a/gfx/gl/GLContextTypes.h b/gfx/gl/GLContextTypes.h new file mode 100644 index 0000000000..09ea3c21a7 --- /dev/null +++ b/gfx/gl/GLContextTypes.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXT_TYPES_H_ +#define GLCONTEXT_TYPES_H_ + +#include "GLTypes.h" +#include "mozilla/DefineEnum.h" +#include "mozilla/TypedEnumBits.h" + +namespace mozilla { +namespace gl { + +class GLContext; + +enum class GLContextType { Unknown, WGL, CGL, GLX, EGL, EAGL }; + +enum class OriginPos : uint8_t { TopLeft, BottomLeft }; + +enum class CreateContextFlags : uint16_t { + NONE = 0, + REQUIRE_COMPAT_PROFILE = 1 << 0, + // Force the use of hardware backed GL, don't allow software implementations. + FORBID_SOFTWARE = 1 << 1, + /* Don't force discrete GPU to be used (if applicable) */ + ALLOW_OFFLINE_RENDERER = 1 << 2, + // Ask for ES3 if possible + PREFER_ES3 = 1 << 3, + + NO_VALIDATION = 1 << 4, + PREFER_ROBUSTNESS = 1 << 5, + HIGH_POWER = 1 << 6, + PROVOKING_VERTEX_DONT_CARE = 1 << 7, + PREFER_EXACT_VERSION = 1 << 8, + PREFER_MULTITHREADED = 1 << 9, + + FORBID_HARDWARE = 1 << 10, +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) + +struct GLContextCreateDesc { + CreateContextFlags flags = CreateContextFlags::NONE; +}; + +struct GLContextDesc final : public GLContextCreateDesc { + bool isOffscreen = false; +}; + +// - + +MOZ_DEFINE_ENUM_CLASS_WITH_BASE(GLVendor, uint8_t, + (Intel, NVIDIA, ATI, Qualcomm, Imagination, + Nouveau, Vivante, VMware, ARM, Other)); + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* GLCONTEXT_TYPES_H_ */ diff --git a/gfx/gl/GLContextWGL.h b/gfx/gl/GLContextWGL.h new file mode 100644 index 0000000000..9a86031d46 --- /dev/null +++ b/gfx/gl/GLContextWGL.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXTWGL_H_ +#define GLCONTEXTWGL_H_ + +#include "GLContext.h" +#include "WGLLibrary.h" + +namespace mozilla { +namespace gl { + +class GLContextWGL final : public GLContext { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextWGL, override) + // From Window: (possibly for offscreen!) + GLContextWGL(const GLContextDesc&, HDC aDC, HGLRC aContext, + HWND aWindow = nullptr); + + // From PBuffer + GLContextWGL(const GLContextDesc&, HANDLE aPbuffer, HDC aDC, HGLRC aContext, + int aPixelFormat); + + ~GLContextWGL(); + + virtual GLContextType GetContextType() const override { + return GLContextType::WGL; + } + + virtual bool MakeCurrentImpl() const override; + virtual bool IsCurrentImpl() const override; + virtual bool IsDoubleBuffered() const override { return mIsDoubleBuffered; } + virtual bool SwapBuffers() override; + virtual void GetWSIInfo(nsCString* const out) const override; + + Maybe<SymbolLoader> GetSymbolLoader() const override { + return Some(sWGLLib.GetSymbolLoader()); + } + + HGLRC Context() { return mContext; } + + protected: + friend class GLContextProviderWGL; + + HDC mDC; + HGLRC mContext; + HWND mWnd; + HANDLE mPBuffer; + int mPixelFormat; + + public: + bool mIsDoubleBuffered = false; +}; + +} // namespace gl +} // namespace mozilla + +#endif // GLCONTEXTWGL_H_ diff --git a/gfx/gl/GLDebugUtils.cpp b/gfx/gl/GLDebugUtils.cpp new file mode 100644 index 0000000000..463ecf2730 --- /dev/null +++ b/gfx/gl/GLDebugUtils.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLDebugUtils.h" +#include "GLConsts.h" + +namespace mozilla { +namespace gl { + +const char* GLenumToStr(GLenum e) { + switch (e) { +#define HANDLE_GL_ENUM(x) \ + case LOCAL_##x: \ + return #x + HANDLE_GL_ENUM(GL_TRIANGLES); + HANDLE_GL_ENUM(GL_TRIANGLE_STRIP); + HANDLE_GL_ENUM(GL_TRIANGLE_FAN); + HANDLE_GL_ENUM(GL_FRAMEBUFFER); + HANDLE_GL_ENUM(GL_RENDERBUFFER); + HANDLE_GL_ENUM(GL_DEPTH_ATTACHMENT); + HANDLE_GL_ENUM(GL_STENCIL_ATTACHMENT); + HANDLE_GL_ENUM(GL_DEPTH_STENCIL_ATTACHMENT); + HANDLE_GL_ENUM(GL_TEXTURE_2D); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_X); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_X); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Y); + HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Z); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT0); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT1); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT2); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT3); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT4); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT5); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT6); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT7); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT8); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT9); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT10); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT11); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT12); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT13); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT14); + HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT15); + HANDLE_GL_ENUM(GL_UNSIGNED_BYTE); + HANDLE_GL_ENUM(GL_UNSIGNED_SHORT); + HANDLE_GL_ENUM(GL_UNSIGNED_INT); + HANDLE_GL_ENUM(GL_RGBA); + HANDLE_GL_ENUM(GL_DEPTH_COMPONENT); +#undef HANDLE_GL_ENUM + } + + return "(unknown)"; +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLDebugUtils.h b/gfx/gl/GLDebugUtils.h new file mode 100644 index 0000000000..d817d060dd --- /dev/null +++ b/gfx/gl/GLDebugUtils.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLDEBUGUTILS_H_ +#define GLDEBUGUTILS_H_ + +#include "GLTypes.h" + +namespace mozilla { +namespace gl { + +const char* GLenumToStr(GLenum e); + +} // namespace gl +} // namespace mozilla + +#endif // !GLDEBUGUTILS_H_ diff --git a/gfx/gl/GLDefs.h b/gfx/gl/GLDefs.h new file mode 100644 index 0000000000..56f8031493 --- /dev/null +++ b/gfx/gl/GLDefs.h @@ -0,0 +1,110 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined(LOCALGL_H_) +# define LOCALGL_H_ + +# include "GLTypes.h" +# include "GLConsts.h" + +namespace mozilla { +namespace gl { +class GLContext; +bool CheckContextLost(const GLContext* gl); +} // namespace gl +} // namespace mozilla + +# define MOZ_GL_ASSERT(glContext, expr) \ + MOZ_ASSERT((expr) || mozilla::gl::CheckContextLost(glContext)) + +// - + +// clang-format off + +// TODO: use official constant names instead of followed ones. + +// IMG_texture_compression_pvrtc +#define LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 0x8C00 +#define LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 0x8C01 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1 0x8C02 +#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 0x8C03 + +// OES_EGL_image_external +#define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 +#define LOCAL_GL_TEXTURE_BINDING_EXTERNAL 0x8D67 + +// AMD_compressed_ATC_texture +#define LOCAL_GL_ATC_RGB 0x8C92 +#define LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA 0x8C93 +#define LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA 0x87EE + +// EGL_ANDROID_image_crop +#define LOCAL_EGL_IMAGE_CROP_LEFT_ANDROID 0x3148 +#define LOCAL_EGL_IMAGE_CROP_TOP_ANDROID 0x3149 +#define LOCAL_EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A +#define LOCAL_EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B + +// EGL_ANGLE_platform_angle +#define LOCAL_EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define LOCAL_EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 +#define LOCAL_EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206 +#define LOCAL_EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451 + +// EGL_ANGLE_keyed_mutex +#define LOCAL_EGL_DXGI_KEYED_MUTEX_ANGLE 0x33A2 + +// EGL_ANGLE_stream_producer_d3d_texture +#define LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB + +// EGL_ANGLE_platform_angle_d3d +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 +#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A +#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B +#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C +#define LOCAL_EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F + +// EGL_ANGLE_d3d_texture_client_buffer +#define LOCAL_EGL_D3D_TEXTURE_ANGLE 0x33A3 + +// EGL_ANGLE_flexible_surface_compatibility +#define LOCAL_EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 + +// EGL_ANGLE_experimental_present_path +#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4 +#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9 +#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE 0x33AA + +// EGL_ANGLE_direct3d_display +#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2) +#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3) + +// EGL_ANGLE_feature_control +#define LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466 + +// WGL_NV_DX_interop +#define LOCAL_WGL_ACCESS_READ_ONLY 0x0000 +#define LOCAL_WGL_ACCESS_READ_WRITE 0x0001 +#define LOCAL_WGL_ACCESS_WRITE_DISCARD 0x0002 + +// Others +#define LOCAL_EGL_PRESERVED_RESOURCES 0x3030 +#define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + +// EGL_ANGLE_create_context_backwards_compatible +#define LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE 0x3483 + +// EGL_ANGLE_image_d3d11_texture +#define LOCAL_EGL_D3D11_TEXTURE_ANGLE 0x3484 + +// clang-format on + +#endif diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp new file mode 100644 index 0000000000..e27081dc95 --- /dev/null +++ b/gfx/gl/GLLibraryEGL.cpp @@ -0,0 +1,1079 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLLibraryEGL.h" + +#include "gfxConfig.h" +#include "gfxCrashReporterUtils.h" +#include "gfxEnv.h" +#include "gfxUtils.h" +#include "mozilla/Preferences.h" +#include "mozilla/Assertions.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/Telemetry.h" +#include "mozilla/Tokenizer.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "mozilla/Unused.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsPrintfCString.h" +#ifdef XP_WIN +# include "mozilla/gfx/DeviceManagerDx.h" +# include "nsWindowsHelpers.h" +# include "prerror.h" + +# include <d3d11.h> +#endif +#include "OGLShaderProgram.h" +#include "prenv.h" +#include "prsystem.h" +#include "GLContext.h" +#include "GLContextProvider.h" +#include "GLLibraryLoader.h" +#include "GLReadTexImageHelper.h" +#include "ScopedGLHelpers.h" +#ifdef MOZ_WIDGET_GTK +# include "mozilla/WidgetUtilsGtk.h" +# include "mozilla/widget/DMABufLibWrapper.h" +# ifdef MOZ_WAYLAND +# include "mozilla/widget/nsWaylandDisplay.h" +# endif // MOZ_WIDGET_GTK +# include <gdk/gdk.h> +#endif // MOZ_WAYLAND + +#include <mutex> // for call_once + +namespace mozilla { +namespace gl { + +StaticMutex GLLibraryEGL::sMutex; +StaticRefPtr<GLLibraryEGL> GLLibraryEGL::sInstance; + +// should match the order of EGLExtensions, and be null-terminated. +static const char* sEGLLibraryExtensionNames[] = { + "EGL_ANDROID_get_native_client_buffer", + "EGL_ANGLE_device_creation", + "EGL_ANGLE_device_creation_d3d11", + "EGL_ANGLE_platform_angle", + "EGL_ANGLE_platform_angle_d3d", + "EGL_EXT_device_enumeration", + "EGL_EXT_device_query", + "EGL_EXT_platform_device", + "EGL_MESA_platform_surfaceless"}; + +// should match the order of EGLExtensions, and be null-terminated. +static const char* sEGLExtensionNames[] = { + "EGL_KHR_image_base", + "EGL_KHR_image_pixmap", + "EGL_KHR_gl_texture_2D_image", + "EGL_ANGLE_surface_d3d_texture_2d_share_handle", + "EGL_EXT_create_context_robustness", + "EGL_KHR_image", + "EGL_KHR_fence_sync", + "EGL_KHR_wait_sync", + "EGL_ANDROID_native_fence_sync", + "EGL_ANDROID_image_crop", + "EGL_ANGLE_d3d_share_handle_client_buffer", + "EGL_KHR_create_context", + "EGL_KHR_stream", + "EGL_KHR_stream_consumer_gltexture", + "EGL_NV_stream_consumer_gltexture_yuv", + "EGL_ANGLE_stream_producer_d3d_texture", + "EGL_KHR_surfaceless_context", + "EGL_KHR_create_context_no_error", + "EGL_MOZ_create_context_provoking_vertex_dont_care", + "EGL_EXT_swap_buffers_with_damage", + "EGL_KHR_swap_buffers_with_damage", + "EGL_EXT_buffer_age", + "EGL_KHR_partial_update", + "EGL_NV_robustness_video_memory_purge", + "EGL_EXT_image_dma_buf_import", + "EGL_EXT_image_dma_buf_import_modifiers", + "EGL_MESA_image_dma_buf_export", + "EGL_KHR_no_config_context", +}; + +PRLibrary* LoadApitraceLibrary() { + const char* path = nullptr; + +#ifdef ANDROID + // We only need to explicitly dlopen egltrace + // on android as we can use LD_PRELOAD or other tricks + // on other platforms. We look for it in /data/local + // as that's writeable by all users. + path = "/data/local/tmp/egltrace.so"; +#endif + if (!path) return nullptr; + + // Initialization of gfx prefs here is only needed during the unit tests... + if (!StaticPrefs::gfx_apitrace_enabled_AtStartup()) { + return nullptr; + } + + static PRLibrary* sApitraceLibrary = nullptr; + if (sApitraceLibrary) return sApitraceLibrary; + + nsAutoCString logFile; + Preferences::GetCString("gfx.apitrace.logfile", logFile); + if (logFile.IsEmpty()) { + logFile = "firefox.trace"; + } + + // The firefox process can't write to /data/local, but it can write + // to $GRE_HOME/ + nsAutoCString logPath; + logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get()); + +#ifndef XP_WIN // Windows is missing setenv and forbids PR_LoadLibrary. + // apitrace uses the TRACE_FILE environment variable to determine where + // to log trace output to + printf_stderr("Logging GL tracing output to %s", logPath.get()); + setenv("TRACE_FILE", logPath.get(), false); + + printf_stderr("Attempting load of %s\n", path); + sApitraceLibrary = PR_LoadLibrary(path); +#endif + + return sApitraceLibrary; +} + +#ifdef XP_WIN +// see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here. +static PRLibrary* LoadLibraryForEGLOnWindows(const nsAString& filename) { + nsAutoString path(gfx::gfxVars::GREDirectory()); + path.Append(PR_GetDirectorySeparator()); + path.Append(filename); + + PRLibSpec lspec; + lspec.type = PR_LibSpec_PathnameU; + lspec.value.pathname_u = path.get(); + PRLibrary* lib = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL); + if (!lib) { + gfxCriticalNote << "Failed to load " << path.get() << " " << PR_GetError() + << " " << PR_GetOSError(); + } + return lib; +} + +#endif // XP_WIN + +static std::shared_ptr<EglDisplay> GetAndInitDisplay( + GLLibraryEGL& egl, void* displayType, + const StaticMutexAutoLock& aProofOfLock) { + const auto display = egl.fGetDisplay(displayType); + if (!display) return nullptr; + return EglDisplay::Create(egl, display, false, aProofOfLock); +} + +#ifdef MOZ_WIDGET_GTK +static std::shared_ptr<EglDisplay> GetAndInitDeviceDisplay( + GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) { + nsAutoCString drmRenderDevice(gfx::gfxVars::DrmRenderDevice()); + if (drmRenderDevice.IsEmpty() || + !egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) || + !egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) { + return nullptr; + } + + EGLint maxDevices; + if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) { + return nullptr; + } + + std::vector<EGLDeviceEXT> devices(maxDevices); + EGLint numDevices; + if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) { + return nullptr; + } + devices.resize(numDevices); + + EGLDisplay display = EGL_NO_DISPLAY; + for (const auto& device : devices) { + const char* renderNodeString = + egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT); + if (renderNodeString && + strcmp(renderNodeString, drmRenderDevice.get()) == 0) { + const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE}; + display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device, + attrib_list); + break; + } + } + if (!display) { + return nullptr; + } + + return EglDisplay::Create(egl, display, true, aProofOfLock); +} + +static std::shared_ptr<EglDisplay> GetAndInitSoftwareDisplay( + GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) { + if (!egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) || + !egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) { + return nullptr; + } + + EGLint maxDevices; + if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) { + return nullptr; + } + + std::vector<EGLDeviceEXT> devices(maxDevices); + EGLint numDevices; + if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) { + return nullptr; + } + devices.resize(numDevices); + + EGLDisplay display = EGL_NO_DISPLAY; + for (const auto& device : devices) { + const char* renderNodeString = + egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT); + // We are looking for a device with no file + if (!renderNodeString || *renderNodeString == 0) { + const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE}; + display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device, + attrib_list); + break; + } + } + if (!display) { + return nullptr; + } + + return EglDisplay::Create(egl, display, true, aProofOfLock); +} + +static std::shared_ptr<EglDisplay> GetAndInitSurfacelessDisplay( + GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) { + if (!egl.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless)) { + return nullptr; + } + + const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE}; + const EGLDisplay display = egl.fGetPlatformDisplay( + LOCAL_EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, attrib_list); + if (display == EGL_NO_DISPLAY) { + return nullptr; + } + return EglDisplay::Create(egl, display, true, aProofOfLock); +} +#endif + +static auto EglDebugLayersEnabled() { + EGLAttrib ret = LOCAL_EGL_FALSE; + if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) { + ret = LOCAL_EGL_TRUE; + } + return ret; +} + +static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay( + GLLibraryEGL& egl, void* displayType, + const StaticMutexAutoLock& aProofOfLock) { + const EGLAttrib attrib_list[] = { + LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, + EglDebugLayersEnabled(), + // Requires: + LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, LOCAL_EGL_NONE}; + const EGLDisplay display = egl.fGetPlatformDisplay( + LOCAL_EGL_PLATFORM_ANGLE_ANGLE, displayType, attrib_list); + + if (display == EGL_NO_DISPLAY) { + const EGLint err = egl.fGetError(); + if (err != LOCAL_EGL_SUCCESS) { + gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err); + MOZ_CRASH("GFX: Unexpected GL error."); + } + return nullptr; + } + + return EglDisplay::Create(egl, display, true, aProofOfLock); +} + +std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay( + ID3D11Device* const d3d11Device) { + StaticMutexAutoLock lock(sMutex); + EGLDeviceEXT eglDevice = + fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE, d3d11Device, nullptr); + if (!eglDevice) { + gfxCriticalNote << "Failed to get EGLDeviceEXT of D3D11Device"; + return nullptr; + } + const char* features[] = {"allowES3OnFL10_0", nullptr}; + // Create an EGLDisplay using the EGLDevice + const EGLAttrib attrib_list[] = {LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, + reinterpret_cast<EGLAttrib>(features), + LOCAL_EGL_NONE}; + const auto display = fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, + eglDevice, attrib_list); + if (!display) { + gfxCriticalNote << "Failed to get EGLDisplay of D3D11Device"; + return nullptr; + } + + if (!display) { + const EGLint err = fGetError(); + if (err != LOCAL_EGL_SUCCESS) { + gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err); + MOZ_CRASH("GFX: Unexpected GL error."); + } + return nullptr; + } + + const auto ret = EglDisplay::Create(*this, display, false, lock); + + if (!ret) { + const EGLint err = fGetError(); + if (err != LOCAL_EGL_SUCCESS) { + gfxCriticalError() + << "Failed to initialize EGLDisplay for WebRender error: " + << gfx::hexa(err); + } + return nullptr; + } + return ret; +} + +static bool IsAccelAngleSupported(nsACString* const out_failureId) { + if (!gfx::gfxVars::AllowWebglAccelAngle()) { + if (out_failureId->IsEmpty()) { + *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NOT_OK"_ns; + } + return false; + } + return true; +} + +class AngleErrorReporting { + public: + AngleErrorReporting() : mFailureId(nullptr) { + // No static constructor + } + + void SetFailureId(nsACString* const aFailureId) { mFailureId = aFailureId; } + + void logError(const char* errorMessage) { + if (!mFailureId) { + return; + } + + nsCString str(errorMessage); + Tokenizer tokenizer(str); + + // Parse "ANGLE Display::initialize error " << error.getID() << ": " + // << error.getMessage() + nsCString currWord; + Tokenizer::Token intToken; + if (tokenizer.CheckWord("ANGLE") && tokenizer.CheckWhite() && + tokenizer.CheckWord("Display") && tokenizer.CheckChar(':') && + tokenizer.CheckChar(':') && tokenizer.CheckWord("initialize") && + tokenizer.CheckWhite() && tokenizer.CheckWord("error") && + tokenizer.CheckWhite() && + tokenizer.Check(Tokenizer::TOKEN_INTEGER, intToken)) { + *mFailureId = "FAILURE_ID_ANGLE_ID_"; + mFailureId->AppendPrintf("%" PRIu64, intToken.AsInteger()); + } else { + *mFailureId = "FAILURE_ID_ANGLE_UNKNOWN"; + } + } + + private: + nsACString* mFailureId; +}; + +AngleErrorReporting gAngleErrorReporter; + +static std::shared_ptr<EglDisplay> GetAndInitDisplayForAccelANGLE( + GLLibraryEGL& egl, nsACString* const out_failureId, + const StaticMutexAutoLock& aProofOfLock) { + gfx::FeatureState& d3d11ANGLE = + gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE); + + if (!StaticPrefs::webgl_angle_try_d3d11()) { + d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref", + "FAILURE_ID_ANGLE_PREF"_ns); + } + if (StaticPrefs::webgl_angle_force_d3d11()) { + d3d11ANGLE.UserForceEnable( + "User force-enabled D3D11 ANGLE on disabled hardware"); + } + gAngleErrorReporter.SetFailureId(out_failureId); + + auto guardShutdown = mozilla::MakeScopeExit([&] { + gAngleErrorReporter.SetFailureId(nullptr); + // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the + // ANGLE display is destroyed. However gAngleErrorReporter + // will live longer than the ANGLE display so we're fine. + }); + + if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE)) { + return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE, + aProofOfLock); + } + + std::shared_ptr<EglDisplay> ret; + if (d3d11ANGLE.IsEnabled()) { + ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE, + aProofOfLock); + } + + if (!ret) { + ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY, aProofOfLock); + } + + if (!ret && out_failureId->IsEmpty()) { + *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NO_DISP"_ns; + } + + return ret; +} + +// - + +#if defined(XP_UNIX) +# define GLES2_LIB "libGLESv2.so" +# define GLES2_LIB2 "libGLESv2.so.2" +# define GL_LIB "libGL.so" +# define GL_LIB2 "libGL.so.1" +#elif defined(XP_WIN) +# define GLES2_LIB "libGLESv2.dll" +#else +# error "Platform not recognized" +#endif + +Maybe<SymbolLoader> GLLibraryEGL::GetSymbolLoader() const { + auto ret = SymbolLoader(mSymbols.fGetProcAddress); + ret.mLib = mGLLibrary; + return Some(ret); +} + +// - + +/* static */ +RefPtr<GLLibraryEGL> GLLibraryEGL::Get(nsACString* const out_failureId) { + StaticMutexAutoLock lock(sMutex); + if (!sInstance) { + sInstance = new GLLibraryEGL; + if (NS_WARN_IF(!sInstance->Init(out_failureId))) { + sInstance = nullptr; + } + } + return sInstance; +} + +/* static */ void GLLibraryEGL::Shutdown() { + StaticMutexAutoLock lock(sMutex); + sInstance = nullptr; +} + +bool GLLibraryEGL::Init(nsACString* const out_failureId) { + MOZ_RELEASE_ASSERT(!mSymbols.fTerminate); + + mozilla::ScopedGfxFeatureReporter reporter("EGL"); + +#ifdef XP_WIN + if (!mEGLLibrary) { + // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul + // and we should look for them there. We have to load the libs in this + // order, because libEGL.dll depends on libGLESv2.dll which depends on the + // DXSDK libraries. This matters especially for WebRT apps which are in a + // different directory. See bug 760323 and bug 749459 + + // Also note that we intentionally leak the libs we load. + + do { + // Windows 8.1+ has d3dcompiler_47.dll in the system directory. + if (LoadLibrarySystem32(L"d3dcompiler_47.dll")) break; + + MOZ_ASSERT(false, "d3dcompiler DLL loading failed."); + } while (false); + + mGLLibrary = LoadLibraryForEGLOnWindows(u"libGLESv2.dll"_ns); + + mEGLLibrary = LoadLibraryForEGLOnWindows(u"libEGL.dll"_ns); + } + +#else // !Windows + + // On non-Windows (Android) we use system copies of libEGL. We look for + // the APITrace lib, libEGL.so, and libEGL.so.1 in that order. + +# if defined(ANDROID) + if (!mEGLLibrary) mEGLLibrary = LoadApitraceLibrary(); +# endif + + if (!mEGLLibrary) { + mEGLLibrary = PR_LoadLibrary("libEGL.so"); + } +# if defined(XP_UNIX) + if (!mEGLLibrary) { + mEGLLibrary = PR_LoadLibrary("libEGL.so.1"); + } +# endif + +# ifdef APITRACE_LIB + if (!mGLLibrary) { + mGLLibrary = PR_LoadLibrary(APITRACE_LIB); + } +# endif + +# ifdef GL_LIB + if (!mGLLibrary) { + mGLLibrary = PR_LoadLibrary(GL_LIB); + } +# endif + +# ifdef GL_LIB2 + if (!mGLLibrary) { + mGLLibrary = PR_LoadLibrary(GL_LIB2); + } +# endif + + if (!mGLLibrary) { + mGLLibrary = PR_LoadLibrary(GLES2_LIB); + } + +# ifdef GLES2_LIB2 + if (!mGLLibrary) { + mGLLibrary = PR_LoadLibrary(GLES2_LIB2); + } +# endif + +#endif // !Windows + + if (!mEGLLibrary || !mGLLibrary) { + NS_WARNING("Couldn't load EGL LIB."); + *out_failureId = "FEATURE_FAILURE_EGL_LOAD_3"_ns; + return false; + } + +#define SYMBOL(X) \ + { \ + (PRFuncPtr*)&mSymbols.f##X, { \ + { "egl" #X } \ + } \ + } +#define END_OF_SYMBOLS \ + { \ + nullptr, {} \ + } + + SymLoadStruct earlySymbols[] = {SYMBOL(GetDisplay), + SYMBOL(Terminate), + SYMBOL(GetCurrentSurface), + SYMBOL(GetCurrentContext), + SYMBOL(MakeCurrent), + SYMBOL(DestroyContext), + SYMBOL(CreateContext), + SYMBOL(DestroySurface), + SYMBOL(CreateWindowSurface), + SYMBOL(CreatePbufferSurface), + SYMBOL(CreatePbufferFromClientBuffer), + SYMBOL(CreatePixmapSurface), + SYMBOL(BindAPI), + SYMBOL(Initialize), + SYMBOL(ChooseConfig), + SYMBOL(GetError), + SYMBOL(GetConfigs), + SYMBOL(GetConfigAttrib), + SYMBOL(WaitNative), + SYMBOL(GetProcAddress), + SYMBOL(SwapBuffers), + SYMBOL(CopyBuffers), + SYMBOL(QueryString), + SYMBOL(QueryContext), + SYMBOL(BindTexImage), + SYMBOL(ReleaseTexImage), + SYMBOL(SwapInterval), + SYMBOL(QuerySurface), + END_OF_SYMBOLS}; + + { + const SymbolLoader libLoader(*mEGLLibrary); + if (!libLoader.LoadSymbols(earlySymbols)) { + NS_WARNING( + "Couldn't find required entry points in EGL library (early init)"); + *out_failureId = "FEATURE_FAILURE_EGL_SYM"_ns; + return false; + } + } + + { + const char internalFuncName[] = + "_Z35eglQueryStringImplementationANDROIDPvi"; + const auto& internalFunc = + PR_FindFunctionSymbol(mEGLLibrary, internalFuncName); + if (internalFunc) { + *(PRFuncPtr*)&mSymbols.fQueryString = internalFunc; + } + } + + // - + + InitLibExtensions(); + + const SymbolLoader pfnLoader(mSymbols.fGetProcAddress); + + const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) { + const bool shouldWarn = gfxEnv::MOZ_GL_SPEW(); + if (pfnLoader.LoadSymbols(symbols, shouldWarn)) return true; + + ClearSymbols(symbols); + return false; + }; + + // Check the ANGLE support the system has + mIsANGLE = IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle); + + // Client exts are ready. (But not display exts!) + + if (mIsANGLE) { + MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)); + const SymLoadStruct angleSymbols[] = {SYMBOL(GetPlatformDisplay), + END_OF_SYMBOLS}; + if (!fnLoadSymbols(angleSymbols)) { + gfxCriticalError() << "Failed to load ANGLE symbols!"; + return false; + } + MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)); + const SymLoadStruct createDeviceSymbols[] = { + SYMBOL(CreateDeviceANGLE), SYMBOL(ReleaseDeviceANGLE), END_OF_SYMBOLS}; + if (!fnLoadSymbols(createDeviceSymbols)) { + NS_ERROR( + "EGL supports ANGLE_device_creation without exposing its functions!"); + MarkExtensionUnsupported(EGLLibExtension::ANGLE_device_creation); + } + } + + // ANDROID_get_native_client_buffer isn't necessarily enumerated in lib exts, + // but it is one. + { + const SymLoadStruct symbols[] = {SYMBOL(GetNativeClientBufferANDROID), + END_OF_SYMBOLS}; + if (fnLoadSymbols(symbols)) { + mAvailableExtensions[UnderlyingValue( + EGLLibExtension::ANDROID_get_native_client_buffer)] = true; + } + } + + // - + // Load possible display ext symbols. + + { + const SymLoadStruct symbols[] = {SYMBOL(QuerySurfacePointerANGLE), + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + SYMBOL(CreateSyncKHR), SYMBOL(DestroySyncKHR), + SYMBOL(ClientWaitSyncKHR), SYMBOL(GetSyncAttribKHR), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(CreateImageKHR), + SYMBOL(DestroyImageKHR), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(WaitSyncKHR), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(DupNativeFenceFDANDROID), + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(CreateStreamKHR), + SYMBOL(DestroyStreamKHR), + SYMBOL(QueryStreamKHR), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(StreamConsumerGLTextureExternalKHR), + SYMBOL(StreamConsumerAcquireKHR), + SYMBOL(StreamConsumerReleaseKHR), + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + SYMBOL(QueryDisplayAttribEXT), SYMBOL(QueryDeviceAttribEXT), + SYMBOL(QueryDeviceStringEXT), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + SYMBOL(StreamConsumerGLTextureExternalAttribsNV), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + SYMBOL(CreateStreamProducerD3DTextureANGLE), + SYMBOL(StreamPostD3DTextureANGLE), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage, + {{"eglSwapBuffersWithDamageEXT"}}}, + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage, + {{"eglSwapBuffersWithDamageKHR"}}}, + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = { + {(PRFuncPtr*)&mSymbols.fSetDamageRegion, {{"eglSetDamageRegionKHR"}}}, + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(GetPlatformDisplay), + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(ExportDMABUFImageQueryMESA), + SYMBOL(ExportDMABUFImageMESA), + END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + { + const SymLoadStruct symbols[] = {SYMBOL(QueryDevicesEXT), END_OF_SYMBOLS}; + (void)fnLoadSymbols(symbols); + } + + return true; +} + +// - + +template <size_t N> +static void MarkExtensions(const char* rawExtString, bool shouldDumpExts, + const char* extType, const char* const (&names)[N], + std::bitset<N>* const out) { + MOZ_ASSERT(rawExtString); + + const nsDependentCString extString(rawExtString); + + std::vector<nsCString> extList; + SplitByChar(extString, ' ', &extList); + + if (shouldDumpExts) { + printf_stderr("%u EGL %s extensions: (*: recognized)\n", + (uint32_t)extList.size(), extType); + } + + MarkBitfieldByStrings(extList, shouldDumpExts, names, out); +} + +// - + +// static +std::shared_ptr<EglDisplay> EglDisplay::Create( + GLLibraryEGL& lib, const EGLDisplay display, const bool isWarp, + const StaticMutexAutoLock& aProofOfLock) { + // Retrieve the EglDisplay if it already exists + { + const auto itr = lib.mActiveDisplays.find(display); + if (itr != lib.mActiveDisplays.end()) { + const auto ret = itr->second.lock(); + if (ret) { + return ret; + } + } + } + + if (!lib.fInitialize(display, nullptr, nullptr)) { + return nullptr; + } + + static std::once_flag sMesaLeakFlag; + std::call_once(sMesaLeakFlag, MesaMemoryLeakWorkaround); + + const auto ret = + std::make_shared<EglDisplay>(PrivateUseOnly{}, lib, display, isWarp); + lib.mActiveDisplays.insert({display, ret}); + return ret; +} + +EglDisplay::EglDisplay(const PrivateUseOnly&, GLLibraryEGL& lib, + const EGLDisplay disp, const bool isWarp) + : mLib(&lib), mDisplay(disp), mIsWARP(isWarp) { + const bool shouldDumpExts = GLContext::ShouldDumpExts(); + + auto rawExtString = + (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_EXTENSIONS); + if (!rawExtString) { + NS_WARNING("Failed to query EGL display extensions!."); + rawExtString = ""; + } + MarkExtensions(rawExtString, shouldDumpExts, "display", sEGLExtensionNames, + &mAvailableExtensions); + + // - + + if (!HasKHRImageBase()) { + MarkExtensionUnsupported(EGLExtension::KHR_image_pixmap); + } + + if (IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) { + const auto vendor = + (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_VENDOR); + + // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this + // extension, but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it + // fails to render anything when a real surface is provided later on. We + // only have the EGL vendor available here, so just avoid using this + // extension on all Mali devices. + if (vendor && (strcmp(vendor, "ARM") == 0)) { + MarkExtensionUnsupported(EGLExtension::KHR_surfaceless_context); + } + } + + // ANDROID_native_fence_sync isn't necessarily enumerated in display ext, + // but it is one. + if (mLib->mSymbols.fDupNativeFenceFDANDROID) { + mAvailableExtensions[UnderlyingValue( + EGLExtension::ANDROID_native_fence_sync)] = true; + } +} + +EglDisplay::~EglDisplay() { + StaticMutexAutoLock lock(GLLibraryEGL::sMutex); + fTerminate(); + mLib->mActiveDisplays.erase(mDisplay); +} + +// - + +std::shared_ptr<EglDisplay> GLLibraryEGL::DefaultDisplay( + nsACString* const out_failureId) { + StaticMutexAutoLock lock(sMutex); + auto ret = mDefaultDisplay.lock(); + if (ret) return ret; + + ret = CreateDisplayLocked(false, out_failureId, lock); + mDefaultDisplay = ret; + return ret; +} + +std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay( + const bool forceAccel, nsACString* const out_failureId) { + StaticMutexAutoLock lock(sMutex); + return CreateDisplayLocked(forceAccel, out_failureId, lock); +} + +std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplayLocked( + const bool forceAccel, nsACString* const out_failureId, + const StaticMutexAutoLock& aProofOfLock) { + std::shared_ptr<EglDisplay> ret; + + if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)) { + nsCString accelAngleFailureId; + bool accelAngleSupport = IsAccelAngleSupported(&accelAngleFailureId); + bool shouldTryAccel = forceAccel || accelAngleSupport; + bool shouldTryWARP = !forceAccel; // Only if ANGLE not supported or fails + + // If WARP preferred, will override ANGLE support + if (StaticPrefs::webgl_angle_force_warp()) { + shouldTryWARP = true; + shouldTryAccel = false; + if (accelAngleFailureId.IsEmpty()) { + accelAngleFailureId = "FEATURE_FAILURE_FORCE_WARP"_ns; + } + } + + // Hardware accelerated ANGLE path (supported or force accel) + if (shouldTryAccel) { + ret = GetAndInitDisplayForAccelANGLE(*this, out_failureId, aProofOfLock); + } + + // Report the acceleration status to telemetry + if (!ret) { + if (accelAngleFailureId.IsEmpty()) { + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID, + "FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"_ns); + } else { + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID, + accelAngleFailureId); + } + } else { + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID, + "SUCCESS"_ns); + } + + // Fallback to a WARP display if ANGLE fails, or if WARP is forced + if (!ret && shouldTryWARP) { + ret = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY, aProofOfLock); + if (!ret) { + if (out_failureId->IsEmpty()) { + *out_failureId = "FEATURE_FAILURE_WARP_FALLBACK"_ns; + } + NS_ERROR("Fallback WARP context failed to initialize."); + return nullptr; + } + } + } else { + void* nativeDisplay = EGL_DEFAULT_DISPLAY; +#ifdef MOZ_WIDGET_GTK + if (!ret && !gfx::gfxVars::WebglUseHardware()) { + // Initialize a swrast egl device such as llvmpipe + ret = GetAndInitSoftwareDisplay(*this, aProofOfLock); + } + // Initialize the display the normal way + if (!ret && !gdk_display_get_default()) { + ret = GetAndInitDeviceDisplay(*this, aProofOfLock); + if (!ret) { + ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock); + } + } +# ifdef MOZ_WAYLAND + else if (!ret && widget::GdkIsWaylandDisplay()) { + // Wayland does not support EGL_DEFAULT_DISPLAY + nativeDisplay = widget::WaylandDisplayGetWLDisplay(); + if (!nativeDisplay) { + NS_WARNING("Failed to get wl_display."); + return nullptr; + } + } +# endif +#endif + if (!ret) { + ret = GetAndInitDisplay(*this, nativeDisplay, aProofOfLock); + } + } + + if (!ret) { + if (out_failureId->IsEmpty()) { + *out_failureId = "FEATURE_FAILURE_NO_DISPLAY"_ns; + } + NS_WARNING("Failed to initialize a display."); + return nullptr; + } + + return ret; +} + +void GLLibraryEGL::InitLibExtensions() { + const bool shouldDumpExts = GLContext::ShouldDumpExts(); + + const char* rawExtString = nullptr; + +#ifndef ANDROID + // Bug 1209612: Crashes on a number of android drivers. + // Ideally we would only blocklist this there, but for now we don't need the + // client extension list on ANDROID (we mostly need it on ANGLE), and we'd + // rather not crash. + rawExtString = (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS); +#endif + + if (!rawExtString) { + if (shouldDumpExts) { + printf_stderr("No EGL lib extensions.\n"); + } + return; + } + + MarkExtensions(rawExtString, shouldDumpExts, "lib", sEGLLibraryExtensionNames, + &mAvailableExtensions); +} + +void EglDisplay::DumpEGLConfig(EGLConfig cfg) const { +#define ATTR(_x) \ + do { \ + int attrval = 0; \ + mLib->fGetConfigAttrib(mDisplay, cfg, LOCAL_EGL_##_x, &attrval); \ + const auto err = mLib->fGetError(); \ + if (err != 0x3000) { \ + printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \ + } else { \ + printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \ + } \ + } while (0) + + printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg); + + ATTR(BUFFER_SIZE); + ATTR(ALPHA_SIZE); + ATTR(BLUE_SIZE); + ATTR(GREEN_SIZE); + ATTR(RED_SIZE); + ATTR(DEPTH_SIZE); + ATTR(STENCIL_SIZE); + ATTR(CONFIG_CAVEAT); + ATTR(CONFIG_ID); + ATTR(LEVEL); + ATTR(MAX_PBUFFER_HEIGHT); + ATTR(MAX_PBUFFER_PIXELS); + ATTR(MAX_PBUFFER_WIDTH); + ATTR(NATIVE_RENDERABLE); + ATTR(NATIVE_VISUAL_ID); + ATTR(NATIVE_VISUAL_TYPE); + ATTR(PRESERVED_RESOURCES); + ATTR(SAMPLES); + ATTR(SAMPLE_BUFFERS); + ATTR(SURFACE_TYPE); + ATTR(TRANSPARENT_TYPE); + ATTR(TRANSPARENT_RED_VALUE); + ATTR(TRANSPARENT_GREEN_VALUE); + ATTR(TRANSPARENT_BLUE_VALUE); + ATTR(BIND_TO_TEXTURE_RGB); + ATTR(BIND_TO_TEXTURE_RGBA); + ATTR(MIN_SWAP_INTERVAL); + ATTR(MAX_SWAP_INTERVAL); + ATTR(LUMINANCE_SIZE); + ATTR(ALPHA_MASK_SIZE); + ATTR(COLOR_BUFFER_TYPE); + ATTR(RENDERABLE_TYPE); + ATTR(CONFORMANT); + +#undef ATTR +} + +void EglDisplay::DumpEGLConfigs() const { + int nc = 0; + mLib->fGetConfigs(mDisplay, nullptr, 0, &nc); + std::vector<EGLConfig> ec(nc); + mLib->fGetConfigs(mDisplay, ec.data(), ec.size(), &nc); + + for (int i = 0; i < nc; ++i) { + printf_stderr("========= EGL Config %d ========\n", i); + DumpEGLConfig(ec[i]); + } +} + +static bool ShouldTrace() { + static bool ret = gfxEnv::MOZ_GL_DEBUG_VERBOSE(); + return ret; +} + +void BeforeEGLCall(const char* glFunction) { + if (ShouldTrace()) { + printf_stderr("[egl] > %s\n", glFunction); + } +} + +void AfterEGLCall(const char* glFunction) { + if (ShouldTrace()) { + printf_stderr("[egl] < %s\n", glFunction); + } +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h new file mode 100644 index 0000000000..de296508bb --- /dev/null +++ b/gfx/gl/GLLibraryEGL.h @@ -0,0 +1,993 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLLIBRARYEGL_H_ +#define GLLIBRARYEGL_H_ + +#if defined(MOZ_X11) +# include "mozilla/X11Util.h" +#endif + +#include "base/platform_thread.h" // for PlatformThreadId +#include "gfxEnv.h" +#include "GLContext.h" +#include "mozilla/EnumTypeTraits.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/Maybe.h" +#include "mozilla/Mutex.h" +#include "mozilla/RefPtr.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/StaticPtr.h" +#include "nsISupports.h" +#include "prlink.h" + +#include <bitset> +#include <memory> +#include <unordered_map> + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/ProfilerLabels.h" +# include "AndroidBuild.h" +#endif + +#if defined(MOZ_X11) +# define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) +#else +# define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#endif + +struct ID3D11Device; + +extern "C" { +struct AHardwareBuffer; +} + +namespace angle { +class Platform; +} + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +} + +namespace gl { + +class SymbolLoader; + +PRLibrary* LoadApitraceLibrary(); + +void BeforeEGLCall(const char* funcName); +void AfterEGLCall(const char* funcName); + +class EglDisplay; +/** + * Known GL extensions that can be queried by + * IsExtensionSupported. The results of this are cached, and as + * such it's safe to use this even in performance critical code. + * If you add to this array, remember to add to the string names + * in GLLibraryEGL.cpp. + */ +enum class EGLLibExtension { + ANDROID_get_native_client_buffer, + ANGLE_device_creation, + ANGLE_device_creation_d3d11, + ANGLE_platform_angle, + ANGLE_platform_angle_d3d, + EXT_device_enumeration, + EXT_device_query, + EXT_platform_device, + MESA_platform_surfaceless, + Max +}; + +/** + * Known GL extensions that can be queried by + * IsExtensionSupported. The results of this are cached, and as + * such it's safe to use this even in performance critical code. + * If you add to this array, remember to add to the string names + * in GLLibraryEGL.cpp. + */ +enum class EGLExtension { + KHR_image_base, + KHR_image_pixmap, + KHR_gl_texture_2D_image, + ANGLE_surface_d3d_texture_2d_share_handle, + EXT_create_context_robustness, + KHR_image, + KHR_fence_sync, + KHR_wait_sync, + ANDROID_native_fence_sync, + EGL_ANDROID_image_crop, + ANGLE_d3d_share_handle_client_buffer, + KHR_create_context, + KHR_stream, + KHR_stream_consumer_gltexture, + NV_stream_consumer_gltexture_yuv, + ANGLE_stream_producer_d3d_texture, + KHR_surfaceless_context, + KHR_create_context_no_error, + MOZ_create_context_provoking_vertex_dont_care, + EXT_swap_buffers_with_damage, + KHR_swap_buffers_with_damage, + EXT_buffer_age, + KHR_partial_update, + NV_robustness_video_memory_purge, + EXT_image_dma_buf_import, + EXT_image_dma_buf_import_modifiers, + MESA_image_dma_buf_export, + KHR_no_config_context, + Max +}; + +// - + +class GLLibraryEGL final { + friend class EglDisplay; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLLibraryEGL) + + private: + PRLibrary* mEGLLibrary = nullptr; + PRLibrary* mGLLibrary = nullptr; + bool mIsANGLE = false; + std::bitset<UnderlyingValue(EGLLibExtension::Max)> mAvailableExtensions; + std::weak_ptr<EglDisplay> mDefaultDisplay; + std::unordered_map<EGLDisplay, std::weak_ptr<EglDisplay>> mActiveDisplays; + + public: + static RefPtr<GLLibraryEGL> Get(nsACString* const out_failureId); + static void Shutdown(); + + private: + ~GLLibraryEGL() = default; + + static StaticMutex sMutex; + static StaticRefPtr<GLLibraryEGL> sInstance MOZ_GUARDED_BY(sMutex); + + bool Init(nsACString* const out_failureId); + void InitLibExtensions(); + + std::shared_ptr<EglDisplay> CreateDisplayLocked( + bool forceAccel, nsACString* const out_failureId, + const StaticMutexAutoLock& aProofOfLock); + + public: + Maybe<SymbolLoader> GetSymbolLoader() const; + + std::shared_ptr<EglDisplay> CreateDisplay(bool forceAccel, + nsACString* const out_failureId); + std::shared_ptr<EglDisplay> CreateDisplay(ID3D11Device*); + std::shared_ptr<EglDisplay> DefaultDisplay(nsACString* const out_failureId); + + bool IsExtensionSupported(EGLLibExtension aKnownExtension) const { + return mAvailableExtensions[UnderlyingValue(aKnownExtension)]; + } + + void MarkExtensionUnsupported(EGLLibExtension aKnownExtension) { + mAvailableExtensions[UnderlyingValue(aKnownExtension)] = false; + } + + bool IsANGLE() const { return mIsANGLE; } + + // - + // PFN wrappers + +#ifdef MOZ_WIDGET_ANDROID +# define PROFILE_CALL AUTO_PROFILER_LABEL(__func__, GRAPHICS); +#else +# define PROFILE_CALL +#endif + +#ifndef MOZ_FUNCTION_NAME +# ifdef __GNUC__ +# define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ +# elif defined(_MSC_VER) +# define MOZ_FUNCTION_NAME __FUNCTION__ +# else +# define MOZ_FUNCTION_NAME \ + __func__ // defined in C99, supported in various C++ compilers. Just raw + // function name. +# endif +#endif + +#ifdef DEBUG +# define BEFORE_CALL BeforeEGLCall(MOZ_FUNCTION_NAME); +# define AFTER_CALL AfterEGLCall(MOZ_FUNCTION_NAME); +#else +# define BEFORE_CALL +# define AFTER_CALL +#endif + +#define WRAP(X) \ + PROFILE_CALL \ + BEFORE_CALL \ + const auto ret = mSymbols.X; \ + AFTER_CALL \ + return ret + + public: + EGLDisplay fGetDisplay(void* display_id) const { + WRAP(fGetDisplay(display_id)); + } + + EGLDisplay fGetPlatformDisplay(EGLenum platform, void* native_display, + const EGLAttrib* attrib_list) const { + WRAP(fGetPlatformDisplay(platform, native_display, attrib_list)); + } + + EGLSurface fGetCurrentSurface(EGLint id) const { + WRAP(fGetCurrentSurface(id)); + } + + EGLContext fGetCurrentContext() const { WRAP(fGetCurrentContext()); } + + EGLBoolean fBindAPI(EGLenum api) const { WRAP(fBindAPI(api)); } + + EGLint fGetError() const { WRAP(fGetError()); } + + EGLBoolean fWaitNative(EGLint engine) const { WRAP(fWaitNative(engine)); } + + EGLCastToRelevantPtr fGetProcAddress(const char* procname) const { + WRAP(fGetProcAddress(procname)); + } + + // ANGLE_device_creation + EGLDeviceEXT fCreateDeviceANGLE(EGLint device_type, void* native_device, + const EGLAttrib* attrib_list) const { + WRAP(fCreateDeviceANGLE(device_type, native_device, attrib_list)); + } + + EGLBoolean fReleaseDeviceANGLE(EGLDeviceEXT device) { + WRAP(fReleaseDeviceANGLE(device)); + } + + // ANDROID_get_native_client_buffer + EGLClientBuffer fGetNativeClientBufferANDROID( + const struct AHardwareBuffer* buffer) { + WRAP(fGetNativeClientBufferANDROID(buffer)); + } + + private: + EGLBoolean fTerminate(EGLDisplay display) const { WRAP(fTerminate(display)); } + + // - + + mutable Mutex mMutex = Mutex{"GLLibraryEGL::mMutex"}; + mutable std::unordered_map<EGLContext, PlatformThreadId> + mOwningThreadByContext MOZ_GUARDED_BY(mMutex); + + EGLBoolean fMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, + EGLContext ctx) const { + const bool CHECK_CONTEXT_OWNERSHIP = true; + if (CHECK_CONTEXT_OWNERSHIP) { + const MutexAutoLock lock(mMutex); + const auto tid = PlatformThread::CurrentId(); + const auto prevCtx = fGetCurrentContext(); + + if (prevCtx) { + mOwningThreadByContext[prevCtx] = 0; + } + if (ctx) { + auto& ctxOwnerThread = mOwningThreadByContext[ctx]; + if (ctxOwnerThread && ctxOwnerThread != tid) { + gfxCriticalError() + << "EGLContext#" << ctx << " is owned by/Current on" + << " thread#" << ctxOwnerThread << " but MakeCurrent requested on" + << " thread#" << tid << "!"; + if (gfxEnv::MOZ_EGL_RELEASE_ASSERT_CONTEXT_OWNERSHIP()) { + MOZ_CRASH("MOZ_EGL_RELEASE_ASSERT_CONTEXT_OWNERSHIP"); + } + return false; + } + ctxOwnerThread = tid; + } + } + + // Always reset the TLS current context. + // If we're called by TLS-caching MakeCurrent, after we return true, + // the caller will set the TLS correctly anyway. + GLContext::ResetTLSCurrentContext(); + + WRAP(fMakeCurrent(dpy, draw, read, ctx)); + } + + // - + + EGLBoolean fDestroyContext(EGLDisplay dpy, EGLContext ctx) const { + { + const MutexAutoLock lock(mMutex); + mOwningThreadByContext.erase(ctx); + } + + WRAP(fDestroyContext(dpy, ctx)); + } + + EGLContext fCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint* attrib_list) const { + WRAP(fCreateContext(dpy, config, share_context, attrib_list)); + } + + EGLBoolean fDestroySurface(EGLDisplay dpy, EGLSurface surface) const { + WRAP(fDestroySurface(dpy, surface)); + } + + public: + EGLSurface fCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint* attrib_list) const { + WRAP(fCreateWindowSurface(dpy, config, win, attrib_list)); + } + + private: + EGLSurface fCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint* attrib_list) const { + WRAP(fCreatePbufferSurface(dpy, config, attrib_list)); + } + + EGLSurface fCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint* attrib_list) const { + WRAP(fCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, + attrib_list)); + } + + EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint* attrib_list) const { + WRAP(fCreatePixmapSurface(dpy, config, pixmap, attrib_list)); + } + + EGLBoolean fInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) const { + WRAP(fInitialize(dpy, major, minor)); + } + + EGLBoolean fChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, + EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + WRAP(fChooseConfig(dpy, attrib_list, configs, config_size, num_config)); + } + + EGLBoolean fGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint* value) const { + WRAP(fGetConfigAttrib(dpy, config, attribute, value)); + } + + EGLBoolean fGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + WRAP(fGetConfigs(dpy, configs, config_size, num_config)); + } + + EGLBoolean fSwapBuffers(EGLDisplay dpy, EGLSurface surface) const { + WRAP(fSwapBuffers(dpy, surface)); + } + + EGLBoolean fCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target) const { + WRAP(fCopyBuffers(dpy, surface, target)); + } + + public: + const GLubyte* fQueryString(EGLDisplay dpy, EGLint name) const { + WRAP(fQueryString(dpy, name)); + } + + private: + EGLBoolean fQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, + EGLint* value) const { + WRAP(fQueryContext(dpy, ctx, attribute, value)); + } + + EGLBoolean fBindTexImage(EGLDisplay dpy, EGLSurface surface, + EGLint buffer) const { + WRAP(fBindTexImage(dpy, surface, buffer)); + } + + EGLBoolean fReleaseTexImage(EGLDisplay dpy, EGLSurface surface, + EGLint buffer) const { + WRAP(fReleaseTexImage(dpy, surface, buffer)); + } + + EGLBoolean fSwapInterval(EGLDisplay dpy, EGLint interval) const { + WRAP(fSwapInterval(dpy, interval)); + } + + EGLImage fCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, + const EGLint* attrib_list) const { + WRAP(fCreateImageKHR(dpy, ctx, target, buffer, attrib_list)); + } + + EGLBoolean fDestroyImage(EGLDisplay dpy, EGLImage image) const { + WRAP(fDestroyImageKHR(dpy, image)); + } + + EGLBoolean fQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, + EGLint* value) const { + WRAP(fQuerySurface(dpy, surface, attribute, value)); + } + + EGLBoolean fQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, void** value) const { + WRAP(fQuerySurfacePointerANGLE(dpy, surface, attribute, value)); + } + + EGLSync fCreateSync(EGLDisplay dpy, EGLenum type, + const EGLint* attrib_list) const { + WRAP(fCreateSyncKHR(dpy, type, attrib_list)); + } + + EGLBoolean fDestroySync(EGLDisplay dpy, EGLSync sync) const { + WRAP(fDestroySyncKHR(dpy, sync)); + } + + EGLint fClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, + EGLTime timeout) const { + WRAP(fClientWaitSyncKHR(dpy, sync, flags, timeout)); + } + + EGLBoolean fGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, + EGLint* value) const { + WRAP(fGetSyncAttribKHR(dpy, sync, attribute, value)); + } + + EGLint fWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) const { + WRAP(fWaitSyncKHR(dpy, sync, flags)); + } + + EGLint fDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync) const { + WRAP(fDupNativeFenceFDANDROID(dpy, sync)); + } + + // KHR_stream + EGLStreamKHR fCreateStreamKHR(EGLDisplay dpy, + const EGLint* attrib_list) const { + WRAP(fCreateStreamKHR(dpy, attrib_list)); + } + + EGLBoolean fDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) const { + WRAP(fDestroyStreamKHR(dpy, stream)); + } + + EGLBoolean fQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint* value) const { + WRAP(fQueryStreamKHR(dpy, stream, attribute, value)); + } + + // KHR_stream_consumer_gltexture + EGLBoolean fStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerGLTextureExternalKHR(dpy, stream)); + } + + EGLBoolean fStreamConsumerAcquireKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerAcquireKHR(dpy, stream)); + } + + EGLBoolean fStreamConsumerReleaseKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerReleaseKHR(dpy, stream)); + } + + // EXT_device_query + EGLBoolean fQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, + EGLAttrib* value) const { + WRAP(fQueryDisplayAttribEXT(dpy, attribute, value)); + } + + public: + EGLBoolean fQueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, + EGLAttrib* value) const { + WRAP(fQueryDeviceAttribEXT(device, attribute, value)); + } + + const char* fQueryDeviceStringEXT(EGLDeviceEXT device, EGLint name) { + WRAP(fQueryDeviceStringEXT(device, name)); + } + + private: + // NV_stream_consumer_gltexture_yuv + EGLBoolean fStreamConsumerGLTextureExternalAttribsNV( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + WRAP(fStreamConsumerGLTextureExternalAttribsNV(dpy, stream, attrib_list)); + } + + // ANGLE_stream_producer_d3d_texture + EGLBoolean fCreateStreamProducerD3DTextureANGLE( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + WRAP(fCreateStreamProducerD3DTextureANGLE(dpy, stream, attrib_list)); + } + + EGLBoolean fStreamPostD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, + void* texture, + const EGLAttrib* attrib_list) const { + WRAP(fStreamPostD3DTextureANGLE(dpy, stream, texture, attrib_list)); + } + + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean fSwapBuffersWithDamage(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, EGLint n_rects) { + WRAP(fSwapBuffersWithDamage(dpy, surface, rects, n_rects)); + } + + // EGL_KHR_partial_update + EGLBoolean fSetDamageRegion(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, EGLint n_rects) { + WRAP(fSetDamageRegion(dpy, surface, rects, n_rects)); + } + // EGL_MESA_image_dma_buf_export + EGLBoolean fExportDMABUFImageQuery(EGLDisplay dpy, EGLImage image, + int* fourcc, int* num_planes, + uint64_t* modifiers) { + WRAP( + fExportDMABUFImageQueryMESA(dpy, image, fourcc, num_planes, modifiers)); + } + EGLBoolean fExportDMABUFImage(EGLDisplay dpy, EGLImage image, int* fds, + EGLint* strides, EGLint* offsets) { + WRAP(fExportDMABUFImageMESA(dpy, image, fds, strides, offsets)); + } + + public: + // EGL_EXT_device_enumeration + EGLBoolean fQueryDevicesEXT(EGLint max_devices, EGLDeviceEXT* devices, + EGLint* num_devices) { + WRAP(fQueryDevicesEXT(max_devices, devices, num_devices)); + } + +#undef WRAP + +#undef WRAP +#undef PROFILE_CALL +#undef BEFORE_CALL +#undef AFTER_CALL +#undef MOZ_FUNCTION_NAME + + //// + + private: + struct { + EGLCastToRelevantPtr(GLAPIENTRY* fGetProcAddress)(const char* procname); + EGLDisplay(GLAPIENTRY* fGetDisplay)(void* display_id); + EGLDisplay(GLAPIENTRY* fGetPlatformDisplay)(EGLenum platform, + void* native_display, + const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fTerminate)(EGLDisplay dpy); + EGLSurface(GLAPIENTRY* fGetCurrentSurface)(EGLint); + EGLContext(GLAPIENTRY* fGetCurrentContext)(void); + EGLBoolean(GLAPIENTRY* fMakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLBoolean(GLAPIENTRY* fDestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLContext(GLAPIENTRY* fCreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLSurface(GLAPIENTRY* fCreateWindowSurface)(EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePbufferSurface)(EGLDisplay dpy, + EGLConfig config, + const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePbufferFromClientBuffer)( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePixmapSurface)(EGLDisplay dpy, + EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fBindAPI)(EGLenum api); + EGLBoolean(GLAPIENTRY* fInitialize)(EGLDisplay dpy, EGLint* major, + EGLint* minor); + EGLBoolean(GLAPIENTRY* fChooseConfig)(EGLDisplay dpy, + const EGLint* attrib_list, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + EGLint(GLAPIENTRY* fGetError)(void); + EGLBoolean(GLAPIENTRY* fGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fGetConfigs)(EGLDisplay dpy, EGLConfig* configs, + EGLint config_size, EGLint* num_config); + EGLBoolean(GLAPIENTRY* fWaitNative)(EGLint engine); + EGLBoolean(GLAPIENTRY* fSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean(GLAPIENTRY* fCopyBuffers)(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + const GLubyte*(GLAPIENTRY* fQueryString)(EGLDisplay, EGLint name); + EGLBoolean(GLAPIENTRY* fQueryContext)(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fBindTexImage)(EGLDisplay, EGLSurface surface, + EGLint buffer); + EGLBoolean(GLAPIENTRY* fReleaseTexImage)(EGLDisplay, EGLSurface surface, + EGLint buffer); + EGLBoolean(GLAPIENTRY* fSwapInterval)(EGLDisplay dpy, EGLint interval); + EGLImage(GLAPIENTRY* fCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, + EGLenum target, + EGLClientBuffer buffer, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroyImageKHR)(EGLDisplay dpy, EGLImage image); + EGLBoolean(GLAPIENTRY* fQuerySurface)(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fQuerySurfacePointerANGLE)(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + void** value); + EGLSync(GLAPIENTRY* fCreateSyncKHR)(EGLDisplay dpy, EGLenum type, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroySyncKHR)(EGLDisplay dpy, EGLSync sync); + EGLint(GLAPIENTRY* fClientWaitSyncKHR)(EGLDisplay dpy, EGLSync sync, + EGLint flags, EGLTime timeout); + EGLBoolean(GLAPIENTRY* fGetSyncAttribKHR)(EGLDisplay dpy, EGLSync sync, + EGLint attribute, EGLint* value); + EGLint(GLAPIENTRY* fWaitSyncKHR)(EGLDisplay dpy, EGLSync sync, + EGLint flags); + EGLint(GLAPIENTRY* fDupNativeFenceFDANDROID)(EGLDisplay dpy, EGLSync sync); + // KHR_stream + EGLStreamKHR(GLAPIENTRY* fCreateStreamKHR)(EGLDisplay dpy, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroyStreamKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fQueryStreamKHR)(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint* value); + // KHR_stream_consumer_gltexture + EGLBoolean(GLAPIENTRY* fStreamConsumerGLTextureExternalKHR)( + EGLDisplay dpy, EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fStreamConsumerAcquireKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fStreamConsumerReleaseKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + // EXT_device_query + EGLBoolean(GLAPIENTRY* fQueryDisplayAttribEXT)(EGLDisplay dpy, + EGLint attribute, + EGLAttrib* value); + EGLBoolean(GLAPIENTRY* fQueryDeviceAttribEXT)(EGLDeviceEXT device, + EGLint attribute, + EGLAttrib* value); + const char*(GLAPIENTRY* fQueryDeviceStringEXT)(EGLDeviceEXT device, + EGLint name); + + // NV_stream_consumer_gltexture_yuv + EGLBoolean(GLAPIENTRY* fStreamConsumerGLTextureExternalAttribsNV)( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list); + // ANGLE_stream_producer_d3d_texture + EGLBoolean(GLAPIENTRY* fCreateStreamProducerD3DTextureANGLE)( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fStreamPostD3DTextureANGLE)( + EGLDisplay dpy, EGLStreamKHR stream, void* texture, + const EGLAttrib* attrib_list); + // ANGLE_device_creation + EGLDeviceEXT(GLAPIENTRY* fCreateDeviceANGLE)(EGLint device_type, + void* native_device, + const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fReleaseDeviceANGLE)(EGLDeviceEXT device); + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean(GLAPIENTRY* fSwapBuffersWithDamage)(EGLDisplay dpy, + EGLSurface surface, + const EGLint* rects, + EGLint n_rects); + // EGL_KHR_partial_update + EGLBoolean(GLAPIENTRY* fSetDamageRegion)(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, + EGLint n_rects); + EGLClientBuffer(GLAPIENTRY* fGetNativeClientBufferANDROID)( + const struct AHardwareBuffer* buffer); + + // EGL_MESA_image_dma_buf_export + EGLBoolean(GLAPIENTRY* fExportDMABUFImageQueryMESA)(EGLDisplay dpy, + EGLImage image, + int* fourcc, + int* num_planes, + uint64_t* modifiers); + EGLBoolean(GLAPIENTRY* fExportDMABUFImageMESA)(EGLDisplay dpy, + EGLImage image, int* fds, + EGLint* strides, + EGLint* offsets); + + EGLBoolean(GLAPIENTRY* fQueryDevicesEXT)(EGLint max_devices, + EGLDeviceEXT* devices, + EGLint* num_devices); + + } mSymbols = {}; +}; + +static bool ShouldLeakEglDisplay() { + // We are seeing crashes in eglTerminate on the Samsung S22 family of devices + // running Android 14, so we leak the EGLDisplay rather than call + // eglTerminate. +#ifdef MOZ_WIDGET_ANDROID + if (jni::GetAPIVersion() >= 34) { + const auto board = java::sdk::Build::BOARD()->ToString(); + if (board.EqualsASCII("s5e9925")) { + return true; + } + } +#endif + return false; +} + +class EglDisplay final { + public: + const RefPtr<GLLibraryEGL> mLib; + const EGLDisplay mDisplay; + const bool mIsWARP; + + private: + std::bitset<UnderlyingValue(EGLExtension::Max)> mAvailableExtensions; + + struct PrivateUseOnly final {}; + + public: + static std::shared_ptr<EglDisplay> Create( + GLLibraryEGL&, EGLDisplay, bool isWarp, + const StaticMutexAutoLock& aProofOfLock); + + // Only `public` for make_shared. + EglDisplay(const PrivateUseOnly&, GLLibraryEGL&, EGLDisplay, bool isWarp); + + public: + ~EglDisplay(); + + bool IsExtensionSupported(EGLExtension aKnownExtension) const { + return mAvailableExtensions[UnderlyingValue(aKnownExtension)]; + } + + void MarkExtensionUnsupported(EGLExtension aKnownExtension) { + mAvailableExtensions[UnderlyingValue(aKnownExtension)] = false; + } + + void DumpEGLConfig(EGLConfig) const; + void DumpEGLConfigs() const; + + void Shutdown(); + + // - + + bool HasKHRImageBase() const { + return IsExtensionSupported(EGLExtension::KHR_image) || + IsExtensionSupported(EGLExtension::KHR_image_base); + } + + bool HasKHRImagePixmap() const { + return IsExtensionSupported(EGLExtension::KHR_image) || + IsExtensionSupported(EGLExtension::KHR_image_pixmap); + } + + // - + + EGLBoolean fTerminate() { + static const bool shouldLeak = ShouldLeakEglDisplay(); + if (shouldLeak) { + return LOCAL_EGL_TRUE; + } + return mLib->fTerminate(mDisplay); + } + + EGLBoolean fMakeCurrent(EGLSurface draw, EGLSurface read, + EGLContext ctx) const { + return mLib->fMakeCurrent(mDisplay, draw, read, ctx); + } + + EGLBoolean fDestroyContext(EGLContext ctx) const { + return mLib->fDestroyContext(mDisplay, ctx); + } + + EGLContext fCreateContext(EGLConfig config, EGLContext share_context, + const EGLint* attrib_list) const { + return mLib->fCreateContext(mDisplay, config, share_context, attrib_list); + } + + EGLBoolean fDestroySurface(EGLSurface surface) const { + return mLib->fDestroySurface(mDisplay, surface); + } + + EGLSurface fCreateWindowSurface(EGLConfig config, EGLNativeWindowType win, + const EGLint* attrib_list) const { + return mLib->fCreateWindowSurface(mDisplay, config, win, attrib_list); + } + + EGLSurface fCreatePbufferSurface(EGLConfig config, + const EGLint* attrib_list) const { + return mLib->fCreatePbufferSurface(mDisplay, config, attrib_list); + } + + EGLSurface fCreatePbufferFromClientBuffer(EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint* attrib_list) const { + return mLib->fCreatePbufferFromClientBuffer(mDisplay, buftype, buffer, + config, attrib_list); + } + + EGLBoolean fChooseConfig(const EGLint* attrib_list, EGLConfig* configs, + EGLint config_size, EGLint* num_config) const { + return mLib->fChooseConfig(mDisplay, attrib_list, configs, config_size, + num_config); + } + + EGLBoolean fGetConfigAttrib(EGLConfig config, EGLint attribute, + EGLint* value) const { + return mLib->fGetConfigAttrib(mDisplay, config, attribute, value); + } + + EGLBoolean fGetConfigs(EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + return mLib->fGetConfigs(mDisplay, configs, config_size, num_config); + } + + EGLBoolean fSwapBuffers(EGLSurface surface) const { + return mLib->fSwapBuffers(mDisplay, surface); + } + + EGLBoolean fBindTexImage(EGLSurface surface, EGLint buffer) const { + return mLib->fBindTexImage(mDisplay, surface, buffer); + } + + EGLBoolean fReleaseTexImage(EGLSurface surface, EGLint buffer) const { + return mLib->fReleaseTexImage(mDisplay, surface, buffer); + } + + EGLBoolean fSwapInterval(EGLint interval) const { + return mLib->fSwapInterval(mDisplay, interval); + } + + EGLImage fCreateImage(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, + const EGLint* attribList) const { + MOZ_ASSERT(HasKHRImageBase()); + return mLib->fCreateImage(mDisplay, ctx, target, buffer, attribList); + } + + EGLBoolean fDestroyImage(EGLImage image) const { + MOZ_ASSERT(HasKHRImageBase()); + return mLib->fDestroyImage(mDisplay, image); + } + + EGLBoolean fQuerySurface(EGLSurface surface, EGLint attribute, + EGLint* value) const { + return mLib->fQuerySurface(mDisplay, surface, attribute, value); + } + + EGLBoolean fQuerySurfacePointerANGLE(EGLSurface surface, EGLint attribute, + void** value) const { + MOZ_ASSERT(IsExtensionSupported( + EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)); + return mLib->fQuerySurfacePointerANGLE(mDisplay, surface, attribute, value); + } + + EGLSync fCreateSync(EGLenum type, const EGLint* attrib_list) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fCreateSync(mDisplay, type, attrib_list); + } + + EGLBoolean fDestroySync(EGLSync sync) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fDestroySync(mDisplay, sync); + } + + EGLint fClientWaitSync(EGLSync sync, EGLint flags, EGLTime timeout) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fClientWaitSync(mDisplay, sync, flags, timeout); + } + + EGLBoolean fGetSyncAttrib(EGLSync sync, EGLint attribute, + EGLint* value) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fGetSyncAttrib(mDisplay, sync, attribute, value); + } + + EGLint fWaitSync(EGLSync sync, EGLint flags) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_wait_sync)); + return mLib->fWaitSync(mDisplay, sync, flags); + } + + EGLint fDupNativeFenceFDANDROID(EGLSync sync) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::ANDROID_native_fence_sync)); + return mLib->fDupNativeFenceFDANDROID(mDisplay, sync); + } + + // EXT_device_query + EGLBoolean fQueryDisplayAttribEXT(EGLint attribute, EGLAttrib* value) const { + MOZ_ASSERT(mLib->IsExtensionSupported(EGLLibExtension::EXT_device_query)); + return mLib->fQueryDisplayAttribEXT(mDisplay, attribute, value); + } + + // KHR_stream + EGLStreamKHR fCreateStreamKHR(const EGLint* attrib_list) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fCreateStreamKHR(mDisplay, attrib_list); + } + + EGLBoolean fDestroyStreamKHR(EGLStreamKHR stream) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fDestroyStreamKHR(mDisplay, stream); + } + + EGLBoolean fQueryStreamKHR(EGLStreamKHR stream, EGLenum attribute, + EGLint* value) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fQueryStreamKHR(mDisplay, stream, attribute, value); + } + + // KHR_stream_consumer_gltexture + EGLBoolean fStreamConsumerGLTextureExternalKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerGLTextureExternalKHR(mDisplay, stream); + } + + EGLBoolean fStreamConsumerAcquireKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerAcquireKHR(mDisplay, stream); + } + + EGLBoolean fStreamConsumerReleaseKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerReleaseKHR(mDisplay, stream); + } + + // NV_stream_consumer_gltexture_yuv + EGLBoolean fStreamConsumerGLTextureExternalAttribsNV( + EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::NV_stream_consumer_gltexture_yuv)); + return mLib->fStreamConsumerGLTextureExternalAttribsNV(mDisplay, stream, + attrib_list); + } + + // ANGLE_stream_producer_d3d_texture + EGLBoolean fCreateStreamProducerD3DTextureANGLE( + EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::ANGLE_stream_producer_d3d_texture)); + return mLib->fCreateStreamProducerD3DTextureANGLE(mDisplay, stream, + attrib_list); + } + + EGLBoolean fStreamPostD3DTextureANGLE(EGLStreamKHR stream, void* texture, + const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::ANGLE_stream_producer_d3d_texture)); + return mLib->fStreamPostD3DTextureANGLE(mDisplay, stream, texture, + attrib_list); + } + + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean fSwapBuffersWithDamage(EGLSurface surface, const EGLint* rects, + EGLint n_rects) { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::EXT_swap_buffers_with_damage) || + IsExtensionSupported(EGLExtension::KHR_swap_buffers_with_damage)); + return mLib->fSwapBuffersWithDamage(mDisplay, surface, rects, n_rects); + } + + // EGL_KHR_partial_update + EGLBoolean fSetDamageRegion(EGLSurface surface, const EGLint* rects, + EGLint n_rects) { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_partial_update)); + return mLib->fSetDamageRegion(mDisplay, surface, rects, n_rects); + } + + EGLBoolean fExportDMABUFImageQuery(EGLImage image, int* fourcc, + int* num_planes, + uint64_t* modifiers) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); + return mLib->fExportDMABUFImageQuery(mDisplay, image, fourcc, num_planes, + modifiers); + } + EGLBoolean fExportDMABUFImage(EGLImage image, int* fds, EGLint* strides, + EGLint* offsets) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); + return mLib->fExportDMABUFImage(mDisplay, image, fds, strides, offsets); + } +}; + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* GLLIBRARYEGL_H_ */ diff --git a/gfx/gl/GLLibraryLoader.cpp b/gfx/gl/GLLibraryLoader.cpp new file mode 100644 index 0000000000..e73f312d29 --- /dev/null +++ b/gfx/gl/GLLibraryLoader.cpp @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLLibraryLoader.h" + +#include <regex> + +#include "mozilla/gfx/Logging.h" +#include "nsDebug.h" + +#ifdef WIN32 +# include <windows.h> +#endif + +namespace mozilla { +namespace gl { + +void ClearSymbols(const SymLoadStruct* const firstStruct) { + for (auto itr = firstStruct; itr->symPointer; ++itr) { + *itr->symPointer = nullptr; + } +} + +bool SymbolLoader::LoadSymbols(const SymLoadStruct* const firstStruct, + const bool warnOnFailures) const { + bool ok = true; + + for (auto itr = firstStruct; itr->symPointer; ++itr) { + *itr->symPointer = nullptr; + + for (const auto& s : itr->symNames) { + if (!s) break; + + const auto p = GetProcAddress(s); + if (p) { + *itr->symPointer = p; + break; + } + } + + if (!*itr->symPointer) { + if (warnOnFailures) { + printf_stderr("Can't find symbol '%s'.\n", itr->symNames[0]); + } + ok = false; + } + } + + return ok; +} + +// - + +PRFuncPtr SymbolLoader::GetProcAddress(const char* const name) const { +#ifdef DEBUG + static const std::regex kRESymbol("[a-z].*"); + if (!std::regex_match(name, kRESymbol)) { + gfxCriticalError() << "Bad symbol name : " << name; + } +#endif + + PRFuncPtr ret = nullptr; + if (!ret && mLib) { + ret = PR_FindFunctionSymbol(mLib, name); + } + if (!ret && mPfn) { + ret = mPfn(name); + } + return ret; +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLLibraryLoader.h b/gfx/gl/GLLibraryLoader.h new file mode 100644 index 0000000000..e44e862f03 --- /dev/null +++ b/gfx/gl/GLLibraryLoader.h @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLLIBRARYLOADER_H_ +#define GLLIBRARYLOADER_H_ + +#include <array> +#include <stdio.h> + +#include "GLDefs.h" +#include "nscore.h" +#include "mozilla/Assertions.h" +#include "mozilla/SharedLibrary.h" + +namespace mozilla { +namespace gl { + +struct SymLoadStruct final { + PRFuncPtr* symPointer; + std::array<const char*, 6> symNames; +}; + +void ClearSymbols(const SymLoadStruct* firstStruct); + +class SymbolLoader final { + public: + typedef PRFuncPtr(GLAPIENTRY* GetProcAddressT)(const char*); + + GetProcAddressT mPfn = nullptr; // Try this first, if not null. + PRLibrary* mLib = nullptr; + + explicit SymbolLoader(void*(GLAPIENTRY* pfn)(const char*)) + : mPfn(GetProcAddressT(pfn)) { + MOZ_ASSERT(mPfn); + } + + explicit SymbolLoader(const GetProcAddressT pfn) : mPfn(pfn) { + MOZ_ASSERT(mPfn); + } + + explicit SymbolLoader(PRLibrary& lib) : mLib(&lib) { MOZ_ASSERT(mLib); } + + PRFuncPtr GetProcAddress(const char*) const; + bool LoadSymbols(const SymLoadStruct* firstStruct, + bool warnOnFailures = true) const; +}; + +} // namespace gl +} // namespace mozilla + +#endif // GLLIBRARYLOADER_H_ diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp new file mode 100644 index 0000000000..d45f700f16 --- /dev/null +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLReadTexImageHelper.h" + +#include <utility> + +#include "GLContext.h" +#include "OGLShaderProgram.h" +#include "ScopedGLHelpers.h" +#include "gfx2DGlue.h" +#include "gfxColor.h" +#include "gfxTypes.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Swizzle.h" + +namespace mozilla { +namespace gl { + +using namespace mozilla::gfx; + +GLReadTexImageHelper::GLReadTexImageHelper(GLContext* gl) : mGL(gl) { + mPrograms[0] = 0; + mPrograms[1] = 0; + mPrograms[2] = 0; + mPrograms[3] = 0; +} + +GLReadTexImageHelper::~GLReadTexImageHelper() { + if (!mGL->MakeCurrent()) return; + + mGL->fDeleteProgram(mPrograms[0]); + mGL->fDeleteProgram(mPrograms[1]); + mGL->fDeleteProgram(mPrograms[2]); + mGL->fDeleteProgram(mPrograms[3]); +} + +static const GLchar readTextureImageVS[] = + "attribute vec2 aVertex;\n" + "attribute vec2 aTexCoord;\n" + "varying vec2 vTexCoord;\n" + "void main() { gl_Position = vec4(aVertex, 0, 1); vTexCoord = aTexCoord; }"; + +static const GLchar readTextureImageFS_TEXTURE_2D[] = + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "varying vec2 vTexCoord;\n" + "uniform sampler2D uTexture;\n" + "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"; + +static const GLchar readTextureImageFS_TEXTURE_2D_BGRA[] = + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "varying vec2 vTexCoord;\n" + "uniform sampler2D uTexture;\n" + "void main() { gl_FragColor = texture2D(uTexture, vTexCoord).bgra; }"; + +static const GLchar readTextureImageFS_TEXTURE_EXTERNAL[] = + "#extension GL_OES_EGL_image_external : require\n" + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "varying vec2 vTexCoord;\n" + "uniform samplerExternalOES uTexture;\n" + "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"; + +static const GLchar readTextureImageFS_TEXTURE_RECTANGLE[] = + "#extension GL_ARB_texture_rectangle\n" + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "varying vec2 vTexCoord;\n" + "uniform sampler2DRect uTexture;\n" + "void main() { gl_FragColor = texture2DRect(uTexture, vTexCoord).bgra; }"; + +GLuint GLReadTexImageHelper::TextureImageProgramFor(GLenum aTextureTarget, + int aConfig) { + int variant = 0; + const GLchar* readTextureImageFS = nullptr; + if (aTextureTarget == LOCAL_GL_TEXTURE_2D) { + if (aConfig & mozilla::layers::ENABLE_TEXTURE_RB_SWAP) { + // Need to swizzle R/B. + readTextureImageFS = readTextureImageFS_TEXTURE_2D_BGRA; + variant = 1; + } else { + readTextureImageFS = readTextureImageFS_TEXTURE_2D; + variant = 0; + } + } else if (aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { + readTextureImageFS = readTextureImageFS_TEXTURE_EXTERNAL; + variant = 2; + } else if (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) { + readTextureImageFS = readTextureImageFS_TEXTURE_RECTANGLE; + variant = 3; + } + + /* This might be overkill, but assure that we don't access out-of-bounds */ + MOZ_ASSERT((size_t)variant < ArrayLength(mPrograms)); + if (!mPrograms[variant]) { + GLuint vs = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER); + const GLchar* vsSourcePtr = &readTextureImageVS[0]; + mGL->fShaderSource(vs, 1, &vsSourcePtr, nullptr); + mGL->fCompileShader(vs); + + GLuint fs = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); + mGL->fShaderSource(fs, 1, &readTextureImageFS, nullptr); + mGL->fCompileShader(fs); + + GLuint program = mGL->fCreateProgram(); + mGL->fAttachShader(program, vs); + mGL->fAttachShader(program, fs); + mGL->fBindAttribLocation(program, 0, "aVertex"); + mGL->fBindAttribLocation(program, 1, "aTexCoord"); + mGL->fLinkProgram(program); + + GLint success; + mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &success); + + if (!success) { + mGL->fDeleteProgram(program); + program = 0; + } + + mGL->fDeleteShader(vs); + mGL->fDeleteShader(fs); + + mPrograms[variant] = program; + } + + return mPrograms[variant]; +} + +bool GLReadTexImageHelper::DidGLErrorOccur(const char* str) { + GLenum error = mGL->fGetError(); + if (error != LOCAL_GL_NO_ERROR) { + printf_stderr("GL ERROR: %s %s\n", + GLContext::GLErrorToString(error).c_str(), str); + return true; + } + + return false; +} + +bool GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, + GLenum* out_readFormat, GLenum* out_readType) { + MOZ_ASSERT(out_readFormat); + MOZ_ASSERT(out_readType); + + if (destFormat == LOCAL_GL_RGBA && destType == LOCAL_GL_UNSIGNED_BYTE) { + *out_readFormat = destFormat; + *out_readType = destType; + return true; + } + + bool fallback = true; + if (gl->IsGLES()) { + GLenum auxFormat = 0; + GLenum auxType = 0; + + gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, + (GLint*)&auxFormat); + gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&auxType); + + if (destFormat == auxFormat && destType == auxType) { + fallback = false; + } + } else { + switch (destFormat) { + case LOCAL_GL_RGB: { + if (destType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV) fallback = false; + break; + } + case LOCAL_GL_BGRA: { + if (destType == LOCAL_GL_UNSIGNED_BYTE || + destType == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) { + fallback = false; + } + break; + } + } + } + + if (fallback) { + *out_readFormat = LOCAL_GL_RGBA; + *out_readType = LOCAL_GL_UNSIGNED_BYTE; + return false; + } else { + *out_readFormat = destFormat; + *out_readType = destType; + return true; + } +} + +void SwapRAndBComponents(DataSourceSurface* surf) { + DataSourceSurface::MappedSurface map; + if (!surf->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { + MOZ_ASSERT(false, "SwapRAndBComponents: Failed to map surface."); + return; + } + MOZ_ASSERT(map.mStride >= 0); + + const size_t rowBytes = surf->GetSize().width * 4; + const size_t rowHole = map.mStride - rowBytes; + + uint8_t* row = map.mData; + if (!row) { + MOZ_ASSERT(false, + "SwapRAndBComponents: Failed to get data from" + " DataSourceSurface."); + surf->Unmap(); + return; + } + + const size_t rows = surf->GetSize().height; + for (size_t i = 0; i < rows; i++) { + const uint8_t* rowEnd = row + rowBytes; + + while (row != rowEnd) { + std::swap(row[0], row[2]); + row += 4; + } + + row += rowHole; + } + + surf->Unmap(); +} + +static int CalcRowStride(int width, int pixelSize, int alignment) { + MOZ_ASSERT(alignment); + + int rowStride = width * pixelSize; + if (rowStride % alignment) { // Extra at the end of the line? + int alignmentCount = rowStride / alignment; + rowStride = (alignmentCount + 1) * alignment; + } + return rowStride; +} + +static int GuessAlignment(int width, int pixelSize, int rowStride) { + int alignment = 8; // Max GLES allows. + while (CalcRowStride(width, pixelSize, alignment) != rowStride) { + alignment /= 2; + if (!alignment) { + NS_WARNING("Bad alignment for GLES. Will use temp surf for readback."); + return 0; + } + } + return alignment; +} + +void ReadPixelsIntoBuffer(GLContext* gl, uint8_t* aData, int32_t aStride, + const IntSize& aSize, SurfaceFormat aFormat) { + gl->MakeCurrent(); + MOZ_ASSERT(aSize.width != 0); + MOZ_ASSERT(aSize.height != 0); + + bool hasAlpha = + aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8; + + int destPixelSize; + GLenum destFormat; + GLenum destType; + + switch (aFormat) { + case SurfaceFormat::B8G8R8A8: + case SurfaceFormat::B8G8R8X8: + // Needs host (little) endian ARGB. + destFormat = LOCAL_GL_BGRA; + destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + break; + case SurfaceFormat::R8G8B8A8: + case SurfaceFormat::R8G8B8X8: + // Needs host (little) endian ABGR. + destFormat = LOCAL_GL_RGBA; + destType = LOCAL_GL_UNSIGNED_BYTE; + break; + case SurfaceFormat::R5G6B5_UINT16: + destFormat = LOCAL_GL_RGB; + destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; + break; + default: + MOZ_CRASH("GFX: Bad format, read pixels."); + } + destPixelSize = BytesPerPixel(aFormat); + + MOZ_ASSERT(aSize.width * destPixelSize <= aStride); + + GLenum readFormat = destFormat; + GLenum readType = destType; + bool needsTempSurf = + !GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType); + + RefPtr<DataSourceSurface> tempSurf; + Maybe<DataSourceSurface::ScopedMap> tempMap; + uint8_t* data = aData; + SurfaceFormat readFormatGFX; + + int readAlignment = GuessAlignment(aSize.width, destPixelSize, aStride); + if (!readAlignment) { + needsTempSurf = true; + } + if (needsTempSurf) { + if (GLContext::ShouldSpew()) { + NS_WARNING( + "Needing intermediary surface for ReadPixels. This will be slow!"); + } + + switch (readFormat) { + case LOCAL_GL_RGBA: { + readFormatGFX = + hasAlpha ? SurfaceFormat::R8G8B8A8 : SurfaceFormat::R8G8B8X8; + break; + } + case LOCAL_GL_BGRA: { + readFormatGFX = + hasAlpha ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8; + break; + } + case LOCAL_GL_RGB: { + MOZ_ASSERT(destPixelSize == 2); + MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); + readFormatGFX = SurfaceFormat::R5G6B5_UINT16; + break; + } + default: { + MOZ_CRASH("GFX: Bad read format, read format."); + } + } + + switch (readType) { + case LOCAL_GL_UNSIGNED_BYTE: { + MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); + readAlignment = 1; + break; + } + case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { + MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); + readAlignment = 4; + break; + } + case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { + MOZ_ASSERT(readFormat == LOCAL_GL_RGB); + readAlignment = 2; + break; + } + default: { + MOZ_CRASH("GFX: Bad read type, read type."); + } + } + + int32_t stride = aSize.width * BytesPerPixel(readFormatGFX); + tempSurf = Factory::CreateDataSourceSurfaceWithStride(aSize, readFormatGFX, + stride); + if (NS_WARN_IF(!tempSurf)) { + return; + } + + tempMap.emplace(tempSurf, DataSourceSurface::READ_WRITE); + if (NS_WARN_IF(!tempMap->IsMapped())) { + return; + } + + data = tempMap->GetData(); + } + + MOZ_ASSERT(readAlignment); + MOZ_ASSERT(reinterpret_cast<uintptr_t>(data) % readAlignment == 0); + + GLsizei width = aSize.width; + GLsizei height = aSize.height; + + { + ScopedPackState safePackState(gl); + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment); + + gl->fReadPixels(0, 0, width, height, readFormat, readType, data); + } + + if (tempMap) { + SwizzleData(tempMap->GetData(), tempMap->GetStride(), readFormatGFX, aData, + aStride, aFormat, aSize); + } +} + +void ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) { + gl->MakeCurrent(); + + DataSourceSurface::ScopedMap map(dest, DataSourceSurface::WRITE); + ReadPixelsIntoBuffer(gl, map.GetData(), map.GetStride(), dest->GetSize(), + dest->GetFormat()); +} + +already_AddRefed<gfx::DataSourceSurface> YInvertImageSurface( + gfx::DataSourceSurface* aSurf, uint32_t aStride) { + RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurfaceWithStride( + aSurf->GetSize(), aSurf->GetFormat(), aStride); + if (NS_WARN_IF(!temp)) { + return nullptr; + } + + DataSourceSurface::MappedSurface map; + if (!temp->Map(DataSourceSurface::MapType::WRITE, &map)) { + return nullptr; + } + + RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData( + BackendType::CAIRO, map.mData, temp->GetSize(), map.mStride, + temp->GetFormat()); + if (!dt) { + temp->Unmap(); + return nullptr; + } + + dt->SetTransform(Matrix::Scaling(1.0, -1.0) * + Matrix::Translation(0.0, aSurf->GetSize().height)); + Rect rect(0, 0, aSurf->GetSize().width, aSurf->GetSize().height); + dt->DrawSurface( + aSurf, rect, rect, DrawSurfaceOptions(), + DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE)); + temp->Unmap(); + return temp.forget(); +} + +already_AddRefed<DataSourceSurface> ReadBackSurface(GLContext* gl, + GLuint aTexture, + bool aYInvert, + SurfaceFormat aFormat) { + gl->MakeCurrent(); + gl->fActiveTexture(LOCAL_GL_TEXTURE0); + gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); + + IntSize size; + gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, + &size.width); + gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, + &size.height); + + RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurfaceWithStride( + size, SurfaceFormat::B8G8R8A8, + GetAlignedStride<4>(size.width, BytesPerPixel(SurfaceFormat::B8G8R8A8))); + + if (NS_WARN_IF(!surf)) { + return nullptr; + } + + uint32_t currentPackAlignment = 0; + gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)¤tPackAlignment); + if (currentPackAlignment != 4) { + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); + } + + DataSourceSurface::ScopedMap map(surf, DataSourceSurface::READ); + gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, map.GetData()); + + if (currentPackAlignment != 4) { + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); + } + + if (aFormat == SurfaceFormat::R8G8B8A8 || + aFormat == SurfaceFormat::R8G8B8X8) { + SwapRAndBComponents(surf); + } + + if (aYInvert) { + surf = YInvertImageSurface(surf, map.GetStride()); + } + + return surf.forget(); +} + +#define CLEANUP_IF_GLERROR_OCCURRED(x) \ + if (DidGLErrorOccur(x)) { \ + return false; \ + } + +already_AddRefed<DataSourceSurface> GLReadTexImageHelper::ReadTexImage( + GLuint aTextureId, GLenum aTextureTarget, const gfx::IntSize& aSize, + /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) { + /* Allocate resulting image surface */ + int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); + RefPtr<DataSourceSurface> isurf = Factory::CreateDataSourceSurfaceWithStride( + aSize, SurfaceFormat::R8G8B8A8, stride); + if (NS_WARN_IF(!isurf)) { + return nullptr; + } + + if (!ReadTexImage(isurf, aTextureId, aTextureTarget, aSize, aConfig, + aYInvert)) { + return nullptr; + } + + return isurf.forget(); +} + +bool GLReadTexImageHelper::ReadTexImage( + DataSourceSurface* aDest, GLuint aTextureId, GLenum aTextureTarget, + const gfx::IntSize& aSize, + /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) { + MOZ_ASSERT(aTextureTarget == LOCAL_GL_TEXTURE_2D || + aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL || + aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB); + + mGL->MakeCurrent(); + + GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex; + GLuint rb, fb; + + do { + mGL->fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb); + mGL->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb); + mGL->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog); + mGL->fGetIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &oldTexUnit); + mGL->fActiveTexture(LOCAL_GL_TEXTURE0); + switch (aTextureTarget) { + case LOCAL_GL_TEXTURE_2D: + mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex); + break; + case LOCAL_GL_TEXTURE_EXTERNAL: + mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldTex); + break; + case LOCAL_GL_TEXTURE_RECTANGLE: + mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &oldTex); + break; + default: /* Already checked above */ + break; + } + + ScopedGLState scopedScissorTestState(mGL, LOCAL_GL_SCISSOR_TEST, false); + ScopedGLState scopedBlendState(mGL, LOCAL_GL_BLEND, false); + ScopedViewportRect scopedViewportRect(mGL, 0, 0, aSize.width, aSize.height); + + /* Setup renderbuffer */ + mGL->fGenRenderbuffers(1, &rb); + mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb); + + GLenum rbInternalFormat = + mGL->IsGLES() ? (mGL->IsExtensionSupported(GLContext::OES_rgb8_rgba8) + ? LOCAL_GL_RGBA8 + : LOCAL_GL_RGBA4) + : LOCAL_GL_RGBA; + mGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, + aSize.width, aSize.height); + CLEANUP_IF_GLERROR_OCCURRED("when binding and creating renderbuffer"); + + /* Setup framebuffer */ + mGL->fGenFramebuffers(1, &fb); + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); + mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, rb); + CLEANUP_IF_GLERROR_OCCURRED("when binding and creating framebuffer"); + + MOZ_ASSERT(mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == + LOCAL_GL_FRAMEBUFFER_COMPLETE); + + /* Setup vertex and fragment shader */ + GLuint program = TextureImageProgramFor(aTextureTarget, aConfig); + MOZ_ASSERT(program); + + mGL->fUseProgram(program); + CLEANUP_IF_GLERROR_OCCURRED("when using program"); + mGL->fUniform1i(mGL->fGetUniformLocation(program, "uTexture"), 0); + CLEANUP_IF_GLERROR_OCCURRED("when setting uniform location"); + + /* Setup quad geometry */ + mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); + + float w = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) + ? (float)aSize.width + : 1.0f; + float h = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) + ? (float)aSize.height + : 1.0f; + + const float vertexArray[4 * 2] = {-1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, 1.0f}; + ScopedVertexAttribPointer autoAttrib0(mGL, 0, 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, 0, 0, vertexArray); + + const float u0 = 0.0f; + const float u1 = w; + const float v0 = aYInvert ? h : 0.0f; + const float v1 = aYInvert ? 0.0f : h; + const float texCoordArray[8] = {u0, v0, u1, v0, u0, v1, u1, v1}; + ScopedVertexAttribPointer autoAttrib1(mGL, 1, 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, 0, 0, texCoordArray); + + /* Bind the texture */ + if (aTextureId) { + mGL->fBindTexture(aTextureTarget, aTextureId); + CLEANUP_IF_GLERROR_OCCURRED("when binding texture"); + } + + mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + CLEANUP_IF_GLERROR_OCCURRED("when drawing texture"); + + /* Read-back draw results */ + ReadPixelsIntoDataSurface(mGL, aDest); + CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface"); + } while (false); + + /* Restore GL state */ + mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb); + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb); + mGL->fUseProgram(oldprog); + + // note that deleting 0 has no effect in any of these calls + mGL->fDeleteRenderbuffers(1, &rb); + mGL->fDeleteFramebuffers(1, &fb); + + if (aTextureId) mGL->fBindTexture(aTextureTarget, oldTex); + + if (oldTexUnit != LOCAL_GL_TEXTURE0) mGL->fActiveTexture(oldTexUnit); + + return true; +} + +#undef CLEANUP_IF_GLERROR_OCCURRED + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLReadTexImageHelper.h b/gfx/gl/GLReadTexImageHelper.h new file mode 100644 index 0000000000..c5b631fc1a --- /dev/null +++ b/gfx/gl/GLReadTexImageHelper.h @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLREADTEXIMAGEHELPER_H_ +#define GLREADTEXIMAGEHELPER_H_ + +#include "GLContextTypes.h" +#include "mozilla/Attributes.h" +#include "nsSize.h" +#include "mozilla/RefPtr.h" +#include "mozilla/gfx/Types.h" + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +} // namespace gfx + +namespace gl { + +// Returns true if the `dest{Format,Type}` are the same as the +// `read{Format,Type}`. +bool GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, + GLenum* out_readFormat, GLenum* out_readType); + +void ReadPixelsIntoBuffer(GLContext* gl, uint8_t* aData, int32_t aStride, + const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat); + +void ReadPixelsIntoDataSurface(GLContext* aGL, + gfx::DataSourceSurface* aSurface); + +already_AddRefed<gfx::DataSourceSurface> ReadBackSurface( + GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat); + +already_AddRefed<gfx::DataSourceSurface> YInvertImageSurface( + gfx::DataSourceSurface* aSurf, uint32_t aStride); + +void SwapRAndBComponents(gfx::DataSourceSurface* surf); + +class GLReadTexImageHelper final { + // The GLContext is the sole owner of the GLBlitHelper. + GLContext* mGL; + + GLuint mPrograms[4]; + + GLuint TextureImageProgramFor(GLenum aTextureTarget, int aShader); + + bool DidGLErrorOccur(const char* str); + + public: + explicit GLReadTexImageHelper(GLContext* gl); + ~GLReadTexImageHelper(); + + /** + * Read the image data contained in aTexture, and return it as an + * ImageSurface. If GL_RGBA is given as the format, a + * SurfaceFormat::A8R8G8B8_UINT32 surface is returned. Not implemented yet: If + * GL_RGB is given as the format, a SurfaceFormat::X8R8G8B8_UINT32 surface is + * returned. If GL_LUMINANCE is given as the format, a SurfaceFormat::A8 + * surface is returned. + * + * THIS IS EXPENSIVE. It is ridiculously expensive. Only do this + * if you absolutely positively must, and never in any performance + * critical path. + * + * NOTE: aShaderProgram is really mozilla::layers::ShaderProgramType. It is + * passed as int to eliminate including LayerManagerOGLProgram.h here. + */ + already_AddRefed<gfx::DataSourceSurface> ReadTexImage( + GLuint aTextureId, GLenum aTextureTarget, const gfx::IntSize& aSize, + /* ShaderProgramType */ int aShaderProgram, bool aYInvert = false); + + bool ReadTexImage(gfx::DataSourceSurface* aDest, GLuint aTextureId, + GLenum aTextureTarget, const gfx::IntSize& aSize, + int aShaderProgram, bool aYInvert = false); +}; + +} // namespace gl +} // namespace mozilla + +#endif diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp new file mode 100644 index 0000000000..9dda11b41a --- /dev/null +++ b/gfx/gl/GLScreenBuffer.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLScreenBuffer.h" + +#include "CompositorTypes.h" +#include "GLContext.h" +#include "gfx2DGlue.h" +#include "MozFramebuffer.h" +#include "SharedSurface.h" + +namespace mozilla::gl { + +// - +// SwapChainPresenter + +// We need to apply pooling on Android because of the AndroidSurface slow +// destructor bugs. They cause a noticeable performance hit. See bug +// #1646073. +static constexpr size_t kPoolSize = +#if defined(MOZ_WIDGET_ANDROID) + 4; +#else + 0; +#endif + +UniquePtr<SwapChainPresenter> SwapChain::Acquire( + const gfx::IntSize& size, const gfx::ColorSpace2 colorSpace) { + MOZ_ASSERT(mFactory); + + std::shared_ptr<SharedSurface> surf; + if (!mPool.empty()) { + // Try reuse + const auto& existingDesc = mPool.front()->mDesc; + auto newDesc = existingDesc; + newDesc.size = size; + newDesc.colorSpace = colorSpace; + if (newDesc != existingDesc || !mPool.front()->IsValid()) { + mPool = {}; + } + } + + // When mDestroyedCallback exists, recycling of SharedSurfaces is managed by + // the owner of the SwapChain by calling StoreRecycledSurface(). + const auto poolSize = mDestroyedCallback ? 0 : kPoolSize; + + if (!mPool.empty() && (!poolSize || mPool.size() == poolSize)) { + surf = mPool.front(); + mPool.pop(); + } + if (!surf) { + auto uniquePtrSurf = mFactory->CreateShared(size, colorSpace); + if (!uniquePtrSurf) return nullptr; + surf.reset(uniquePtrSurf.release()); + } + mPool.push(surf); + while (mPool.size() > poolSize) { + mPool.pop(); + } + + auto ret = MakeUnique<SwapChainPresenter>(*this); + const auto old = ret->SwapBackBuffer(surf); + MOZ_ALWAYS_TRUE(!old); + return ret; +} + +void SwapChain::ClearPool() { + mPool = {}; + mPrevFrontBuffer = nullptr; +} + +bool SwapChain::StoreRecycledSurface( + const std::shared_ptr<SharedSurface>& surf) { + MOZ_ASSERT(mFactory); + if (!mFactory || NS_WARN_IF(surf->mDesc.gl != mFactory->mDesc.gl)) { + // Ensure we don't accidentally store an expired shared surface or from a + // different context. + return false; + } + mPool.push(surf); + return true; +} + +// - + +SwapChainPresenter::SwapChainPresenter(SwapChain& swapChain) + : mSwapChain(&swapChain) { + MOZ_RELEASE_ASSERT(mSwapChain->mPresenter == nullptr); + mSwapChain->mPresenter = this; +} + +SwapChainPresenter::~SwapChainPresenter() { + if (!mSwapChain) return; + MOZ_RELEASE_ASSERT(mSwapChain->mPresenter == this); + mSwapChain->mPresenter = nullptr; + + auto newFront = SwapBackBuffer(nullptr); + if (newFront) { + mSwapChain->mPrevFrontBuffer = mSwapChain->mFrontBuffer; + mSwapChain->mFrontBuffer = newFront; + } +} + +std::shared_ptr<SharedSurface> SwapChainPresenter::SwapBackBuffer( + std::shared_ptr<SharedSurface> back) { + if (mBackBuffer) { + mBackBuffer->UnlockProd(); + mBackBuffer->ProducerRelease(); + mBackBuffer->Commit(); + } + auto old = mBackBuffer; + mBackBuffer = back; + if (mBackBuffer) { + mBackBuffer->WaitForBufferOwnership(); + mBackBuffer->ProducerAcquire(); + mBackBuffer->LockProd(); + } + return old; +} + +GLuint SwapChainPresenter::Fb() const { + if (!mBackBuffer) return 0; + const auto& fb = mBackBuffer->mFb; + if (!fb) return 0; + return fb->mFB; +} + +// - +// SwapChain + +SwapChain::SwapChain() = default; + +SwapChain::~SwapChain() { + if (mPresenter) { + // Out of order destruction, but ok. + (void)mPresenter->SwapBackBuffer(nullptr); + mPresenter->mSwapChain = nullptr; + mPresenter = nullptr; + } + if (mDestroyedCallback) { + mDestroyedCallback(); + } +} + +} // namespace mozilla::gl diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h new file mode 100644 index 0000000000..d281249771 --- /dev/null +++ b/gfx/gl/GLScreenBuffer.h @@ -0,0 +1,87 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* GLScreenBuffer is the abstraction for the "default framebuffer" used + * by an offscreen GLContext. Since it's only for offscreen GLContext's, + * it's only useful for things like WebGL, and is NOT used by the + * compositor's GLContext. Remember that GLContext provides an abstraction + * so that even if you want to draw to the 'screen', even if that's not + * actually the screen, just draw to 0. This GLScreenBuffer class takes the + * logic handling out of GLContext. + */ + +#ifndef SCREEN_BUFFER_H_ +#define SCREEN_BUFFER_H_ + +#include "GLTypes.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/UniquePtr.h" + +#include <functional> +#include <queue> +#include <memory> + +namespace mozilla { +namespace gl { + +class SharedSurface; +class SurfaceFactory; +class SwapChain; + +class SwapChainPresenter final { + friend class SwapChain; + + SwapChain* mSwapChain; + std::shared_ptr<SharedSurface> mBackBuffer; + + public: + explicit SwapChainPresenter(SwapChain& swapChain); + ~SwapChainPresenter(); + + const auto& BackBuffer() const { return mBackBuffer; } + + std::shared_ptr<SharedSurface> SwapBackBuffer(std::shared_ptr<SharedSurface>); + GLuint Fb() const; +}; + +// - + +class SwapChain final { + friend class SwapChainPresenter; + + public: + UniquePtr<SurfaceFactory> mFactory; + + private: + std::queue<std::shared_ptr<SharedSurface>> mPool; + std::shared_ptr<SharedSurface> mFrontBuffer; + std::function<void()> mDestroyedCallback; + + public: + std::shared_ptr<SharedSurface> + mPrevFrontBuffer; // Hold this ref while it's in-flight. + private: + SwapChainPresenter* mPresenter = nullptr; + + public: + SwapChain(); + virtual ~SwapChain(); + + void ClearPool(); + bool StoreRecycledSurface(const std::shared_ptr<SharedSurface>& surf); + const auto& FrontBuffer() const { return mFrontBuffer; } + UniquePtr<SwapChainPresenter> Acquire(const gfx::IntSize&, gfx::ColorSpace2); + + void SetDestroyedCallback(std::function<void()>&& aDestroyedCallback) { + MOZ_ASSERT(!mDestroyedCallback); + mDestroyedCallback = std::move(aDestroyedCallback); + mPool = {}; + } +}; + +} // namespace gl +} // namespace mozilla + +#endif // SCREEN_BUFFER_H_ diff --git a/gfx/gl/GLTextureImage.cpp b/gfx/gl/GLTextureImage.cpp new file mode 100644 index 0000000000..e2295753fc --- /dev/null +++ b/gfx/gl/GLTextureImage.cpp @@ -0,0 +1,453 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLTextureImage.h" +#include "GLContext.h" +#include "gfxContext.h" +#include "gfxPlatform.h" +#include "gfxUtils.h" +#include "gfx2DGlue.h" +#include "mozilla/gfx/2D.h" +#include "ScopedGLHelpers.h" +#include "GLUploadHelpers.h" +#include "GfxTexturesReporter.h" + +using namespace mozilla::gfx; + +namespace mozilla { +namespace gl { + +already_AddRefed<TextureImage> CreateTextureImage( + GLContext* gl, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, GLenum aWrapMode, + TextureImage::Flags aFlags, TextureImage::ImageFormat aImageFormat) { + GLint maxTextureSize; + gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); + if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) { + NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, + "Can't support wrapping with tiles!"); + return CreateTiledTextureImage(gl, aSize, aContentType, aFlags, + aImageFormat); + } else { + return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags); + } +} + +static already_AddRefed<TextureImage> TileGenFunc( + GLContext* gl, const IntSize& aSize, TextureImage::ContentType aContentType, + TextureImage::Flags aFlags, TextureImage::ImageFormat aImageFormat) { + return CreateBasicTextureImage(gl, aSize, aContentType, + LOCAL_GL_CLAMP_TO_EDGE, aFlags); +} + +already_AddRefed<TextureImage> TextureImage::Create( + GLContext* gl, const gfx::IntSize& size, + TextureImage::ContentType contentType, GLenum wrapMode, + TextureImage::Flags flags) { + return CreateTextureImage(gl, size, contentType, wrapMode, flags); +} + +bool TextureImage::UpdateFromDataSource(gfx::DataSourceSurface* aSurface, + const nsIntRegion* aDestRegion, + const gfx::IntPoint* aSrcOffset, + const gfx::IntPoint* aDstOffset) { + nsIntRegion destRegion = aDestRegion + ? *aDestRegion + : IntRect(0, 0, aSurface->GetSize().width, + aSurface->GetSize().height); + gfx::IntPoint srcPoint = aSrcOffset ? *aSrcOffset : gfx::IntPoint(0, 0); + gfx::IntPoint srcPointOut = aDstOffset ? *aDstOffset : gfx::IntPoint(0, 0); + return DirectUpdate(aSurface, destRegion, srcPoint, srcPointOut); +} + +gfx::IntRect TextureImage::GetTileRect() { + return gfx::IntRect(gfx::IntPoint(0, 0), mSize); +} + +gfx::IntRect TextureImage::GetSrcTileRect() { return GetTileRect(); } + +void TextureImage::UpdateUploadSize(size_t amount) { + if (mUploadSize > 0) { + GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryFreed, + mUploadSize); + } + mUploadSize = amount; + GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryAllocated, + mUploadSize); +} + +BasicTextureImage::~BasicTextureImage() { + GLContext* ctx = mGLContext; + if (ctx->IsDestroyed() || !ctx->IsValidOwningThread()) { + ctx = ctx->GetSharedContext(); + } + + // If we have a context, then we need to delete the texture; + // if we don't have a context (either real or shared), + // then they went away when the contex was deleted, because it + // was the only one that had access to it. + if (ctx && ctx->MakeCurrent()) { + ctx->fDeleteTextures(1, &mTexture); + } +} + +void BasicTextureImage::BindTexture(GLenum aTextureUnit) { + mGLContext->fActiveTexture(aTextureUnit); + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); +} + +bool BasicTextureImage::DirectUpdate( + gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, + const gfx::IntPoint& aSrcOffset /* = gfx::IntPoint(0, 0) */, + const gfx::IntPoint& aDstOffset /* = gfx::IntPoint(0, 0) */) { + nsIntRegion region; + if (mTextureState == Valid) { + region = aRegion; + } else { + region = nsIntRegion(IntRect(0, 0, mSize.width, mSize.height)); + } + bool needInit = mTextureState == Created; + size_t uploadSize; + + mTextureFormat = + UploadSurfaceToTexture(mGLContext, aSurf, region, mTexture, mSize, + &uploadSize, needInit, aSrcOffset, aDstOffset); + if (mTextureFormat == SurfaceFormat::UNKNOWN) { + return false; + } + + if (uploadSize > 0) { + UpdateUploadSize(uploadSize); + } + mTextureState = Valid; + return true; +} + +void BasicTextureImage::Resize(const gfx::IntSize& aSize) { + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + + // This matches the logic in UploadImageDataToTexture so that + // we avoid mixing formats. + GLenum format; + GLenum type; + if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { + MOZ_ASSERT(!mGLContext->IsGLES()); + format = LOCAL_GL_BGRA; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + } else { + format = LOCAL_GL_RGBA; + type = LOCAL_GL_UNSIGNED_BYTE; + } + + mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, aSize.width, + aSize.height, 0, format, type, nullptr); + + mTextureState = Allocated; + mSize = aSize; +} + +gfx::IntSize TextureImage::GetSize() const { return mSize; } + +TextureImage::TextureImage(const gfx::IntSize& aSize, GLenum aWrapMode, + ContentType aContentType, Flags aFlags) + : mSize(aSize), + mWrapMode(aWrapMode), + mContentType(aContentType), + mTextureFormat(gfx::SurfaceFormat::UNKNOWN), + mSamplingFilter(SamplingFilter::GOOD), + mFlags(aFlags), + mUploadSize(0) {} + +BasicTextureImage::BasicTextureImage(GLuint aTexture, const gfx::IntSize& aSize, + GLenum aWrapMode, ContentType aContentType, + GLContext* aContext, + TextureImage::Flags aFlags) + : TextureImage(aSize, aWrapMode, aContentType, aFlags), + mTexture(aTexture), + mTextureState(Created), + mGLContext(aContext) {} + +static bool WantsSmallTiles(GLContext* gl) { + // We can't use small tiles on the SGX 540, because of races in texture + // upload. + if (gl->WorkAroundDriverBugs() && gl->Renderer() == GLRenderer::SGX540) + return false; + + // We should use small tiles for good performance if we can't use + // glTexSubImage2D() for some reason. + if (!ShouldUploadSubTextures(gl)) return true; + + // Don't use small tiles otherwise. (If we implement incremental texture + // upload, then we will want to revisit this.) + return false; +} + +TiledTextureImage::TiledTextureImage(GLContext* aGL, gfx::IntSize aSize, + TextureImage::ContentType aContentType, + TextureImage::Flags aFlags, + TextureImage::ImageFormat aImageFormat) + : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags), + mCurrentImage(0), + mIterationCallback(nullptr), + mIterationCallbackData(nullptr), + mTileSize(0), + mRows(0), + mColumns(0), + mGL(aGL), + mTextureState(Created), + mImageFormat(aImageFormat) { + if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) { + mTileSize = 256; + } else { + mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mTileSize); + } + if (aSize.width != 0 && aSize.height != 0) { + Resize(aSize); + } +} + +TiledTextureImage::~TiledTextureImage() = default; + +bool TiledTextureImage::DirectUpdate( + gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, + const gfx::IntPoint& aSrcOffset /* = gfx::IntPoint(0, 0) */, + const gfx::IntPoint& aDstOffset /* = gfx::IntPoint(0, 0) */) { + // We don't handle non-zero aDstOffset + MOZ_RELEASE_ASSERT(aDstOffset == gfx::IntPoint()); + + if (mSize.width == 0 || mSize.height == 0) { + return true; + } + + nsIntRegion region; + + if (mTextureState != Valid) { + IntRect bounds = IntRect(0, 0, mSize.width, mSize.height); + region = nsIntRegion(bounds); + } else { + region = aRegion; + } + + bool result = true; + int oldCurrentImage = mCurrentImage; + BeginBigImageIteration(); + do { + IntRect tileRect = GetSrcTileRect(); + int xPos = tileRect.X(); + int yPos = tileRect.Y(); + + nsIntRegion tileRegion; + tileRegion.And(region, tileRect); // intersect with tile + + if (tileRegion.IsEmpty()) continue; + + tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space + + result &= mImages[mCurrentImage]->DirectUpdate( + aSurf, tileRegion, aSrcOffset + gfx::IntPoint(xPos, yPos)); + + if (mCurrentImage == mImages.Length() - 1) { + // We know we're done, but we still need to ensure that the callback + // gets called (e.g. to update the uploaded region). + NextTile(); + break; + } + // Override a callback cancelling iteration if the texture wasn't valid. + // We need to force the update in that situation, or we may end up + // showing invalid/out-of-date texture data. + } while (NextTile() || (mTextureState != Valid)); + mCurrentImage = oldCurrentImage; + + mTextureFormat = mImages[0]->GetTextureFormat(); + mTextureState = Valid; + return result; +} + +void TiledTextureImage::BeginBigImageIteration() { mCurrentImage = 0; } + +bool TiledTextureImage::NextTile() { + bool continueIteration = true; + + if (mIterationCallback) + continueIteration = + mIterationCallback(this, mCurrentImage, mIterationCallbackData); + + if (mCurrentImage + 1 < mImages.Length()) { + mCurrentImage++; + return continueIteration; + } + return false; +} + +void TiledTextureImage::SetIterationCallback( + BigImageIterationCallback aCallback, void* aCallbackData) { + mIterationCallback = aCallback; + mIterationCallbackData = aCallbackData; +} + +gfx::IntRect TiledTextureImage::GetTileRect() { + if (!GetTileCount()) { + return gfx::IntRect(); + } + gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect(); + unsigned int xPos = (mCurrentImage % mColumns) * mTileSize; + unsigned int yPos = (mCurrentImage / mColumns) * mTileSize; + rect.MoveBy(xPos, yPos); + return rect; +} + +gfx::IntRect TiledTextureImage::GetSrcTileRect() { + gfx::IntRect rect = GetTileRect(); + const bool needsYFlip = mFlags & OriginBottomLeft; + unsigned int srcY = + needsYFlip ? mSize.height - rect.Height() - rect.Y() : rect.Y(); + return gfx::IntRect(rect.X(), srcY, rect.Width(), rect.Height()); +} + +void TiledTextureImage::BindTexture(GLenum aTextureUnit) { + if (!GetTileCount()) { + return; + } + mImages[mCurrentImage]->BindTexture(aTextureUnit); +} + +/* + * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per + * column. A tile on a column is reused if it hasn't changed size, otherwise it + * is discarded/replaced. Extra tiles on a column are pruned after iterating + * each column, and extra rows are pruned after iteration over the entire image + * finishes. + */ +void TiledTextureImage::Resize(const gfx::IntSize& aSize) { + if (mSize == aSize && mTextureState != Created) { + return; + } + + // calculate rows and columns, rounding up + unsigned int columns = (aSize.width + mTileSize - 1) / mTileSize; + unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize; + + // Iterate over old tile-store and insert/remove tiles as necessary + int row; + unsigned int i = 0; + for (row = 0; row < (int)rows; row++) { + // If we've gone beyond how many rows there were before, set mColumns to + // zero so that we only create new tiles. + if (row >= (int)mRows) mColumns = 0; + + // Similarly, if we're on the last row of old tiles and the height has + // changed, discard all tiles in that row. + // This will cause the pruning of columns not to work, but we don't need + // to worry about that, as no more tiles will be reused past this point + // anyway. + if ((row == (int)mRows - 1) && (aSize.height != mSize.height)) mColumns = 0; + + int col; + for (col = 0; col < (int)columns; col++) { + IntSize size( // use tilesize first, then the remainder + (col + 1) * mTileSize > (unsigned int)aSize.width + ? aSize.width % mTileSize + : mTileSize, + (row + 1) * mTileSize > (unsigned int)aSize.height + ? aSize.height % mTileSize + : mTileSize); + + bool replace = false; + + // Check if we can re-use old tiles. + if (col < (int)mColumns) { + // Reuse an existing tile. If the tile is an end-tile and the + // width differs, replace it instead. + if (mSize.width != aSize.width) { + if (col == (int)mColumns - 1) { + // Tile at the end of the old column, replace it with + // a new one. + replace = true; + } else if (col == (int)columns - 1) { + // Tile at the end of the new column, create a new one. + } else { + // Before the last column on both the old and new sizes, + // reuse existing tile. + i++; + continue; + } + } else { + // Width hasn't changed, reuse existing tile. + i++; + continue; + } + } + + // Create a new tile. + RefPtr<TextureImage> teximg = + TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat); + if (replace) + mImages.ReplaceElementAt(i, teximg); + else + mImages.InsertElementAt(i, teximg); + i++; + } + + // Prune any unused tiles on the end of the column. + if (row < (int)mRows) { + for (col = (int)mColumns - col; col > 0; col--) { + mImages.RemoveElementAt(i); + } + } + } + + // Prune any unused tiles at the end of the store. + mImages.RemoveLastElements(mImages.Length() - i); + + // Reset tile-store properties. + mRows = rows; + mColumns = columns; + mSize = aSize; + mTextureState = Allocated; + mCurrentImage = 0; +} + +uint32_t TiledTextureImage::GetTileCount() { return mImages.Length(); } + +already_AddRefed<TextureImage> CreateTiledTextureImage( + GLContext* aGL, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, TextureImage::Flags aFlags, + TextureImage::ImageFormat aImageFormat) { + RefPtr<TextureImage> texImage = + static_cast<TextureImage*>(new gl::TiledTextureImage( + aGL, aSize, aContentType, aFlags, aImageFormat)); + return texImage.forget(); +} + +already_AddRefed<TextureImage> CreateBasicTextureImage( + GLContext* aGL, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, GLenum aWrapMode, + TextureImage::Flags aFlags) { + bool useNearestFilter = aFlags & TextureImage::UseNearestFilter; + if (!aGL->MakeCurrent()) { + return nullptr; + } + + GLuint texture = 0; + aGL->fGenTextures(1, &texture); + + ScopedBindTexture bind(aGL, texture); + + GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, + texfilter); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, + texfilter); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode); + + RefPtr<BasicTextureImage> texImage = new BasicTextureImage( + texture, aSize, aWrapMode, aContentType, aGL, aFlags); + return texImage.forget(); +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLTextureImage.h b/gfx/gl/GLTextureImage.h new file mode 100644 index 0000000000..eb07b08832 --- /dev/null +++ b/gfx/gl/GLTextureImage.h @@ -0,0 +1,288 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLTEXTUREIMAGE_H_ +#define GLTEXTUREIMAGE_H_ + +#include "nsRegion.h" +#include "nsTArray.h" +#include "gfxTypes.h" +#include "GLContextTypes.h" +#include "mozilla/gfx/Rect.h" +#include "mozilla/RefPtr.h" + +class gfxASurface; + +namespace mozilla { +namespace gfx { +class DataSourceSurface; +class DrawTarget; +} // namespace gfx +} // namespace mozilla + +namespace mozilla { +namespace gl { +class GLContext; + +/** + * A TextureImage provides a mechanism to synchronize data from a + * surface to a texture in the server. TextureImages are associated + * with one and only one GLContext. + */ +class TextureImage { + NS_INLINE_DECL_REFCOUNTING(TextureImage) + public: + enum TextureState { + Created, // Texture created, but has not had glTexImage called to + // initialize it. + Allocated, // Texture memory exists, but contents are invalid. + Valid // Texture fully ready to use. + }; + + enum Flags { + NoFlags = 0x0, + UseNearestFilter = 0x1, + OriginBottomLeft = 0x2, + DisallowBigImage = 0x4 + }; + + typedef gfxContentType ContentType; + typedef gfxImageFormat ImageFormat; + + static already_AddRefed<TextureImage> Create( + GLContext* gl, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, GLenum aWrapMode, + TextureImage::Flags aFlags = TextureImage::NoFlags); + + /** + * The Image may contain several textures for different regions (tiles). + * These functions iterate over each sub texture image tile. + */ + virtual void BeginBigImageIteration() {} + + virtual bool NextTile() { return false; } + + // Function prototype for a tile iteration callback. Returning false will + // cause iteration to be interrupted (i.e. the corresponding NextTile call + // will return false). + typedef bool (*BigImageIterationCallback)(TextureImage* aImage, + int aTileNumber, + void* aCallbackData); + + // Sets a callback to be called every time NextTile is called. + virtual void SetIterationCallback(BigImageIterationCallback aCallback, + void* aCallbackData) {} + + virtual gfx::IntRect GetTileRect(); + + virtual GLuint GetTextureID() = 0; + + virtual uint32_t GetTileCount() { return 1; } + + /** + * Set this TextureImage's size, and ensure a texture has been + * allocated. + * After a resize, the contents are undefined. + */ + virtual void Resize(const gfx::IntSize& aSize) = 0; + + /** + * Mark this texture as having valid contents. Call this after modifying + * the texture contents externally. + */ + virtual void MarkValid() {} + + /** + * aSurf - the source surface to update from + * aRegion - the region in this image to update + * aSrcOffset - offset in the source to update from + * aDstOffset - offset in the destination to update to + */ + virtual bool DirectUpdate( + gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, + const gfx::IntPoint& aSrcOffset = gfx::IntPoint(0, 0), + const gfx::IntPoint& aDstOffset = gfx::IntPoint(0, 0)) = 0; + bool UpdateFromDataSource(gfx::DataSourceSurface* aSurf, + const nsIntRegion* aDstRegion = nullptr, + const gfx::IntPoint* aSrcOffset = nullptr, + const gfx::IntPoint* aDstOffset = nullptr); + + virtual void BindTexture(GLenum aTextureUnit) = 0; + + /** + * Returns the image format of the texture. Only valid after + * DirectUpdate has been called. + */ + virtual gfx::SurfaceFormat GetTextureFormat() { return mTextureFormat; } + + /** Can be called safely at any time. */ + + /** + * If this TextureImage has a permanent gfxASurface backing, + * return it. Otherwise return nullptr. + */ + virtual already_AddRefed<gfxASurface> GetBackingSurface() { return nullptr; } + + gfx::IntSize GetSize() const; + ContentType GetContentType() const { return mContentType; } + GLenum GetWrapMode() const { return mWrapMode; } + + void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) { + mSamplingFilter = aSamplingFilter; + } + + protected: + friend class GLContext; + + void UpdateUploadSize(size_t amount); + + /** + * After the ctor, the TextureImage is invalid. Implementations + * must allocate resources successfully before returning the new + * TextureImage from GLContext::CreateTextureImage(). That is, + * clients must not be given partially-constructed TextureImages. + */ + TextureImage(const gfx::IntSize& aSize, GLenum aWrapMode, + ContentType aContentType, Flags aFlags = NoFlags); + + // Protected destructor, to discourage deletion outside of Release(): + virtual ~TextureImage() { UpdateUploadSize(0); } + + virtual gfx::IntRect GetSrcTileRect(); + + gfx::IntSize mSize; + GLenum mWrapMode; + ContentType mContentType; + gfx::SurfaceFormat mTextureFormat; + gfx::SamplingFilter mSamplingFilter; + Flags mFlags; + size_t mUploadSize; +}; + +/** + * BasicTextureImage is the baseline TextureImage implementation --- + * it updates its texture by allocating a scratch buffer for the + * client to draw into, then using glTexSubImage2D() to upload the new + * pixels. Platforms must provide the code to create a new surface + * into which the updated pixels will be drawn, and the code to + * convert the update surface's pixels into an image on which we can + * glTexSubImage2D(). + */ +class BasicTextureImage : public TextureImage { + public: + virtual ~BasicTextureImage(); + + BasicTextureImage(GLuint aTexture, const gfx::IntSize& aSize, + GLenum aWrapMode, ContentType aContentType, + GLContext* aContext, + TextureImage::Flags aFlags = TextureImage::NoFlags); + + void BindTexture(GLenum aTextureUnit) override; + + bool DirectUpdate( + gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, + const gfx::IntPoint& aSrcOffset = gfx::IntPoint(0, 0), + const gfx::IntPoint& aDstOffset = gfx::IntPoint(0, 0)) override; + GLuint GetTextureID() override { return mTexture; } + + void MarkValid() override { mTextureState = Valid; } + + void Resize(const gfx::IntSize& aSize) override; + + protected: + GLuint mTexture; + TextureState mTextureState; + RefPtr<GLContext> mGLContext; +}; + +/** + * A container class that complements many sub TextureImages into a big + * TextureImage. Aims to behave just like the real thing. + */ + +class TiledTextureImage final : public TextureImage { + public: + TiledTextureImage( + GLContext* aGL, gfx::IntSize aSize, TextureImage::ContentType, + TextureImage::Flags aFlags = TextureImage::NoFlags, + TextureImage::ImageFormat aImageFormat = gfx::SurfaceFormat::UNKNOWN); + virtual ~TiledTextureImage(); + void DumpDiv(); + void Resize(const gfx::IntSize& aSize) override; + uint32_t GetTileCount() override; + void BeginBigImageIteration() override; + bool NextTile() override; + void SetIterationCallback(BigImageIterationCallback aCallback, + void* aCallbackData) override; + gfx::IntRect GetTileRect() override; + GLuint GetTextureID() override { + return mImages[mCurrentImage]->GetTextureID(); + } + bool DirectUpdate( + gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, + const gfx::IntPoint& aSrcOffset = gfx::IntPoint(0, 0), + const gfx::IntPoint& aDstOffset = gfx::IntPoint(0, 0)) override; + void BindTexture(GLenum) override; + + protected: + gfx::IntRect GetSrcTileRect() override; + + unsigned int mCurrentImage; + BigImageIterationCallback mIterationCallback; + void* mIterationCallbackData; + nsTArray<RefPtr<TextureImage> > mImages; + unsigned int mTileSize; + unsigned int mRows, mColumns; + GLContext* mGL; + TextureState mTextureState; + TextureImage::ImageFormat mImageFormat; +}; + +/** + * Creates a TextureImage of the basic implementation, can be useful in cases + * where we know we don't want to use platform-specific TextureImage. + * In doubt, use GLContext::CreateTextureImage instead. + */ +already_AddRefed<TextureImage> CreateBasicTextureImage( + GLContext* aGL, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, GLenum aWrapMode, + TextureImage::Flags aFlags); + +/** + * Creates a TiledTextureImage backed by platform-specific or basic + * TextureImages. In doubt, use GLContext::CreateTextureImage instead. + */ +already_AddRefed<TextureImage> CreateTiledTextureImage( + GLContext* aGL, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, TextureImage::Flags aFlags, + TextureImage::ImageFormat aImageFormat); + +/** + * Return a valid, allocated TextureImage of |aSize| with + * |aContentType|. If |aContentType| is COLOR, |aImageFormat| can be used + * to hint at the preferred RGB format, however it is not necessarily + * respected. The TextureImage's texture is configured to use + * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by + * default, GL_LINEAR filtering. Specify + * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify + * |aFlags=OriginBottomLeft| if the image is origin-bottom-left, instead of the + * default origin-top-left. Return + * nullptr if creating the TextureImage fails. + * + * The returned TextureImage may only be used with this GLContext. + * Attempting to use the returned TextureImage after this + * GLContext is destroyed will result in undefined (and likely + * crashy) behavior. + */ +already_AddRefed<TextureImage> CreateTextureImage( + GLContext* gl, const gfx::IntSize& aSize, + TextureImage::ContentType aContentType, GLenum aWrapMode, + TextureImage::Flags aFlags = TextureImage::NoFlags, + TextureImage::ImageFormat aImageFormat = gfx::SurfaceFormat::UNKNOWN); + +} // namespace gl +} // namespace mozilla + +#endif /* GLTEXTUREIMAGE_H_ */ diff --git a/gfx/gl/GLTypes.h b/gfx/gl/GLTypes.h new file mode 100644 index 0000000000..f5b317b4b7 --- /dev/null +++ b/gfx/gl/GLTypes.h @@ -0,0 +1,115 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLTYPES_H_ +#define GLTYPES_H_ + +#include <stddef.h> +#include <stdint.h> + +#ifndef GLAPIENTRY +# ifdef WIN32 +# include <windef.h> +# define GLAPIENTRY APIENTRY +# define GLAPI +# else +# define GLAPIENTRY +# define GLAPI +# endif +#endif + +typedef uint8_t realGLboolean; + +#if !defined(__gltypes_h_) && !defined(__gl_h_) +# define __gltypes_h_ +# define __gl_h_ + +typedef uint32_t GLenum; +typedef uint32_t GLbitfield; +typedef uint32_t GLuint; +typedef int32_t GLint; +typedef int32_t GLsizei; +typedef int8_t GLbyte; +typedef int16_t GLshort; +typedef uint8_t GLubyte; +typedef uint16_t GLushort; +typedef float GLfloat; +typedef float GLclampf; +# ifndef GLdouble_defined +typedef double GLdouble; +# endif +typedef double GLclampd; +typedef void GLvoid; + +typedef char GLchar; +# ifndef __gl2_h_ +# ifdef _WIN64 +typedef signed long long int GLintptr; +typedef signed long long int GLsizeiptr; +# else +typedef signed long int GLintptr; +typedef signed long int GLsizeiptr; +# endif +# endif + +#endif /* #if !defined(__gltypes_h_) && !defined(__gl_h_) */ + +#include <stdint.h> + +// ARB_sync +typedef struct __GLsync* GLsync; +typedef int64_t GLint64; +typedef uint64_t GLuint64; + +// OES_EGL_image (GLES) +typedef void* GLeglImage; + +// KHR_debug +typedef void(GLAPIENTRY* GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar* message, + const GLvoid* userParam); + +// EGL types +typedef void* EGLImage; +typedef int EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef intptr_t EGLAttrib; +typedef void* EGLConfig; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLDeviceEXT; +typedef void* EGLSurface; +typedef void* EGLClientBuffer; +typedef void* EGLCastToRelevantPtr; +typedef void* EGLImage; +typedef void* EGLSync; +typedef void* EGLStreamKHR; +typedef uint64_t EGLTime; + +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) +#define EGL_NO_CONFIG ((EGLConfig) nullptr) +#define EGL_NO_SYNC ((EGLSync)0) +#define EGL_NO_IMAGE ((EGLImage)0) + +#ifdef XP_WIN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif + +# include <windef.h> + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; +#else +typedef void* EGLNativeDisplayType; +typedef void* EGLNativePixmapType; +typedef void* EGLNativeWindowType; +#endif + +#endif // GLTYPES_H_ diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp new file mode 100644 index 0000000000..c6efcfd656 --- /dev/null +++ b/gfx/gl/GLUploadHelpers.cpp @@ -0,0 +1,518 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLUploadHelpers.h" + +#include "GLContext.h" +#include "mozilla/gfx/2D.h" +#include "gfxUtils.h" +#include "mozilla/gfx/Tools.h" // For BytesPerPixel +#include "nsRegion.h" +#include "GfxTexturesReporter.h" +#include "mozilla/gfx/Logging.h" + +namespace mozilla { + +using namespace gfx; + +namespace gl { + +static unsigned int DataOffset(const IntPoint& aPoint, int32_t aStride, + SurfaceFormat aFormat) { + unsigned int data = aPoint.y * aStride; + data += aPoint.x * BytesPerPixel(aFormat); + return data; +} + +static bool CheckUploadBounds(const IntSize& aDst, const IntSize& aSrc, + const IntPoint& aOffset) { + if (aOffset.x < 0 || aOffset.y < 0 || aOffset.x >= aSrc.width || + aOffset.y >= aSrc.height) { + MOZ_ASSERT_UNREACHABLE("Offset outside source bounds"); + return false; + } + if (aDst.width > (aSrc.width - aOffset.x) || + aDst.height > (aSrc.height - aOffset.y)) { + MOZ_ASSERT_UNREACHABLE("Source has insufficient data"); + return false; + } + return true; +} + +static GLint GetAddressAlignment(ptrdiff_t aAddress) { + if (!(aAddress & 0x7)) { + return 8; + } else if (!(aAddress & 0x3)) { + return 4; + } else if (!(aAddress & 0x1)) { + return 2; + } else { + return 1; + } +} + +// Take texture data in a given buffer and copy it into a larger buffer, +// padding out the edge pixels for filtering if necessary +static void CopyAndPadTextureData(const GLvoid* srcBuffer, GLvoid* dstBuffer, + GLsizei srcWidth, GLsizei srcHeight, + GLsizei dstWidth, GLsizei dstHeight, + GLsizei stride, GLint pixelsize) { + unsigned char* rowDest = static_cast<unsigned char*>(dstBuffer); + const unsigned char* source = static_cast<const unsigned char*>(srcBuffer); + + for (GLsizei h = 0; h < srcHeight; ++h) { + memcpy(rowDest, source, srcWidth * pixelsize); + rowDest += dstWidth * pixelsize; + source += stride; + } + + GLsizei padHeight = srcHeight; + + // Pad out an extra row of pixels so that edge filtering doesn't use garbage + // data + if (dstHeight > srcHeight) { + memcpy(rowDest, source - stride, srcWidth * pixelsize); + padHeight++; + } + + // Pad out an extra column of pixels + if (dstWidth > srcWidth) { + rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize; + for (GLsizei h = 0; h < padHeight; ++h) { + memcpy(rowDest, rowDest - pixelsize, pixelsize); + rowDest += dstWidth * pixelsize; + } + } +} + +// In both of these cases (for the Adreno at least) it is impossible +// to determine good or bad driver versions for POT texture uploads, +// so blacklist them all. Newer drivers use a different rendering +// string in the form "Adreno (TM) 200" and the drivers we've seen so +// far work fine with NPOT textures, so don't blacklist those until we +// have evidence of any problems with them. +bool ShouldUploadSubTextures(GLContext* gl) { + if (!gl->WorkAroundDriverBugs()) return true; + + // There are certain GPUs that we don't want to use glTexSubImage2D on + // because that function can be very slow and/or buggy + if (gl->Renderer() == GLRenderer::Adreno200 || + gl->Renderer() == GLRenderer::Adreno205) { + return false; + } + + // On PowerVR glTexSubImage does a readback, so it will be slower + // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms + if (gl->Renderer() == GLRenderer::SGX540 || + gl->Renderer() == GLRenderer::SGX530) { + return false; + } + + return true; +} + +static void TexSubImage2DWithUnpackSubimageGLES( + GLContext* gl, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLsizei stride, GLint pixelsize, + GLenum format, GLenum type, const GLvoid* pixels) { + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra + // driver crash where the driver apparently tries to read + // (stride - width * pixelsize) bytes past the end of the last input + // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH, + // and then we upload the final row separately. See bug 697990. + int rowLength = stride / pixelsize; + if (gl->HasPBOState()) { + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); + } else { + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height - 1, + format, type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); + gl->fTexSubImage2D(target, level, xoffset, yoffset + height - 1, width, 1, + format, type, + (const unsigned char*)pixels + (height - 1) * stride); + } + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); +} + +static void TexSubImage2DWithoutUnpackSubimage( + GLContext* gl, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLsizei stride, GLint pixelsize, + GLenum format, GLenum type, const GLvoid* pixels) { + // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH + // isn't supported. We make a copy of the texture data we're using, + // such that we're using the whole row of data in the copy. This turns + // out to be more efficient than uploading row-by-row; see bug 698197. + + // Width and height are never more than 16384. At 16Ki*16Ki, 4bpp is 1GiB, but + // if we allow 8bpp (or higher) here, that's 2GiB, which would overflow on + // 32-bit. + MOZ_ASSERT(width <= 16384); + MOZ_ASSERT(height <= 16384); + MOZ_ASSERT(pixelsize < 8); + + const auto size = CheckedInt<size_t>(width) * height * pixelsize; + if (!size.isValid()) { + // This should never happen, but we use a defensive check. + MOZ_ASSERT_UNREACHABLE("Unacceptable size calculated.!"); + return; + } + + unsigned char* newPixels = new (fallible) unsigned char[size.value()]; + + if (newPixels) { + unsigned char* rowDest = newPixels; + const unsigned char* rowSource = (const unsigned char*)pixels; + for (int h = 0; h < height; h++) { + memcpy(rowDest, rowSource, width * pixelsize); + rowDest += width * pixelsize; + rowSource += stride; + } + + stride = width * pixelsize; + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)newPixels), + GetAddressAlignment((ptrdiff_t)stride))); + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + type, newPixels); + delete[] newPixels; + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + + } else { + // If we did not have sufficient memory for the required + // temporary buffer, then fall back to uploading row-by-row. + const unsigned char* rowSource = (const unsigned char*)pixels; + + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + + for (int i = 0; i < height; i++) { + gl->fTexSubImage2D(target, level, xoffset, yoffset + i, width, 1, format, + type, rowSource); + rowSource += stride; + } + + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + } +} +static void TexSubImage2DHelper(GLContext* gl, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLsizei stride, GLint pixelsize, + GLenum format, GLenum type, + const GLvoid* pixels) { + if (gl->IsGLES()) { + if (stride == width * pixelsize) { + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + } else if (gl->IsExtensionSupported(GLContext::EXT_unpack_subimage) || + gl->HasPBOState()) { + TexSubImage2DWithUnpackSubimageGLES(gl, target, level, xoffset, yoffset, + width, height, stride, pixelsize, + format, type, pixels); + + } else { + TexSubImage2DWithoutUnpackSubimage(gl, target, level, xoffset, yoffset, + width, height, stride, pixelsize, + format, type, pixels); + } + } else { + // desktop GL (non-ES) path + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + int rowLength = stride / pixelsize; + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + } +} + +static void TexImage2DHelper(GLContext* gl, GLenum target, GLint level, + GLint internalformat, GLsizei width, + GLsizei height, GLsizei stride, GLint pixelsize, + GLint border, GLenum format, GLenum type, + const GLvoid* pixels) { + if (gl->IsGLES()) { + NS_ASSERTION( + format == (GLenum)internalformat, + "format and internalformat not the same for glTexImage2D on GLES2"); + + MOZ_ASSERT(width >= 0 && height >= 0); + if (!CanUploadNonPowerOfTwo(gl) && + (stride != width * pixelsize || !IsPowerOfTwo((uint32_t)width) || + !IsPowerOfTwo((uint32_t)height))) { + // Pad out texture width and height to the next power of two + // as we don't support/want non power of two texture uploads + GLsizei paddedWidth = RoundUpPow2((uint32_t)width); + GLsizei paddedHeight = RoundUpPow2((uint32_t)height); + + // Width and height are never more than 16384. At 16Ki*16Ki, 4bpp is 1GiB, + // but if we allow 8bpp (or higher) here, that's 2GiB, which would + // overflow on 32-bit. + MOZ_ASSERT(width <= 16384); + MOZ_ASSERT(height <= 16384); + MOZ_ASSERT(pixelsize < 8); + + const auto size = + CheckedInt<size_t>(paddedWidth) * paddedHeight * pixelsize; + if (!size.isValid()) { + // This should never happen, but we use a defensive check. + MOZ_ASSERT_UNREACHABLE("Unacceptable size calculated.!"); + return; + } + + GLvoid* paddedPixels = new unsigned char[size.value()]; + + // Pad out texture data to be in a POT sized buffer for uploading to + // a POT sized texture + CopyAndPadTextureData(pixels, paddedPixels, width, height, paddedWidth, + paddedHeight, stride, pixelsize); + + gl->fPixelStorei( + LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)paddedPixels), + GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize))); + gl->fTexImage2D(target, border, internalformat, paddedWidth, paddedHeight, + border, format, type, paddedPixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + + delete[] static_cast<unsigned char*>(paddedPixels); + return; + } + + if (stride == width * pixelsize) { + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + gl->fTexImage2D(target, border, internalformat, width, height, border, + format, type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + } else { + // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are + // implemented in TexSubImage2D. + gl->fTexImage2D(target, border, internalformat, width, height, border, + format, type, nullptr); + TexSubImage2DHelper(gl, target, level, 0, 0, width, height, stride, + pixelsize, format, type, pixels); + } + } else { + // desktop GL (non-ES) path + + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, + std::min(GetAddressAlignment((ptrdiff_t)pixels), + GetAddressAlignment((ptrdiff_t)stride))); + int rowLength = stride / pixelsize; + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); + gl->fTexImage2D(target, level, internalformat, width, height, border, + format, type, pixels); + gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); + gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); + } +} + +SurfaceFormat UploadImageDataToTexture( + GLContext* gl, unsigned char* aData, const gfx::IntSize& aDataSize, + const IntPoint& aDstOffset, int32_t aStride, SurfaceFormat aFormat, + const nsIntRegion& aDstRegion, GLuint aTexture, const gfx::IntSize& aSize, + size_t* aOutUploadSize, bool aNeedInit, GLenum aTextureUnit, + GLenum aTextureTarget) { + gl->MakeCurrent(); + gl->fActiveTexture(aTextureUnit); + gl->fBindTexture(aTextureTarget, aTexture); + + GLenum format = 0; + GLenum internalFormat = 0; + GLenum type = 0; + int32_t pixelSize = BytesPerPixel(aFormat); + SurfaceFormat surfaceFormat = gfx::SurfaceFormat::UNKNOWN; + + MOZ_ASSERT(gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA || + gl->GetPreferredARGB32Format() == LOCAL_GL_RGBA); + + switch (aFormat) { + case SurfaceFormat::B8G8R8A8: + if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { + format = LOCAL_GL_BGRA; + surfaceFormat = SurfaceFormat::R8G8B8A8; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + } else { + format = LOCAL_GL_RGBA; + surfaceFormat = SurfaceFormat::B8G8R8A8; + type = LOCAL_GL_UNSIGNED_BYTE; + } + internalFormat = LOCAL_GL_RGBA; + break; + case SurfaceFormat::B8G8R8X8: + // Treat BGRX surfaces as BGRA except for the surface + // format used. + if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { + format = LOCAL_GL_BGRA; + surfaceFormat = SurfaceFormat::R8G8B8X8; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + } else { + format = LOCAL_GL_RGBA; + surfaceFormat = SurfaceFormat::B8G8R8X8; + type = LOCAL_GL_UNSIGNED_BYTE; + } + internalFormat = LOCAL_GL_RGBA; + break; + case SurfaceFormat::R8G8B8A8: + if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { + // Upload our RGBA as BGRA, but store that the uploaded format is + // BGRA. (sample from R to get B) + format = LOCAL_GL_BGRA; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + surfaceFormat = SurfaceFormat::B8G8R8A8; + } else { + format = LOCAL_GL_RGBA; + type = LOCAL_GL_UNSIGNED_BYTE; + surfaceFormat = SurfaceFormat::R8G8B8A8; + } + internalFormat = LOCAL_GL_RGBA; + break; + case SurfaceFormat::R8G8B8X8: + // Treat RGBX surfaces as RGBA except for the surface + // format used. + if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { + format = LOCAL_GL_BGRA; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; + surfaceFormat = SurfaceFormat::B8G8R8X8; + } else { + format = LOCAL_GL_RGBA; + type = LOCAL_GL_UNSIGNED_BYTE; + surfaceFormat = SurfaceFormat::R8G8B8X8; + } + internalFormat = LOCAL_GL_RGBA; + break; + case SurfaceFormat::R5G6B5_UINT16: + internalFormat = format = LOCAL_GL_RGB; + type = LOCAL_GL_UNSIGNED_SHORT_5_6_5; + surfaceFormat = SurfaceFormat::R5G6B5_UINT16; + break; + case SurfaceFormat::A8: + if (gl->IsGLES()) { + format = LOCAL_GL_LUMINANCE; + internalFormat = LOCAL_GL_LUMINANCE; + } else { + format = LOCAL_GL_RED; + internalFormat = LOCAL_GL_R8; + } + type = LOCAL_GL_UNSIGNED_BYTE; + // We don't have a specific luminance shader + surfaceFormat = SurfaceFormat::A8; + break; + case SurfaceFormat::A16: + if (gl->IsGLES()) { + format = LOCAL_GL_LUMINANCE; + internalFormat = LOCAL_GL_LUMINANCE16; + } else { + format = LOCAL_GL_RED; + internalFormat = LOCAL_GL_R16; + } + type = LOCAL_GL_UNSIGNED_SHORT; + // We don't have a specific luminance shader + surfaceFormat = SurfaceFormat::A8; + pixelSize = 2; + break; + default: + MOZ_ASSERT_UNREACHABLE("Unhandled image surface format!"); + } + + if (aOutUploadSize) { + *aOutUploadSize = 0; + } + + if (surfaceFormat == gfx::SurfaceFormat::UNKNOWN) { + return gfx::SurfaceFormat::UNKNOWN; + } + + // We can only skip SubTextures if aOffset = 0 because we need the whole + // buffer + if (aNeedInit || (!ShouldUploadSubTextures(gl) && aDstOffset == IntPoint())) { + if (!CheckUploadBounds(aSize, aDataSize, IntPoint())) { + return SurfaceFormat::UNKNOWN; + } + // If the texture needs initialized, or we are unable to + // upload sub textures, then initialize and upload the entire + // texture. + TexImage2DHelper(gl, aTextureTarget, 0, internalFormat, aSize.width, + aSize.height, aStride, pixelSize, 0, format, type, aData); + + if (aOutUploadSize && aNeedInit) { + uint32_t texelSize = GetBytesPerTexel(internalFormat, type); + size_t numTexels = size_t(aSize.width) * size_t(aSize.height); + *aOutUploadSize += texelSize * numTexels; + } + } else { + // Upload each rect in the region to the texture + for (auto iter = aDstRegion.RectIter(); !iter.Done(); iter.Next()) { + IntRect rect = iter.Get(); + if (!CheckUploadBounds(rect.Size(), aDataSize, rect.TopLeft())) { + return SurfaceFormat::UNKNOWN; + } + + const unsigned char* rectData = + aData + DataOffset(rect.TopLeft(), aStride, aFormat); + + rect += aDstOffset; + TexSubImage2DHelper(gl, aTextureTarget, 0, rect.X(), rect.Y(), + rect.Width(), rect.Height(), aStride, pixelSize, + format, type, rectData); + } + } + + return surfaceFormat; +} + +SurfaceFormat UploadSurfaceToTexture(GLContext* gl, DataSourceSurface* aSurface, + const nsIntRegion& aDstRegion, + GLuint aTexture, const gfx::IntSize& aSize, + size_t* aOutUploadSize, bool aNeedInit, + const gfx::IntPoint& aSrcOffset, + const gfx::IntPoint& aDstOffset, + GLenum aTextureUnit, + GLenum aTextureTarget) { + DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::READ); + int32_t stride = map.GetStride(); + SurfaceFormat format = aSurface->GetFormat(); + gfx::IntSize size = aSurface->GetSize(); + + // only fail if we'll need the entire surface for initialization + if (aNeedInit && !CheckUploadBounds(aSize, size, aSrcOffset)) { + return SurfaceFormat::UNKNOWN; + } + + unsigned char* data = map.GetData() + DataOffset(aSrcOffset, stride, format); + size.width -= aSrcOffset.x; + size.height -= aSrcOffset.y; + + return UploadImageDataToTexture(gl, data, size, aDstOffset, stride, format, + aDstRegion, aTexture, aSize, aOutUploadSize, + aNeedInit, aTextureUnit, aTextureTarget); +} + +bool CanUploadNonPowerOfTwo(GLContext* gl) { + if (!gl->WorkAroundDriverBugs()) return true; + + // Some GPUs driver crash when uploading non power of two 565 textures. + return gl->Renderer() != GLRenderer::Adreno200 && + gl->Renderer() != GLRenderer::Adreno205; +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h new file mode 100644 index 0000000000..3bf071fd0b --- /dev/null +++ b/gfx/gl/GLUploadHelpers.h @@ -0,0 +1,77 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLUploadHelpers_h_ +#define GLUploadHelpers_h_ + +#include "GLDefs.h" +#include "mozilla/gfx/Types.h" +#include "nsPoint.h" +#include "nsRegionFwd.h" + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +} // namespace gfx + +namespace gl { + +class GLContext; + +/** + * Uploads image data to an OpenGL texture, initializing the texture + * first if necessary. + * + * \param gl The GL Context to use. + * \param aData Start of image data of surface to upload. + * Corresponds to the first pixel of the texture. + * \param aDataSize The image data's size. + * \param aStride The image data's stride. + * \param aFormat The image data's format. + * \param aDstRegion Region of the texture to upload. + * \param aTexture The OpenGL texture to use. Must refer to a valid texture. + * \param aSize The full size of the texture. + * \param aOutUploadSize If set, the number of bytes the texture requires will + * be returned here. + * \param aNeedInit Indicates whether a new texture must be allocated. + * \param aTextureUnit The texture unit used temporarily to upload the surface. + * This may be overridden, so clients should not rely on + * the aTexture being bound to aTextureUnit after this call, + * or even on aTextureUnit being active. + * \param aTextureTarget The texture target to use. + * \return Surface format of this texture. + */ +gfx::SurfaceFormat UploadImageDataToTexture( + GLContext* gl, unsigned char* aData, const gfx::IntSize& aDataSize, + const gfx::IntPoint& aDstOffset, int32_t aStride, + gfx::SurfaceFormat aFormat, const nsIntRegion& aDstRegion, GLuint aTexture, + const gfx::IntSize& aSize, size_t* aOutUploadSize = nullptr, + bool aNeedInit = false, GLenum aTextureUnit = LOCAL_GL_TEXTURE0, + GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D); + +/** + * Convenience wrapper around UploadImageDataToTexture for + * gfx::DataSourceSurface's. + * + * \param aSurface The surface from which to upload image data. + * \param aSrcPoint Offset into aSurface where this texture's data begins. + */ +gfx::SurfaceFormat UploadSurfaceToTexture( + GLContext* gl, gfx::DataSourceSurface* aSurface, + const nsIntRegion& aDstRegion, GLuint aTexture, const gfx::IntSize& aSize, + size_t* aOutUploadSize = nullptr, bool aNeedInit = false, + const gfx::IntPoint& aSrcOffset = gfx::IntPoint(0, 0), + const gfx::IntPoint& aDstOffset = gfx::IntPoint(0, 0), + GLenum aTextureUnit = LOCAL_GL_TEXTURE0, + GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D); + +bool ShouldUploadSubTextures(GLContext* gl); +bool CanUploadNonPowerOfTwo(GLContext* gl); + +} // namespace gl +} // namespace mozilla + +#endif diff --git a/gfx/gl/GLXLibrary.h b/gfx/gl/GLXLibrary.h new file mode 100644 index 0000000000..d2577c935c --- /dev/null +++ b/gfx/gl/GLXLibrary.h @@ -0,0 +1,285 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_GLXLIBRARY_H +#define GFX_GLXLIBRARY_H + +#include "GLContext.h" +#include "mozilla/Assertions.h" +#include "mozilla/DataMutex.h" +#include "mozilla/gfx/XlibDisplay.h" +#include "prlink.h" +typedef realGLboolean GLboolean; + +// stuff from glx.h +#include "X11/Xlib.h" +#include "X11/Xutil.h" // for XVisualInfo +#include "X11UndefineNone.h" +typedef struct __GLXcontextRec* GLXContext; +typedef XID GLXPixmap; +typedef XID GLXDrawable; +/* GLX 1.3 and later */ +typedef struct __GLXFBConfigRec* GLXFBConfig; +// end of stuff from glx.h +#include "prenv.h" + +struct PRLibrary; +class gfxASurface; + +namespace mozilla { +namespace gl { + +class GLContextGLX; + +class GLXLibrary final { + public: + bool EnsureInitialized(Display* aDisplay); + + private: + class WrapperScope final { + const GLXLibrary& mGlx; + const char* const mFuncName; + Display* const mDisplay; + + public: + WrapperScope(const GLXLibrary& glx, const char* const funcName, + Display* aDisplay); + ~WrapperScope(); + }; + + public: +#ifdef DEBUG +# define DECL_WRAPPER_SCOPE(display) \ + const WrapperScope wrapperScope(*this, __func__, display); +#else +# define DECL_WRAPPER_SCOPE(display) +#endif + + void fDestroyContext(Display* display, GLXContext context) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fDestroyContext(display, context); + } + + Bool fMakeCurrent(Display* display, GLXDrawable drawable, + GLXContext context) const { + DECL_WRAPPER_SCOPE(display) + GLContext::ResetTLSCurrentContext(); + return mSymbols.fMakeCurrent(display, drawable, context); + } + + XVisualInfo* fGetConfig(Display* display, XVisualInfo* info, int attrib, + int* value) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fGetConfig(display, info, attrib, value); + } + + GLXContext fGetCurrentContext() const { + DECL_WRAPPER_SCOPE(nullptr) + return mSymbols.fGetCurrentContext(); + } + + GLXFBConfig* fChooseFBConfig(Display* display, int screen, + const int* attrib_list, int* nelements) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fChooseFBConfig(display, screen, attrib_list, nelements); + } + + XVisualInfo* fChooseVisual(Display* display, int screen, + int* attrib_list) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fChooseVisual(display, screen, attrib_list); + } + + GLXFBConfig* fGetFBConfigs(Display* display, int screen, + int* nelements) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fGetFBConfigs(display, screen, nelements); + } + + GLXContext fCreateNewContext(Display* display, GLXFBConfig config, + int render_type, GLXContext share_list, + Bool direct) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fCreateNewContext(display, config, render_type, share_list, + direct); + } + + int fGetFBConfigAttrib(Display* display, GLXFBConfig config, int attribute, + int* value) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fGetFBConfigAttrib(display, config, attribute, value); + } + + void fSwapBuffers(Display* display, GLXDrawable drawable) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fSwapBuffers(display, drawable); + } + + const char* fQueryExtensionsString(Display* display, int screen) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fQueryExtensionsString(display, screen); + } + + const char* fGetClientString(Display* display, int screen) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fGetClientString(display, screen); + } + + const char* fQueryServerString(Display* display, int screen, int name) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fQueryServerString(display, screen, name); + } + + GLXPixmap fCreatePixmap(Display* display, GLXFBConfig config, Pixmap pixmap, + const int* attrib_list) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fCreatePixmap(display, config, pixmap, attrib_list); + } + + GLXPixmap fCreateGLXPixmapWithConfig(Display* display, GLXFBConfig config, + Pixmap pixmap) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fCreateGLXPixmapWithConfig(display, config, pixmap); + } + + void fDestroyPixmap(Display* display, GLXPixmap pixmap) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fDestroyPixmap(display, pixmap); + } + + Bool fQueryVersion(Display* display, int* major, int* minor) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fQueryVersion(display, major, minor); + } + + void fBindTexImage(Display* display, GLXDrawable drawable, int buffer, + const int* attrib_list) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fBindTexImageEXT(display, drawable, buffer, attrib_list); + } + + void fReleaseTexImage(Display* display, GLXDrawable drawable, + int buffer) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fReleaseTexImageEXT(display, drawable, buffer); + } + + void fWaitGL() const { + DECL_WRAPPER_SCOPE(nullptr) + return mSymbols.fWaitGL(); + } + + void fWaitX() const { + DECL_WRAPPER_SCOPE(nullptr) + return mSymbols.fWaitX(); + } + + GLXContext fCreateContextAttribs(Display* display, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int* attrib_list) const { + DECL_WRAPPER_SCOPE(display) + return mSymbols.fCreateContextAttribsARB(display, config, share_list, + direct, attrib_list); + } + + int fGetVideoSync(unsigned int* count) const { + DECL_WRAPPER_SCOPE(nullptr) + return mSymbols.fGetVideoSyncSGI(count); + } + + int fWaitVideoSync(int divisor, int remainder, unsigned int* count) const { + DECL_WRAPPER_SCOPE(nullptr) + return mSymbols.fWaitVideoSyncSGI(divisor, remainder, count); + } + + void fSwapInterval(Display* dpy, GLXDrawable drawable, int interval) const { + DECL_WRAPPER_SCOPE(dpy) + return mSymbols.fSwapIntervalEXT(dpy, drawable, interval); + } + + int fQueryDrawable(Display* dpy, GLXDrawable drawable, int attribute, + unsigned int* value) const { + DECL_WRAPPER_SCOPE(dpy) + return mSymbols.fQueryDrawable(dpy, drawable, attribute, value); + } +#undef DECL_WRAPPER_SCOPE + + //// + + bool HasRobustness() { return mHasRobustness; } + bool HasVideoMemoryPurge() { return mHasVideoMemoryPurge; } + bool HasCreateContextAttribs() { return mHasCreateContextAttribs; } + bool SupportsTextureFromPixmap(gfxASurface* aSurface); + bool SupportsVideoSync(Display* aDisplay); + bool SupportsSwapControl() const { return bool(mSymbols.fSwapIntervalEXT); } + bool SupportsBufferAge() const { + MOZ_ASSERT(mInitialized); + return mHasBufferAge; + } + bool IsATI() { return mIsATI; } + bool IsMesa() { return mClientIsMesa; } + + auto GetGetProcAddress() const { return mSymbols.fGetProcAddress; } + + std::shared_ptr<gfx::XlibDisplay> GetDisplay(); + + private: + struct { + void(GLAPIENTRY* fDestroyContext)(Display*, GLXContext); + Bool(GLAPIENTRY* fMakeCurrent)(Display*, GLXDrawable, GLXContext); + XVisualInfo*(GLAPIENTRY* fGetConfig)(Display*, XVisualInfo*, int, int*); + GLXContext(GLAPIENTRY* fGetCurrentContext)(); + void*(GLAPIENTRY* fGetProcAddress)(const char*); + GLXFBConfig*(GLAPIENTRY* fChooseFBConfig)(Display*, int, const int*, int*); + XVisualInfo*(GLAPIENTRY* fChooseVisual)(Display*, int, const int*); + GLXFBConfig*(GLAPIENTRY* fGetFBConfigs)(Display*, int, int*); + GLXContext(GLAPIENTRY* fCreateNewContext)(Display*, GLXFBConfig, int, + GLXContext, Bool); + int(GLAPIENTRY* fGetFBConfigAttrib)(Display*, GLXFBConfig, int, int*); + void(GLAPIENTRY* fSwapBuffers)(Display*, GLXDrawable); + const char*(GLAPIENTRY* fQueryExtensionsString)(Display*, int); + const char*(GLAPIENTRY* fGetClientString)(Display*, int); + const char*(GLAPIENTRY* fQueryServerString)(Display*, int, int); + GLXPixmap(GLAPIENTRY* fCreatePixmap)(Display*, GLXFBConfig, Pixmap, + const int*); + GLXPixmap(GLAPIENTRY* fCreateGLXPixmapWithConfig)(Display*, GLXFBConfig, + Pixmap); + void(GLAPIENTRY* fDestroyPixmap)(Display*, GLXPixmap); + Bool(GLAPIENTRY* fQueryVersion)(Display*, int*, int*); + void(GLAPIENTRY* fWaitGL)(); + void(GLAPIENTRY* fWaitX)(); + void(GLAPIENTRY* fBindTexImageEXT)(Display*, GLXDrawable, int, const int*); + void(GLAPIENTRY* fReleaseTexImageEXT)(Display*, GLXDrawable, int); + GLXContext(GLAPIENTRY* fCreateContextAttribsARB)(Display*, GLXFBConfig, + GLXContext, Bool, + const int*); + int(GLAPIENTRY* fGetVideoSyncSGI)(unsigned int*); + int(GLAPIENTRY* fWaitVideoSyncSGI)(int, int, unsigned int*); + void(GLAPIENTRY* fSwapIntervalEXT)(Display*, GLXDrawable, int); + int(GLAPIENTRY* fQueryDrawable)(Display*, GLXDrawable, int, unsigned int*); + } mSymbols = {}; + + bool mInitialized = false; + bool mTriedInitializing = false; + bool mDebug = false; + bool mHasRobustness = false; + bool mHasVideoMemoryPurge = false; + bool mHasCreateContextAttribs = false; + bool mHasVideoSync = false; + bool mHasBufferAge = false; + bool mIsATI = false; + bool mIsNVIDIA = false; + bool mClientIsMesa = false; + PRLibrary* mOGLLibrary = nullptr; + StaticDataMutex<std::weak_ptr<gfx::XlibDisplay>> mOwnDisplay{ + "GLXLibrary::mOwnDisplay"}; +}; + +// a global GLXLibrary instance +extern GLXLibrary sGLXLibrary; + +} /* namespace gl */ +} /* namespace mozilla */ +#endif /* GFX_GLXLIBRARY_H */ diff --git a/gfx/gl/GfxTexturesReporter.cpp b/gfx/gl/GfxTexturesReporter.cpp new file mode 100644 index 0000000000..bd169e0013 --- /dev/null +++ b/gfx/gl/GfxTexturesReporter.cpp @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <string> +#include <sstream> +#include "nsExceptionHandler.h" +#include "GfxTexturesReporter.h" +#include "mozilla/StaticPrefs_gfx.h" + +using namespace mozilla::gl; + +NS_IMPL_ISUPPORTS(GfxTexturesReporter, nsIMemoryReporter) + +mozilla::Atomic<size_t> GfxTexturesReporter::sAmount(0); +mozilla::Atomic<size_t> GfxTexturesReporter::sPeakAmount(0); +mozilla::Atomic<size_t> GfxTexturesReporter::sTileWasteAmount(0); + +static std::string FormatBytes(size_t amount) { + std::stringstream stream; + int depth = 0; + double val = amount; + while (val > 1024) { + val /= 1024; + depth++; + } + + const char* unit; + switch (depth) { + case 0: + unit = "bytes"; + break; + case 1: + unit = "KB"; + break; + case 2: + unit = "MB"; + break; + case 3: + unit = "GB"; + break; + default: + unit = ""; + break; + } + + stream << val << " " << unit; + return stream.str(); +} + +/* static */ +void GfxTexturesReporter::UpdateAmount(MemoryUse action, size_t amount) { + if (action == MemoryFreed) { + MOZ_RELEASE_ASSERT( + amount <= sAmount, + "GFX: Current texture usage greater than update amount."); + sAmount -= amount; + + if (StaticPrefs::gfx_logging_texture_usage_enabled_AtStartup()) { + printf_stderr("Current texture usage: %s\n", + FormatBytes(sAmount).c_str()); + } + } else { + sAmount += amount; + if (sAmount > sPeakAmount) { + sPeakAmount.exchange(sAmount); + if (StaticPrefs::gfx_logging_peak_texture_usage_enabled_AtStartup()) { + printf_stderr("Peak texture usage: %s\n", + FormatBytes(sPeakAmount).c_str()); + } + } + } + + CrashReporter::AnnotateTexturesSize(sAmount); +} diff --git a/gfx/gl/GfxTexturesReporter.h b/gfx/gl/GfxTexturesReporter.h new file mode 100644 index 0000000000..077fc0e879 --- /dev/null +++ b/gfx/gl/GfxTexturesReporter.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFXTEXTURESREPORTER_H_ +#define GFXTEXTURESREPORTER_H_ + +#include "mozilla/Atomics.h" +#include "nsIMemoryReporter.h" +#include "GLTypes.h" + +namespace mozilla { +namespace gl { + +class GfxTexturesReporter final : public nsIMemoryReporter { + ~GfxTexturesReporter() = default; + + public: + NS_DECL_ISUPPORTS + + GfxTexturesReporter() { +#ifdef DEBUG + // There must be only one instance of this class, due to |sAmount| + // being static. Assert this. + static bool hasRun = false; + MOZ_ASSERT(!hasRun); + hasRun = true; +#endif + } + + enum MemoryUse { + // when memory being allocated is reported to a memory reporter + MemoryAllocated, + // when memory being freed is reported to a memory reporter + MemoryFreed + }; + + // When memory is used/freed for tile textures, call this method to update + // the value reported by this memory reporter. + static void UpdateAmount(MemoryUse action, size_t amount); + + static void UpdateWasteAmount(size_t delta) { sTileWasteAmount += delta; } + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) override { + MOZ_COLLECT_REPORT( + "gfx-tiles-waste", KIND_OTHER, UNITS_BYTES, int64_t(sTileWasteAmount), + "Memory lost due to tiles extending past content boundaries"); + + MOZ_COLLECT_REPORT("gfx-textures", KIND_OTHER, UNITS_BYTES, + int64_t(sAmount), + "Memory used for storing GL textures."); + + MOZ_COLLECT_REPORT("gfx-textures-peak", KIND_OTHER, UNITS_BYTES, + int64_t(sPeakAmount), + "Peak memory used for storing GL textures."); + + return NS_OK; + } + + private: + static Atomic<size_t> sAmount; + static Atomic<size_t> sPeakAmount; + // Count the amount of memory lost to tile waste + static Atomic<size_t> sTileWasteAmount; +}; + +class GfxTextureWasteTracker { + public: + GfxTextureWasteTracker() : mBytes(0) { + MOZ_COUNT_CTOR(GfxTextureWasteTracker); + } + + void Update(int32_t aPixelArea, int32_t aBytesPerPixel) { + GfxTexturesReporter::UpdateWasteAmount(-mBytes); + mBytes = aPixelArea * aBytesPerPixel; + GfxTexturesReporter::UpdateWasteAmount(mBytes); + } + + ~GfxTextureWasteTracker() { + GfxTexturesReporter::UpdateWasteAmount(-mBytes); + MOZ_COUNT_DTOR(GfxTextureWasteTracker); + } + + private: + GfxTextureWasteTracker(const GfxTextureWasteTracker& aRef); + + int32_t mBytes; +}; + +} // namespace gl +} // namespace mozilla + +#endif // GFXTEXTURESREPORTER_H_ diff --git a/gfx/gl/HeapCopyOfStackArray.h b/gfx/gl/HeapCopyOfStackArray.h new file mode 100644 index 0000000000..ffcadde461 --- /dev/null +++ b/gfx/gl/HeapCopyOfStackArray.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef HEAPCOPYOFSTACKARRAY_H_ +#define HEAPCOPYOFSTACKARRAY_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/UniquePtr.h" + +#include <string.h> + +namespace mozilla { + +// Takes a stack array and copies it into a heap buffer. +// Useful to retain the convenience of declaring static arrays, while +// avoiding passing stack pointers to the GL (see bug 1005658). + +template <typename ElemType> +class HeapCopyOfStackArray { + public: + template <size_t N> + MOZ_IMPLICIT HeapCopyOfStackArray(const ElemType (&array)[N]) + : mArrayLength(N), mArrayData(MakeUnique<ElemType[]>(N)) { + memcpy(mArrayData.get(), &array[0], N * sizeof(ElemType)); + } + + ElemType* Data() const { return mArrayData.get(); } + size_t ArrayLength() const { return mArrayLength; } + size_t ByteLength() const { return mArrayLength * sizeof(ElemType); } + + private: + HeapCopyOfStackArray() = delete; + HeapCopyOfStackArray(const HeapCopyOfStackArray&) = delete; + + const size_t mArrayLength; + UniquePtr<ElemType[]> const mArrayData; +}; + +} // namespace mozilla + +#endif // HEAPCOPYOFSTACKARRAY_H_ diff --git a/gfx/gl/MozFramebuffer.cpp b/gfx/gl/MozFramebuffer.cpp new file mode 100644 index 0000000000..10995a7ee1 --- /dev/null +++ b/gfx/gl/MozFramebuffer.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MozFramebuffer.h" + +#include "GLContext.h" +#include "mozilla/gfx/Logging.h" +#include "ScopedGLHelpers.h" + +namespace mozilla { +namespace gl { + +static void DeleteByTarget(GLContext* const gl, const GLenum target, + const GLuint name) { + if (target == LOCAL_GL_RENDERBUFFER) { + gl->DeleteRenderbuffer(name); + } else { + gl->DeleteTexture(name); + } +} + +UniquePtr<MozFramebuffer> MozFramebuffer::Create(GLContext* const gl, + const gfx::IntSize& size, + const uint32_t samples, + const bool depthStencil) { + if (samples && !gl->IsSupported(GLFeature::framebuffer_multisample)) + return nullptr; + + if (uint32_t(size.width) > gl->MaxTexOrRbSize() || + uint32_t(size.height) > gl->MaxTexOrRbSize() || + samples > gl->MaxSamples()) { + return nullptr; + } + + gl->MakeCurrent(); + + GLContext::LocalErrorScope errorScope(*gl); + + GLenum colorTarget; + GLuint colorName; + if (samples) { + colorTarget = LOCAL_GL_RENDERBUFFER; + colorName = gl->CreateRenderbuffer(); + const ScopedBindRenderbuffer bindRB(gl, colorName); + gl->fRenderbufferStorageMultisample(colorTarget, samples, LOCAL_GL_RGBA8, + size.width, size.height); + } else { + colorTarget = LOCAL_GL_TEXTURE_2D; + colorName = gl->CreateTexture(); + const ScopedBindTexture bindTex(gl, colorName); + gl->TexParams_SetClampNoMips(); + gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA, size.width, size.height, 0, + LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); + } + + const auto err = errorScope.GetError(); + if (err) { + if (err != LOCAL_GL_OUT_OF_MEMORY) { + gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": " + << GLContext::GLErrorToString(err); + } + DeleteByTarget(gl, colorTarget, colorName); + return nullptr; + } + + return CreateImpl( + gl, size, samples, + depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, + colorTarget, colorName); +} + +UniquePtr<MozFramebuffer> MozFramebuffer::CreateForBacking( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples, + bool depthStencil, const GLenum colorTarget, const GLuint colorName) { + return CreateImpl( + gl, size, samples, + depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, + colorTarget, colorName); +} + +/* static */ UniquePtr<MozFramebuffer> +MozFramebuffer::CreateForBackingWithSharedDepthAndStencil( + const gfx::IntSize& size, const uint32_t samples, GLenum colorTarget, + GLuint colorName, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer) { + auto gl = depthAndStencilBuffer->gl(); + if (!gl || !gl->MakeCurrent()) { + return nullptr; + } + return CreateImpl(gl, size, samples, depthAndStencilBuffer, colorTarget, + colorName); +} + +/* static */ UniquePtr<MozFramebuffer> MozFramebuffer::CreateImpl( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer, + const GLenum colorTarget, const GLuint colorName) { + GLuint fb = gl->CreateFramebuffer(); + const ScopedBindFramebuffer bindFB(gl, fb); + + if (colorTarget == LOCAL_GL_RENDERBUFFER) { + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, colorTarget, + colorName); + } else { + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + colorTarget, colorName, 0); + } + + if (depthAndStencilBuffer) { + gl->fFramebufferRenderbuffer( + LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, + depthAndStencilBuffer->mDepthRB); + gl->fFramebufferRenderbuffer( + LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, depthAndStencilBuffer->mStencilRB); + } + + const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { + gfxCriticalNote << "MozFramebuffer::CreateImpl(size:" << size + << ", samples:" << samples + << ", depthAndStencil:" << bool(depthAndStencilBuffer) + << ", colorTarget:" << gfx::hexa(colorTarget) + << ", colorName:" << colorName << "): Incomplete: 0x" + << gfx::hexa(status); + return nullptr; + } + + return UniquePtr<MozFramebuffer>(new MozFramebuffer( + gl, size, fb, samples, depthAndStencilBuffer, colorTarget, colorName)); +} + +/* static */ RefPtr<DepthAndStencilBuffer> DepthAndStencilBuffer::Create( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples) { + const auto fnAllocRB = [&](GLenum format) { + GLuint rb = gl->CreateRenderbuffer(); + const ScopedBindRenderbuffer bindRB(gl, rb); + if (samples) { + gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, + format, size.width, size.height); + } else { + gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width, + size.height); + } + return rb; + }; + + GLuint depthRB, stencilRB; + { + GLContext::LocalErrorScope errorScope(*gl); + + if (gl->IsSupported(GLFeature::packed_depth_stencil)) { + depthRB = fnAllocRB(LOCAL_GL_DEPTH24_STENCIL8); + stencilRB = depthRB; // Ignore unused mStencilRB. + } else { + depthRB = fnAllocRB(LOCAL_GL_DEPTH_COMPONENT24); + stencilRB = fnAllocRB(LOCAL_GL_STENCIL_INDEX8); + } + + const auto err = errorScope.GetError(); + if (err) { + MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY); + return nullptr; + } + } + + return new DepthAndStencilBuffer(gl, size, depthRB, stencilRB); +} + +//////////////////// + +MozFramebuffer::MozFramebuffer( + GLContext* const gl, const gfx::IntSize& size, GLuint fb, + const uint32_t samples, RefPtr<DepthAndStencilBuffer> depthAndStencilBuffer, + const GLenum colorTarget, const GLuint colorName) + : mWeakGL(gl), + mSize(size), + mSamples(samples), + mFB(fb), + mColorTarget(colorTarget), + mDepthAndStencilBuffer(std::move(depthAndStencilBuffer)), + mColorName(colorName) { + MOZ_ASSERT(mColorTarget); + MOZ_ASSERT(mColorName); +} + +MozFramebuffer::~MozFramebuffer() { + GLContext* const gl = mWeakGL; + if (!gl || !gl->MakeCurrent()) { + return; + } + + gl->DeleteFramebuffer(mFB); + + DeleteByTarget(gl, mColorTarget, mColorName); +} + +bool MozFramebuffer::HasDepth() const { + return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mDepthRB; +} + +bool MozFramebuffer::HasStencil() const { + return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mStencilRB; +} + +DepthAndStencilBuffer::DepthAndStencilBuffer(GLContext* gl, + const gfx::IntSize& size, + GLuint depthRB, GLuint stencilRB) + : mWeakGL(gl), mSize(size), mDepthRB(depthRB), mStencilRB(stencilRB) {} + +DepthAndStencilBuffer::~DepthAndStencilBuffer() { + GLContext* const gl = mWeakGL; + if (!gl || !gl->MakeCurrent()) { + return; + } + + gl->DeleteRenderbuffer(mDepthRB); + gl->DeleteRenderbuffer(mStencilRB); +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/MozFramebuffer.h b/gfx/gl/MozFramebuffer.h new file mode 100644 index 0000000000..dd51ef6154 --- /dev/null +++ b/gfx/gl/MozFramebuffer.h @@ -0,0 +1,109 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZ_FRAMEBUFFER_H_ +#define MOZ_FRAMEBUFFER_H_ + +#include "gfx2DGlue.h" +#include "GLConsts.h" +#include "GLContextTypes.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" + +namespace mozilla { +namespace gl { + +class DepthAndStencilBuffer final : public SupportsWeakPtr { + const WeakPtr<GLContext> mWeakGL; + const gfx::IntSize mSize; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DepthAndStencilBuffer) + + const GLuint mDepthRB; + const GLuint mStencilRB; + + static RefPtr<DepthAndStencilBuffer> Create(GLContext* const gl, + const gfx::IntSize& size, + const uint32_t samples); + + RefPtr<GLContext> gl() const { return mWeakGL.get(); } + + // 4 bytes per pixel (24-bit depth + 8-bit stencil). + uint64_t EstimateMemory() const { + return static_cast<uint64_t>(mSize.width) * 4 * mSize.height; + } + + protected: + DepthAndStencilBuffer(GLContext* gl, const gfx::IntSize& size, GLuint depthRB, + GLuint stencilRB); + ~DepthAndStencilBuffer(); +}; + +class MozFramebuffer final { + const WeakPtr<GLContext> mWeakGL; + + public: + const gfx::IntSize mSize; + const uint32_t mSamples; + const GLuint mFB; + const GLenum mColorTarget; + + private: + const RefPtr<DepthAndStencilBuffer> mDepthAndStencilBuffer; + const GLuint mColorName; + + public: + // Create a new framebuffer with the specified properties. + static UniquePtr<MozFramebuffer> Create(GLContext* gl, + const gfx::IntSize& size, + uint32_t samples, bool depthStencil); + + // Create a new framebuffer backed by an existing texture or buffer. + // Assumes that gl is the current context. + static UniquePtr<MozFramebuffer> CreateForBacking( + GLContext* gl, const gfx::IntSize& size, uint32_t samples, + bool depthStencil, GLenum colorTarget, GLuint colorName); + + // Create a new framebuffer backed by an existing texture or buffer. + // Use the same GLContext, size, and samples as framebufferToShareWith. + // The new framebuffer will share its depth and stencil buffer with + // framebufferToShareWith. The depth and stencil buffers will be destroyed + // once the last MozFramebuffer using them is destroyed. + static UniquePtr<MozFramebuffer> CreateForBackingWithSharedDepthAndStencil( + const gfx::IntSize& size, const uint32_t samples, GLenum colorTarget, + GLuint colorName, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer); + + private: + MozFramebuffer(GLContext* gl, const gfx::IntSize& size, GLuint fb, + uint32_t samples, + RefPtr<DepthAndStencilBuffer> depthAndStencilBuffer, + GLenum colorTarget, GLuint colorName); + + // gl must be the current context when this is called. + static UniquePtr<MozFramebuffer> CreateImpl( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer, + const GLenum colorTarget, const GLuint colorName); + + public: + ~MozFramebuffer(); + + GLuint ColorTex() const { + if (mColorTarget == LOCAL_GL_RENDERBUFFER) return 0; + return mColorName; + } + const auto& GetDepthAndStencilBuffer() const { + return mDepthAndStencilBuffer; + } + bool HasDepth() const; + bool HasStencil() const; +}; + +} // namespace gl +} // namespace mozilla + +#endif // MOZ_FRAMEBUFFER_H_ diff --git a/gfx/gl/ScopedGLHelpers.cpp b/gfx/gl/ScopedGLHelpers.cpp new file mode 100644 index 0000000000..d654cae163 --- /dev/null +++ b/gfx/gl/ScopedGLHelpers.cpp @@ -0,0 +1,490 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/UniquePtr.h" + +#include "GLContext.h" +#include "ScopedGLHelpers.h" + +namespace mozilla { +namespace gl { + +/* ScopedGLState - Wraps glEnable/glDisable. **********************************/ + +// Use |newState = true| to enable, |false| to disable. +ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState) + : mGL(aGL), mCapability(aCapability) { + mOldState = mGL->fIsEnabled(mCapability); + + // Early out if we're already in the right state. + if (aNewState == mOldState) return; + + if (aNewState) { + mGL->fEnable(mCapability); + } else { + mGL->fDisable(mCapability); + } +} + +ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability) + : mGL(aGL), mCapability(aCapability) { + mOldState = mGL->fIsEnabled(mCapability); +} + +ScopedGLState::~ScopedGLState() { + if (mOldState) { + mGL->fEnable(mCapability); + } else { + mGL->fDisable(mCapability); + } +} + +/* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and + * BindUserFB. */ + +void ScopedBindFramebuffer::Init() { + if (mGL->IsSupported(GLFeature::split_framebuffer)) { + mOldReadFB = mGL->GetReadFB(); + mOldDrawFB = mGL->GetDrawFB(); + } else { + mOldReadFB = mOldDrawFB = mGL->GetFB(); + } +} + +ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL) : mGL(aGL) { + Init(); +} + +ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB) + : mGL(aGL) { + Init(); + mGL->BindFB(aNewFB); +} + +ScopedBindFramebuffer::~ScopedBindFramebuffer() { + if (mOldReadFB == mOldDrawFB) { + mGL->BindFB(mOldDrawFB); + } else { + mGL->BindDrawFB(mOldDrawFB); + mGL->BindReadFB(mOldReadFB); + } +} + +/* ScopedBindTextureUnit ******************************************************/ + +ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit) + : mGL(aGL), mOldTexUnit(0) { + MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0); + mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit); + mGL->fActiveTexture(aTexUnit); +} + +ScopedBindTextureUnit::~ScopedBindTextureUnit() { + mGL->fActiveTexture(mOldTexUnit); +} + +/* ScopedTexture **************************************************************/ + +ScopedTexture::ScopedTexture(GLContext* aGL) : mGL(aGL), mTexture(0) { + mGL->fGenTextures(1, &mTexture); +} + +ScopedTexture::~ScopedTexture() { mGL->fDeleteTextures(1, &mTexture); } + +/* ScopedFramebuffer + * **************************************************************/ + +ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL) : mGL(aGL), mFB(0) { + mGL->fGenFramebuffers(1, &mFB); +} + +ScopedFramebuffer::~ScopedFramebuffer() { mGL->fDeleteFramebuffers(1, &mFB); } + +/* ScopedRenderbuffer + * **************************************************************/ + +ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL) : mGL(aGL), mRB(0) { + mGL->fGenRenderbuffers(1, &mRB); +} + +ScopedRenderbuffer::~ScopedRenderbuffer() { + mGL->fDeleteRenderbuffers(1, &mRB); +} + +/* ScopedBindTexture **********************************************************/ + +static GLuint GetBoundTexture(GLContext* gl, GLenum texTarget) { + GLenum bindingTarget; + switch (texTarget) { + case LOCAL_GL_TEXTURE_2D: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D; + break; + + case LOCAL_GL_TEXTURE_CUBE_MAP: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP; + break; + + case LOCAL_GL_TEXTURE_3D: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D; + break; + + case LOCAL_GL_TEXTURE_2D_ARRAY: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY; + break; + + case LOCAL_GL_TEXTURE_RECTANGLE_ARB: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB; + break; + + case LOCAL_GL_TEXTURE_EXTERNAL: + bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL; + break; + + default: + MOZ_CRASH("bad texTarget"); + } + + GLuint ret = 0; + gl->GetUIntegerv(bindingTarget, &ret); + return ret; +} + +ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, + GLenum aTarget) + : mGL(aGL), mTarget(aTarget), mOldTex(GetBoundTexture(aGL, aTarget)) { + mGL->fBindTexture(mTarget, aNewTex); +} + +ScopedBindTexture::~ScopedBindTexture() { mGL->fBindTexture(mTarget, mOldTex); } + +/* ScopedBindRenderbuffer *****************************************************/ + +void ScopedBindRenderbuffer::Init() { + mOldRB = 0; + mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB); +} + +ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL) : mGL(aGL) { + Init(); +} + +ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB) + : mGL(aGL) { + Init(); + mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB); +} + +ScopedBindRenderbuffer::~ScopedBindRenderbuffer() { + mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB); +} + +/* ScopedFramebufferForTexture ************************************************/ +ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL, + GLuint aTexture, + GLenum aTarget) + : mGL(aGL), mComplete(false), mFB(0) { + mGL->fGenFramebuffers(1, &mFB); + ScopedBindFramebuffer autoFB(aGL, mFB); + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + aTarget, aTexture, 0); + + GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { + mComplete = true; + } else { + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; + } +} + +ScopedFramebufferForTexture::~ScopedFramebufferForTexture() { + if (!mFB) return; + + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; +} + +/* ScopedFramebufferForRenderbuffer *******************************************/ + +ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer( + GLContext* aGL, GLuint aRB) + : mGL(aGL), mComplete(false), mFB(0) { + mGL->fGenFramebuffers(1, &mFB); + ScopedBindFramebuffer autoFB(aGL, mFB); + mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, aRB); + + GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { + mComplete = true; + } else { + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; + } +} + +ScopedFramebufferForRenderbuffer::~ScopedFramebufferForRenderbuffer() { + if (!mFB) return; + + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; +} + +/* ScopedViewportRect *********************************************************/ + +ScopedViewportRect::ScopedViewportRect(GLContext* aGL, GLint x, GLint y, + GLsizei width, GLsizei height) + : mGL(aGL) { + mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect); + mGL->fViewport(x, y, width, height); +} + +ScopedViewportRect::~ScopedViewportRect() { + mGL->fViewport(mSavedViewportRect[0], mSavedViewportRect[1], + mSavedViewportRect[2], mSavedViewportRect[3]); +} + +/* ScopedScissorRect **********************************************************/ + +ScopedScissorRect::ScopedScissorRect(GLContext* aGL, GLint x, GLint y, + GLsizei width, GLsizei height) + : mGL(aGL) { + mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect); + mGL->fScissor(x, y, width, height); +} + +ScopedScissorRect::ScopedScissorRect(GLContext* aGL) : mGL(aGL) { + mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect); +} + +ScopedScissorRect::~ScopedScissorRect() { + mGL->fScissor(mSavedScissorRect[0], mSavedScissorRect[1], + mSavedScissorRect[2], mSavedScissorRect[3]); +} + +/* ScopedVertexAttribPointer **************************************************/ + +ScopedVertexAttribPointer::ScopedVertexAttribPointer( + GLContext* aGL, GLuint index, GLint size, GLenum type, + realGLboolean normalized, GLsizei stride, GLuint buffer, + const GLvoid* pointer) + : mGL(aGL), + mAttribEnabled(0), + mAttribSize(0), + mAttribStride(0), + mAttribType(0), + mAttribNormalized(0), + mAttribBufferBinding(0), + mAttribPointer(nullptr), + mBoundBuffer(0) { + WrapImpl(index); + mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer); + mGL->fVertexAttribPointer(index, size, type, normalized, stride, pointer); + mGL->fEnableVertexAttribArray(index); +} + +ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL, + GLuint index) + : mGL(aGL), + mAttribEnabled(0), + mAttribSize(0), + mAttribStride(0), + mAttribType(0), + mAttribNormalized(0), + mAttribBufferBinding(0), + mAttribPointer(nullptr), + mBoundBuffer(0) { + WrapImpl(index); +} + +void ScopedVertexAttribPointer::WrapImpl(GLuint index) { + mAttribIndex = index; + + /* + * mGL->fGetVertexAttribiv takes: + * VERTEX_ATTRIB_ARRAY_ENABLED + * VERTEX_ATTRIB_ARRAY_SIZE, + * VERTEX_ATTRIB_ARRAY_STRIDE, + * VERTEX_ATTRIB_ARRAY_TYPE, + * VERTEX_ATTRIB_ARRAY_NORMALIZED, + * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, + * CURRENT_VERTEX_ATTRIB + * + * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/ + * Others appear to be vertex array state, + * or alternatively in the internal vertex array state + * for a buffer object. + */ + + mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, + &mAttribEnabled); + mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, + &mAttribSize); + mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, + &mAttribStride); + mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, + &mAttribType); + mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, + &mAttribNormalized); + mGL->fGetVertexAttribiv(mAttribIndex, + LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, + &mAttribBufferBinding); + mGL->fGetVertexAttribPointerv( + mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &mAttribPointer); + + // Note that uniform values are program state, so we don't need to rebind + // those. + + mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &mBoundBuffer); +} + +ScopedVertexAttribPointer::~ScopedVertexAttribPointer() { + mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBufferBinding); + mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType, + mAttribNormalized, mAttribStride, mAttribPointer); + if (mAttribEnabled) + mGL->fEnableVertexAttribArray(mAttribIndex); + else + mGL->fDisableVertexAttribArray(mAttribIndex); + mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer); +} + +//////////////////////////////////////////////////////////////////////// +// ScopedPackState + +ScopedPackState::ScopedPackState(GLContext* gl) + : mGL(gl), + mAlignment(0), + mPixelBuffer(0), + mRowLength(0), + mSkipPixels(0), + mSkipRows(0) { + mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment); + + if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); + + if (!mGL->HasPBOState()) return; + + mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer); + mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength); + mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels); + mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows); + + if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0); + if (mRowLength != 0) mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0); + if (mSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0); + if (mSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0); +} + +bool ScopedPackState::SetForWidthAndStrideRGBA(GLsizei aWidth, + GLsizei aStride) { + MOZ_ASSERT(aStride % 4 == 0, "RGBA data should always be 4-byte aligned"); + MOZ_ASSERT(aStride / 4 >= aWidth, "Stride too small"); + if (aStride / 4 == aWidth) { + // No special handling needed. + return true; + } + if (mGL->HasPBOState()) { + // HasPBOState implies support for GL_PACK_ROW_LENGTH. + mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, aStride / 4); + return true; + } + return false; +} + +ScopedPackState::~ScopedPackState() { + mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment); + + if (!mGL->HasPBOState()) return; + + mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer); + mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength); + mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels); + mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows); +} + +//////////////////////////////////////////////////////////////////////// +// ResetUnpackState + +ResetUnpackState::ResetUnpackState(GLContext* gl) + : mGL(gl), + mAlignment(0), + mPBO(0), + mRowLength(0), + mImageHeight(0), + mSkipPixels(0), + mSkipRows(0), + mSkipImages(0) { + const auto fnReset = [&](GLenum pname, GLuint val, GLuint* const out_old) { + mGL->GetUIntegerv(pname, out_old); + if (*out_old != val) { + mGL->fPixelStorei(pname, val); + } + }; + + // Default is 4, but 1 is more useful. + fnReset(LOCAL_GL_UNPACK_ALIGNMENT, 1, &mAlignment); + + if (!mGL->HasPBOState()) return; + + mGL->GetUIntegerv(LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING, &mPBO); + if (mPBO != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); + + fnReset(LOCAL_GL_UNPACK_ROW_LENGTH, 0, &mRowLength); + fnReset(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0, &mImageHeight); + fnReset(LOCAL_GL_UNPACK_SKIP_PIXELS, 0, &mSkipPixels); + fnReset(LOCAL_GL_UNPACK_SKIP_ROWS, 0, &mSkipRows); + fnReset(LOCAL_GL_UNPACK_SKIP_IMAGES, 0, &mSkipImages); +} + +ResetUnpackState::~ResetUnpackState() { + mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mAlignment); + + if (!mGL->HasPBOState()) return; + + mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO); + + mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength); + mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight); + mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mSkipPixels); + mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mSkipRows); + mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages); +} + +//////////////////////////////////////////////////////////////////////// +// ScopedBindPBO + +static GLuint GetPBOBinding(GLContext* gl, GLenum target) { + if (!gl->HasPBOState()) return 0; + + GLenum targetBinding; + switch (target) { + case LOCAL_GL_PIXEL_PACK_BUFFER: + targetBinding = LOCAL_GL_PIXEL_PACK_BUFFER_BINDING; + break; + + case LOCAL_GL_PIXEL_UNPACK_BUFFER: + targetBinding = LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING; + break; + + default: + MOZ_CRASH(); + } + + return gl->GetIntAs<GLuint>(targetBinding); +} + +ScopedBindPBO::ScopedBindPBO(GLContext* gl, GLenum target) + : mGL(gl), mTarget(target), mPBO(GetPBOBinding(mGL, mTarget)) {} + +ScopedBindPBO::~ScopedBindPBO() { + if (!mGL->HasPBOState()) return; + + mGL->fBindBuffer(mTarget, mPBO); +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/ScopedGLHelpers.h b/gfx/gl/ScopedGLHelpers.h new file mode 100644 index 0000000000..6e3b9867bc --- /dev/null +++ b/gfx/gl/ScopedGLHelpers.h @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SCOPEDGLHELPERS_H_ +#define SCOPEDGLHELPERS_H_ + +#include "GLDefs.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace gl { + +class GLContext; + +#ifdef DEBUG +bool IsContextCurrent(GLContext* gl); +#endif + +// Wraps glEnable/Disable. +struct ScopedGLState final { + private: + GLContext* const mGL; + const GLenum mCapability; + bool mOldState; + + public: + // Use |newState = true| to enable, |false| to disable. + ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState); + // variant that doesn't change state; simply records existing state to be + // restored by the destructor + ScopedGLState(GLContext* aGL, GLenum aCapability); + ~ScopedGLState(); +}; + +// Saves and restores with GetUserBoundFB and BindUserFB. +struct ScopedBindFramebuffer final { + private: + GLContext* const mGL; + GLuint mOldReadFB; + GLuint mOldDrawFB; + + void Init(); + + public: + explicit ScopedBindFramebuffer(GLContext* aGL); + ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB); + ~ScopedBindFramebuffer(); +}; + +struct ScopedBindTextureUnit final { + private: + GLContext* const mGL; + GLenum mOldTexUnit; + + public: + ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit); + ~ScopedBindTextureUnit(); +}; + +struct ScopedTexture final { + private: + GLContext* const mGL; + GLuint mTexture; + + public: + explicit ScopedTexture(GLContext* aGL); + ~ScopedTexture(); + + GLuint Texture() const { return mTexture; } + operator GLuint() const { return mTexture; } +}; + +struct ScopedFramebuffer final { + private: + GLContext* const mGL; + GLuint mFB; + + public: + explicit ScopedFramebuffer(GLContext* aGL); + ~ScopedFramebuffer(); + + const auto& FB() const { return mFB; } + operator GLuint() const { return mFB; } +}; + +struct ScopedRenderbuffer final { + private: + GLContext* const mGL; + GLuint mRB; + + public: + explicit ScopedRenderbuffer(GLContext* aGL); + ~ScopedRenderbuffer(); + + GLuint RB() { return mRB; } + operator GLuint() const { return mRB; } +}; + +struct ScopedBindTexture final { + private: + GLContext* const mGL; + const GLenum mTarget; + const GLuint mOldTex; + + public: + ScopedBindTexture(GLContext* aGL, GLuint aNewTex, + GLenum aTarget = LOCAL_GL_TEXTURE_2D); + ~ScopedBindTexture(); +}; + +struct ScopedBindRenderbuffer final { + private: + GLContext* const mGL; + GLuint mOldRB; + + private: + void Init(); + + public: + explicit ScopedBindRenderbuffer(GLContext* aGL); + ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB); + ~ScopedBindRenderbuffer(); +}; + +struct ScopedFramebufferForTexture final { + private: + GLContext* const mGL; + bool mComplete; // True if the framebuffer we create is complete. + GLuint mFB; + + public: + ScopedFramebufferForTexture(GLContext* aGL, GLuint aTexture, + GLenum aTarget = LOCAL_GL_TEXTURE_2D); + ~ScopedFramebufferForTexture(); + + bool IsComplete() const { return mComplete; } + + GLuint FB() const { + MOZ_GL_ASSERT(mGL, IsComplete()); + return mFB; + } +}; + +struct ScopedFramebufferForRenderbuffer final { + private: + GLContext* const mGL; + bool mComplete; // True if the framebuffer we create is complete. + GLuint mFB; + + public: + ScopedFramebufferForRenderbuffer(GLContext* aGL, GLuint aRB); + ~ScopedFramebufferForRenderbuffer(); + + bool IsComplete() const { return mComplete; } + GLuint FB() const { + MOZ_GL_ASSERT(mGL, IsComplete()); + return mFB; + } +}; + +struct ScopedViewportRect final { + private: + GLContext* const mGL; + GLint mSavedViewportRect[4]; + + public: + ScopedViewportRect(GLContext* aGL, GLint x, GLint y, GLsizei width, + GLsizei height); + ~ScopedViewportRect(); +}; + +struct ScopedScissorRect final { + private: + GLContext* const mGL; + GLint mSavedScissorRect[4]; + + public: + ScopedScissorRect(GLContext* aGL, GLint x, GLint y, GLsizei width, + GLsizei height); + explicit ScopedScissorRect(GLContext* aGL); + ~ScopedScissorRect(); +}; + +struct ScopedVertexAttribPointer final { + private: + GLContext* const mGL; + GLuint mAttribIndex; + GLint mAttribEnabled; + GLint mAttribSize; + GLint mAttribStride; + GLint mAttribType; + GLint mAttribNormalized; + GLint mAttribBufferBinding; + void* mAttribPointer; + GLuint mBoundBuffer; + + public: + ScopedVertexAttribPointer(GLContext* aGL, GLuint index, GLint size, + GLenum type, realGLboolean normalized, + GLsizei stride, GLuint buffer, + const GLvoid* pointer); + explicit ScopedVertexAttribPointer(GLContext* aGL, GLuint index); + ~ScopedVertexAttribPointer(); + + private: + void WrapImpl(GLuint index); +}; + +struct ScopedPackState final { + private: + GLContext* const mGL; + GLint mAlignment; + + GLuint mPixelBuffer; + GLint mRowLength; + GLint mSkipPixels; + GLint mSkipRows; + + public: + explicit ScopedPackState(GLContext* gl); + ~ScopedPackState(); + + // Returns whether the stride was handled successfully. + bool SetForWidthAndStrideRGBA(GLsizei aWidth, GLsizei aStride); +}; + +struct ResetUnpackState final { + private: + GLContext* const mGL; + GLuint mAlignment; + + GLuint mPBO; + GLuint mRowLength; + GLuint mImageHeight; + GLuint mSkipPixels; + GLuint mSkipRows; + GLuint mSkipImages; + + public: + explicit ResetUnpackState(GLContext* gl); + ~ResetUnpackState(); +}; + +struct ScopedBindPBO final { + private: + GLContext* const mGL; + const GLenum mTarget; + const GLuint mPBO; + + public: + ScopedBindPBO(GLContext* gl, GLenum target); + ~ScopedBindPBO(); +}; + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* SCOPEDGLHELPERS_H_ */ diff --git a/gfx/gl/SharedSurface.cpp b/gfx/gl/SharedSurface.cpp new file mode 100644 index 0000000000..2fbfd3f625 --- /dev/null +++ b/gfx/gl/SharedSurface.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurface.h" + +#include "../2d/2D.h" +#include "GLBlitHelper.h" +#include "GLContext.h" +#include "GLReadTexImageHelper.h" +#include "GLScreenBuffer.h" +#include "nsThreadUtils.h" +#include "ScopedGLHelpers.h" +#include "SharedSurfaceGL.h" +#include "SharedSurfaceEGL.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/TextureClientSharedSurface.h" +#include "mozilla/layers/TextureForwarder.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "mozilla/Unused.h" +#include "VRManagerChild.h" + +#ifdef XP_WIN +# include "SharedSurfaceANGLE.h" +# include "SharedSurfaceD3D11Interop.h" +#endif + +#ifdef XP_MACOSX +# include "SharedSurfaceIO.h" +#endif + +#ifdef MOZ_WIDGET_GTK +# include "gfxPlatformGtk.h" +# include "SharedSurfaceDMABUF.h" +# include "mozilla/widget/DMABufLibWrapper.h" +#endif + +#ifdef MOZ_WIDGET_ANDROID +# include "SharedSurfaceAndroidHardwareBuffer.h" +#endif + +namespace mozilla { +namespace gl { + +//////////////////////////////////////////////////////////////////////// +// SharedSurface + +SharedSurface::SharedSurface(const SharedSurfaceDesc& desc, + UniquePtr<MozFramebuffer> fb) + : mDesc(desc), mFb(std::move(fb)) {} + +SharedSurface::~SharedSurface() = default; + +void SharedSurface::LockProd() { + MOZ_ASSERT(!mIsLocked); + + LockProdImpl(); + + mDesc.gl->LockSurface(this); + mIsLocked = true; +} + +void SharedSurface::UnlockProd() { + if (!mIsLocked) return; + + UnlockProdImpl(); + + mDesc.gl->UnlockSurface(this); + mIsLocked = false; +} + +//////////////////////////////////////////////////////////////////////// +// SurfaceFactory + +/* static */ +UniquePtr<SurfaceFactory> SurfaceFactory::Create( + GLContext* const pGl, const layers::TextureType consumerType) { + auto& gl = *pGl; + + switch (consumerType) { + case layers::TextureType::D3D11: +#ifdef XP_WIN + if (gl.IsANGLE()) { + return SurfaceFactory_ANGLEShareHandle::Create(gl); + } + if (StaticPrefs::webgl_dxgl_enabled()) { + return SurfaceFactory_D3D11Interop::Create(gl); + } +#endif + return nullptr; + + case layers::TextureType::MacIOSurface: +#ifdef XP_MACOSX + return MakeUnique<SurfaceFactory_IOSurface>(gl); +#else + return nullptr; +#endif + + case layers::TextureType::DMABUF: +#ifdef MOZ_WIDGET_GTK + if (gl.GetContextType() == GLContextType::EGL && + widget::DMABufDevice::IsDMABufWebGLEnabled()) { + return SurfaceFactory_DMABUF::Create(gl); + } +#endif + return nullptr; + + case layers::TextureType::AndroidNativeWindow: +#ifdef MOZ_WIDGET_ANDROID + return MakeUnique<SurfaceFactory_SurfaceTexture>(gl); +#else + return nullptr; +#endif + + case layers::TextureType::AndroidHardwareBuffer: +#ifdef MOZ_WIDGET_ANDROID + if (XRE_IsGPUProcess()) { + // Enable SharedSurface of AndroidHardwareBuffer only in GPU process. + return SurfaceFactory_AndroidHardwareBuffer::Create(gl); + } +#endif + return nullptr; + + case layers::TextureType::EGLImage: +#ifdef MOZ_WIDGET_ANDROID + if (XRE_IsParentProcess()) { + return SurfaceFactory_EGLImage::Create(gl); + } +#endif + return nullptr; + + case layers::TextureType::Unknown: + case layers::TextureType::Last: + break; + } + +#ifdef MOZ_X11 + // Silence a warning. + Unused << gl; +#endif + + return nullptr; +} + +SurfaceFactory::SurfaceFactory(const PartialSharedSurfaceDesc& partialDesc) + : mDesc(partialDesc), mMutex("SurfaceFactor::mMutex") {} + +SurfaceFactory::~SurfaceFactory() = default; + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h new file mode 100644 index 0000000000..4168de69a2 --- /dev/null +++ b/gfx/gl/SharedSurface.h @@ -0,0 +1,199 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* SharedSurface abstracts an actual surface (can be a GL texture, but + * not necessarily) that handles sharing. + * Its specializations are: + * SharedSurface_Basic (client-side bitmap, does readback) + * SharedSurface_GLTexture + * SharedSurface_EGLImage + * SharedSurface_ANGLEShareHandle + */ + +#ifndef SHARED_SURFACE_H_ +#define SHARED_SURFACE_H_ + +#include <queue> +#include <set> +#include <stdint.h> + +#include "GLContext.h" // Bug 1635644 +#include "GLContextTypes.h" +#include "GLDefs.h" +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/Mutex.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" +#include "SurfaceTypes.h" + +class nsIThread; + +namespace mozilla { +namespace gfx { +class DataSourceSurface; +class DrawTarget; +} // namespace gfx + +namespace layers { +class KnowsCompositor; +enum class LayersBackend : int8_t; +class LayersIPCChannel; +class SharedSurfaceTextureClient; +class SurfaceDescriptor; +class TextureClient; +enum class TextureFlags : uint32_t; +enum class TextureType : int8_t; +} // namespace layers + +namespace gl { + +class MozFramebuffer; +struct ScopedBindFramebuffer; +class SurfaceFactory; + +struct PartialSharedSurfaceDesc { + const WeakPtr<GLContext> gl; + const SharedSurfaceType type; + const layers::TextureType consumerType; + const bool canRecycle; + + bool operator==(const PartialSharedSurfaceDesc& rhs) const { + return gl == rhs.gl && type == rhs.type && + consumerType == rhs.consumerType && canRecycle == rhs.canRecycle; + } +}; +struct SharedSurfaceDesc : public PartialSharedSurfaceDesc { + gfx::IntSize size = {}; + gfx::ColorSpace2 colorSpace = gfx::ColorSpace2::UNKNOWN; + + bool operator==(const SharedSurfaceDesc& rhs) const { + return PartialSharedSurfaceDesc::operator==(rhs) && size == rhs.size && + colorSpace == rhs.colorSpace; + } + bool operator!=(const SharedSurfaceDesc& rhs) const { + return !(*this == rhs); + } +}; + +class SharedSurface { + public: + const SharedSurfaceDesc mDesc; + const UniquePtr<MozFramebuffer> mFb; // null if we should use fb=0. + + protected: + bool mIsLocked = false; + bool mIsProducerAcquired = false; + + SharedSurface(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>); + + public: + virtual ~SharedSurface(); + + bool IsLocked() const { return mIsLocked; } + bool IsProducerAcquired() const { return mIsProducerAcquired; } + + // This locks the SharedSurface as the production buffer for the context. + // This is needed by backends which use PBuffers and/or EGLSurfaces. + void LockProd(); + + // Unlocking is harmless if we're already unlocked. + void UnlockProd(); + + // This surface has been moved to the front buffer and will not be locked + // again until it is recycled. Do any finalization steps here. + virtual void Commit() {} + + protected: + virtual void LockProdImpl(){}; + virtual void UnlockProdImpl(){}; + + virtual void ProducerAcquireImpl(){}; + virtual void ProducerReleaseImpl(){}; + + virtual void ProducerReadAcquireImpl() { ProducerAcquireImpl(); } + virtual void ProducerReadReleaseImpl() { ProducerReleaseImpl(); } + + public: + void ProducerAcquire() { + MOZ_ASSERT(!mIsProducerAcquired); + ProducerAcquireImpl(); + mIsProducerAcquired = true; + } + void ProducerRelease() { + MOZ_ASSERT(mIsProducerAcquired); + ProducerReleaseImpl(); + mIsProducerAcquired = false; + } + void ProducerReadAcquire() { + MOZ_ASSERT(!mIsProducerAcquired); + ProducerReadAcquireImpl(); + mIsProducerAcquired = true; + } + void ProducerReadRelease() { + MOZ_ASSERT(mIsProducerAcquired); + ProducerReadReleaseImpl(); + mIsProducerAcquired = false; + } + + // This function waits until the buffer is no longer being used. + // To optimize the performance, some implementaions recycle SharedSurfaces + // even when its buffer is still being used. + virtual void WaitForBufferOwnership() {} + + // Returns true if the buffer is available. + // You can call WaitForBufferOwnership to wait for availability. + virtual bool IsBufferAvailable() const { return true; } + + virtual bool NeedsIndirectReads() const { return false; } + + // Returns true if the surface is still valid to use. If false, the underlying + // resource has been released and we must allocate a new surface instead. + virtual bool IsValid() const { return true; }; + + virtual Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() = 0; +}; + +// - + +class SurfaceFactory { + public: + const PartialSharedSurfaceDesc mDesc; + + layers::TextureType GetConsumerType() const { return mDesc.consumerType; } + + protected: + Mutex mMutex MOZ_UNANNOTATED; + + public: + static UniquePtr<SurfaceFactory> Create(GLContext*, layers::TextureType); + + protected: + explicit SurfaceFactory(const PartialSharedSurfaceDesc&); + + public: + virtual ~SurfaceFactory(); + + protected: + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc&) = 0; + + public: + UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size, + gfx::ColorSpace2 cs) { + return CreateSharedImpl({mDesc, size, cs}); + } +}; + +template <typename T> +inline UniquePtr<T> AsUnique(T* const p) { + return UniquePtr<T>(p); +} + +} // namespace gl +} // namespace mozilla + +#endif // SHARED_SURFACE_H_ diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp new file mode 100644 index 0000000000..8fae962b9f --- /dev/null +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceANGLE.h" + +#include <d3d11.h> +#include "GLContextEGL.h" +#include "GLLibraryEGL.h" +#include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/gfx/FileHandleWrapper.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc + +namespace mozilla { +namespace gl { + +static ID3D11Device* GetD3D11DeviceOfEGLDisplay(GLContextEGL* gle) { + const auto& egl = gle->mEgl; + MOZ_ASSERT(egl); + if (!egl || + !egl->mLib->IsExtensionSupported(gl::EGLLibExtension::EXT_device_query)) { + return nullptr; + } + + // Fetch the D3D11 device. + EGLDeviceEXT eglDevice = nullptr; + egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); + MOZ_ASSERT(eglDevice); + ID3D11Device* device = nullptr; + egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, + (EGLAttrib*)&device); + if (!device) { + return nullptr; + } + return device; +} + +// Returns `EGL_NO_SURFACE` (`0`) on error. +static EGLSurface CreatePBufferSurface(EglDisplay* egl, EGLConfig config, + const gfx::IntSize& size, + RefPtr<ID3D11Texture2D> texture2D) { + const EGLint attribs[] = {LOCAL_EGL_WIDTH, size.width, LOCAL_EGL_HEIGHT, + size.height, LOCAL_EGL_NONE}; + const auto buffer = reinterpret_cast<EGLClientBuffer>(texture2D.get()); + + EGLSurface surface = egl->fCreatePbufferFromClientBuffer( + LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, config, attribs); + if (!surface) { + EGLint err = egl->mLib->fGetError(); + gfxCriticalError() << "Failed to create Pbuffer surface error: " + << gfx::hexa(err) << " Size : " << size; + return 0; + } + + return surface; +} + +/*static*/ +UniquePtr<SharedSurface_ANGLEShareHandle> +SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) { + const auto& gle = GLContextEGL::Cast(desc.gl); + const auto& egl = gle->mEgl; + MOZ_ASSERT(egl); + MOZ_ASSERT(egl->IsExtensionSupported( + EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)); + + auto* device = GetD3D11DeviceOfEGLDisplay(gle); + if (!device) { + return nullptr; + } + + // Create a texture in case we need to readback. + const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM; + CD3D11_TEXTURE2D_DESC texDesc( + format, desc.size.width, desc.size.height, 1, 1, + D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; + + RefPtr<ID3D11Texture2D> texture2D; + auto hr = + device->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(texture2D)); + if (FAILED(hr)) { + return nullptr; + } + + RefPtr<IDXGIResource1> texDXGI; + hr = texture2D->QueryInterface(__uuidof(IDXGIResource1), + getter_AddRefs(texDXGI)); + if (FAILED(hr)) { + return nullptr; + } + + HANDLE sharedHandle = nullptr; + texDXGI->CreateSharedHandle( + nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, + &sharedHandle); + + RefPtr<gfx::FileHandleWrapper> handle = + new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); + + RefPtr<IDXGIKeyedMutex> keyedMutex; + texture2D->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(keyedMutex)); + if (!keyedMutex) { + return nullptr; + } + + const auto& config = gle->mSurfaceConfig; + MOZ_ASSERT(config); + + EGLSurface pbuffer = + CreatePBufferSurface(egl.get(), config, desc.size, texture2D); + if (!pbuffer) return nullptr; + + return AsUnique(new SharedSurface_ANGLEShareHandle( + desc, egl, pbuffer, std::move(handle), keyedMutex)); +} + +SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle( + const SharedSurfaceDesc& desc, const std::weak_ptr<EglDisplay>& egl, + EGLSurface pbuffer, RefPtr<gfx::FileHandleWrapper>&& aSharedHandle, + const RefPtr<IDXGIKeyedMutex>& keyedMutex) + : SharedSurface(desc, nullptr), + mEGL(egl), + mPBuffer(pbuffer), + mSharedHandle(std::move(aSharedHandle)), + mKeyedMutex(keyedMutex) {} + +SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() { + const auto& gl = mDesc.gl; + + if (gl && GLContextEGL::Cast(gl)->GetEGLSurfaceOverride() == mPBuffer) { + GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(EGL_NO_SURFACE); + } + const auto egl = mEGL.lock(); + if (egl) { + egl->fDestroySurface(mPBuffer); + } +} + +void SharedSurface_ANGLEShareHandle::LockProdImpl() { + const auto& gl = mDesc.gl; + GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(mPBuffer); +} + +void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {} + +void SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() { + HRESULT hr = mKeyedMutex->AcquireSync(0, 10000); + if (hr == WAIT_TIMEOUT) { + MOZ_CRASH("GFX: ANGLE share handle timeout"); + } +} + +void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() { + const auto& gl = mDesc.gl; + // XXX: ReleaseSync() has an implicit flush of the D3D commands + // whether we need Flush() or not depends on the ANGLE semantics. + // For now, we'll just do it + gl->fFlush(); + mKeyedMutex->ReleaseSync(0); +} + +void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() { + ProducerAcquireImpl(); +} + +void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() { + mKeyedMutex->ReleaseSync(0); +} + +Maybe<layers::SurfaceDescriptor> +SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() { + const auto format = gfx::SurfaceFormat::B8G8R8A8; + return Some(layers::SurfaceDescriptorD3D10( + mSharedHandle, /* gpuProcessTextureId */ Nothing(), + /* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace, + gfx::ColorRange::FULL, /* hasKeyedMutex */ true, + /* fenceInfo */ Nothing(), /* gpuProcessQueryId */ Nothing())); +} + +//////////////////////////////////////////////////////////////////////////////// +// Factory + +/*static*/ +UniquePtr<SurfaceFactory_ANGLEShareHandle> +SurfaceFactory_ANGLEShareHandle::Create(GLContext& gl) { + if (!gl.IsANGLE()) return nullptr; + + const auto& gle = *GLContextEGL::Cast(&gl); + const auto& egl = gle.mEgl; + + if (!egl->IsExtensionSupported( + EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)) { + return nullptr; + } + + if (XRE_IsContentProcess()) { + gfxPlatform::GetPlatform()->EnsureDevicesInitialized(); + } + + gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get(); + MOZ_ASSERT(dm); + if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) { + return nullptr; + } + + return AsUnique(new SurfaceFactory_ANGLEShareHandle( + {&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11, + true})); +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h new file mode 100644 index 0000000000..5a1a617338 --- /dev/null +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -0,0 +1,75 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_ANGLE_H_ +#define SHARED_SURFACE_ANGLE_H_ + +#include <windows.h> +#include <memory> +#include "SharedSurface.h" + +struct IDXGIKeyedMutex; +struct ID3D11Texture2D; + +namespace mozilla { + +namespace gfx { +class FileHandleWrapper; +} // namespace gfx + +namespace gl { + +class GLContext; +class EglDisplay; + +class SharedSurface_ANGLEShareHandle final : public SharedSurface { + public: + const std::weak_ptr<EglDisplay> mEGL; + const EGLSurface mPBuffer; + const RefPtr<gfx::FileHandleWrapper> mSharedHandle; + const RefPtr<IDXGIKeyedMutex> mKeyedMutex; + + static UniquePtr<SharedSurface_ANGLEShareHandle> Create( + const SharedSurfaceDesc&); + + private: + SharedSurface_ANGLEShareHandle(const SharedSurfaceDesc&, + const std::weak_ptr<EglDisplay>& egl, + EGLSurface pbuffer, + RefPtr<gfx::FileHandleWrapper>&& aSharedHandle, + const RefPtr<IDXGIKeyedMutex>& keyedMutex); + + public: + virtual ~SharedSurface_ANGLEShareHandle(); + + virtual void LockProdImpl() override; + virtual void UnlockProdImpl() override; + + virtual void ProducerAcquireImpl() override; + virtual void ProducerReleaseImpl() override; + virtual void ProducerReadAcquireImpl() override; + virtual void ProducerReadReleaseImpl() override; + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; +}; + +class SurfaceFactory_ANGLEShareHandle final : public SurfaceFactory { + public: + static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext& gl); + + private: + explicit SurfaceFactory_ANGLEShareHandle(const PartialSharedSurfaceDesc& desc) + : SurfaceFactory(desc) {} + + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_ANGLEShareHandle::Create(desc); + } +}; + +} // namespace gl +} /* namespace mozilla */ + +#endif /* SHARED_SURFACE_ANGLE_H_ */ diff --git a/gfx/gl/SharedSurfaceAndroidHardwareBuffer.cpp b/gfx/gl/SharedSurfaceAndroidHardwareBuffer.cpp new file mode 100644 index 0000000000..00f925ce75 --- /dev/null +++ b/gfx/gl/SharedSurfaceAndroidHardwareBuffer.cpp @@ -0,0 +1,168 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceAndroidHardwareBuffer.h" + +#include "GLBlitHelper.h" +#include "GLContextEGL.h" +#include "GLContextProvider.h" +#include "GLLibraryEGL.h" +#include "GLReadTexImageHelper.h" +#include "MozFramebuffer.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/AndroidHardwareBuffer.h" +#include "ScopedGLHelpers.h" +#include "SharedSurface.h" + +namespace mozilla { +namespace gl { + +/*static*/ +UniquePtr<SharedSurface_AndroidHardwareBuffer> +SharedSurface_AndroidHardwareBuffer::Create(const SharedSurfaceDesc& desc) { + const auto& gle = GLContextEGL::Cast(desc.gl); + const auto& egl = gle->mEgl; + + RefPtr<layers::AndroidHardwareBuffer> buffer = + layers::AndroidHardwareBuffer::Create(desc.size, + gfx::SurfaceFormat::R8G8B8A8); + if (!buffer) { + return nullptr; + } + + const EGLint attrs[] = { + LOCAL_EGL_IMAGE_PRESERVED, + LOCAL_EGL_TRUE, + LOCAL_EGL_NONE, + LOCAL_EGL_NONE, + }; + + EGLClientBuffer clientBuffer = + egl->mLib->fGetNativeClientBufferANDROID(buffer->GetNativeBuffer()); + const auto image = egl->fCreateImage( + EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); + if (!image) { + return nullptr; + } + + auto tex = MakeUnique<Texture>(*desc.gl); + { + ScopedBindTexture texture(gle, tex->name, LOCAL_GL_TEXTURE_2D); + gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, + LOCAL_GL_LINEAR); + gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, + LOCAL_GL_LINEAR); + gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + gle->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image); + egl->fDestroyImage(image); + } + + const GLenum target = LOCAL_GL_TEXTURE_2D; + auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, + target, tex->name); + if (!fb) { + return nullptr; + } + + return AsUnique(new SharedSurface_AndroidHardwareBuffer( + desc, std::move(fb), std::move(tex), buffer)); +} + +SharedSurface_AndroidHardwareBuffer::SharedSurface_AndroidHardwareBuffer( + const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer> fb, + UniquePtr<Texture> tex, RefPtr<layers::AndroidHardwareBuffer> buffer) + : SharedSurface(desc, std::move(fb)), + mTex(std::move(tex)), + mAndroidHardwareBuffer(buffer) {} + +SharedSurface_AndroidHardwareBuffer::~SharedSurface_AndroidHardwareBuffer() { + const auto& gl = mDesc.gl; + if (!gl || !gl->MakeCurrent()) { + return; + } + const auto& gle = GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + + if (mSync) { + egl->fDestroySync(mSync); + mSync = 0; + } +} + +void SharedSurface_AndroidHardwareBuffer::ProducerReleaseImpl() { + const auto& gl = mDesc.gl; + if (!gl || !gl->MakeCurrent()) { + return; + } + const auto& gle = GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + + if (mSync) { + MOZ_ALWAYS_TRUE(egl->fDestroySync(mSync)); + mSync = 0; + } + + mSync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + MOZ_ASSERT(mSync); + int rawFd = egl->fDupNativeFenceFDANDROID(mSync); + if (rawFd >= 0) { + auto fenceFd = ipc::FileDescriptor(UniqueFileHandle(rawFd)); + mAndroidHardwareBuffer->SetAcquireFence(std::move(fenceFd)); + } + + gl->fFlush(); +} + +Maybe<layers::SurfaceDescriptor> +SharedSurface_AndroidHardwareBuffer::ToSurfaceDescriptor() { + return Some(layers::SurfaceDescriptorAndroidHardwareBuffer( + mAndroidHardwareBuffer->mId, mAndroidHardwareBuffer->mSize, + mAndroidHardwareBuffer->mFormat)); +} + +void SharedSurface_AndroidHardwareBuffer::WaitForBufferOwnership() { + ipc::FileDescriptor fenceFd = + mAndroidHardwareBuffer->GetAndResetReleaseFence(); + if (!fenceFd.IsValid()) { + return; + } + + const auto& gle = GLContextEGL::Cast(mDesc.gl); + const auto& egl = gle->mEgl; + + auto rawFD = fenceFd.TakePlatformHandle(); + const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, rawFD.get(), + LOCAL_EGL_NONE}; + + EGLSync sync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (!sync) { + gfxCriticalNote << "Failed to create EGLSync from fd"; + return; + } + // Release fd here, since it is owned by EGLSync + Unused << rawFD.release(); + + egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER); + egl->fDestroySync(sync); +} + +/*static*/ +UniquePtr<SurfaceFactory_AndroidHardwareBuffer> +SurfaceFactory_AndroidHardwareBuffer::Create(GLContext& gl) { + const auto partialDesc = PartialSharedSurfaceDesc{ + &gl, + SharedSurfaceType::AndroidHardwareBuffer, + layers::TextureType::AndroidHardwareBuffer, + true, + }; + return AsUnique(new SurfaceFactory_AndroidHardwareBuffer(partialDesc)); +} + +} // namespace gl + +} /* namespace mozilla */ diff --git a/gfx/gl/SharedSurfaceAndroidHardwareBuffer.h b/gfx/gl/SharedSurfaceAndroidHardwareBuffer.h new file mode 100644 index 0000000000..ef40ad622d --- /dev/null +++ b/gfx/gl/SharedSurfaceAndroidHardwareBuffer.h @@ -0,0 +1,70 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_ANDROID_HARDWARE_BUFFER_H_ +#define SHARED_SURFACE_ANDROID_HARDWARE_BUFFER_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/Mutex.h" +#include "CompositorTypes.h" +#include "SharedSurface.h" + +namespace mozilla { + +namespace layers { +class AndroidHardwareBuffer; +} // namespace layers + +namespace gl { + +class SharedSurface_AndroidHardwareBuffer final : public SharedSurface { + public: + const UniquePtr<Texture> mTex; + const RefPtr<layers::AndroidHardwareBuffer> mAndroidHardwareBuffer; + EGLSync mSync = 0; + + static UniquePtr<SharedSurface_AndroidHardwareBuffer> Create( + const SharedSurfaceDesc&); + + protected: + SharedSurface_AndroidHardwareBuffer( + const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>, UniquePtr<Texture>, + RefPtr<layers::AndroidHardwareBuffer> buffer); + + public: + virtual ~SharedSurface_AndroidHardwareBuffer(); + + void LockProdImpl() override {} + void UnlockProdImpl() override {} + + void ProducerAcquireImpl() override {} + void ProducerReleaseImpl() override; + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; + + void WaitForBufferOwnership() override; +}; + +class SurfaceFactory_AndroidHardwareBuffer final : public SurfaceFactory { + public: + static UniquePtr<SurfaceFactory_AndroidHardwareBuffer> Create(GLContext&); + + private: + explicit SurfaceFactory_AndroidHardwareBuffer( + const PartialSharedSurfaceDesc& desc) + : SurfaceFactory(desc) {} + + public: + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_AndroidHardwareBuffer::Create(desc); + } +}; + +} // namespace gl + +} /* namespace mozilla */ + +#endif /* SHARED_SURFACE_ANDROID_HARDWARE_BUFFER_H_ */ diff --git a/gfx/gl/SharedSurfaceD3D11Interop.cpp b/gfx/gl/SharedSurfaceD3D11Interop.cpp new file mode 100644 index 0000000000..4248bdf23d --- /dev/null +++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp @@ -0,0 +1,489 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceD3D11Interop.h" + +#include <d3d11.h> +#include <d3d11_1.h> +#include "GLContext.h" +#include "GLBlitHelper.h" +#include "MozFramebuffer.h" +#include "ScopedGLHelpers.h" +#include "WGLLibrary.h" +#include "nsPrintfCString.h" +#include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/gfx/FileHandleWrapper.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/LayersSurfaces.h" +#include "mozilla/StaticPrefs_webgl.h" + +namespace mozilla { +namespace gl { + +/* +Sample Code for WGL_NV_DX_interop2: +Example: Render to Direct3D 11 backbuffer with openGL: + +// create D3D11 device, context and swap chain. +ID3D11Device *device; +ID3D11DeviceContext *devCtx; +IDXGISwapChain *swapChain; + +DXGI_SWAP_CHAIN_DESC scd; + +<set appropriate swap chain parameters in scd> + +hr = D3D11CreateDeviceAndSwapChain( + NULL, // pAdapter + D3D_DRIVER_TYPE_HARDWARE, // DriverType + NULL, // Software + 0, // Flags (Do not set + // D3D11_CREATE_DEVICE_SINGLETHREADED) + NULL, // pFeatureLevels + 0, // FeatureLevels + D3D11_SDK_VERSION, // SDKVersion + &scd, // pSwapChainDesc + &swapChain, // ppSwapChain + &device, // ppDevice + NULL, // pFeatureLevel + &devCtx); // ppImmediateContext + +// Fetch the swapchain backbuffer +ID3D11Texture2D *dxColorbuffer; +swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)&dxColorbuffer); + +// Create depth stencil texture +ID3D11Texture2D *dxDepthBuffer; +D3D11_TEXTURE2D_DESC depthDesc; +depthDesc.Usage = D3D11_USAGE_DEFAULT; +<set other depthDesc parameters appropriately> + +// Create Views +ID3D11RenderTargetView *colorBufferView; +D3D11_RENDER_TARGET_VIEW_DESC rtd; +<set rtd parameters appropriately> +device->CreateRenderTargetView(dxColorbuffer, &rtd, &colorBufferView); + +ID3D11DepthStencilView *depthBufferView; +D3D11_DEPTH_STENCIL_VIEW_DESC dsd; +<set dsd parameters appropriately> +device->CreateDepthStencilView(dxDepthBuffer, &dsd, &depthBufferView); + +// Attach back buffer and depth texture to redertarget for the device. +devCtx->OMSetRenderTargets(1, &colorBufferView, depthBufferView); + +// Register D3D11 device with GL +HANDLE gl_handleD3D; +gl_handleD3D = wglDXOpenDeviceNV(device); + +// register the Direct3D color and depth/stencil buffers as +// renderbuffers in opengl +GLuint gl_names[2]; +HANDLE gl_handles[2]; + +glGenRenderbuffers(2, gl_names); + +gl_handles[0] = wglDXRegisterObjectNV(gl_handleD3D, dxColorBuffer, + gl_names[0], + GL_RENDERBUFFER, + WGL_ACCESS_READ_WRITE_NV); + +gl_handles[1] = wglDXRegisterObjectNV(gl_handleD3D, dxDepthBuffer, + gl_names[1], + GL_RENDERBUFFER, + WGL_ACCESS_READ_WRITE_NV); + +// attach the Direct3D buffers to an FBO +glBindFramebuffer(GL_FRAMEBUFFER, fbo); +glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, gl_names[0]); +glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, gl_names[1]); +glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl_names[1]); + +while (!done) { + <direct3d renders to the render targets> + + // lock the render targets for GL access + wglDXLockObjectsNVX(gl_handleD3D, 2, gl_handles); + + <opengl renders to the render targets> + + // unlock the render targets + wglDXUnlockObjectsNVX(gl_handleD3D, 2, gl_handles); + + <direct3d renders to the render targets and presents + the results on the screen> +} +*/ + +//////////////////////////////////////////////////////////////////////////////// +// DXInterop2Device + +class ScopedContextState final { + ID3D11DeviceContext1* const mD3DContext; + RefPtr<ID3DDeviceContextState> mOldContextState; + + public: + ScopedContextState(ID3D11DeviceContext1* d3dContext, + ID3DDeviceContextState* newContextState) + : mD3DContext(d3dContext), mOldContextState(nullptr) { + if (!mD3DContext) return; + + mD3DContext->SwapDeviceContextState(newContextState, + getter_AddRefs(mOldContextState)); + } + + ~ScopedContextState() { + if (!mD3DContext) return; + + mD3DContext->SwapDeviceContextState(mOldContextState, nullptr); + } +}; + +class DXInterop2Device : public RefCounted<DXInterop2Device> { + public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(DXInterop2Device) + + WGLLibrary* const mWGL; + const RefPtr<ID3D11Device> mD3D; // Only needed for lifetime guarantee. + const HANDLE mInteropDevice; + GLContext* const mGL; + + // AMD workaround. + const RefPtr<ID3D11DeviceContext1> mD3DContext; + const RefPtr<ID3DDeviceContextState> mContextState; + + static already_AddRefed<DXInterop2Device> Open(WGLLibrary* wgl, + GLContext* gl) { + MOZ_ASSERT(wgl->HasDXInterop2()); + + const RefPtr<ID3D11Device> d3d = + gfx::DeviceManagerDx::Get()->GetContentDevice(); + if (!d3d) { + gfxCriticalNote + << "DXInterop2Device::Open: Failed to create D3D11 device."; + return nullptr; + } + + if (!gl->MakeCurrent()) return nullptr; + + RefPtr<ID3D11DeviceContext1> d3dContext; + RefPtr<ID3DDeviceContextState> contextState; + if (gl->WorkAroundDriverBugs() && gl->Vendor() == GLVendor::ATI) { + // AMD calls ID3D10Device::Flush, so we need to be in ID3D10Device mode. + RefPtr<ID3D11Device1> d3d11_1; + auto hr = + d3d->QueryInterface(__uuidof(ID3D11Device1), getter_AddRefs(d3d11_1)); + if (!SUCCEEDED(hr)) return nullptr; + + d3d11_1->GetImmediateContext1(getter_AddRefs(d3dContext)); + MOZ_ASSERT(d3dContext); + + const D3D_FEATURE_LEVEL featureLevel10_0 = D3D_FEATURE_LEVEL_10_0; + hr = d3d11_1->CreateDeviceContextState( + 0, &featureLevel10_0, 1, D3D11_SDK_VERSION, __uuidof(ID3D10Device), + nullptr, getter_AddRefs(contextState)); + if (!SUCCEEDED(hr)) return nullptr; + } + + const auto interopDevice = wgl->mSymbols.fDXOpenDeviceNV(d3d); + if (!interopDevice) { + gfxCriticalNote << "DXInterop2Device::Open: DXOpenDevice failed."; + return nullptr; + } + + return MakeAndAddRef<DXInterop2Device>(wgl, d3d, interopDevice, gl, + d3dContext, contextState); + } + + DXInterop2Device(WGLLibrary* wgl, ID3D11Device* d3d, HANDLE interopDevice, + GLContext* gl, ID3D11DeviceContext1* d3dContext, + ID3DDeviceContextState* contextState) + : mWGL(wgl), + mD3D(d3d), + mInteropDevice(interopDevice), + mGL(gl), + mD3DContext(d3dContext), + mContextState(contextState) {} + + ~DXInterop2Device() { + const auto isCurrent = mGL->MakeCurrent(); + + if (mWGL->mSymbols.fDXCloseDeviceNV(mInteropDevice)) return; + + if (isCurrent) { + // That shouldn't have failed. + const uint32_t error = GetLastError(); + const nsPrintfCString errorMessage( + "wglDXCloseDevice(0x%p) failed:" + " GetLastError(): %u\n", + mInteropDevice, error); + gfxCriticalError() << errorMessage.BeginReading(); + } + } + + HANDLE RegisterObject(void* d3dObject, GLuint name, GLenum type, + GLenum access) const { + if (!mGL->MakeCurrent()) return nullptr; + + const ScopedContextState autoCS(mD3DContext, mContextState); + const auto ret = mWGL->mSymbols.fDXRegisterObjectNV( + mInteropDevice, d3dObject, name, type, access); + if (ret) return ret; + + const uint32_t error = GetLastError(); + const nsPrintfCString errorMessage( + "wglDXRegisterObject(0x%p, 0x%p, %u, 0x%04x," + " 0x%04x) failed: GetLastError(): %u\n", + mInteropDevice, d3dObject, name, type, access, error); + gfxCriticalNote << errorMessage.BeginReading(); + return nullptr; + } + + bool UnregisterObject(HANDLE lockHandle) const { + const auto isCurrent = mGL->MakeCurrent(); + + const ScopedContextState autoCS(mD3DContext, mContextState); + if (mWGL->mSymbols.fDXUnregisterObjectNV(mInteropDevice, lockHandle)) + return true; + + if (!isCurrent) { + // That shouldn't have failed. + const uint32_t error = GetLastError(); + const nsPrintfCString errorMessage( + "wglDXUnregisterObject(0x%p, 0x%p) failed:" + " GetLastError(): %u\n", + mInteropDevice, lockHandle, error); + gfxCriticalError() << errorMessage.BeginReading(); + } + return false; + } + + bool LockObject(HANDLE lockHandle) const { + MOZ_ASSERT(mGL->IsCurrent()); + + if (mWGL->mSymbols.fDXLockObjectsNV(mInteropDevice, 1, &lockHandle)) + return true; + + if (!mGL->MakeCurrent()) return false; + + gfxCriticalNote << "wglDXLockObjects called without mGL being current." + << " Retrying after MakeCurrent."; + + if (mWGL->mSymbols.fDXLockObjectsNV(mInteropDevice, 1, &lockHandle)) + return true; + + const uint32_t error = GetLastError(); + const nsPrintfCString errorMessage( + "wglDXLockObjects(0x%p, 1, {0x%p}) failed:" + " GetLastError(): %u\n", + mInteropDevice, lockHandle, error); + gfxCriticalError() << errorMessage.BeginReading(); + return false; + } + + bool UnlockObject(HANDLE lockHandle) const { + MOZ_ASSERT(mGL->IsCurrent()); + + if (mWGL->mSymbols.fDXUnlockObjectsNV(mInteropDevice, 1, &lockHandle)) + return true; + + if (!mGL->MakeCurrent()) return false; + + gfxCriticalNote << "wglDXUnlockObjects called without mGL being current." + << " Retrying after MakeCurrent."; + + if (mWGL->mSymbols.fDXUnlockObjectsNV(mInteropDevice, 1, &lockHandle)) + return true; + + const uint32_t error = GetLastError(); + const nsPrintfCString errorMessage( + "wglDXUnlockObjects(0x%p, 1, {0x%p}) failed:" + " GetLastError(): %u\n", + mInteropDevice, lockHandle, error); + gfxCriticalError() << errorMessage.BeginReading(); + return false; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Shared Surface + +/*static*/ +UniquePtr<SharedSurface_D3D11Interop> SharedSurface_D3D11Interop::Create( + const SharedSurfaceDesc& desc, DXInterop2Device* interop) { + const auto& gl = desc.gl; + const auto& size = desc.size; + const auto& d3d = interop->mD3D; + + auto data = Data{interop}; + + // Create a texture in case we need to readback. + const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM; + CD3D11_TEXTURE2D_DESC texDesc(format, size.width, size.height, 1, 1); + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; + + auto hr = + d3d->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(data.texD3D)); + if (FAILED(hr)) { + NS_WARNING("Failed to create texture for CanvasLayer!"); + return nullptr; + } + + RefPtr<IDXGIResource1> texDXGI; + hr = data.texD3D->QueryInterface(__uuidof(IDXGIResource1), + getter_AddRefs(texDXGI)); + if (FAILED(hr)) { + NS_WARNING("Failed to open texture for sharing!"); + return nullptr; + } + + HANDLE sharedHandle = nullptr; + texDXGI->CreateSharedHandle( + nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, + &sharedHandle); + + data.dxgiHandle = new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); + + //// + + if (!gl->MakeCurrent()) { + NS_WARNING("MakeCurrent failed."); + return nullptr; + } + + data.interopRb = MakeUnique<Renderbuffer>(*gl); + data.lockHandle = interop->RegisterObject(data.texD3D, data.interopRb->name, + LOCAL_GL_RENDERBUFFER, + LOCAL_WGL_ACCESS_WRITE_DISCARD_NV); + if (!data.lockHandle) { + NS_WARNING("Failed to register D3D object with WGL."); + return nullptr; + } + + auto fbForDrawing = MozFramebuffer::CreateForBacking( + gl, size, 0, false, LOCAL_GL_RENDERBUFFER, data.interopRb->name); + if (!fbForDrawing) return nullptr; + + // - + + { + GLint samples = 0; + { + const ScopedBindRenderbuffer bindRB(gl, data.interopRb->name); + gl->fGetRenderbufferParameteriv(LOCAL_GL_RENDERBUFFER, + LOCAL_GL_RENDERBUFFER_SAMPLES, &samples); + } + if (samples > 0) { // Intel + // Intel's dx_interop GL-side textures have SAMPLES=1, likely because + // that's what the D3DTextures technically have. However, SAMPLES=1 is + // very different from SAMPLES=0 in GL. For more, see + // https://bugzilla.mozilla.org/show_bug.cgi?id=1325835 + + // Our ShSurf tex or rb must be single-sampled. + data.interopFbIfNeedsIndirect = std::move(fbForDrawing); + fbForDrawing = MozFramebuffer::Create(gl, size, 0, false); + } + } + + // - + + return AsUnique(new SharedSurface_D3D11Interop(desc, std::move(fbForDrawing), + std::move(data))); +} + +SharedSurface_D3D11Interop::SharedSurface_D3D11Interop( + const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer>&& fbForDrawing, + Data&& data) + : SharedSurface(desc, std::move(fbForDrawing)), + mData(std::move(data)), + mNeedsFinish(StaticPrefs::webgl_dxgl_needs_finish()) {} + +SharedSurface_D3D11Interop::~SharedSurface_D3D11Interop() { + MOZ_ASSERT(!IsProducerAcquired()); + + const auto& gl = mDesc.gl; + if (!gl || !gl->MakeCurrent()) return; + + if (!mData.interop->UnregisterObject(mData.lockHandle)) { + NS_WARNING("Failed to release mLockHandle, possibly leaking it."); + } +} + +void SharedSurface_D3D11Interop::ProducerAcquireImpl() { + MOZ_ASSERT(!mLockedForGL); + + // Now we have the mutex, we can lock for GL. + MOZ_ALWAYS_TRUE(mData.interop->LockObject(mData.lockHandle)); + + mLockedForGL = true; +} + +void SharedSurface_D3D11Interop::ProducerReleaseImpl() { + const auto& gl = mDesc.gl; + MOZ_ASSERT(mLockedForGL); + + if (mData.interopFbIfNeedsIndirect) { + const ScopedBindFramebuffer bindFB(gl, mData.interopFbIfNeedsIndirect->mFB); + gl->BlitHelper()->DrawBlitTextureToFramebuffer(mFb->ColorTex(), mDesc.size, + mDesc.size); + } + + if (mNeedsFinish) { + gl->fFinish(); + } else { + // We probably don't even need this. + gl->fFlush(); + } + MOZ_ALWAYS_TRUE(mData.interop->UnlockObject(mData.lockHandle)); + + mLockedForGL = false; +} + +Maybe<layers::SurfaceDescriptor> +SharedSurface_D3D11Interop::ToSurfaceDescriptor() { + const auto format = gfx::SurfaceFormat::B8G8R8A8; + return Some(layers::SurfaceDescriptorD3D10( + mData.dxgiHandle, /* gpuProcessTextureId */ Nothing(), + /* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace, + gfx::ColorRange::FULL, /* hasKeyedMutex */ true, + /* fenceInfo */ Nothing(), /* gpuProcessQueryId */ Nothing())); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Factory + +/*static*/ +UniquePtr<SurfaceFactory_D3D11Interop> SurfaceFactory_D3D11Interop::Create( + GLContext& gl) { + WGLLibrary* wgl = &sWGLLib; + if (!wgl || !wgl->HasDXInterop2()) return nullptr; + + if (XRE_IsContentProcess()) { + gfxPlatform::GetPlatform()->EnsureDevicesInitialized(); + } + + const RefPtr<DXInterop2Device> interop = DXInterop2Device::Open(wgl, &gl); + if (!interop) { + NS_WARNING("Failed to open D3D device for use by WGL."); + return nullptr; + } + + return AsUnique(new SurfaceFactory_D3D11Interop( + {&gl, SharedSurfaceType::DXGLInterop2, layers::TextureType::D3D11, true}, + interop)); +} + +SurfaceFactory_D3D11Interop::SurfaceFactory_D3D11Interop( + const PartialSharedSurfaceDesc& desc, DXInterop2Device* interop) + : SurfaceFactory(desc), mInterop(interop) {} + +SurfaceFactory_D3D11Interop::~SurfaceFactory_D3D11Interop() = default; + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/SharedSurfaceD3D11Interop.h b/gfx/gl/SharedSurfaceD3D11Interop.h new file mode 100644 index 0000000000..960850c27e --- /dev/null +++ b/gfx/gl/SharedSurfaceD3D11Interop.h @@ -0,0 +1,84 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_D3D11_INTEROP_H_ +#define SHARED_SURFACE_D3D11_INTEROP_H_ + +#include <d3d11.h> +#include <windows.h> +#include "SharedSurface.h" + +namespace mozilla { + +namespace gfx { +class FileHandleWrapper; +} // namespace gfx + +namespace gl { + +class DXInterop2Device; +class GLContext; +class WGLLibrary; + +class SharedSurface_D3D11Interop final : public SharedSurface { + public: + struct Data final { + const RefPtr<DXInterop2Device> interop; + HANDLE lockHandle; + RefPtr<ID3D11Texture2D> texD3D; + RefPtr<gfx::FileHandleWrapper> dxgiHandle; + UniquePtr<Renderbuffer> interopRb; + UniquePtr<MozFramebuffer> interopFbIfNeedsIndirect; + }; + const Data mData; + const bool mNeedsFinish; + + private: + bool mLockedForGL = false; + + public: + static UniquePtr<SharedSurface_D3D11Interop> Create(const SharedSurfaceDesc&, + DXInterop2Device*); + + private: + SharedSurface_D3D11Interop(const SharedSurfaceDesc&, + UniquePtr<MozFramebuffer>&& fbForDrawing, Data&&); + + public: + virtual ~SharedSurface_D3D11Interop(); + + void LockProdImpl() override {} + void UnlockProdImpl() override {} + + void ProducerAcquireImpl() override; + void ProducerReleaseImpl() override; + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; +}; + +class SurfaceFactory_D3D11Interop : public SurfaceFactory { + public: + const RefPtr<DXInterop2Device> mInterop; + + static UniquePtr<SurfaceFactory_D3D11Interop> Create(GLContext& gl); + + protected: + SurfaceFactory_D3D11Interop(const PartialSharedSurfaceDesc&, + DXInterop2Device* interop); + + public: + virtual ~SurfaceFactory_D3D11Interop(); + + protected: + UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_D3D11Interop::Create(desc, mInterop); + } +}; + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* SHARED_SURFACE_D3D11_INTEROP_H_ */ diff --git a/gfx/gl/SharedSurfaceDMABUF.cpp b/gfx/gl/SharedSurfaceDMABUF.cpp new file mode 100644 index 0000000000..56315bb317 --- /dev/null +++ b/gfx/gl/SharedSurfaceDMABUF.cpp @@ -0,0 +1,142 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceDMABUF.h" + +#include "gfxPlatform.h" +#include "GLContextEGL.h" +#include "MozFramebuffer.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/widget/DMABufLibWrapper.h" + +namespace mozilla::gl { + +static bool HasDmaBufExtensions(const GLContextEGL* gl) { + const auto& egl = *(gl->mEgl); + return egl.IsExtensionSupported(EGLExtension::EXT_image_dma_buf_import) && + egl.IsExtensionSupported( + EGLExtension::EXT_image_dma_buf_import_modifiers) && + egl.IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export); +} + +/*static*/ +UniquePtr<SharedSurface_DMABUF> SharedSurface_DMABUF::Create( + const SharedSurfaceDesc& desc) { + const auto& gle = GLContextEGL::Cast(desc.gl); + const auto& context = gle->mContext; + const auto& egl = *(gle->mEgl); + + RefPtr<DMABufSurface> surface; + UniquePtr<MozFramebuffer> fb; + + if (!HasDmaBufExtensions(gle) || !gfx::gfxVars::UseDMABufSurfaceExport()) { + // Using MESA_image_dma_buf_export is not supported or it's broken. + // Create dmabuf surface directly via GBM and create + // EGLImage/framebuffer over it. + const auto flags = static_cast<DMABufSurfaceFlags>( + DMABUF_TEXTURE | DMABUF_USE_MODIFIERS | DMABUF_ALPHA); + surface = DMABufSurfaceRGBA::CreateDMABufSurface(desc.size.width, + desc.size.height, flags); + if (!surface || !surface->CreateTexture(desc.gl)) { + return nullptr; + } + const auto tex = surface->GetTexture(); + fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, + LOCAL_GL_TEXTURE_2D, tex); + if (!fb) return nullptr; + } else { + // Use MESA_image_dma_buf_export to create EGLImage/framebuffer directly + // and derive dmabuf from it. + fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false); + if (!fb) return nullptr; + + const auto buffer = reinterpret_cast<EGLClientBuffer>(fb->ColorTex()); + const auto image = + egl.fCreateImage(context, LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr); + if (!image) return nullptr; + + surface = DMABufSurfaceRGBA::CreateDMABufSurface( + desc.gl, image, desc.size.width, desc.size.height); + if (!surface) return nullptr; + } + return AsUnique(new SharedSurface_DMABUF(desc, std::move(fb), surface)); +} + +SharedSurface_DMABUF::SharedSurface_DMABUF(const SharedSurfaceDesc& desc, + UniquePtr<MozFramebuffer> fb, + const RefPtr<DMABufSurface> surface) + : SharedSurface(desc, std::move(fb)), mSurface(surface) {} + +SharedSurface_DMABUF::~SharedSurface_DMABUF() { + const auto& gl = mDesc.gl; + if (!gl || !gl->MakeCurrent()) { + return; + } + mSurface->ReleaseTextures(); +} + +void SharedSurface_DMABUF::ProducerReleaseImpl() { mSurface->FenceSet(); } + +void SharedSurface_DMABUF::WaitForBufferOwnership() { mSurface->FenceWait(); } + +Maybe<layers::SurfaceDescriptor> SharedSurface_DMABUF::ToSurfaceDescriptor() { + layers::SurfaceDescriptor desc; + if (!mSurface->Serialize(desc)) return {}; + return Some(desc); +} + +/*static*/ +UniquePtr<SurfaceFactory_DMABUF> SurfaceFactory_DMABUF::Create(GLContext& gl) { + if (!widget::DMABufDevice::IsDMABufWebGLEnabled()) { + return nullptr; + } + + auto dmabufFactory = MakeUnique<SurfaceFactory_DMABUF>(gl); + if (dmabufFactory->CanCreateSurface(gl)) { + return dmabufFactory; + } + + LOGDMABUF( + ("SurfaceFactory_DMABUF::Create() failed, fallback to SW buffers.\n")); + widget::DMABufDevice::DisableDMABufWebGL(); + return nullptr; +} + +bool SurfaceFactory_DMABUF::CanCreateSurface(GLContext& gl) { + UniquePtr<SharedSurface> test = + CreateShared(gfx::IntSize(1, 1), gfx::ColorSpace2::SRGB); + if (!test) { + LOGDMABUF(( + "SurfaceFactory_DMABUF::CanCreateSurface() failed to create surface.")); + return false; + } + auto desc = test->ToSurfaceDescriptor(); + if (!desc) { + LOGDMABUF( + ("SurfaceFactory_DMABUF::CanCreateSurface() failed to serialize " + "surface.")); + return false; + } + RefPtr<DMABufSurface> importedSurface = + DMABufSurface::CreateDMABufSurface(*desc); + if (!importedSurface) { + LOGDMABUF(( + "SurfaceFactory_DMABUF::CanCreateSurface() failed to import surface.")); + return false; + } + if (!importedSurface->CreateTexture(&gl)) { + LOGDMABUF( + ("SurfaceFactory_DMABUF::CanCreateSurface() failed to create texture " + "over surface.")); + return false; + } + return true; +} + +SurfaceFactory_DMABUF::SurfaceFactory_DMABUF(GLContext& gl) + : SurfaceFactory({&gl, SharedSurfaceType::EGLSurfaceDMABUF, + layers::TextureType::DMABUF, true}) {} +} // namespace mozilla::gl diff --git a/gfx/gl/SharedSurfaceDMABUF.h b/gfx/gl/SharedSurfaceDMABUF.h new file mode 100644 index 0000000000..6aaa4d333e --- /dev/null +++ b/gfx/gl/SharedSurfaceDMABUF.h @@ -0,0 +1,69 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_DMABUF_H_ +#define SHARED_SURFACE_DMABUF_H_ + +#include "SharedSurface.h" +#include "mozilla/widget/DMABufSurface.h" + +namespace mozilla { +namespace gl { + +class GLContext; +class GLLibraryEGL; + +class SharedSurface_DMABUF final : public SharedSurface { + public: + const RefPtr<DMABufSurface> mSurface; + + static UniquePtr<SharedSurface_DMABUF> Create(const SharedSurfaceDesc&); + + private: + SharedSurface_DMABUF(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>, + RefPtr<DMABufSurface>); + + void UpdateProdTexture(const MutexAutoLock& curAutoLock); + + public: + virtual ~SharedSurface_DMABUF(); + + // Exclusive Content/WebGL lock/unlock of surface for write + virtual void LockProdImpl() override {} + virtual void UnlockProdImpl() override {} + + // Non-exclusive Content/WebGL lock/unlock of surface for write + virtual void ProducerAcquireImpl() override {} + virtual void ProducerReleaseImpl() override; + + // Non-exclusive Content/WebGL lock/unlock for read from surface + virtual void ProducerReadAcquireImpl() override {} + virtual void ProducerReadReleaseImpl() override {} + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; + + void WaitForBufferOwnership() override; +}; + +class SurfaceFactory_DMABUF : public SurfaceFactory { + public: + static UniquePtr<SurfaceFactory_DMABUF> Create(GLContext& gl); + + explicit SurfaceFactory_DMABUF(GLContext&); + + public: + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_DMABUF::Create(desc); + } + + bool CanCreateSurface(GLContext& gl); +}; + +} // namespace gl + +} // namespace mozilla + +#endif /* SHARED_SURFACE_DMABUF_H_ */ diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp new file mode 100644 index 0000000000..74dd695393 --- /dev/null +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -0,0 +1,269 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceEGL.h" + +#include "GLBlitHelper.h" +#include "GLContextEGL.h" +#include "GLContextProvider.h" +#include "GLLibraryEGL.h" +#include "GLReadTexImageHelper.h" +#include "MozFramebuffer.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "SharedSurface.h" + +#if defined(MOZ_WIDGET_ANDROID) +# include "AndroidNativeWindow.h" +# include "mozilla/java/SurfaceAllocatorWrappers.h" +# include "mozilla/java/GeckoSurfaceTextureWrappers.h" +#endif // defined(MOZ_WIDGET_ANDROID) + +namespace mozilla { +namespace gl { + +static bool HasEglImageExtensions(const GLContextEGL& gl) { + const auto& egl = *(gl.mEgl); + return egl.HasKHRImageBase() && + egl.IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) && + (gl.IsExtensionSupported(GLContext::OES_EGL_image_external) || + gl.IsExtensionSupported(GLContext::OES_EGL_image)); +} + +/*static*/ +UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create( + GLContext& gl_) { + auto& gl = *GLContextEGL::Cast(&gl_); + if (!HasEglImageExtensions(gl)) return nullptr; + + const auto partialDesc = PartialSharedSurfaceDesc{ + &gl, SharedSurfaceType::EGLImageShare, layers::TextureType::EGLImage, + false, // Can't recycle, as mSync changes never update TextureHost. + }; + return AsUnique(new SurfaceFactory_EGLImage(partialDesc)); +} + +// - + +/*static*/ +UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create( + const SharedSurfaceDesc& desc) { + const auto& gle = GLContextEGL::Cast(desc.gl); + const auto& context = gle->mContext; + const auto& egl = *(gle->mEgl); + + auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false); + if (!fb) return nullptr; + + const auto buffer = reinterpret_cast<EGLClientBuffer>(fb->ColorTex()); + const auto image = + egl.fCreateImage(context, LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr); + if (!image) return nullptr; + + return AsUnique(new SharedSurface_EGLImage(desc, std::move(fb), image)); +} + +SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc& desc, + UniquePtr<MozFramebuffer>&& fb, + const EGLImage image) + : SharedSurface(desc, std::move(fb)), + mMutex("SharedSurface_EGLImage mutex"), + mImage(image) {} + +SharedSurface_EGLImage::~SharedSurface_EGLImage() { + const auto& gle = GLContextEGL::Cast(mDesc.gl); + const auto& egl = gle->mEgl; + egl->fDestroyImage(mImage); + + if (mSync) { + // We can't call this unless we have the ext, but we will always have + // the ext if we have something to destroy. + egl->fDestroySync(mSync); + mSync = 0; + } +} + +void SharedSurface_EGLImage::ProducerReleaseImpl() { + const auto& gl = GLContextEGL::Cast(mDesc.gl); + const auto& egl = gl->mEgl; + + MutexAutoLock lock(mMutex); + gl->MakeCurrent(); + + if (egl->IsExtensionSupported(EGLExtension::KHR_fence_sync) && + gl->IsExtensionSupported(GLContext::OES_EGL_sync)) { + if (mSync) { + MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice."); + MOZ_ALWAYS_TRUE(egl->fDestroySync(mSync)); + mSync = 0; + } + + mSync = egl->fCreateSync(LOCAL_EGL_SYNC_FENCE, nullptr); + if (mSync) { + gl->fFlush(); + return; + } + } + + MOZ_ASSERT(!mSync); + gl->fFinish(); +} + +void SharedSurface_EGLImage::ProducerReadAcquireImpl() { + const auto& gle = GLContextEGL::Cast(mDesc.gl); + const auto& egl = gle->mEgl; + // Wait on the fence, because presumably we're going to want to read this + // surface + if (mSync) { + egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER); + } +} + +Maybe<layers::SurfaceDescriptor> SharedSurface_EGLImage::ToSurfaceDescriptor() { + return Some(layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync, + mDesc.size, true)); +} + +//////////////////////////////////////////////////////////////////////// + +#ifdef MOZ_WIDGET_ANDROID + +/*static*/ +UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create( + const SharedSurfaceDesc& desc) { + const auto& size = desc.size; + + jni::Object::LocalRef surfaceObj; + const bool useSingleBuffer = + desc.gl->Renderer() != GLRenderer::AndroidEmulator; + + if (useSingleBuffer) { + surfaceObj = + java::SurfaceAllocator::AcquireSurface(size.width, size.height, true); + } + + if (!surfaceObj) { + // Try multi-buffer mode + surfaceObj = + java::SurfaceAllocator::AcquireSurface(size.width, size.height, false); + } + + if (!surfaceObj) { + // Give up + NS_WARNING("Failed to allocate SurfaceTexture!"); + return nullptr; + } + const auto surface = java::GeckoSurface::Ref::From(surfaceObj); + + AndroidNativeWindow window(surface); + const auto& gle = GLContextEGL::Cast(desc.gl); + MOZ_ASSERT(gle); + const auto eglSurface = gle->CreateCompatibleSurface(window.NativeWindow()); + if (!eglSurface) return nullptr; + + return AsUnique(new SharedSurface_SurfaceTexture(desc, surface, eglSurface)); +} + +SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture( + const SharedSurfaceDesc& desc, java::GeckoSurface::Param surface, + const EGLSurface eglSurface) + : SharedSurface(desc, nullptr), + mSurface(surface), + mEglSurface(eglSurface), + mEglDisplay(GLContextEGL::Cast(desc.gl)->mEgl) {} + +SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture() { + if (mOrigEglSurface) { + // We are about to destroy mEglSurface. + // Make sure gl->SetEGLSurfaceOverride() doesn't keep a reference + // to the surface. + UnlockProd(); + } + + std::shared_ptr<EglDisplay> display = mEglDisplay.lock(); + if (display) { + display->fDestroySurface(mEglSurface); + } + java::SurfaceAllocator::DisposeSurface(mSurface); +} + +void SharedSurface_SurfaceTexture::LockProdImpl() { + MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); + + GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl); + mOrigEglSurface = gl->GetEGLSurfaceOverride(); + gl->SetEGLSurfaceOverride(mEglSurface); +} + +void SharedSurface_SurfaceTexture::UnlockProdImpl() { + MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); + + GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl); + MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface); + + gl->SetEGLSurfaceOverride(mOrigEglSurface); + mOrigEglSurface = nullptr; +} + +void SharedSurface_SurfaceTexture::ProducerReadReleaseImpl() { + // This GeckoSurfaceTexture is not SurfaceTexture of this class's GeckoSurface + // when current process is content process. In this case, SurfaceTexture of + // this class's GeckoSurface does not exist in this process. It exists in + // compositor's process. Then GeckoSurfaceTexture in this process is a sync + // surface that copies back the SurfaceTextrure from compositor's process. It + // was added by Bug 1486659. Then SurfaceTexture::UpdateTexImage() becomes + // very heavy weight, since it does copy back the SurfaceTextrure from + // compositor's process. + java::GeckoSurfaceTexture::LocalRef surfaceTexture = + java::GeckoSurfaceTexture::Lookup(mSurface->GetHandle()); + if (!surfaceTexture) { + NS_ERROR("Didn't find GeckoSurfaceTexture in ProducerReadReleaseImpl"); + return; + } + surfaceTexture->UpdateTexImage(); + // Non single buffer mode Surface does not need ReleaseTexImage() call. + // When SurfaceTexture is sync Surface, it might not be single buffer mode. + if (surfaceTexture->IsSingleBuffer()) { + surfaceTexture->ReleaseTexImage(); + } +} + +void SharedSurface_SurfaceTexture::Commit() { + MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); + + LockProdImpl(); + mDesc.gl->SwapBuffers(); + UnlockProdImpl(); + mSurface->SetAvailable(false); +} + +void SharedSurface_SurfaceTexture::WaitForBufferOwnership() { + mSurface->SetAvailable(true); +} + +bool SharedSurface_SurfaceTexture::IsBufferAvailable() const { + return mSurface->GetAvailable(); +} + +bool SharedSurface_SurfaceTexture::IsValid() const { + return !mSurface->IsReleased(); +} + +Maybe<layers::SurfaceDescriptor> +SharedSurface_SurfaceTexture::ToSurfaceDescriptor() { + return Some(layers::SurfaceTextureDescriptor( + mSurface->GetHandle(), mDesc.size, gfx::SurfaceFormat::R8G8B8A8, + false /* Do NOT override colorspace */, false /* NOT continuous */, + Nothing() /* Do not override transform */)); +} + +SurfaceFactory_SurfaceTexture::SurfaceFactory_SurfaceTexture(GLContext& gl) + : SurfaceFactory({&gl, SharedSurfaceType::AndroidSurfaceTexture, + layers::TextureType::AndroidNativeWindow, true}) {} + +#endif // MOZ_WIDGET_ANDROID + +} // namespace gl + +} /* namespace mozilla */ diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h new file mode 100644 index 0000000000..569421f945 --- /dev/null +++ b/gfx/gl/SharedSurfaceEGL.h @@ -0,0 +1,130 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_EGL_H_ +#define SHARED_SURFACE_EGL_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/Mutex.h" +#include "CompositorTypes.h" +#include "SharedSurface.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "AndroidNativeWindow.h" +# include "GLLibraryEGL.h" +#endif + +namespace mozilla { +namespace gl { + +class GLLibraryEGL; + +// - +// EGLImage + +class SharedSurface_EGLImage final : public SharedSurface { + mutable Mutex mMutex MOZ_UNANNOTATED; + EGLSync mSync = 0; + + public: + const EGLImage mImage; + + static UniquePtr<SharedSurface_EGLImage> Create(const SharedSurfaceDesc&); + + protected: + SharedSurface_EGLImage(const SharedSurfaceDesc&, + UniquePtr<MozFramebuffer>&& fb, EGLImage); + + void UpdateProdTexture(const MutexAutoLock& curAutoLock); + + public: + virtual ~SharedSurface_EGLImage(); + + virtual void LockProdImpl() override {} + virtual void UnlockProdImpl() override {} + + virtual void ProducerAcquireImpl() override {} + virtual void ProducerReleaseImpl() override; + + virtual void ProducerReadAcquireImpl() override; + virtual void ProducerReadReleaseImpl() override{}; + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; +}; + +class SurfaceFactory_EGLImage final : public SurfaceFactory { + public: + static UniquePtr<SurfaceFactory_EGLImage> Create(GLContext&); + + private: + explicit SurfaceFactory_EGLImage(const PartialSharedSurfaceDesc& desc) + : SurfaceFactory(desc) {} + + public: + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_EGLImage::Create(desc); + } +}; + +// - +// SurfaceTexture + +#ifdef MOZ_WIDGET_ANDROID + +class SharedSurface_SurfaceTexture final : public SharedSurface { + const java::GeckoSurface::GlobalRef mSurface; + const EGLSurface mEglSurface; + const std::weak_ptr<EglDisplay> mEglDisplay; + EGLSurface mOrigEglSurface = 0; + + public: + static UniquePtr<SharedSurface_SurfaceTexture> Create( + const SharedSurfaceDesc&); + + java::GeckoSurface::Param JavaSurface() { return mSurface; } + + protected: + SharedSurface_SurfaceTexture(const SharedSurfaceDesc&, + java::GeckoSurface::Param surface, EGLSurface); + + public: + virtual ~SharedSurface_SurfaceTexture(); + + virtual void LockProdImpl() override; + virtual void UnlockProdImpl() override; + + virtual void ProducerAcquireImpl() override {} + virtual void ProducerReleaseImpl() override {} + virtual void ProducerReadReleaseImpl() override; + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; + + virtual void Commit() override; + + virtual void WaitForBufferOwnership() override; + + virtual bool IsBufferAvailable() const override; + + bool IsValid() const override; +}; + +class SurfaceFactory_SurfaceTexture final : public SurfaceFactory { + public: + explicit SurfaceFactory_SurfaceTexture(GLContext&); + + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_SurfaceTexture::Create(desc); + } +}; + +#endif // MOZ_WIDGET_ANDROID + +} // namespace gl + +} /* namespace mozilla */ + +#endif /* SHARED_SURFACE_EGL_H_ */ diff --git a/gfx/gl/SharedSurfaceGL.cpp b/gfx/gl/SharedSurfaceGL.cpp new file mode 100644 index 0000000000..5b33088e2e --- /dev/null +++ b/gfx/gl/SharedSurfaceGL.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceGL.h" + +#include "GLBlitHelper.h" +#include "GLContext.h" +#include "GLReadTexImageHelper.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/layers/TextureForwarder.h" +#include "ScopedGLHelpers.h" + +namespace mozilla { +namespace gl { + +/*static*/ +UniquePtr<SharedSurface_Basic> SharedSurface_Basic::Create( + const SharedSurfaceDesc& desc) { + auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false); + if (!fb) return nullptr; + + return AsUnique(new SharedSurface_Basic(desc, std::move(fb))); +} + +SharedSurface_Basic::SharedSurface_Basic(const SharedSurfaceDesc& desc, + UniquePtr<MozFramebuffer>&& fb) + : SharedSurface(desc, std::move(fb)) {} + +Maybe<layers::SurfaceDescriptor> SharedSurface_Basic::ToSurfaceDescriptor() { + return Nothing(); +} + +//////////////////////////////////////////////////////////////////////// + +SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext& gl) + : SurfaceFactory({&gl, SharedSurfaceType::Basic, + layers::TextureType::Unknown, true}) {} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/SharedSurfaceGL.h b/gfx/gl/SharedSurfaceGL.h new file mode 100644 index 0000000000..fef3d59fb0 --- /dev/null +++ b/gfx/gl/SharedSurfaceGL.h @@ -0,0 +1,42 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACE_GL_H_ +#define SHARED_SURFACE_GL_H_ + +#include "SharedSurface.h" + +namespace mozilla { +namespace gl { + +class MozFramebuffer; + +// For readback and bootstrapping: +class SharedSurface_Basic final : public SharedSurface { + public: + static UniquePtr<SharedSurface_Basic> Create(const SharedSurfaceDesc&); + + private: + SharedSurface_Basic(const SharedSurfaceDesc& desc, + UniquePtr<MozFramebuffer>&& fb); + + public: + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; +}; + +class SurfaceFactory_Basic final : public SurfaceFactory { + public: + explicit SurfaceFactory_Basic(GLContext& gl); + + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + return SharedSurface_Basic::Create(desc); + } +}; + +} // namespace gl +} // namespace mozilla + +#endif // SHARED_SURFACE_GL_H_ diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp new file mode 100644 index 0000000000..1fd0f22d31 --- /dev/null +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -0,0 +1,103 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedSurfaceIO.h" + +#include "GLContextCGL.h" +#include "MozFramebuffer.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/gfx/MacIOSurface.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/LayersTypes.h" +#include "ScopedGLHelpers.h" + +namespace mozilla { +namespace gl { + +// - +// Factory + +SurfaceFactory_IOSurface::SurfaceFactory_IOSurface(GLContext& gl) + : SurfaceFactory({&gl, SharedSurfaceType::IOSurface, + layers::TextureType::MacIOSurface, true}), + mMaxDims(gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(), + MacIOSurface::GetMaxHeight())) {} + +// - +// Surface + +static void BackTextureWithIOSurf(GLContext* const gl, const GLuint tex, + MacIOSurface* const ioSurf) { + MOZ_ASSERT(gl->IsCurrent()); + + ScopedBindTexture texture(gl, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB); + + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, + LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, + LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + + CGLContextObj cgl = GLContextCGL::Cast(gl)->GetCGLContext(); + MOZ_ASSERT(cgl); + + ioSurf->CGLTexImageIOSurface2D(gl, cgl, 0); +} + +/*static*/ +UniquePtr<SharedSurface_IOSurface> SharedSurface_IOSurface::Create( + const SharedSurfaceDesc& desc) { + const auto& size = desc.size; + const RefPtr<MacIOSurface> ioSurf = + MacIOSurface::CreateIOSurface(size.width, size.height, true); + if (!ioSurf) { + NS_WARNING("Failed to create MacIOSurface."); + return nullptr; + } + + ioSurf->SetColorSpace(desc.colorSpace); + + // - + + auto tex = MakeUnique<Texture>(*desc.gl); + BackTextureWithIOSurf(desc.gl, tex->name, ioSurf); + + const GLenum target = LOCAL_GL_TEXTURE_RECTANGLE; + auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, + target, tex->name); + if (!fb) return nullptr; + + return AsUnique( + new SharedSurface_IOSurface(desc, std::move(fb), std::move(tex), ioSurf)); +} + +SharedSurface_IOSurface::SharedSurface_IOSurface( + const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer> fb, + UniquePtr<Texture> tex, const RefPtr<MacIOSurface>& ioSurf) + : SharedSurface(desc, std::move(fb)), + mTex(std::move(tex)), + mIOSurf(ioSurf) {} + +SharedSurface_IOSurface::~SharedSurface_IOSurface() = default; + +void SharedSurface_IOSurface::ProducerReleaseImpl() { + const auto& gl = mDesc.gl; + if (!gl) return; + gl->MakeCurrent(); + gl->fFlush(); +} + +Maybe<layers::SurfaceDescriptor> +SharedSurface_IOSurface::ToSurfaceDescriptor() { + const bool isOpaque = false; // RGBA + return Some(layers::SurfaceDescriptorMacIOSurface( + mIOSurf->GetIOSurfaceID(), isOpaque, mIOSurf->GetYUVColorSpace())); +} + +} // namespace gl +} // namespace mozilla diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h new file mode 100644 index 0000000000..938173b982 --- /dev/null +++ b/gfx/gl/SharedSurfaceIO.h @@ -0,0 +1,64 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_SURFACEIO_H_ +#define SHARED_SURFACEIO_H_ + +#include "mozilla/RefPtr.h" +#include "SharedSurface.h" + +class MacIOSurface; + +namespace mozilla { +namespace gl { + +class Texture; + +class SharedSurface_IOSurface final : public SharedSurface { + public: + const UniquePtr<Texture> mTex; + const RefPtr<MacIOSurface> mIOSurf; + + static UniquePtr<SharedSurface_IOSurface> Create(const SharedSurfaceDesc&); + + private: + SharedSurface_IOSurface(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>, + UniquePtr<Texture>, const RefPtr<MacIOSurface>&); + + public: + ~SharedSurface_IOSurface(); + + virtual void LockProdImpl() override {} + virtual void UnlockProdImpl() override {} + + virtual void ProducerAcquireImpl() override {} + virtual void ProducerReleaseImpl() override; + + virtual bool NeedsIndirectReads() const override { return true; } + + Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override; +}; + +class SurfaceFactory_IOSurface : public SurfaceFactory { + public: + const gfx::IntSize mMaxDims; + + explicit SurfaceFactory_IOSurface(GLContext& gl); + + virtual UniquePtr<SharedSurface> CreateSharedImpl( + const SharedSurfaceDesc& desc) override { + if (desc.size.width > mMaxDims.width || + desc.size.height > mMaxDims.height) { + return nullptr; + } + return SharedSurface_IOSurface::Create(desc); + } +}; + +} // namespace gl + +} /* namespace mozilla */ + +#endif /* SHARED_SURFACEIO_H_ */ diff --git a/gfx/gl/SurfaceTypes.h b/gfx/gl/SurfaceTypes.h new file mode 100644 index 0000000000..5967b6f7b4 --- /dev/null +++ b/gfx/gl/SurfaceTypes.h @@ -0,0 +1,35 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SURFACE_TYPES_H_ +#define SURFACE_TYPES_H_ + +#include <cstdint> + +namespace mozilla { +namespace layers { +class LayersIPCChannel; +} // namespace layers + +namespace gl { + +enum class SharedSurfaceType : uint8_t { + Basic, + EGLImageShare, + EGLSurfaceANGLE, + DXGLInterop, + DXGLInterop2, + IOSurface, + GLXDrawable, + SharedGLTexture, + AndroidSurfaceTexture, + AndroidHardwareBuffer, + EGLSurfaceDMABUF, +}; + +} // namespace gl +} // namespace mozilla + +#endif // SURFACE_TYPES_H_ diff --git a/gfx/gl/WGLLibrary.h b/gfx/gl/WGLLibrary.h new file mode 100644 index 0000000000..82c764b3db --- /dev/null +++ b/gfx/gl/WGLLibrary.h @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLContextTypes.h" +#include "GLLibraryLoader.h" +#include "mozilla/UniquePtr.h" +#include <windows.h> + +struct PRLibrary; + +namespace mozilla { +namespace gl { +/* +struct ScopedDC +{ + const HDC mDC; + + ScopedDC() = delete; + virtual ~ScopedDC() = 0; +}; + +struct WindowDC final : public ScopedDC +{ + const HWND mWindow; + + WindowDC() = delete; + ~WindowDC(); +}; + +struct PBufferDC final : public ScopedDC +{ + const HWND mWindow; + + PBufferDC() = delete; + ~PBufferDC(); +}; +*/ +class WGLLibrary { + public: + ~WGLLibrary() { Reset(); } + + private: + void Reset(); + + public: + struct { + HGLRC(GLAPIENTRY* fCreateContext)(HDC); + BOOL(GLAPIENTRY* fDeleteContext)(HGLRC); + BOOL(GLAPIENTRY* fMakeCurrent)(HDC, HGLRC); + PROC(GLAPIENTRY* fGetProcAddress)(LPCSTR); + HGLRC(GLAPIENTRY* fGetCurrentContext)(void); + HDC(GLAPIENTRY* fGetCurrentDC)(void); + // BOOL (GLAPIENTRY * fShareLists) (HGLRC oldContext, HGLRC newContext); + HANDLE(GLAPIENTRY* fCreatePbuffer) + (HDC hDC, int iPixelFormat, int iWidth, int iHeight, + const int* piAttribList); + BOOL(GLAPIENTRY* fDestroyPbuffer)(HANDLE hPbuffer); + HDC(GLAPIENTRY* fGetPbufferDC)(HANDLE hPbuffer); + int(GLAPIENTRY* fReleasePbufferDC)(HANDLE hPbuffer, HDC dc); + // BOOL (GLAPIENTRY * fBindTexImage) (HANDLE hPbuffer, int iBuffer); + // BOOL (GLAPIENTRY * fReleaseTexImage) (HANDLE hPbuffer, int iBuffer); + BOOL(GLAPIENTRY* fChoosePixelFormat) + (HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, + UINT nMaxFormats, int* piFormats, UINT* nNumFormats); + // BOOL (GLAPIENTRY * fGetPixelFormatAttribiv) (HDC hdc, + // int iPixelFormat, + // int iLayerPlane, + // UINT nAttributes, + // int* piAttributes, + // int* piValues); + const char*(GLAPIENTRY* fGetExtensionsStringARB)(HDC hdc); + HGLRC(GLAPIENTRY* fCreateContextAttribsARB) + (HDC hdc, HGLRC hShareContext, const int* attribList); + // WGL_NV_DX_interop: + BOOL(GLAPIENTRY* fDXSetResourceShareHandleNV) + (void* dxObject, HANDLE shareHandle); + HANDLE(GLAPIENTRY* fDXOpenDeviceNV)(void* dxDevice); + BOOL(GLAPIENTRY* fDXCloseDeviceNV)(HANDLE hDevice); + HANDLE(GLAPIENTRY* fDXRegisterObjectNV) + (HANDLE hDevice, void* dxObject, GLuint name, GLenum type, GLenum access); + BOOL(GLAPIENTRY* fDXUnregisterObjectNV)(HANDLE hDevice, HANDLE hObject); + BOOL(GLAPIENTRY* fDXObjectAccessNV)(HANDLE hObject, GLenum access); + BOOL(GLAPIENTRY* fDXLockObjectsNV) + (HANDLE hDevice, GLint count, HANDLE* hObjects); + BOOL(GLAPIENTRY* fDXUnlockObjectsNV) + (HANDLE hDevice, GLint count, HANDLE* hObjects); + } mSymbols = {}; + + bool EnsureInitialized(); + // UniquePtr<WindowDC> CreateDummyWindow(); + HGLRC CreateContextWithFallback(HDC dc, bool tryRobustBuffers) const; + + bool HasDXInterop2() const { return bool(mSymbols.fDXOpenDeviceNV); } + bool IsInitialized() const { return mInitialized; } + auto GetOGLLibrary() const { return mOGLLibrary; } + auto RootDc() const { return mRootDc; } + SymbolLoader GetSymbolLoader() const; + + private: + bool mInitialized = false; + PRLibrary* mOGLLibrary; + bool mHasRobustness; + HWND mDummyWindow; + HDC mRootDc; + HGLRC mDummyGlrc; +}; + +// a global WGLLibrary instance +extern WGLLibrary sWGLLib; + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/gl/gtest/TestColorspaces.cpp b/gfx/gl/gtest/TestColorspaces.cpp new file mode 100644 index 0000000000..c437e204af --- /dev/null +++ b/gfx/gl/gtest/TestColorspaces.cpp @@ -0,0 +1,698 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "Colorspaces.h" + +#include <array> +#include <limits> + +namespace mozilla::color { +mat4 YuvFromYcbcr(const YcbcrDesc&); +float TfFromLinear(const PiecewiseGammaDesc&, float linear); +float LinearFromTf(const PiecewiseGammaDesc&, float tf); +mat3 XyzFromLinearRgb(const Chromaticities&); +} // namespace mozilla::color + +using namespace mozilla::color; + +auto Calc8From8(const ColorspaceTransform& ct, const ivec3 in8) { + const auto in = vec3(in8) / vec3(255); + const auto out = ct.DstFromSrc(in); + const auto out8 = ivec3(round(out * vec3(255))); + return out8; +} + +auto Sample8From8(const Lut3& lut, const vec3 in8) { + const auto in = in8 / vec3(255); + const auto out = lut.Sample(in); + const auto out8 = ivec3(round(out * vec3(255))); + return out8; +} + +TEST(Colorspaces, YcbcrDesc_Narrow8) +{ + const auto m = YuvFromYcbcr(YcbcrDesc::Narrow8()); + + const auto Yuv8 = [&](const ivec3 ycbcr8) { + const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1); + const auto yuv = m * ycbcr; + return ivec3(round(yuv * 255)); + }; + + EXPECT_EQ(Yuv8({{16, 128, 128}}), (ivec3{{0, 0, 0}})); + EXPECT_EQ(Yuv8({{17, 128, 128}}), (ivec3{{1, 0, 0}})); + // y = 0.5 => (16 + 235) / 2 = 125.5 + EXPECT_EQ(Yuv8({{125, 128, 128}}), (ivec3{{127, 0, 0}})); + EXPECT_EQ(Yuv8({{126, 128, 128}}), (ivec3{{128, 0, 0}})); + EXPECT_EQ(Yuv8({{234, 128, 128}}), (ivec3{{254, 0, 0}})); + EXPECT_EQ(Yuv8({{235, 128, 128}}), (ivec3{{255, 0, 0}})); + + // Check that we get the naive out-of-bounds behavior we'd expect: + EXPECT_EQ(Yuv8({{15, 128, 128}}), (ivec3{{-1, 0, 0}})); + EXPECT_EQ(Yuv8({{236, 128, 128}}), (ivec3{{256, 0, 0}})); +} + +TEST(Colorspaces, YcbcrDesc_Full8) +{ + const auto m = YuvFromYcbcr(YcbcrDesc::Full8()); + + const auto Yuv8 = [&](const ivec3 ycbcr8) { + const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1); + const auto yuv = m * ycbcr; + return ivec3(round(yuv * 255)); + }; + + EXPECT_EQ(Yuv8({{0, 128, 128}}), (ivec3{{0, 0, 0}})); + EXPECT_EQ(Yuv8({{1, 128, 128}}), (ivec3{{1, 0, 0}})); + EXPECT_EQ(Yuv8({{127, 128, 128}}), (ivec3{{127, 0, 0}})); + EXPECT_EQ(Yuv8({{128, 128, 128}}), (ivec3{{128, 0, 0}})); + EXPECT_EQ(Yuv8({{254, 128, 128}}), (ivec3{{254, 0, 0}})); + EXPECT_EQ(Yuv8({{255, 128, 128}}), (ivec3{{255, 0, 0}})); +} + +TEST(Colorspaces, YcbcrDesc_Float) +{ + const auto m = YuvFromYcbcr(YcbcrDesc::Float()); + + const auto Yuv8 = [&](const vec3 ycbcr8) { + const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1); + const auto yuv = m * ycbcr; + return ivec3(round(yuv * 255)); + }; + + EXPECT_EQ(Yuv8({{0, 0.5 * 255, 0.5 * 255}}), (ivec3{{0, 0, 0}})); + EXPECT_EQ(Yuv8({{1, 0.5 * 255, 0.5 * 255}}), (ivec3{{1, 0, 0}})); + EXPECT_EQ(Yuv8({{127, 0.5 * 255, 0.5 * 255}}), (ivec3{{127, 0, 0}})); + EXPECT_EQ(Yuv8({{128, 0.5 * 255, 0.5 * 255}}), (ivec3{{128, 0, 0}})); + EXPECT_EQ(Yuv8({{254, 0.5 * 255, 0.5 * 255}}), (ivec3{{254, 0, 0}})); + EXPECT_EQ(Yuv8({{255, 0.5 * 255, 0.5 * 255}}), (ivec3{{255, 0, 0}})); +} + +TEST(Colorspaces, ColorspaceTransform_Rec709Narrow) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {}, + }; + const auto ct = ColorspaceTransform::Create(src, dst); + + EXPECT_EQ(Calc8From8(ct, {{16, 128, 128}}), (ivec3{0})); + EXPECT_EQ(Calc8From8(ct, {{17, 128, 128}}), (ivec3{1})); + EXPECT_EQ(Calc8From8(ct, {{126, 128, 128}}), (ivec3{128})); + EXPECT_EQ(Calc8From8(ct, {{234, 128, 128}}), (ivec3{254})); + EXPECT_EQ(Calc8From8(ct, {{235, 128, 128}}), (ivec3{255})); + + // Check that we get the naive out-of-bounds behavior we'd expect: + EXPECT_EQ(Calc8From8(ct, {{15, 128, 128}}), (ivec3{-1})); + EXPECT_EQ(Calc8From8(ct, {{236, 128, 128}}), (ivec3{256})); +} + +TEST(Colorspaces, LutSample_Rec709Float) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Float()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {}, + }; + const auto lut = ColorspaceTransform::Create(src, dst).ToLut3(); + + EXPECT_EQ(Sample8From8(lut, {{0, 0.5 * 255, 0.5 * 255}}), (ivec3{0})); + EXPECT_EQ(Sample8From8(lut, {{1, 0.5 * 255, 0.5 * 255}}), (ivec3{1})); + EXPECT_EQ(Sample8From8(lut, {{127, 0.5 * 255, 0.5 * 255}}), (ivec3{127})); + EXPECT_EQ(Sample8From8(lut, {{128, 0.5 * 255, 0.5 * 255}}), (ivec3{128})); + EXPECT_EQ(Sample8From8(lut, {{254, 0.5 * 255, 0.5 * 255}}), (ivec3{254})); + EXPECT_EQ(Sample8From8(lut, {{255, 0.5 * 255, 0.5 * 255}}), (ivec3{255})); +} + +TEST(Colorspaces, LutSample_Rec709Narrow) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {}, + }; + const auto lut = ColorspaceTransform::Create(src, dst).ToLut3(); + + EXPECT_EQ(Sample8From8(lut, {{16, 128, 128}}), (ivec3{0})); + EXPECT_EQ(Sample8From8(lut, {{17, 128, 128}}), (ivec3{1})); + EXPECT_EQ(Sample8From8(lut, {{int((235 + 16) / 2), 128, 128}}), (ivec3{127})); + EXPECT_EQ(Sample8From8(lut, {{int((235 + 16) / 2) + 1, 128, 128}}), + (ivec3{128})); + EXPECT_EQ(Sample8From8(lut, {{234, 128, 128}}), (ivec3{254})); + EXPECT_EQ(Sample8From8(lut, {{235, 128, 128}}), (ivec3{255})); +} + +TEST(Colorspaces, LutSample_Rec709Full) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {}, + }; + const auto lut = ColorspaceTransform::Create(src, dst).ToLut3(); + + EXPECT_EQ(Sample8From8(lut, {{0, 128, 128}}), (ivec3{0})); + EXPECT_EQ(Sample8From8(lut, {{1, 128, 128}}), (ivec3{1})); + EXPECT_EQ(Sample8From8(lut, {{16, 128, 128}}), (ivec3{16})); + EXPECT_EQ(Sample8From8(lut, {{128, 128, 128}}), (ivec3{128})); + EXPECT_EQ(Sample8From8(lut, {{235, 128, 128}}), (ivec3{235})); + EXPECT_EQ(Sample8From8(lut, {{254, 128, 128}}), (ivec3{254})); + EXPECT_EQ(Sample8From8(lut, {{255, 128, 128}}), (ivec3{255})); +} + +TEST(Colorspaces, PiecewiseGammaDesc_Srgb) +{ + const auto tf = PiecewiseGammaDesc::Srgb(); + + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x00 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x01 / 255.0) * 255)), 0x0d); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x37 / 255.0) * 255)), 0x80); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x80 / 255.0) * 255)), 0xbc); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfd / 255.0) * 255)), 0xfe); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfe / 255.0) * 255)), 0xff); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xff / 255.0) * 255)), 0xff); + + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x00 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x01 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x06 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x07 / 255.0) * 255)), 0x01); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x0d / 255.0) * 255)), 0x01); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x80 / 255.0) * 255)), 0x37); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xbc / 255.0) * 255)), 0x80); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xfe / 255.0) * 255)), 0xfd); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xff / 255.0) * 255)), 0xff); +} + +TEST(Colorspaces, PiecewiseGammaDesc_Rec709) +{ + const auto tf = PiecewiseGammaDesc::Rec709(); + + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x00 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x01 / 255.0) * 255)), 0x05); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x43 / 255.0) * 255)), 0x80); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x80 / 255.0) * 255)), 0xb4); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfd / 255.0) * 255)), 0xfe); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfe / 255.0) * 255)), 0xff); + EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xff / 255.0) * 255)), 0xff); + + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x00 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x01 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x02 / 255.0) * 255)), 0x00); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x03 / 255.0) * 255)), 0x01); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x05 / 255.0) * 255)), 0x01); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x80 / 255.0) * 255)), 0x43); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xb4 / 255.0) * 255)), 0x80); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xfe / 255.0) * 255)), 0xfd); + EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xff / 255.0) * 255)), 0xff); +} + +TEST(Colorspaces, ColorspaceTransform_PiecewiseGammaDesc) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Srgb(), + {}, + {}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Srgb(), + PiecewiseGammaDesc::Srgb(), + {}, + }; + const auto toGamma = ColorspaceTransform::Create(src, dst); + const auto toLinear = ColorspaceTransform::Create(dst, src); + + EXPECT_EQ(Calc8From8(toGamma, ivec3{0x00}), (ivec3{0x00})); + EXPECT_EQ(Calc8From8(toGamma, ivec3{0x01}), (ivec3{0x0d})); + EXPECT_EQ(Calc8From8(toGamma, ivec3{0x37}), (ivec3{0x80})); + EXPECT_EQ(Calc8From8(toGamma, ivec3{0x80}), (ivec3{0xbc})); + EXPECT_EQ(Calc8From8(toGamma, ivec3{0xfd}), (ivec3{0xfe})); + EXPECT_EQ(Calc8From8(toGamma, ivec3{0xff}), (ivec3{0xff})); + + EXPECT_EQ(Calc8From8(toLinear, ivec3{0x00}), (ivec3{0x00})); + EXPECT_EQ(Calc8From8(toLinear, ivec3{0x0d}), (ivec3{0x01})); + EXPECT_EQ(Calc8From8(toLinear, ivec3{0x80}), (ivec3{0x37})); + EXPECT_EQ(Calc8From8(toLinear, ivec3{0xbc}), (ivec3{0x80})); + EXPECT_EQ(Calc8From8(toLinear, ivec3{0xfe}), (ivec3{0xfd})); + EXPECT_EQ(Calc8From8(toLinear, ivec3{0xff}), (ivec3{0xff})); +} + +// - +// Actual end-to-end tests + +TEST(Colorspaces, SrgbFromRec709) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Srgb(), + PiecewiseGammaDesc::Srgb(), + {}, + }; + const auto ct = ColorspaceTransform::Create(src, dst); + + EXPECT_EQ(Calc8From8(ct, ivec3{{16, 128, 128}}), (ivec3{0})); + EXPECT_EQ(Calc8From8(ct, ivec3{{17, 128, 128}}), (ivec3{3})); + EXPECT_EQ(Calc8From8(ct, ivec3{{115, 128, 128}}), (ivec3{128})); + EXPECT_EQ(Calc8From8(ct, ivec3{{126, 128, 128}}), (ivec3{140})); + EXPECT_EQ(Calc8From8(ct, ivec3{{234, 128, 128}}), (ivec3{254})); + EXPECT_EQ(Calc8From8(ct, ivec3{{235, 128, 128}}), (ivec3{255})); +} + +TEST(Colorspaces, SrgbFromDisplayP3) +{ + const auto p3C = ColorspaceDesc{ + Chromaticities::DisplayP3(), + PiecewiseGammaDesc::DisplayP3(), + }; + const auto srgbC = ColorspaceDesc{ + Chromaticities::Srgb(), + PiecewiseGammaDesc::Srgb(), + }; + const auto srgbLinearC = ColorspaceDesc{ + Chromaticities::Srgb(), + {}, + }; + const auto srgbFromP3 = ColorspaceTransform::Create(p3C, srgbC); + const auto srgbLinearFromP3 = ColorspaceTransform::Create(p3C, srgbLinearC); + + // E.g. + // https://colorjs.io/apps/convert/?color=color(display-p3%200.4%200.8%200.4)&precision=4 + auto srgb = srgbFromP3.DstFromSrc(vec3{{0.4, 0.8, 0.4}}); + EXPECT_NEAR(srgb.x(), 0.179, 0.001); + EXPECT_NEAR(srgb.y(), 0.812, 0.001); + EXPECT_NEAR(srgb.z(), 0.342, 0.001); + auto srgbLinear = srgbLinearFromP3.DstFromSrc(vec3{{0.4, 0.8, 0.4}}); + EXPECT_NEAR(srgbLinear.x(), 0.027, 0.001); + EXPECT_NEAR(srgbLinear.y(), 0.624, 0.001); + EXPECT_NEAR(srgbLinear.z(), 0.096, 0.001); +} + +// - + +template <class Fn, class Tuple, size_t... I> +constexpr auto map_tups_seq(const Tuple& a, const Tuple& b, const Fn& fn, + std::index_sequence<I...>) { + return std::tuple{fn(std::get<I>(a), std::get<I>(b))...}; +} +template <class Fn, class Tuple> +constexpr auto map_tups(const Tuple& a, const Tuple& b, const Fn& fn) { + return map_tups_seq(a, b, fn, + std::make_index_sequence<std::tuple_size_v<Tuple>>{}); +} + +template <class Fn, class Tuple> +constexpr auto cmp_tups_all(const Tuple& a, const Tuple& b, const Fn& fn) { + bool all = true; + map_tups(a, b, [&](const auto& a, const auto& b) { return all &= fn(a, b); }); + return all; +} + +struct Stats { + double mean = 0; + double variance = 0; + double min = std::numeric_limits<double>::infinity(); + double max = -std::numeric_limits<double>::infinity(); + + template <class T> + static Stats For(const T& iterable) { + auto ret = Stats{}; + for (const auto& cur : iterable) { + ret.mean += cur; + ret.min = std::min(ret.min, cur); + ret.max = std::max(ret.max, cur); + } + ret.mean /= iterable.size(); + // Gather mean first before we can calc variance. + for (const auto& cur : iterable) { + ret.variance += pow(cur - ret.mean, 2); + } + ret.variance /= iterable.size(); + return ret; + } + + template <class T, class U> + static Stats Diff(const T& a, const U& b) { + MOZ_ASSERT(a.size() == b.size()); + std::vector<double> diff; + diff.reserve(a.size()); + for (size_t i = 0; i < diff.capacity(); i++) { + diff.push_back(a[i] - b[i]); + } + return Stats::For(diff); + } + + double standardDeviation() const { return sqrt(variance); } + + friend std::ostream& operator<<(std::ostream& s, const Stats& a) { + return s << "Stats" + << "{ mean:" << a.mean << ", stddev:" << a.standardDeviation() + << ", min:" << a.min << ", max:" << a.max << " }"; + } + + struct Error { + double absmean = std::numeric_limits<double>::infinity(); + double stddev = std::numeric_limits<double>::infinity(); + double absmax = std::numeric_limits<double>::infinity(); + + constexpr auto Fields() const { return std::tie(absmean, stddev, absmax); } + + template <class Fn> + friend constexpr bool cmp_all(const Error& a, const Error& b, + const Fn& fn) { + return cmp_tups_all(a.Fields(), b.Fields(), fn); + } + friend constexpr bool operator<(const Error& a, const Error& b) { + return cmp_all(a, b, [](const auto& a, const auto& b) { return a < b; }); + } + friend constexpr bool operator<=(const Error& a, const Error& b) { + return cmp_all(a, b, [](const auto& a, const auto& b) { return a <= b; }); + } + + friend std::ostream& operator<<(std::ostream& s, const Error& a) { + return s << "Stats::Error" + << "{ absmean:" << a.absmean << ", stddev:" << a.stddev + << ", absmax:" << a.absmax << " }"; + } + }; + + operator Error() const { + return {abs(mean), standardDeviation(), std::max(abs(min), abs(max))}; + } +}; +static_assert(Stats::Error{0, 0, 0} < Stats::Error{1, 1, 1}); +static_assert(!(Stats::Error{0, 1, 0} < Stats::Error{1, 1, 1})); +static_assert(Stats::Error{0, 1, 0} <= Stats::Error{1, 1, 1}); +static_assert(!(Stats::Error{0, 2, 0} <= Stats::Error{1, 1, 1})); + +// - + +static Stats StatsForLutError(const ColorspaceTransform& ct, + const ivec3 srcQuants, const ivec3 dstQuants) { + const auto lut = ct.ToLut3(); + + const auto dstScale = vec3(dstQuants - 1); + + std::vector<double> quantErrors; + quantErrors.reserve(srcQuants.x() * srcQuants.y() * srcQuants.z()); + ForEachSampleWithin(srcQuants, [&](const vec3& src) { + const auto sampled = lut.Sample(src); + const auto actual = ct.DstFromSrc(src); + const auto isampled = ivec3(round(sampled * dstScale)); + const auto iactual = ivec3(round(actual * dstScale)); + const auto ierr = abs(isampled - iactual); + const auto quantError = dot(ierr, ivec3{1}); + quantErrors.push_back(quantError); + if (quantErrors.size() % 100000 == 0) { + printf("%zu of %zu\n", quantErrors.size(), quantErrors.capacity()); + } + }); + + const auto quantErrStats = Stats::For(quantErrors); + return quantErrStats; +} + +TEST(Colorspaces, LutError_Rec709Full_Rec709Rgb) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {}, + }; + const auto ct = ColorspaceTransform::Create(src, dst); + const auto stats = StatsForLutError(ct, ivec3{64}, ivec3{256}); + EXPECT_NEAR(stats.mean, 0.000, 0.001); + EXPECT_NEAR(stats.standardDeviation(), 0.008, 0.001); + EXPECT_NEAR(stats.min, 0, 0.001); + EXPECT_NEAR(stats.max, 1, 0.001); +} + +TEST(Colorspaces, LutError_Rec709Full_Srgb) +{ + const auto src = ColorspaceDesc{ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + {{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}}, + }; + const auto dst = ColorspaceDesc{ + Chromaticities::Srgb(), + PiecewiseGammaDesc::Srgb(), + {}, + }; + const auto ct = ColorspaceTransform::Create(src, dst); + const auto stats = StatsForLutError(ct, ivec3{64}, ivec3{256}); + EXPECT_NEAR(stats.mean, 0.530, 0.001); + EXPECT_NEAR(stats.standardDeviation(), 1.674, 0.001); + EXPECT_NEAR(stats.min, 0, 0.001); + EXPECT_NEAR(stats.max, 17, 0.001); +} + +// - +// https://www.reedbeta.com/blog/python-like-enumerate-in-cpp17/ + +template <typename T, typename TIter = decltype(std::begin(std::declval<T>())), + typename = decltype(std::end(std::declval<T>()))> +constexpr auto enumerate(T&& iterable) { + struct iterator { + size_t i; + TIter iter; + bool operator!=(const iterator& other) const { return iter != other.iter; } + void operator++() { + ++i; + ++iter; + } + auto operator*() const { return std::tie(i, *iter); } + }; + struct iterable_wrapper { + T iterable; + auto begin() { return iterator{0, std::begin(iterable)}; } + auto end() { return iterator{0, std::end(iterable)}; } + }; + return iterable_wrapper{std::forward<T>(iterable)}; +} + +inline auto MakeLinear(const float from, const float to, const int n) { + std::vector<float> ret; + ret.resize(n); + for (auto [i, val] : enumerate(ret)) { + const auto t = i / float(ret.size() - 1); + val = from + (to - from) * t; + } + return ret; +}; + +inline auto MakeGamma(const float exp, const int n) { + std::vector<float> ret; + ret.resize(n); + for (auto [i, val] : enumerate(ret)) { + const auto t = i / float(ret.size() - 1); + val = powf(t, exp); + } + return ret; +}; + +// - + +TEST(Colorspaces, GuessGamma) +{ + EXPECT_NEAR(GuessGamma(MakeGamma(1, 11)), 1.0, 0); + EXPECT_NEAR(GuessGamma(MakeGamma(2.2, 11)), 2.2, 4.8e-8); + EXPECT_NEAR(GuessGamma(MakeGamma(1 / 2.2, 11)), 1 / 2.2, 1.7e-7); +} + +// - + +template <class T, class U> +float StdDev(const T& test, const U& ref) { + float sum = 0; + for (size_t i = 0; i < test.size(); i++) { + const auto diff = test[i] - ref[i]; + sum += diff * diff; + } + const auto variance = sum / test.size(); + return sqrt(variance); +} + +template <class T> +inline void AutoLinearFill(T& vals) { + LinearFill(vals, { + {0, 0}, + {vals.size() - 1.0f, 1}, + }); +} + +template <class T, class... More> +auto MakeArray(const T& a0, const More&... args) { + return std::array<T, 1 + sizeof...(More)>{a0, static_cast<float>(args)...}; +} + +TEST(Colorspaces, LinearFill) +{ + EXPECT_NEAR(StdDev(MakeLinear(0, 1, 3), MakeArray<float>(0, 0.5, 1)), 0, + 0.001); + + auto vals = std::vector<float>(3); + LinearFill(vals, { + {0, 0}, + {vals.size() - 1.0f, 1}, + }); + EXPECT_NEAR(StdDev(vals, MakeArray<float>(0, 0.5, 1)), 0, 0.001); + + LinearFill(vals, { + {0, 1}, + {vals.size() - 1.0f, 0}, + }); + EXPECT_NEAR(StdDev(vals, MakeArray<float>(1, 0.5, 0)), 0, 0.001); +} + +TEST(Colorspaces, DequantizeMonotonic) +{ + auto orig = std::vector<float>{0, 0, 0, 1, 1, 2}; + auto vals = orig; + EXPECT_TRUE(IsMonotonic(vals)); + EXPECT_TRUE(!IsMonotonic(vals, std::less<float>{})); + DequantizeMonotonic(vals); + EXPECT_TRUE(IsMonotonic(vals, std::less<float>{})); + EXPECT_LT(StdDev(vals, orig), + StdDev(MakeLinear(orig.front(), orig.back(), vals.size()), orig)); +} + +TEST(Colorspaces, InvertLut) +{ + const auto linear = MakeLinear(0, 1, 256); + auto linearFromSrgb = linear; + for (auto& val : linearFromSrgb) { + val = powf(val, 2.2); + } + auto srgbFromLinearExpected = linear; + for (auto& val : srgbFromLinearExpected) { + val = powf(val, 1 / 2.2); + } + + auto srgbFromLinearViaInvert = linearFromSrgb; + InvertLut(linearFromSrgb, &srgbFromLinearViaInvert); + // I just want to appreciate that InvertLut is a non-analytical approximation, + // and yet it's extraordinarily close to the analytical inverse. + EXPECT_LE(Stats::Diff(srgbFromLinearViaInvert, srgbFromLinearExpected), + (Stats::Error{3e-6, 3e-6, 3e-5})); + + const auto srcSrgb = MakeLinear(0, 1, 256); + auto roundtripSrgb = srcSrgb; + for (auto& srgb : roundtripSrgb) { + const auto linear = SampleOutByIn(linearFromSrgb, srgb); + const auto srgb2 = SampleOutByIn(srgbFromLinearViaInvert, linear); + // printf("[%f] %f -> %f -> %f\n", srgb2-srgb, srgb, linear, srgb2); + srgb = srgb2; + } + EXPECT_LE(Stats::Diff(roundtripSrgb, srcSrgb), + (Stats::Error{0.0013, 0.0046, 0.023})); +} + +TEST(Colorspaces, XyzFromLinearRgb) +{ + const auto xyzd65FromLinearRgb = XyzFromLinearRgb(Chromaticities::Srgb()); + + // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + const auto XYZD65_FROM_LINEAR_RGB = mat3({ + vec3{{0.4124564, 0.3575761, 0.1804375}}, + vec3{{0.2126729, 0.7151522, 0.0721750}}, + vec3{{0.0193339, 0.1191920, 0.9503041}}, + }); + EXPECT_NEAR(sqrt(dotDifference(xyzd65FromLinearRgb, XYZD65_FROM_LINEAR_RGB)), + 0, 0.001); +} + +TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) +{ + const auto srgb = ColorProfileDesc::From({ + Chromaticities::Srgb(), + PiecewiseGammaDesc::Srgb(), + }); + const auto rec709 = ColorProfileDesc::From({ + Chromaticities::Rec709(), + PiecewiseGammaDesc::Rec709(), + }); + + { + const auto conv = ColorProfileConversionDesc::From({ + .src = srgb, + .dst = srgb, + }); + auto src = vec3(16.0); + auto dst = conv.Apply(src / 255) * 255; + + const auto tfa = PiecewiseGammaDesc::Srgb(); + const auto tfb = PiecewiseGammaDesc::Srgb(); + const auto expected = + TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; + + printf("%f %f %f\n", src.x(), src.y(), src.z()); + printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); + EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{0.42})); + } + { + const auto conv = ColorProfileConversionDesc::From({ + .src = rec709, + .dst = rec709, + }); + auto src = vec3(16.0); + auto dst = conv.Apply(src / 255) * 255; + + const auto tfa = PiecewiseGammaDesc::Rec709(); + const auto tfb = PiecewiseGammaDesc::Rec709(); + const auto expected = + TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; + + printf("%f %f %f\n", src.x(), src.y(), src.z()); + printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); + EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{1e-6})); + } + { + const auto conv = ColorProfileConversionDesc::From({ + .src = rec709, + .dst = srgb, + }); + auto src = vec3(16.0); + auto dst = conv.Apply(src / 255) * 255; + + const auto tfa = PiecewiseGammaDesc::Rec709(); + const auto tfb = PiecewiseGammaDesc::Srgb(); + const auto expected = + TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; + printf("expected: %f\n", expected); + printf("%f %f %f\n", src.x(), src.y(), src.z()); + printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); + EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{0.12})); + } +} diff --git a/gfx/gl/gtest/moz.build b/gfx/gl/gtest/moz.build new file mode 100644 index 0000000000..5b57e3ded1 --- /dev/null +++ b/gfx/gl/gtest/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +LOCAL_INCLUDES += [ + "/gfx/gl", +] + +UNIFIED_SOURCES += [ + "TestColorspaces.cpp", +] + +FINAL_LIBRARY = "xul-gtest" diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build new file mode 100644 index 0000000000..f45e85b8f4 --- /dev/null +++ b/gfx/gl/moz.build @@ -0,0 +1,163 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +gl_provider = "Null" + +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": + gl_provider = "WGL" +elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": + gl_provider = "CGL" +elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "uikit": + gl_provider = "EAGL" +elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": + gl_provider = "Linux" +elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": + gl_provider = "EGL" + +if CONFIG["MOZ_GL_PROVIDER"]: + gl_provider = CONFIG["MOZ_GL_PROVIDER"] + +EXPORTS += [ + "AndroidSurfaceTexture.h", + "AutoMappable.h", + "Colorspaces.h", + "ForceDiscreteGPUHelperCGL.h", + "GfxTexturesReporter.h", + "GLBlitHelper.h", + "GLConsts.h", + "GLContext.h", + "GLContextEGL.h", + "GLContextProvider.h", + "GLContextProviderImpl.h", + "GLContextSymbols.h", + "GLContextTypes.h", + "GLDefs.h", + "GLLibraryEGL.h", + "GLLibraryLoader.h", + "GLReadTexImageHelper.h", + "GLScreenBuffer.h", + "GLTextureImage.h", + "GLTypes.h", + "GLUploadHelpers.h", + "HeapCopyOfStackArray.h", + "MozFramebuffer.h", + "ScopedGLHelpers.h", + "SharedSurface.h", + "SharedSurfaceEGL.h", + "SharedSurfaceGL.h", + "SurfaceTypes.h", +] + +# Win32 is a special snowflake, for ANGLE +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": + EXPORTS += [ + "GLContextWGL.h", + "SharedSurfaceANGLE.h", # Needs <windows.h> for `HANDLE`. + "SharedSurfaceD3D11Interop.h", + "WGLLibrary.h", + ] + UNIFIED_SOURCES += [ + "GLBlitHelperD3D.cpp", + "GLContextProviderWGL.cpp", + "SharedSurfaceANGLE.cpp", + "SharedSurfaceD3D11Interop.cpp", + ] + +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": + EXPORTS += [ + "AndroidNativeWindow.h", + "SharedSurfaceAndroidHardwareBuffer.h", + ] + UNIFIED_SOURCES += [ + "SharedSurfaceAndroidHardwareBuffer.cpp", + ] + +if gl_provider == "CGL": + # These files include Mac headers that are unfriendly to unified builds + SOURCES += [ + "GLContextProviderCGL.mm", + ] + EXPORTS += [ + "GLContextCGL.h", + "SharedSurfaceIO.h", + ] + # SharedSurfaceIO.cpp includes MacIOSurface.h which include Mac headers + # which define Size and Point types in root namespace with often conflict with + # our own types. While I haven't actually hit this issue in the present case, + # it's been an issue in gfx/layers so let's not risk it. + SOURCES += [ + "SharedSurfaceIO.cpp", + ] + OS_LIBS += [ + "-framework IOSurface", + ] + +elif gl_provider == "EAGL": + # These files include ObjC headers that are unfriendly to unified builds + SOURCES += [ + "GLContextProviderEAGL.mm", + ] + EXPORTS += [ + "GLContextEAGL.h", + ] + +elif gl_provider == "Linux": + # GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES + # as it includes X11 headers which cause conflicts. + SOURCES += [ + "GLContextProviderLinux.cpp", + "SharedSurfaceDMABUF.cpp", + ] + EXPORTS += ["GLContextGLX.h", "GLXLibrary.h"] + if CONFIG["MOZ_X11"]: + SOURCES += ["GLContextProviderGLX.cpp"] + +UNIFIED_SOURCES += [ + "AndroidSurfaceTexture.cpp", + "Colorspaces.cpp", + "GfxTexturesReporter.cpp", + "GLBlitHelper.cpp", + "GLContext.cpp", + "GLContextFeatures.cpp", + "GLContextProviderEGL.cpp", + "GLDebugUtils.cpp", + "GLLibraryEGL.cpp", + "GLLibraryLoader.cpp", + "GLReadTexImageHelper.cpp", + "GLTextureImage.cpp", + "GLUploadHelpers.cpp", + "MozFramebuffer.cpp", + "ScopedGLHelpers.cpp", + "SharedSurface.cpp", + "SharedSurfaceEGL.cpp", + "SharedSurfaceGL.cpp", +] +SOURCES += [ + "GLScreenBuffer.cpp", +] + +TEST_DIRS += [ + "gtest", +] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" + +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": + CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] + CFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] + +CXXFLAGS += ["-Werror=switch"] + +if CONFIG["MOZ_WAYLAND"]: + CXXFLAGS += CONFIG["MOZ_WAYLAND_CFLAGS"] + CFLAGS += CONFIG["MOZ_WAYLAND_CFLAGS"] + +LOCAL_INCLUDES += CONFIG["SKIA_INCLUDES"] +LOCAL_INCLUDES += [ + "/gfx/cairo/cairo/src", +] |