Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/gl/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 119 kB image not shown  

Quelle  GLContext.h   Sprache: C

 
/* -*- 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"

template <class ElemT, class... More>
constexpr inline std::array<ElemT, 1 + sizeof...(More)> make_array(
    ElemT&& arg1, More&&... more) {
  return {std::forward<ElemT>(arg1), std::forward<ElemT>(more)...};
}

#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_clamp,
  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 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 = falseconst;

  /**
   * 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_clamp,
    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_depth_clamp,
    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,
    EXT_semaphore,
    EXT_semaphore_fd,
    EXT_memory_object,
    EXT_memory_object_fd,
    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 charconst 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 charconst 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 InvalidateFramebuffer(GLenum target) {
    constexpr auto ATTACHMENTS = make_array(GLenum{LOCAL_GL_COLOR_ATTACHMENT0},
                                            LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
    fInvalidateFramebuffer(target, ATTACHMENTS.size(), ATTACHMENTS.data());
  }

  void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments,
                              const GLenum* attachments) {
    if (!mSymbols.fInvalidateFramebuffer) return;
    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) {
    if (!mSymbols.fInvalidateSubFramebuffer) return;
    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 BindSamplerTexture(GLuint texUnitId, GLuint samplerHandle,
                          GLenum texTarget, GLuint texHandle) {
    fBindSampler(texUnitId, samplerHandle);
    fActiveTexture(LOCAL_GL_TEXTURE0 + texUnitId);
    fBindTexture(texTarget, texHandle);
  }

  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;

  // If e.g. GL_DRAW_FRAMEBUFFER isn't supported, will bind GL_FRAMEBUFFER.
  void fBindFramebuffer(GLenum target, const GLuint fb) const {
    if (!IsSupported(gl::GLFeature::framebuffer_blit)) {
      target = LOCAL_GL_FRAMEBUFFER;
    }
    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));
  }

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=95 G=96

¤ Dauer der Verarbeitung: 0.29 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.