/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim: set ts=8 sts=4 et sw=4 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 <ctype.h> #include <stdint.h> #include <stdio.h> #include <map> #include <queue> #include <stack> #ifdef DEBUG #include <string.h> #endif #ifdef GetClassName #undef GetClassName #endif // Define MOZ_GL_DEBUG unconditionally to enable GL debugging in opt // builds. #ifdef DEBUG #define MOZ_GL_DEBUG 1 #endif #include "../../mfbt/RefPtr.h" #include "../../mfbt/UniquePtr.h" #include "GLDefs.h" #include "GLLibraryLoader.h" #include "nsISupportsImpl.h" #include "plstr.h" #include "GLContextTypes.h" #include "SurfaceTypes.h" #include "GLContextSymbols.h" #include "base/platform_thread.h" // for PlatformThreadId #include "mozilla/GenericRefCounted.h" #include "mozilla/WeakPtr.h" #include "gfx2DGlue.h" #include "GeckoProfiler.h" class nsIWidget; namespace android { class GraphicBuffer; } // namespace android namespace mozilla { namespace gfx { class DataSourceSurface; class SourceSurface; } // namespace gfx namespace gl { class GLBlitHelper; class GLBlitTextureImageHelper; class GLContext; class GLLibraryEGL; class GLReadTexImageHelper; class GLScreenBuffer; class SharedSurface; class TextureGarbageBin; struct SurfaceCaps; } // namespace gl namespace layers { class ColorTextureLayerProgram; } // namespace layers } // namespace mozilla namespace mozilla { namespace gl { enum class GLFeature { bind_buffer_offset, blend_minmax, clear_buffers, copy_buffer, depth_texture, draw_buffers, draw_instanced, draw_range_elements, 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, get_string_indexed, gpu_shader4, gpu_shader5, instanced_arrays, instanced_non_arrays, internalformat_query, invalidate_framebuffer, map_buffer_range, occlusion_query, occlusion_query_boolean, occlusion_query2, packed_depth_stencil, prim_restart, prim_restart_fixed, query_counter, query_objects, query_time_elapsed, read_buffer, renderbuffer_color_float, renderbuffer_color_half_float, robustness, sRGB_framebuffer, sRGB_texture, sampler_objects, seamless_cube_map_opt_in, shader_texture_lod, split_framebuffer, standard_derivatives, sync, texture_3D, texture_3D_compressed, texture_3D_copy, texture_float, texture_float_linear, texture_half_float, texture_half_float_linear, texture_non_power_of_two, 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, OpenGL, // only for IsAtLeast's <profile> parameter OpenGLCore, OpenGLCompatibility, OpenGLES }; enum class GLVendor { Intel, NVIDIA, ATI, Qualcomm, Imagination, Nouveau, Vivante, VMware, ARM, Other }; enum class GLRenderer { Adreno200, Adreno205, AdrenoTM200, AdrenoTM205, AdrenoTM305, AdrenoTM320, AdrenoTM330, AdrenoTM420, Mali400MP, Mali450MP, SGX530, SGX540, SGX544MP, Tegra, AndroidEmulator, GalliumLlvmpipe, IntelHD3000, MicrosoftBasicRenderDriver, Other }; class GLContext : public GLLibraryLoader , public GenericAtomicRefCounted , public SupportsWeakPtr<GLContext> { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GLContext) // ----------------------------------------------------------------------------- // basic enums public: // ----------------------------------------------------------------------------- // 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; } /** * Return true if the context is a true OpenGL ES context or an ANGLE context */ inline bool IsGLES() const { MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); return mProfile == ContextProfile::OpenGLES; } static const char* GetProfileName(ContextProfile profile) { switch (profile) { case ContextProfile::OpenGL: return "OpenGL"; case ContextProfile::OpenGLCore: return "OpenGL Core"; case ContextProfile::OpenGLCompatibility: return "OpenGL Compatibility"; case ContextProfile::OpenGLES: return "OpenGL ES"; default: break; } MOZ_ASSERT(profile != ContextProfile::Unknown, "unknown context profile"); return "OpenGL unknown profile"; } /** * Return true if we are running on a OpenGL core profile context */ const char* ProfileString() const { return GetProfileName(mProfile); } /** * Return true if the context is compatible with given parameters * * IsAtLeast(ContextProfile::OpenGL, N) is exactly same as * IsAtLeast(ContextProfile::OpenGLCore, N) || IsAtLeast(ContextProfile::OpenGLCompatibility, N) */ 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; } if (profile == ContextProfile::OpenGL) { return mProfile == ContextProfile::OpenGLCore || mProfile == ContextProfile::OpenGLCompatibility; } 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; } const char* VersionString() const { return mVersionString.get(); } inline uint32_t ShadingLanguageVersion() const { return mShadingLanguageVersion; } GLVendor Vendor() const { return mVendor; } GLRenderer Renderer() const { return mRenderer; } bool IsContextLost() const { return mContextLost; } /** * If this context is double-buffered, returns TRUE. */ virtual bool IsDoubleBuffered() const { return false; } virtual GLContextType GetContextType() const = 0; virtual bool IsCurrent() = 0; /** * Get the default framebuffer for this context. */ virtual GLuint GetDefaultFramebuffer() { return 0; } protected: bool mIsOffscreen; bool mContextLost; bool mIsDestroyed = false; /** * 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; nsCString mVersionString; ContextProfile mProfile; uint32_t mShadingLanguageVersion; GLVendor mVendor; GLRenderer mRenderer; void SetProfileVersion(ContextProfile profile, uint32_t version) { MOZ_ASSERT(!mSymbols.fBindFramebuffer, "SetProfileVersion can only be called before initialization!"); MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion"); MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion"); mVersion = version; mProfile = profile; } // ----------------------------------------------------------------------------- // 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). */ public: /** * 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_texture_compression_dxt3, ANGLE_texture_compression_dxt5, ANGLE_timer_query, APPLE_client_storage, APPLE_framebuffer_multisample, APPLE_sync, APPLE_texture_range, APPLE_vertex_array_object, ARB_ES2_compatibility, ARB_ES3_compatibility, ARB_color_buffer_float, ARB_copy_buffer, ARB_depth_texture, ARB_draw_buffers, ARB_draw_instanced, ARB_framebuffer_object, ARB_framebuffer_sRGB, ARB_geometry_shader4, ARB_gpu_shader5, 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_robustness, ARB_sampler_objects, ARB_seamless_cube_map, ARB_shader_texture_lod, ARB_sync, ARB_texture_compression, 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, 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_draw_range_elements, EXT_frag_depth, EXT_framebuffer_blit, EXT_framebuffer_multisample, EXT_framebuffer_object, EXT_framebuffer_sRGB, EXT_gpu_shader4, EXT_gpu_shader5, EXT_multisampled_render_to_texture, EXT_occlusion_query_boolean, EXT_packed_depth_stencil, EXT_read_format_bgra, EXT_robustness, EXT_sRGB, EXT_sRGB_write_control, EXT_shader_texture_lod, EXT_texture3D, EXT_texture_compression_dxt1, EXT_texture_compression_s3tc, EXT_texture_filter_anisotropic, EXT_texture_format_BGRA8888, 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, NV_draw_instanced, NV_fence, NV_framebuffer_blit, NV_geometry_program4, NV_gpu_shader5, 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_element_index_uint, 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, 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); // ----------------------------------------------------------------------------- // Robustness handling private: /** * The derived class is expected to provide information on whether or not it * supports robustness. */ virtual bool SupportsRobustness() const = 0; public: // ----------------------------------------------------------------------------- // Error handling static const char* GLErrorToString(GLenum aError) { switch (aError) { 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"; default: return ""; } } private: GLenum mTopError; GLenum RawGetError() { return mSymbols.fGetError(); } GLenum RawGetErrorAndClear() { GLenum err = RawGetError(); if (err) while (RawGetError()) {} return err; } public: GLenum FlushErrors() { GLenum err = RawGetErrorAndClear(); if (!mTopError) mTopError = err; return err; } // 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. GLenum fGetError() { FlushErrors(); GLenum err = mTopError; mTopError = LOCAL_GL_NO_ERROR; return err; } //////////////////////////////////// // Use this safer option. class LocalErrorScope; private: std::stack<const LocalErrorScope*> mLocalErrorScopeStack; public: class LocalErrorScope { GLContext& mGL; GLenum mOldTop; bool mHasBeenChecked; public: explicit LocalErrorScope(GLContext& gl) : mGL(gl) , mHasBeenChecked(false) { mGL.mLocalErrorScopeStack.push(this); mGL.FlushErrors(); mOldTop = mGL.mTopError; mGL.mTopError = LOCAL_GL_NO_ERROR; } GLenum GetError() { MOZ_ASSERT(!mHasBeenChecked); mHasBeenChecked = true; const GLenum ret = mGL.fGetError(); while (mGL.fGetError()) {} return ret; } ~LocalErrorScope() { MOZ_ASSERT(mHasBeenChecked); MOZ_ASSERT(mGL.fGetError() == LOCAL_GL_NO_ERROR); 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; } private: static void GLAPIENTRY StaticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam); void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); // ----------------------------------------------------------------------------- // MOZ_GL_DEBUG implementation private: #undef BEFORE_GL_CALL #undef AFTER_GL_CALL #ifdef MOZ_GL_DEBUG #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 void BeforeGLCall(const char* funcName) { MOZ_ASSERT(IsCurrent()); if (mDebugFlags) { FlushErrors(); if (mDebugFlags & DebugFlagTrace) { printf_stderr("[gl:%p] > %s\n", this, funcName); } GLContext* tlsContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS); if (this != tlsContext) { printf_stderr("Fatal: %s called on non-current context %p. The" " current context for this thread is %p.\n", funcName, this, tlsContext); MOZ_CRASH("GFX: GLContext is not current."); } } } void AfterGLCall(const char* funcName) { if (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(); GLenum err = FlushErrors(); if (mDebugFlags & DebugFlagTrace) { printf_stderr("[gl:%p] < %s [%s (0x%04x)]\n", this, funcName, GLErrorToString(err), err); } if (err != LOCAL_GL_NO_ERROR && !mLocalErrorScopeStack.size()) { printf_stderr("[gl:%p] %s: Generated unexpected %s error." " (0x%04x)\n", this, funcName, GLErrorToString(err), err); if (mDebugFlags & DebugFlagAbortOnError) { MOZ_CRASH("Unexpected error with MOZ_GL_DEBUG_ABORT_ON_ERROR. (Run" " with MOZ_GL_DEBUG_ABORT_ON_ERROR=0 to disable)"); } } } } GLContext* TrackingContext() { GLContext* tip = this; while (tip->mSharedContext) tip = tip->mSharedContext; return tip; } static void AssertNotPassingStackBufferToTheGL(const void* ptr); #ifdef MOZ_WIDGET_ANDROID // Record the name of the GL call for better hang stacks on Android. #define BEFORE_GL_CALL \ PROFILER_LABEL_FUNC( \ js::ProfileEntry::Category::GRAPHICS);\ BeforeGLCall(MOZ_FUNCTION_NAME) #else #define BEFORE_GL_CALL \ do { \ BeforeGLCall(MOZ_FUNCTION_NAME); \ } while (0) #endif #define AFTER_GL_CALL \ do { \ AfterGLCall(MOZ_FUNCTION_NAME); \ } while (0) #define TRACKING_CONTEXT(a) \ do { \ TrackingContext()->a; \ } while (0) #define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) AssertNotPassingStackBufferToTheGL(ptr) #else // ifdef MOZ_GL_DEBUG #ifdef MOZ_WIDGET_ANDROID // Record the name of the GL call for better hang stacks on Android. #define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS) #else #define BEFORE_GL_CALL do { } while (0) #endif #define AFTER_GL_CALL do { } while (0) #define TRACKING_CONTEXT(a) do {} while (0) #define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) do {} while (0) #endif // ifdef MOZ_GL_DEBUG #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) // 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(); // 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() { } // ----------------------------------------------------------------------------- // GL official entry points public: 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 fBindFramebuffer(GLenum target, GLuint framebuffer); 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); 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(); 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); 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); AFTER_GL_CALL; } void fGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { BEFORE_GL_CALL; mSymbols.fGetAttachedShaders(program, maxCount, count, shaders); AFTER_GL_CALL; } GLint fGetAttribLocation(GLuint program, const GLchar* name) { BEFORE_GL_CALL; GLint retval = mSymbols.fGetAttribLocation(program, name); AFTER_GL_CALL; return retval; } private: void raw_fGetIntegerv(GLenum pname, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetIntegerv(pname, params); AFTER_GL_CALL; } public: void fGetIntegerv(GLenum pname, GLint* params); void GetUIntegerv(GLenum pname, GLuint* params) { fGetIntegerv(pname, reinterpret_cast<GLint*>(params)); } template<typename T> T GetIntAs(GLenum pname) { static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); T ret = 0; fGetIntegerv(pname, (GLint*)&ret); return ret; } void fGetFloatv(GLenum pname, GLfloat* params) { BEFORE_GL_CALL; mSymbols.fGetFloatv(pname, params); AFTER_GL_CALL; } void fGetBooleanv(GLenum pname, realGLboolean* params) { BEFORE_GL_CALL; mSymbols.fGetBooleanv(pname, params); AFTER_GL_CALL; } void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetBufferParameteriv(target, pname, params); AFTER_GL_CALL; } GLuint fGetDebugMessageLog(GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetDebugMessageLog); GLuint ret = mSymbols.fGetDebugMessageLog(count, bufsize, sources, types, ids, severities, lengths, messageLog); AFTER_GL_CALL; return ret; } void fGetPointerv(GLenum pname, GLvoid** params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetPointerv); mSymbols.fGetPointerv(pname, params); 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); 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); 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); AFTER_GL_CALL; } void fGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { BEFORE_GL_CALL; mSymbols.fGetProgramInfoLog(program, bufSize, length, infoLog); 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) { BEFORE_GL_CALL; const GLubyte* result = mSymbols.fGetString(name); 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); 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); AFTER_GL_CALL; } void fGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { BEFORE_GL_CALL; mSymbols.fGetTexParameterfv(target, pname, params); AFTER_GL_CALL; } void fGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetTexParameteriv(target, pname, params); AFTER_GL_CALL; } void fGetUniformfv(GLuint program, GLint location, GLfloat* params) { BEFORE_GL_CALL; mSymbols.fGetUniformfv(program, location, params); AFTER_GL_CALL; } void fGetUniformiv(GLuint program, GLint location, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetUniformiv(program, location, params); AFTER_GL_CALL; } void fGetUniformuiv(GLuint program, GLint location, GLuint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetUniformuiv); mSymbols.fGetUniformuiv(program, location, params); AFTER_GL_CALL; } GLint fGetUniformLocation (GLint programObj, const GLchar* name) { BEFORE_GL_CALL; GLint retval = mSymbols.fGetUniformLocation(programObj, name); AFTER_GL_CALL; return retval; } void fGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribfv(index, pname, retval); AFTER_GL_CALL; } void fGetVertexAttribiv(GLuint index, GLenum pname, GLint* retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribiv(index, pname, retval); AFTER_GL_CALL; } void fGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribPointerv(index, pname, retval); AFTER_GL_CALL; } void fHint(GLenum target, GLenum mode) { BEFORE_GL_CALL; mSymbols.fHint(target, mode); AFTER_GL_CALL; } realGLboolean fIsBuffer(GLuint buffer) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsBuffer(buffer); AFTER_GL_CALL; return retval; } realGLboolean fIsEnabled(GLenum capability) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsEnabled(capability); AFTER_GL_CALL; return retval; } realGLboolean fIsProgram(GLuint program) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsProgram(program); AFTER_GL_CALL; return retval; } realGLboolean fIsShader(GLuint shader) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsShader(shader); AFTER_GL_CALL; return retval; } realGLboolean fIsTexture(GLuint texture) { BEFORE_GL_CALL; realGLboolean 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 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) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; mSymbols.fReadPixels(x, y, width, height, format, type, pixels); 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 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); AFTER_GL_CALL; } void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { BEFORE_GL_CALL; mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog); 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); 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); 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: friend class SharedSurface; void raw_fBindFramebuffer(GLenum target, GLuint framebuffer) { BEFORE_GL_CALL; mSymbols.fBindFramebuffer(target, framebuffer); AFTER_GL_CALL; } public: void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { BEFORE_GL_CALL; mSymbols.fBindRenderbuffer(target, renderbuffer); AFTER_GL_CALL; } GLenum fCheckFramebufferStatus(GLenum target) { BEFORE_GL_CALL; GLenum retval = mSymbols.fCheckFramebufferStatus(target); 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; if (mNeedsCheckAfterAttachTextureToFb) { fCheckFramebufferStatus(target); } } 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); AFTER_GL_CALL; } void fGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* value) { BEFORE_GL_CALL; mSymbols.fGetRenderbufferParameteriv(target, pname, value); AFTER_GL_CALL; } realGLboolean fIsFramebuffer (GLuint framebuffer) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsFramebuffer(framebuffer); AFTER_GL_CALL; return retval; } public: realGLboolean fIsRenderbuffer (GLuint renderbuffer) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fMapBuffer); void* ret = mSymbols.fMapBuffer(target, access); AFTER_GL_CALL; return ret; } realGLboolean fUnmapBuffer(GLenum target) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUnmapBuffer); realGLboolean ret = mSymbols.fUnmapBuffer(target); AFTER_GL_CALL; return ret; } private: GLuint raw_fCreateProgram() { BEFORE_GL_CALL; GLuint ret = mSymbols.fCreateProgram(); AFTER_GL_CALL; return ret; } GLuint raw_fCreateShader(GLenum t) { BEFORE_GL_CALL; GLuint ret = mSymbols.fCreateShader(t); AFTER_GL_CALL; return ret; } void raw_fGenBuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenBuffers(n, names); AFTER_GL_CALL; } void raw_fGenFramebuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenFramebuffers(n, names); AFTER_GL_CALL; } void raw_fGenRenderbuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenRenderbuffers(n, names); AFTER_GL_CALL; } void raw_fGenTextures(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenTextures(n, names); 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; } 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) { raw_fDeleteTextures(n, names); TRACKING_CONTEXT(DeletedTextures(this, n, names)); } GLenum fGetGraphicsResetStatus() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetGraphicsResetStatus); GLenum ret = mSymbols.fGetGraphicsResetStatus(); AFTER_GL_CALL; return ret; } // ----------------------------------------------------------------------------- // Extension ARB_sync (GL) public: GLsync fFenceSync(GLenum condition, GLbitfield flags) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fFenceSync); GLsync ret = mSymbols.fFenceSync(condition, flags); AFTER_GL_CALL; return ret; } realGLboolean fIsSync(GLsync sync) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsSync); realGLboolean ret = mSymbols.fIsSync(sync); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fClientWaitSync); GLenum ret = mSymbols.fClientWaitSync(sync, flags, timeout); 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); 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; } // ----------------------------------------------------------------------------- // Feature draw_range_elements public: void fDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) { BeforeGLDrawCall(); raw_fDrawRangeElements(mode, start, end, count, type, indices); AfterGLDrawCall(); } private: void raw_fDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDrawRangeElements); mSymbols.fDrawRangeElements(mode, start, end, count, type, indices); 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); AFTER_GL_CALL; } void fGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) { ASSERT_SYMBOL_PRESENT(fGetVertexAttribIuiv); BEFORE_GL_CALL; mSymbols.fGetVertexAttribIuiv(index, pname, params); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetFragDataLocation); GLint result = mSymbols.fGetFragDataLocation(program, name); 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); 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); AFTER_GL_CALL; } void fGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjectuiv); mSymbols.fGetQueryObjectuiv(id, pname, params); AFTER_GL_CALL; } realGLboolean fIsQuery(GLuint query) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsQuery); realGLboolean retval = mSymbols.fIsQuery(query); 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); AFTER_GL_CALL; } void fGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjectui64v); mSymbols.fGetQueryObjectui64v(id, pname, params); 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); 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); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsTransformFeedback); realGLboolean result = mSymbols.fIsTransformFeedback(id); 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); 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); 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); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsVertexArray); realGLboolean ret = mSymbols.fIsVertexArray(array); 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) { ASSERT_SYMBOL_PRESENT(fTestFence); BEFORE_GL_CALL; realGLboolean ret = mSymbols.fTestFence(fence); AFTER_GL_CALL; return ret; } void fFinishFence(GLuint fence) { ASSERT_SYMBOL_PRESENT(fFinishFence); BEFORE_GL_CALL; mSymbols.fFinishFence(fence); AFTER_GL_CALL; } realGLboolean fIsFence(GLuint fence) { ASSERT_SYMBOL_PRESENT(fIsFence); BEFORE_GL_CALL; realGLboolean ret = mSymbols.fIsFence(fence); 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); 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) { ASSERT_SYMBOL_PRESENT(fMapBufferRange); BEFORE_GL_CALL; void* data = mSymbols.fMapBufferRange(target, offset, length, access); 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) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsSampler); realGLboolean result = mSymbols.fIsSampler(sampler); 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); 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); AFTER_GL_CALL; } GLuint fGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) { ASSERT_SYMBOL_PRESENT(fGetUniformBlockIndex); BEFORE_GL_CALL; GLuint result = mSymbols.fGetUniformBlockIndex(program, uniformBlockName); 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); 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); 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); 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); 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); 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); 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; } // ----------------------------------------------------------------------------- // get_string_indexed const GLubyte* fGetStringi(GLenum name, GLuint index) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetStringi); const GLubyte* ret = mSymbols.fGetStringi(name, index); AFTER_GL_CALL; return ret; } // ----------------------------------------------------------------------------- // APPLE_framebuffer_multisample void fResolveMultisampleFramebufferAPPLE() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE); mSymbols.fResolveMultisampleFramebufferAPPLE(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // prim_restart void fPrimitiveRestartIndex(GLuint index) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fPrimitiveRestartIndex); mSymbols.fPrimitiveRestartIndex(index); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Constructor protected: explicit GLContext(CreateContextFlags flags, const SurfaceCaps& caps, GLContext* sharedContext = nullptr, bool isOffscreen = false); // ----------------------------------------------------------------------------- // Destructor public: virtual ~GLContext(); // Mark this context as destroyed. This will nullptr out all // the GL function pointers! void MarkDestroyed(); // ----------------------------------------------------------------------------- // Everything that isn't standard GL APIs protected: typedef gfx::SurfaceFormat SurfaceFormat; virtual bool MakeCurrentImpl(bool aForce) = 0; public: #ifdef MOZ_GL_DEBUG static void StaticInit() { PR_NewThreadPrivateIndex(&sCurrentGLContextTLS, nullptr); } #endif bool MakeCurrent(bool aForce = false) { if (IsDestroyed()) { return false; } #ifdef MOZ_GL_DEBUG PR_SetThreadPrivate(sCurrentGLContextTLS, this); // XXX this assertion is disabled because it's triggering on Mac; // we need to figure out why and reenable it. #if 0 // IsOwningThreadCurrent is a bit of a misnomer; // the "owning thread" is the creation thread, // and the only thread that can own this. We don't // support contexts used on multiple threads. NS_ASSERTION(IsOwningThreadCurrent(), "MakeCurrent() called on different thread than this context was created on!"); #endif #endif return MakeCurrentImpl(aForce); } virtual bool Init() = 0; virtual bool SetupLookupFunction() = 0; virtual void ReleaseSurface() {} bool IsDestroyed() { return mIsDestroyed; } GLContext* GetSharedContext() { return mSharedContext; } /** * Returns true if the thread on which this context was created is the currently * executing thread. */ bool IsOwningThreadCurrent(); 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; } /** * 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; } // Before reads from offscreen texture void GuaranteeResolve(); /* * Resize the current offscreen buffer. Returns true on success. * If it returns false, the context should be treated as unusable * and should be recreated. After the resize, the viewport is not * changed; glViewport should be called as appropriate. * * Only valid if IsOffscreen() returns true. */ bool ResizeOffscreen(const gfx::IntSize& size) { return ResizeScreenBuffer(size); } /* * Return size of this offscreen context. * * Only valid if IsOffscreen() returns true. */ const gfx::IntSize& OffscreenSize() const; void BindFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); MOZ_ASSERT(!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(); GLuint GetReadFB(); GLuint GetFB(); 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: void ForceDirtyScreen(); void CleanDirtyScreen(); virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; } virtual GLenum GetPreferredEGLImageTextureTarget() const { return IsExtensionSupported(OES_EGL_image_external) ? LOCAL_GL_TEXTURE_EXTERNAL : LOCAL_GL_TEXTURE_2D; } virtual bool RenewSurface(nsIWidget* aWidget) { return false; } // Shared code for GL extensions and GLX extensions. static bool ListHasExtension(const GLubyte* extensions, const char* extension); GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; } public: std::map<GLuint, SharedSurface*> mFBOMapping; enum { DebugFlagEnabled = 1 << 0, DebugFlagTrace = 1 << 1, DebugFlagAbortOnError = 1 << 2 }; const uint8_t mDebugFlags; protected: RefPtr<GLContext> mSharedContext; // The thread id which this context was created. PlatformThreadId mOwningThreadId; GLContextSymbols mSymbols; #ifdef MOZ_GL_DEBUG // Non-zero debug flags will check that we don't send call // to a GLContext that isn't current on the current // thread. // Store the current context when binding to thread local // storage to support debug flags on an arbitrary thread. static unsigned sCurrentGLContextTLS; #endif UniquePtr<GLBlitHelper> mBlitHelper; UniquePtr<GLReadTexImageHelper> mReadTexImageHelper; public: GLBlitHelper* BlitHelper(); GLBlitTextureImageHelper* BlitTextureImageHelper(); 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 InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps); protected: // Note that it does -not- clear the resized buffers. bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps) { if (!IsOffscreenSizeAllowed(size)) return false; return CreateScreenBufferImpl(size, caps); } bool CreateScreenBufferImpl(const gfx::IntSize& size, const SurfaceCaps& caps); public: bool ResizeScreenBuffer(const gfx::IntSize& size); protected: SurfaceCaps mCaps; public: const SurfaceCaps& Caps() const { return mCaps; } // Only varies based on bpp16 and alpha. GLFormats ChooseGLFormats(const SurfaceCaps& caps) const; 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: friend class GLScreenBuffer; UniquePtr<GLScreenBuffer> mScreen; SharedSurface* mLockedSurface; public: void LockSurface(SharedSurface* surf) { MOZ_ASSERT(!mLockedSurface); mLockedSurface = surf; } void UnlockSurface(SharedSurface* surf) { MOZ_ASSERT(mLockedSurface == surf); mLockedSurface = nullptr; } SharedSurface* GetLockedSurface() const { return mLockedSurface; } bool IsOffscreen() const { return mIsOffscreen; } GLScreenBuffer* Screen() const { return mScreen.get(); } /* Clear to transparent black, with 0 depth and stencil, * while preserving current ClearColor etc. values. * Useful for resizing offscreen buffers. */ void ClearSafely(); bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } bool IsDrawingToDefaultFramebuffer(); protected: RefPtr<TextureGarbageBin> mTexGarbageBin; public: TextureGarbageBin* TexGarbageBin() { MOZ_ASSERT(mTexGarbageBin); return mTexGarbageBin; } void EmptyTexGarbageBin(); bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; protected: bool InitWithPrefix(const char* prefix, bool trygl); private: bool InitWithPrefixImpl(const char* prefix, bool trygl); void LoadMoreSymbols(const char* prefix, bool trygl); bool LoadExtSymbols(const char* prefix, bool trygl, const SymLoadStruct* list, GLExtensions ext); bool LoadFeatureSymbols(const char* prefix, bool trygl, const SymLoadStruct* list, GLFeature feature); protected: void InitExtensions(); GLint mViewportRect[4]; GLint mScissorRect[4]; GLint mMaxTextureSize; GLint mMaxCubeMapTextureSize; GLint mMaxTextureImageSize; GLint mMaxRenderbufferSize; GLint mMaxViewportDims[2]; GLsizei mMaxSamples; bool mNeedsTextureSizeChecks; bool mNeedsFlushBeforeDeleteFB; bool mTextureAllocCrashesOnMapFailure; bool mNeedsCheckAfterAttachTextureToFb; bool mWorkAroundDriverBugs; 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: GLsizei MaxSamples() const { return mMaxSamples; } 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; } #undef ASSERT_SYMBOL_PRESENT #ifdef MOZ_GL_DEBUG 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; public: void FlushIfHeavyGLCallsSinceLastFlush(); static bool ShouldSpew(); static bool ShouldDumpExts(); void Readback(SharedSurface* src, gfx::DataSourceSurface* dest); }; 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 ? "(*)" : ""); } } /** * 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. */ GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, const gfx::IntSize& aSize); /** * Helper function that creates a 2D texture aSize.width x aSize.height with * storage type aInternalFormat. Returns GL texture object id. * * Initialize textyre parameters to: * GL_TEXTURE_MIN_FILTER = GL_LINEAR * GL_TEXTURE_MAG_FILTER = GL_LINEAR * GL_TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE * GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE */ GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, GLenum aType, const gfx::IntSize& aSize, bool linear = true); /** * 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); } /* namespace gl */ } /* namespace mozilla */ #endif /* GLCONTEXT_H_ */