/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GLCONTEXT_H_ #define GLCONTEXT_H_ #include #include #include #include #include #ifdef DEBUG # include #endif #ifdef GetClassName # undef GetClassName #endif // Define MOZ_GL_DEBUG_BUILD unconditionally to enable GL debugging in opt // builds. #ifdef DEBUG # define MOZ_GL_DEBUG_BUILD 1 #endif #include "mozilla/IntegerRange.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "mozilla/ThreadLocal.h" #include "MozFramebuffer.h" #include "nsTArray.h" #include "GLConsts.h" #include "GLDefs.h" #include "GLTypes.h" #include "GLVendor.h" #include "nsRegionFwd.h" #include "nsString.h" #include "GLContextTypes.h" #include "GLContextSymbols.h" #include "base/platform_thread.h" // for PlatformThreadId #include "mozilla/GenericRefCounted.h" #include "mozilla/WeakPtr.h" #ifdef MOZ_WIDGET_ANDROID # include "mozilla/ProfilerLabels.h" #endif namespace mozilla { namespace gl { class GLBlitHelper; class GLLibraryEGL; class GLReadTexImageHelper; class SharedSurface; class SymbolLoader; struct SymLoadStruct; } // namespace gl namespace layers { class ColorTextureLayerProgram; } // namespace layers namespace widget { class CompositorWidget; } // namespace widget } // namespace mozilla namespace mozilla { namespace gl { enum class GLFeature { bind_buffer_offset, blend_minmax, clear_buffers, copy_buffer, depth_texture, draw_buffers, draw_buffers_indexed, draw_instanced, element_index_uint, ES2_compatibility, ES3_compatibility, EXT_color_buffer_float, frag_color_float, frag_depth, framebuffer_blit, framebuffer_multisample, framebuffer_object, framebuffer_object_EXT_OES, get_integer_indexed, get_integer64_indexed, get_query_object_i64v, get_query_object_iv, gpu_shader4, instanced_arrays, instanced_non_arrays, internalformat_query, invalidate_framebuffer, map_buffer_range, multiview, occlusion_query, occlusion_query_boolean, occlusion_query2, packed_depth_stencil, prim_restart, prim_restart_fixed, provoking_vertex, query_counter, query_objects, query_time_elapsed, read_buffer, renderbuffer_color_float, renderbuffer_color_half_float, robust_buffer_access_behavior, robustness, sRGB, sampler_objects, seamless_cube_map_opt_in, shader_texture_lod, split_framebuffer, standard_derivatives, sync, texture_3D, texture_3D_compressed, texture_3D_copy, texture_compression_bptc, texture_compression_rgtc, texture_float, texture_float_linear, texture_half_float, texture_half_float_linear, texture_non_power_of_two, texture_norm16, texture_rg, texture_storage, texture_swizzle, transform_feedback2, uniform_buffer_object, uniform_matrix_nonsquare, vertex_array_object, EnumMax }; enum class ContextProfile : uint8_t { Unknown = 0, OpenGLCore, OpenGLCompatibility, OpenGLES }; enum class GLRenderer { Adreno200, Adreno205, AdrenoTM200, AdrenoTM205, AdrenoTM305, AdrenoTM320, AdrenoTM330, AdrenoTM420, Mali400MP, Mali450MP, MaliT, SGX530, SGX540, SGX544MP, Tegra, AndroidEmulator, GalliumLlvmpipe, IntelHD3000, MicrosoftBasicRenderDriver, Other }; class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { public: static MOZ_THREAD_LOCAL(const GLContext*) sCurrentContext; const GLContextDesc mDesc; bool mImplicitMakeCurrent = false; bool mUseTLSIsCurrent; class TlsScope final { const WeakPtr mGL; const bool mWasTlsOk; public: explicit TlsScope(GLContext* const gl) : mGL(gl), mWasTlsOk(gl && gl->mUseTLSIsCurrent) { if (mGL) { mGL->mUseTLSIsCurrent = true; } } ~TlsScope() { if (mGL) { mGL->mUseTLSIsCurrent = mWasTlsOk; } } }; // ----------------------------------------------------------------------------- // basic getters public: /** * Returns true if the context is using ANGLE. This should only be overridden * for an ANGLE implementation. */ virtual bool IsANGLE() const { return false; } /** * Returns true if the context is using WARP. This should only be overridden * for an ANGLE implementation. */ virtual bool IsWARP() const { return false; } virtual void GetWSIInfo(nsCString* const out) const = 0; /** * Return true if we are running on a OpenGL core profile context */ inline bool IsCoreProfile() const { MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); return mProfile == ContextProfile::OpenGLCore; } /** * Return true if we are running on a OpenGL compatibility profile context * (legacy profile 2.1 on Max OS X) */ inline bool IsCompatibilityProfile() const { MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); return mProfile == ContextProfile::OpenGLCompatibility; } inline bool IsGLES() const { MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); return mProfile == ContextProfile::OpenGLES; } inline bool IsAtLeast(ContextProfile profile, unsigned int version) const { MOZ_ASSERT(profile != ContextProfile::Unknown, "IsAtLeast: bad parameter"); MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); MOZ_ASSERT(mVersion != 0, "unknown context version"); if (version > mVersion) { return false; } return profile == mProfile; } /** * Return the version of the context. * Example : * If this a OpenGL 2.1, that will return 210 */ inline uint32_t Version() const { return mVersion; } inline uint32_t ShadingLanguageVersion() const { return mShadingLanguageVersion; } GLVendor Vendor() const { return mVendor; } GLRenderer Renderer() const { return mRenderer; } bool IsMesa() const { return mIsMesa; } bool IsContextLost() const { return mContextLost; } bool CheckContextLost() const { mTopError = GetError(); return IsContextLost(); } bool HasPBOState() const { return (!IsGLES() || Version() >= 300); } /** * If this context is double-buffered, returns TRUE. */ virtual bool IsDoubleBuffered() const { return false; } virtual GLContextType GetContextType() const = 0; virtual bool IsCurrentImpl() const = 0; virtual bool MakeCurrentImpl() const = 0; bool IsCurrent() const { if (mImplicitMakeCurrent) return MakeCurrent(); return IsCurrentImpl(); } bool MakeCurrent(bool aForce = false) const; /** * Get the default framebuffer for this context. */ UniquePtr mOffscreenDefaultFb; bool CreateOffscreenDefaultFb(const gfx::IntSize& size); virtual GLuint GetDefaultFramebuffer() { if (mOffscreenDefaultFb) { return mOffscreenDefaultFb->mFB; } return 0; } /** * mVersion store the OpenGL's version, multiplied by 100. For example, if * the context is an OpenGL 2.1 context, mVersion value will be 210. */ uint32_t mVersion = 0; ContextProfile mProfile = ContextProfile::Unknown; uint32_t mShadingLanguageVersion = 0; GLVendor mVendor = GLVendor::Other; GLRenderer mRenderer = GLRenderer::Other; bool mIsMesa = false; // ----------------------------------------------------------------------------- // Extensions management /** * This mechanism is designed to know if an extension is supported. In the * long term, we would like to only use the extension group queries XXX_* to * have full compatibility with context version and profiles (especialy the * core that officialy don't bring any extensions). */ /** * Known GL extensions that can be queried by * IsExtensionSupported. The results of this are cached, and as * such it's safe to use this even in performance critical code. * If you add to this array, remember to add to the string names * in GLContext.cpp. */ enum GLExtensions { Extension_None = 0, AMD_compressed_ATC_texture, ANGLE_depth_texture, ANGLE_framebuffer_blit, ANGLE_framebuffer_multisample, ANGLE_instanced_arrays, ANGLE_multiview, ANGLE_provoking_vertex, ANGLE_texture_compression_dxt3, ANGLE_texture_compression_dxt5, ANGLE_timer_query, APPLE_client_storage, APPLE_fence, APPLE_framebuffer_multisample, APPLE_sync, APPLE_texture_range, APPLE_vertex_array_object, ARB_ES2_compatibility, ARB_ES3_compatibility, ARB_color_buffer_float, ARB_compatibility, ARB_copy_buffer, ARB_depth_texture, ARB_draw_buffers, ARB_draw_instanced, ARB_framebuffer_object, ARB_framebuffer_sRGB, ARB_geometry_shader4, ARB_half_float_pixel, ARB_instanced_arrays, ARB_internalformat_query, ARB_invalidate_subdata, ARB_map_buffer_range, ARB_occlusion_query2, ARB_pixel_buffer_object, ARB_provoking_vertex, ARB_robust_buffer_access_behavior, ARB_robustness, ARB_sampler_objects, ARB_seamless_cube_map, ARB_shader_texture_lod, ARB_sync, ARB_texture_compression, ARB_texture_compression_bptc, ARB_texture_compression_rgtc, ARB_texture_float, ARB_texture_non_power_of_two, ARB_texture_rectangle, ARB_texture_rg, ARB_texture_storage, ARB_texture_swizzle, ARB_timer_query, ARB_transform_feedback2, ARB_uniform_buffer_object, ARB_vertex_array_object, CHROMIUM_color_buffer_float_rgb, CHROMIUM_color_buffer_float_rgba, EXT_bgra, EXT_blend_minmax, EXT_color_buffer_float, EXT_color_buffer_half_float, EXT_copy_texture, EXT_disjoint_timer_query, EXT_draw_buffers, EXT_draw_buffers2, EXT_draw_instanced, EXT_float_blend, EXT_frag_depth, EXT_framebuffer_blit, EXT_framebuffer_multisample, EXT_framebuffer_object, EXT_framebuffer_sRGB, EXT_gpu_shader4, EXT_map_buffer_range, EXT_multisampled_render_to_texture, EXT_occlusion_query_boolean, EXT_packed_depth_stencil, EXT_provoking_vertex, EXT_read_format_bgra, EXT_robustness, EXT_sRGB, EXT_sRGB_write_control, EXT_shader_texture_lod, EXT_texture_compression_bptc, EXT_texture_compression_dxt1, EXT_texture_compression_rgtc, EXT_texture_compression_s3tc, EXT_texture_compression_s3tc_srgb, EXT_texture_filter_anisotropic, EXT_texture_format_BGRA8888, EXT_texture_norm16, EXT_texture_sRGB, EXT_texture_storage, EXT_timer_query, EXT_transform_feedback, EXT_unpack_subimage, IMG_read_format, IMG_texture_compression_pvrtc, IMG_texture_npot, KHR_debug, KHR_parallel_shader_compile, KHR_robust_buffer_access_behavior, KHR_robustness, KHR_texture_compression_astc_hdr, KHR_texture_compression_astc_ldr, NV_draw_instanced, NV_fence, NV_framebuffer_blit, NV_geometry_program4, NV_half_float, NV_instanced_arrays, NV_primitive_restart, NV_texture_barrier, NV_transform_feedback, NV_transform_feedback2, OES_EGL_image, OES_EGL_image_external, OES_EGL_sync, OES_compressed_ETC1_RGB8_texture, OES_depth24, OES_depth32, OES_depth_texture, OES_draw_buffers_indexed, OES_element_index_uint, OES_fbo_render_mipmap, OES_framebuffer_object, OES_packed_depth_stencil, OES_rgb8_rgba8, OES_standard_derivatives, OES_stencil8, OES_texture_3D, OES_texture_float, OES_texture_float_linear, OES_texture_half_float, OES_texture_half_float_linear, OES_texture_npot, OES_vertex_array_object, OVR_multiview2, Extensions_Max, Extensions_End }; bool IsExtensionSupported(GLExtensions aKnownExtension) const { return mAvailableExtensions[aKnownExtension]; } protected: void MarkExtensionUnsupported(GLExtensions aKnownExtension) { mAvailableExtensions[aKnownExtension] = 0; } void MarkExtensionSupported(GLExtensions aKnownExtension) { mAvailableExtensions[aKnownExtension] = 1; } std::bitset 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 mAvailableFeatures; /** * Init features regarding OpenGL extension and context version and profile */ void InitFeatures(); /** * Mark the feature and associated extensions as unsupported */ void MarkUnsupported(GLFeature feature); /** * Is this feature supported using the core (unsuffixed) symbols? */ bool IsFeatureProvidedByCoreSymbols(GLFeature feature); // ----------------------------------------------------------------------------- // Error handling private: mutable bool mContextLost = false; mutable GLenum mTopError = 0; protected: void OnContextLostError() const; public: static std::string GLErrorToString(GLenum aError); static bool IsBadCallError(const GLenum err) { return !(err == 0 || err == LOCAL_GL_CONTEXT_LOST); } class LocalErrorScope; private: mutable std::stack mLocalErrorScopeStack; mutable UniquePtr mDebugErrorScope; //////////////////////////////////// // Use this safer option. public: class LocalErrorScope { const GLContext& mGL; GLenum mOldTop; bool mHasBeenChecked; public: explicit LocalErrorScope(const GLContext& gl) : mGL(gl), mHasBeenChecked(false) { mGL.mLocalErrorScopeStack.push(this); mOldTop = mGL.GetError(); } /// Never returns CONTEXT_LOST. GLenum GetError() { MOZ_ASSERT(!mHasBeenChecked); mHasBeenChecked = true; const auto ret = mGL.GetError(); if (ret == LOCAL_GL_CONTEXT_LOST) return 0; return ret; } ~LocalErrorScope() { MOZ_ASSERT(mHasBeenChecked); MOZ_ASSERT(!IsBadCallError(mGL.GetError())); MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this); mGL.mLocalErrorScopeStack.pop(); mGL.mTopError = mOldTop; } }; // - bool GetPotentialInteger(GLenum pname, GLint* param) { LocalErrorScope localError(*this); fGetIntegerv(pname, param); GLenum err = localError.GetError(); MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_INVALID_ENUM); return err == LOCAL_GL_NO_ERROR; } void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); private: static void GLAPIENTRY StaticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam); // ----------------------------------------------------------------------------- // Debugging implementation private: #ifndef MOZ_FUNCTION_NAME # ifdef __GNUC__ # define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ # elif defined(_MSC_VER) # define MOZ_FUNCTION_NAME __FUNCTION__ # else # define MOZ_FUNCTION_NAME \ __func__ // defined in C99, supported in various C++ compilers. Just raw // function name. # endif #endif #ifdef MOZ_WIDGET_ANDROID // Record the name of the GL call for better hang stacks on Android. # define ANDROID_ONLY_PROFILER_LABEL AUTO_PROFILER_LABEL(__func__, GRAPHICS); #else # define ANDROID_ONLY_PROFILER_LABEL #endif #define BEFORE_GL_CALL \ ANDROID_ONLY_PROFILER_LABEL \ if (MOZ_LIKELY(BeforeGLCall(MOZ_FUNCTION_NAME))) { \ do { \ } while (0) #define AFTER_GL_CALL \ AfterGLCall(MOZ_FUNCTION_NAME); \ } \ do { \ } while (0) void BeforeGLCall_Debug(const char* funcName) const; void AfterGLCall_Debug(const char* funcName) const; static void OnImplicitMakeCurrentFailure(const char* funcName); bool BeforeGLCall(const char* const funcName) const { if (mImplicitMakeCurrent) { if (MOZ_UNLIKELY(!MakeCurrent())) { if (!mContextLost) { OnImplicitMakeCurrentFailure(funcName); } return false; } } MOZ_GL_ASSERT(this, IsCurrentImpl()); if (MOZ_UNLIKELY(mDebugFlags)) { BeforeGLCall_Debug(funcName); } return true; } void AfterGLCall(const char* const funcName) const { if (MOZ_UNLIKELY(mDebugFlags)) { AfterGLCall_Debug(funcName); } } GLContext* TrackingContext() { GLContext* tip = this; while (tip->mSharedContext) tip = tip->mSharedContext; return tip; } static void AssertNotPassingStackBufferToTheGL(const void* ptr); #ifdef MOZ_GL_DEBUG_BUILD # define TRACKING_CONTEXT(a) \ do { \ TrackingContext()->a; \ } while (0) # define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ AssertNotPassingStackBufferToTheGL(ptr) # define ASSERT_SYMBOL_PRESENT(func) \ do { \ MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, \ "Mismatched symbol check."); \ if (MOZ_UNLIKELY(!mSymbols.func)) { \ printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", \ #func); \ MOZ_CRASH("GFX: Uninitialized GL function"); \ } \ } while (0) #else // ifdef MOZ_GL_DEBUG_BUILD # define TRACKING_CONTEXT(a) \ do { \ } while (0) # define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ do { \ } while (0) # define ASSERT_SYMBOL_PRESENT(func) \ do { \ } while (0) #endif // ifdef MOZ_GL_DEBUG_BUILD // Do whatever setup is necessary to draw to our offscreen FBO, if it's // bound. void BeforeGLDrawCall() {} // Do whatever tear-down is necessary after drawing to our offscreen FBO, // if it's bound. void AfterGLDrawCall() { mHeavyGLCallsSinceLastFlush = true; } // Do whatever setup is necessary to read from our offscreen FBO, if it's // bound. void BeforeGLReadCall() {} // Do whatever tear-down is necessary after reading from our offscreen FBO, // if it's bound. void AfterGLReadCall() {} public: void OnSyncCall() const { mSyncGLCallCount++; } uint64_t GetSyncCallCount() const { return mSyncGLCallCount; } void ResetSyncCallCount(const char* resetReason) const; // ----------------------------------------------------------------------------- // GL official entry points public: // We smash all errors together, so you never have to loop on this. We // guarantee that immediately after this call, there are no errors left. // Always returns the top-most error, except if followed by CONTEXT_LOST, then // return that instead. GLenum GetError() const; GLenum fGetError() { return GetError(); } GLenum fGetGraphicsResetStatus() const; // - void fActiveTexture(GLenum texture) { BEFORE_GL_CALL; mSymbols.fActiveTexture(texture); AFTER_GL_CALL; } void fAttachShader(GLuint program, GLuint shader) { BEFORE_GL_CALL; mSymbols.fAttachShader(program, shader); AFTER_GL_CALL; } void fBeginQuery(GLenum target, GLuint id) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBeginQuery); mSymbols.fBeginQuery(target, id); AFTER_GL_CALL; } void fBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { BEFORE_GL_CALL; mSymbols.fBindAttribLocation(program, index, name); AFTER_GL_CALL; } void fBindBuffer(GLenum target, GLuint buffer) { BEFORE_GL_CALL; mSymbols.fBindBuffer(target, buffer); AFTER_GL_CALL; } void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) { BeforeGLDrawCall(); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer); mSymbols.fInvalidateFramebuffer(target, numAttachments, attachments); AFTER_GL_CALL; AfterGLDrawCall(); } void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) { BeforeGLDrawCall(); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer); mSymbols.fInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); AFTER_GL_CALL; AfterGLDrawCall(); } void fBindTexture(GLenum target, GLuint texture) { BEFORE_GL_CALL; mSymbols.fBindTexture(target, texture); AFTER_GL_CALL; } void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { BEFORE_GL_CALL; mSymbols.fBlendColor(red, green, blue, alpha); AFTER_GL_CALL; } void fBlendEquation(GLenum mode) { BEFORE_GL_CALL; mSymbols.fBlendEquation(mode); AFTER_GL_CALL; } void fBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { BEFORE_GL_CALL; mSymbols.fBlendEquationSeparate(modeRGB, modeAlpha); AFTER_GL_CALL; } void fBlendFunc(GLenum sfactor, GLenum dfactor) { BEFORE_GL_CALL; mSymbols.fBlendFunc(sfactor, dfactor); AFTER_GL_CALL; } void fBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) { BEFORE_GL_CALL; mSymbols.fBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); AFTER_GL_CALL; } private: void raw_fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); BEFORE_GL_CALL; mSymbols.fBufferData(target, size, data, usage); OnSyncCall(); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } public: void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { raw_fBufferData(target, size, data, usage); // bug 744888 if (WorkAroundDriverBugs() && !data && Vendor() == GLVendor::NVIDIA) { UniquePtr buf = MakeUnique(1); buf[0] = 0; fBufferSubData(target, size - 1, 1, buf.get()); } } void fBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); BEFORE_GL_CALL; mSymbols.fBufferSubData(target, offset, size, data); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } private: void raw_fClear(GLbitfield mask) { BEFORE_GL_CALL; mSymbols.fClear(mask); AFTER_GL_CALL; } public: void fClear(GLbitfield mask) { BeforeGLDrawCall(); raw_fClear(mask); AfterGLDrawCall(); } void fClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { BeforeGLDrawCall(); BEFORE_GL_CALL; mSymbols.fClearBufferfi(buffer, drawbuffer, depth, stencil); AFTER_GL_CALL; AfterGLDrawCall(); } void fClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { BeforeGLDrawCall(); BEFORE_GL_CALL; mSymbols.fClearBufferfv(buffer, drawbuffer, value); AFTER_GL_CALL; AfterGLDrawCall(); } void fClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { BeforeGLDrawCall(); BEFORE_GL_CALL; mSymbols.fClearBufferiv(buffer, drawbuffer, value); AFTER_GL_CALL; AfterGLDrawCall(); } void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { BeforeGLDrawCall(); BEFORE_GL_CALL; mSymbols.fClearBufferuiv(buffer, drawbuffer, value); AFTER_GL_CALL; AfterGLDrawCall(); } void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { BEFORE_GL_CALL; mSymbols.fClearColor(r, g, b, a); AFTER_GL_CALL; } void fClearStencil(GLint s) { BEFORE_GL_CALL; mSymbols.fClearStencil(s); AFTER_GL_CALL; } void fClientActiveTexture(GLenum texture) { BEFORE_GL_CALL; mSymbols.fClientActiveTexture(texture); AFTER_GL_CALL; } void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha) { BEFORE_GL_CALL; mSymbols.fColorMask(red, green, blue, alpha); AFTER_GL_CALL; } void fCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* pixels) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; mSymbols.fCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, pixels); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* pixels) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, pixels); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { BeforeGLReadCall(); raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); AfterGLReadCall(); } void fCullFace(GLenum mode) { BEFORE_GL_CALL; mSymbols.fCullFace(mode); AFTER_GL_CALL; } void fDebugMessageCallback(GLDEBUGPROC callback, const GLvoid* userParam) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDebugMessageCallback); mSymbols.fDebugMessageCallback(callback, userParam); AFTER_GL_CALL; } void fDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, realGLboolean enabled) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDebugMessageControl); mSymbols.fDebugMessageControl(source, type, severity, count, ids, enabled); AFTER_GL_CALL; } void fDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDebugMessageInsert); mSymbols.fDebugMessageInsert(source, type, id, severity, length, buf); AFTER_GL_CALL; } void fDetachShader(GLuint program, GLuint shader) { BEFORE_GL_CALL; mSymbols.fDetachShader(program, shader); AFTER_GL_CALL; } void fDepthFunc(GLenum func) { BEFORE_GL_CALL; mSymbols.fDepthFunc(func); AFTER_GL_CALL; } void fDepthMask(realGLboolean flag) { BEFORE_GL_CALL; mSymbols.fDepthMask(flag); AFTER_GL_CALL; } void fDisable(GLenum capability) { BEFORE_GL_CALL; mSymbols.fDisable(capability); AFTER_GL_CALL; } void fDisableClientState(GLenum capability) { BEFORE_GL_CALL; mSymbols.fDisableClientState(capability); AFTER_GL_CALL; } void fDisableVertexAttribArray(GLuint index) { BEFORE_GL_CALL; mSymbols.fDisableVertexAttribArray(index); AFTER_GL_CALL; } void fDrawBuffer(GLenum mode) { BEFORE_GL_CALL; mSymbols.fDrawBuffer(mode); AFTER_GL_CALL; } private: void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) { BEFORE_GL_CALL; mSymbols.fDrawArrays(mode, first, count); AFTER_GL_CALL; } void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { BEFORE_GL_CALL; mSymbols.fDrawElements(mode, count, type, indices); AFTER_GL_CALL; } public: void fDrawArrays(GLenum mode, GLint first, GLsizei count) { BeforeGLDrawCall(); raw_fDrawArrays(mode, first, count); AfterGLDrawCall(); } void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { BeforeGLDrawCall(); raw_fDrawElements(mode, count, type, indices); AfterGLDrawCall(); } void fEnable(GLenum capability) { BEFORE_GL_CALL; mSymbols.fEnable(capability); AFTER_GL_CALL; } void fEnableClientState(GLenum capability) { BEFORE_GL_CALL; mSymbols.fEnableClientState(capability); AFTER_GL_CALL; } void fEnableVertexAttribArray(GLuint index) { BEFORE_GL_CALL; mSymbols.fEnableVertexAttribArray(index); AFTER_GL_CALL; } void fEndQuery(GLenum target) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fEndQuery); mSymbols.fEndQuery(target); AFTER_GL_CALL; } void fFinish() { BEFORE_GL_CALL; mSymbols.fFinish(); OnSyncCall(); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = false; } void fFlush() { BEFORE_GL_CALL; mSymbols.fFlush(); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = false; } void fFrontFace(GLenum face) { BEFORE_GL_CALL; mSymbols.fFrontFace(face); AFTER_GL_CALL; } void fGetActiveAttrib(GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { BEFORE_GL_CALL; mSymbols.fGetActiveAttrib(program, index, maxLength, length, size, type, name); OnSyncCall(); AFTER_GL_CALL; } void fGetActiveUniform(GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { BEFORE_GL_CALL; mSymbols.fGetActiveUniform(program, index, maxLength, length, size, type, name); OnSyncCall(); AFTER_GL_CALL; } void fGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { BEFORE_GL_CALL; mSymbols.fGetAttachedShaders(program, maxCount, count, shaders); OnSyncCall(); AFTER_GL_CALL; } GLint fGetAttribLocation(GLuint program, const GLchar* name) { GLint retval = 0; BEFORE_GL_CALL; retval = mSymbols.fGetAttribLocation(program, name); OnSyncCall(); AFTER_GL_CALL; return retval; } private: void raw_fGetIntegerv(GLenum pname, GLint* params) const { BEFORE_GL_CALL; mSymbols.fGetIntegerv(pname, params); OnSyncCall(); AFTER_GL_CALL; } public: void fGetIntegerv(GLenum pname, GLint* params) const; template void GetInt(const GLenum pname, T* const params) const { static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); fGetIntegerv(pname, reinterpret_cast(params)); } void GetUIntegerv(GLenum pname, GLuint* params) const { GetInt(pname, params); } template T GetIntAs(GLenum pname) const { static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); T ret = 0; fGetIntegerv(pname, (GLint*)&ret); return ret; } void fGetFloatv(GLenum pname, GLfloat* params) const { BEFORE_GL_CALL; mSymbols.fGetFloatv(pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetBooleanv(GLenum pname, realGLboolean* params) const { BEFORE_GL_CALL; mSymbols.fGetBooleanv(pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetBufferParameteriv(target, pname, params); OnSyncCall(); AFTER_GL_CALL; } GLuint fGetDebugMessageLog(GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog) { GLuint ret = 0; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetDebugMessageLog); ret = mSymbols.fGetDebugMessageLog(count, bufsize, sources, types, ids, severities, lengths, messageLog); OnSyncCall(); AFTER_GL_CALL; return ret; } void fGetPointerv(GLenum pname, GLvoid** params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetPointerv); mSymbols.fGetPointerv(pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetObjectLabel); mSymbols.fGetObjectLabel(identifier, name, bufSize, length, label); OnSyncCall(); AFTER_GL_CALL; } void fGetObjectPtrLabel(const GLvoid* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetObjectPtrLabel); mSymbols.fGetObjectPtrLabel(ptr, bufSize, length, label); OnSyncCall(); AFTER_GL_CALL; } void fGenerateMipmap(GLenum target) { BEFORE_GL_CALL; mSymbols.fGenerateMipmap(target); AFTER_GL_CALL; } void fGetProgramiv(GLuint program, GLenum pname, GLint* param) { BEFORE_GL_CALL; mSymbols.fGetProgramiv(program, pname, param); OnSyncCall(); AFTER_GL_CALL; } void fGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { BEFORE_GL_CALL; mSymbols.fGetProgramInfoLog(program, bufSize, length, infoLog); OnSyncCall(); AFTER_GL_CALL; } void fTexParameteri(GLenum target, GLenum pname, GLint param) { BEFORE_GL_CALL; mSymbols.fTexParameteri(target, pname, param); AFTER_GL_CALL; } void fTexParameteriv(GLenum target, GLenum pname, const GLint* params) { BEFORE_GL_CALL; mSymbols.fTexParameteriv(target, pname, params); AFTER_GL_CALL; } void fTexParameterf(GLenum target, GLenum pname, GLfloat param) { BEFORE_GL_CALL; mSymbols.fTexParameterf(target, pname, param); AFTER_GL_CALL; } const GLubyte* fGetString(GLenum name) { const GLubyte* result = nullptr; BEFORE_GL_CALL; result = mSymbols.fGetString(name); OnSyncCall(); AFTER_GL_CALL; return result; } void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* img) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetTexImage); mSymbols.fGetTexImage(target, level, format, type, img); OnSyncCall(); AFTER_GL_CALL; } void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv); mSymbols.fGetTexLevelParameteriv(target, level, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { BEFORE_GL_CALL; mSymbols.fGetTexParameterfv(target, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetTexParameteriv(target, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetUniformfv(GLuint program, GLint location, GLfloat* params) { BEFORE_GL_CALL; mSymbols.fGetUniformfv(program, location, params); OnSyncCall(); AFTER_GL_CALL; } void fGetUniformiv(GLuint program, GLint location, GLint* params) { BEFORE_GL_CALL; mSymbols.fGetUniformiv(program, location, params); OnSyncCall(); AFTER_GL_CALL; } void fGetUniformuiv(GLuint program, GLint location, GLuint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetUniformuiv); mSymbols.fGetUniformuiv(program, location, params); OnSyncCall(); AFTER_GL_CALL; } GLint fGetUniformLocation(GLuint programObj, const GLchar* name) { GLint retval = 0; BEFORE_GL_CALL; retval = mSymbols.fGetUniformLocation(programObj, name); OnSyncCall(); AFTER_GL_CALL; return retval; } void fGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribfv(index, pname, retval); OnSyncCall(); AFTER_GL_CALL; } void fGetVertexAttribiv(GLuint index, GLenum pname, GLint* retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribiv(index, pname, retval); OnSyncCall(); AFTER_GL_CALL; } void fGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** retval) { BEFORE_GL_CALL; mSymbols.fGetVertexAttribPointerv(index, pname, retval); OnSyncCall(); AFTER_GL_CALL; } void fHint(GLenum target, GLenum mode) { BEFORE_GL_CALL; mSymbols.fHint(target, mode); AFTER_GL_CALL; } realGLboolean fIsBuffer(GLuint buffer) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsBuffer(buffer); OnSyncCall(); AFTER_GL_CALL; return retval; } realGLboolean fIsEnabled(GLenum capability) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsEnabled(capability); AFTER_GL_CALL; return retval; } void SetEnabled(const GLenum cap, const bool val) { if (val) { fEnable(cap); } else { fDisable(cap); } } bool PushEnabled(const GLenum cap, const bool newVal) { const bool oldVal = fIsEnabled(cap); if (oldVal != newVal) { SetEnabled(cap, newVal); } return oldVal; } realGLboolean fIsProgram(GLuint program) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsProgram(program); AFTER_GL_CALL; return retval; } realGLboolean fIsShader(GLuint shader) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsShader(shader); AFTER_GL_CALL; return retval; } realGLboolean fIsTexture(GLuint texture) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsTexture(texture); AFTER_GL_CALL; return retval; } void fLineWidth(GLfloat width) { BEFORE_GL_CALL; mSymbols.fLineWidth(width); AFTER_GL_CALL; } void fLinkProgram(GLuint program) { BEFORE_GL_CALL; mSymbols.fLinkProgram(program); AFTER_GL_CALL; } void fObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fObjectLabel); mSymbols.fObjectLabel(identifier, name, length, label); AFTER_GL_CALL; } void fObjectPtrLabel(const GLvoid* ptr, GLsizei length, const GLchar* label) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fObjectPtrLabel); mSymbols.fObjectPtrLabel(ptr, length, label); AFTER_GL_CALL; } void fLoadIdentity() { BEFORE_GL_CALL; mSymbols.fLoadIdentity(); AFTER_GL_CALL; } void fLoadMatrixf(const GLfloat* matrix) { BEFORE_GL_CALL; mSymbols.fLoadMatrixf(matrix); AFTER_GL_CALL; } void fMatrixMode(GLenum mode) { BEFORE_GL_CALL; mSymbols.fMatrixMode(mode); AFTER_GL_CALL; } void fPixelStorei(GLenum pname, GLint param) { BEFORE_GL_CALL; mSymbols.fPixelStorei(pname, param); AFTER_GL_CALL; } void fTextureRangeAPPLE(GLenum target, GLsizei length, GLvoid* pointer) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pointer); BEFORE_GL_CALL; mSymbols.fTextureRangeAPPLE(target, length, pointer); AFTER_GL_CALL; } void fPointParameterf(GLenum pname, GLfloat param) { BEFORE_GL_CALL; mSymbols.fPointParameterf(pname, param); AFTER_GL_CALL; } void fPolygonMode(GLenum face, GLenum mode) { BEFORE_GL_CALL; mSymbols.fPolygonMode(face, mode); AFTER_GL_CALL; } void fPolygonOffset(GLfloat factor, GLfloat bias) { BEFORE_GL_CALL; mSymbols.fPolygonOffset(factor, bias); AFTER_GL_CALL; } void fPopDebugGroup() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fPopDebugGroup); mSymbols.fPopDebugGroup(); AFTER_GL_CALL; } void fPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fPushDebugGroup); mSymbols.fPushDebugGroup(source, id, length, message); AFTER_GL_CALL; } void fReadBuffer(GLenum mode) { BEFORE_GL_CALL; mSymbols.fReadBuffer(mode); AFTER_GL_CALL; } void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { BEFORE_GL_CALL; mSymbols.fReadPixels(x, y, width, height, format, type, pixels); OnSyncCall(); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); public: void fSampleCoverage(GLclampf value, realGLboolean invert) { BEFORE_GL_CALL; mSymbols.fSampleCoverage(value, invert); AFTER_GL_CALL; } void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) { if (mScissorRect[0] == x && mScissorRect[1] == y && mScissorRect[2] == width && mScissorRect[3] == height) { return; } mScissorRect[0] = x; mScissorRect[1] = y; mScissorRect[2] = width; mScissorRect[3] = height; BEFORE_GL_CALL; mSymbols.fScissor(x, y, width, height); AFTER_GL_CALL; } void fStencilFunc(GLenum func, GLint reference, GLuint mask) { BEFORE_GL_CALL; mSymbols.fStencilFunc(func, reference, mask); AFTER_GL_CALL; } void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint reference, GLuint mask) { BEFORE_GL_CALL; mSymbols.fStencilFuncSeparate(frontfunc, backfunc, reference, mask); AFTER_GL_CALL; } void fStencilMask(GLuint mask) { BEFORE_GL_CALL; mSymbols.fStencilMask(mask); AFTER_GL_CALL; } void fStencilMaskSeparate(GLenum face, GLuint mask) { BEFORE_GL_CALL; mSymbols.fStencilMaskSeparate(face, mask); AFTER_GL_CALL; } void fStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { BEFORE_GL_CALL; mSymbols.fStencilOp(fail, zfail, zpass); AFTER_GL_CALL; } void fStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) { BEFORE_GL_CALL; mSymbols.fStencilOpSeparate(face, sfail, dpfail, dppass); AFTER_GL_CALL; } void fTexGeni(GLenum coord, GLenum pname, GLint param) { BEFORE_GL_CALL; mSymbols.fTexGeni(coord, pname, param); AFTER_GL_CALL; } void fTexGenf(GLenum coord, GLenum pname, GLfloat param) { BEFORE_GL_CALL; mSymbols.fTexGenf(coord, pname, param); AFTER_GL_CALL; } void fTexGenfv(GLenum coord, GLenum pname, const GLfloat* params) { BEFORE_GL_CALL; mSymbols.fTexGenfv(coord, pname, params); AFTER_GL_CALL; } private: void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; mSymbols.fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } public: void fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); void fTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; mSymbols.fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } void fUniform1f(GLint location, GLfloat v0) { BEFORE_GL_CALL; mSymbols.fUniform1f(location, v0); AFTER_GL_CALL; } void fUniform1fv(GLint location, GLsizei count, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniform1fv(location, count, value); AFTER_GL_CALL; } void fUniform1i(GLint location, GLint v0) { BEFORE_GL_CALL; mSymbols.fUniform1i(location, v0); AFTER_GL_CALL; } void fUniform1iv(GLint location, GLsizei count, const GLint* value) { BEFORE_GL_CALL; mSymbols.fUniform1iv(location, count, value); AFTER_GL_CALL; } void fUniform2f(GLint location, GLfloat v0, GLfloat v1) { BEFORE_GL_CALL; mSymbols.fUniform2f(location, v0, v1); AFTER_GL_CALL; } void fUniform2fv(GLint location, GLsizei count, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniform2fv(location, count, value); AFTER_GL_CALL; } void fUniform2i(GLint location, GLint v0, GLint v1) { BEFORE_GL_CALL; mSymbols.fUniform2i(location, v0, v1); AFTER_GL_CALL; } void fUniform2iv(GLint location, GLsizei count, const GLint* value) { BEFORE_GL_CALL; mSymbols.fUniform2iv(location, count, value); AFTER_GL_CALL; } void fUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { BEFORE_GL_CALL; mSymbols.fUniform3f(location, v0, v1, v2); AFTER_GL_CALL; } void fUniform3fv(GLint location, GLsizei count, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniform3fv(location, count, value); AFTER_GL_CALL; } void fUniform3i(GLint location, GLint v0, GLint v1, GLint v2) { BEFORE_GL_CALL; mSymbols.fUniform3i(location, v0, v1, v2); AFTER_GL_CALL; } void fUniform3iv(GLint location, GLsizei count, const GLint* value) { BEFORE_GL_CALL; mSymbols.fUniform3iv(location, count, value); AFTER_GL_CALL; } void fUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { BEFORE_GL_CALL; mSymbols.fUniform4f(location, v0, v1, v2, v3); AFTER_GL_CALL; } void fUniform4fv(GLint location, GLsizei count, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniform4fv(location, count, value); AFTER_GL_CALL; } void fUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { BEFORE_GL_CALL; mSymbols.fUniform4i(location, v0, v1, v2, v3); AFTER_GL_CALL; } void fUniform4iv(GLint location, GLsizei count, const GLint* value) { BEFORE_GL_CALL; mSymbols.fUniform4iv(location, count, value); AFTER_GL_CALL; } void fUniformMatrix2fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniformMatrix2fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix2x3fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix2x3fv); mSymbols.fUniformMatrix2x3fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix2x4fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix2x4fv); mSymbols.fUniformMatrix2x4fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix3fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniformMatrix3fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix3x2fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix3x2fv); mSymbols.fUniformMatrix3x2fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix3x4fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix3x4fv); mSymbols.fUniformMatrix3x4fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix4fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; mSymbols.fUniformMatrix4fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix4x2fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix4x2fv); mSymbols.fUniformMatrix4x2fv(location, count, transpose, value); AFTER_GL_CALL; } void fUniformMatrix4x3fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniformMatrix4x3fv); mSymbols.fUniformMatrix4x3fv(location, count, transpose, value); AFTER_GL_CALL; } void fUseProgram(GLuint program) { BEFORE_GL_CALL; mSymbols.fUseProgram(program); AFTER_GL_CALL; } void fValidateProgram(GLuint program) { BEFORE_GL_CALL; mSymbols.fValidateProgram(program); AFTER_GL_CALL; } void fVertexAttribPointer(GLuint index, GLint size, GLenum type, realGLboolean normalized, GLsizei stride, const GLvoid* pointer) { BEFORE_GL_CALL; mSymbols.fVertexAttribPointer(index, size, type, normalized, stride, pointer); AFTER_GL_CALL; } void fVertexAttrib1f(GLuint index, GLfloat x) { BEFORE_GL_CALL; mSymbols.fVertexAttrib1f(index, x); AFTER_GL_CALL; } void fVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { BEFORE_GL_CALL; mSymbols.fVertexAttrib2f(index, x, y); AFTER_GL_CALL; } void fVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { BEFORE_GL_CALL; mSymbols.fVertexAttrib3f(index, x, y, z); AFTER_GL_CALL; } void fVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { BEFORE_GL_CALL; mSymbols.fVertexAttrib4f(index, x, y, z, w); AFTER_GL_CALL; } void fVertexAttrib1fv(GLuint index, const GLfloat* v) { BEFORE_GL_CALL; mSymbols.fVertexAttrib1fv(index, v); AFTER_GL_CALL; } void fVertexAttrib2fv(GLuint index, const GLfloat* v) { BEFORE_GL_CALL; mSymbols.fVertexAttrib2fv(index, v); AFTER_GL_CALL; } void fVertexAttrib3fv(GLuint index, const GLfloat* v) { BEFORE_GL_CALL; mSymbols.fVertexAttrib3fv(index, v); AFTER_GL_CALL; } void fVertexAttrib4fv(GLuint index, const GLfloat* v) { BEFORE_GL_CALL; mSymbols.fVertexAttrib4fv(index, v); AFTER_GL_CALL; } void fVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) { BEFORE_GL_CALL; mSymbols.fVertexPointer(size, type, stride, pointer); AFTER_GL_CALL; } void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) { if (mViewportRect[0] == x && mViewportRect[1] == y && mViewportRect[2] == width && mViewportRect[3] == height) { return; } mViewportRect[0] = x; mViewportRect[1] = y; mViewportRect[2] = width; mViewportRect[3] = height; BEFORE_GL_CALL; mSymbols.fViewport(x, y, width, height); AFTER_GL_CALL; } void fCompileShader(GLuint shader) { BEFORE_GL_CALL; mSymbols.fCompileShader(shader); AFTER_GL_CALL; } private: friend class SharedSurface_IOSurface; void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { BEFORE_GL_CALL; mSymbols.fCopyTexImage2D(target, level, internalformat, x, y, width, height, border); AFTER_GL_CALL; } void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { BEFORE_GL_CALL; mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); AFTER_GL_CALL; } public: void fGetShaderiv(GLuint shader, GLenum pname, GLint* param) { BEFORE_GL_CALL; mSymbols.fGetShaderiv(shader, pname, param); OnSyncCall(); AFTER_GL_CALL; } void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { BEFORE_GL_CALL; mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog); OnSyncCall(); AFTER_GL_CALL; } private: void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { MOZ_ASSERT(IsGLES()); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat); mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); OnSyncCall(); AFTER_GL_CALL; } public: void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { if (IsGLES()) { raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); } else { // Fall back to automatic values because almost all desktop hardware // supports the OpenGL standard precisions. GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, precision); } } void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source) { BEFORE_GL_CALL; mSymbols.fGetShaderSource(obj, maxLength, length, source); OnSyncCall(); AFTER_GL_CALL; } void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths) { BEFORE_GL_CALL; mSymbols.fShaderSource(shader, count, strings, lengths); AFTER_GL_CALL; } private: mutable GLuint mCachedDrawFb = 0; mutable GLuint mCachedReadFb = 0; public: bool mElideDuplicateBindFramebuffers = false; void fBindFramebuffer(const GLenum target, const GLuint fb) const { if (mElideDuplicateBindFramebuffers) { MOZ_ASSERT(mCachedDrawFb == GetIntAs(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING)); MOZ_ASSERT(mCachedReadFb == GetIntAs(LOCAL_GL_READ_FRAMEBUFFER_BINDING)); switch (target) { case LOCAL_GL_FRAMEBUFFER: if (mCachedDrawFb == fb && mCachedReadFb == fb) return; break; case LOCAL_GL_DRAW_FRAMEBUFFER: if (mCachedDrawFb == fb) return; break; case LOCAL_GL_READ_FRAMEBUFFER: if (mCachedReadFb == fb) return; break; } } BEFORE_GL_CALL; mSymbols.fBindFramebuffer(target, fb); AFTER_GL_CALL; switch (target) { case LOCAL_GL_FRAMEBUFFER: mCachedDrawFb = fb; mCachedReadFb = fb; break; case LOCAL_GL_DRAW_FRAMEBUFFER: mCachedDrawFb = fb; break; case LOCAL_GL_READ_FRAMEBUFFER: mCachedReadFb = fb; break; } } void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { BEFORE_GL_CALL; mSymbols.fBindRenderbuffer(target, renderbuffer); AFTER_GL_CALL; } GLenum fCheckFramebufferStatus(GLenum target) { GLenum retval = 0; BEFORE_GL_CALL; retval = mSymbols.fCheckFramebufferStatus(target); OnSyncCall(); AFTER_GL_CALL; return retval; } void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer) { BEFORE_GL_CALL; mSymbols.fFramebufferRenderbuffer(target, attachmentPoint, renderbufferTarget, renderbuffer); AFTER_GL_CALL; } void fFramebufferTexture2D(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level) { BEFORE_GL_CALL; mSymbols.fFramebufferTexture2D(target, attachmentPoint, textureTarget, texture, level); AFTER_GL_CALL; 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); OnSyncCall(); AFTER_GL_CALL; } void fGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* value) { BEFORE_GL_CALL; mSymbols.fGetRenderbufferParameteriv(target, pname, value); OnSyncCall(); AFTER_GL_CALL; } realGLboolean fIsFramebuffer(GLuint framebuffer) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsFramebuffer(framebuffer); OnSyncCall(); AFTER_GL_CALL; return retval; } public: realGLboolean fIsRenderbuffer(GLuint renderbuffer) { realGLboolean retval = false; BEFORE_GL_CALL; retval = mSymbols.fIsRenderbuffer(renderbuffer); OnSyncCall(); AFTER_GL_CALL; return retval; } void fRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height) { BEFORE_GL_CALL; mSymbols.fRenderbufferStorage(target, internalFormat, width, height); AFTER_GL_CALL; } private: void raw_fDepthRange(GLclampf a, GLclampf b) { MOZ_ASSERT(!IsGLES()); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDepthRange); mSymbols.fDepthRange(a, b); AFTER_GL_CALL; } void raw_fDepthRangef(GLclampf a, GLclampf b) { MOZ_ASSERT(IsGLES()); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDepthRangef); mSymbols.fDepthRangef(a, b); AFTER_GL_CALL; } void raw_fClearDepth(GLclampf v) { MOZ_ASSERT(!IsGLES()); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fClearDepth); mSymbols.fClearDepth(v); AFTER_GL_CALL; } void raw_fClearDepthf(GLclampf v) { MOZ_ASSERT(IsGLES()); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fClearDepthf); mSymbols.fClearDepthf(v); AFTER_GL_CALL; } public: void fDepthRange(GLclampf a, GLclampf b) { if (IsGLES()) { raw_fDepthRangef(a, b); } else { raw_fDepthRange(a, b); } } void fClearDepth(GLclampf v) { if (IsGLES()) { raw_fClearDepthf(v); } else { raw_fClearDepth(v); } } void* fMapBuffer(GLenum target, GLenum access) { void* ret = nullptr; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fMapBuffer); ret = mSymbols.fMapBuffer(target, access); OnSyncCall(); AFTER_GL_CALL; return ret; } realGLboolean fUnmapBuffer(GLenum target) { realGLboolean ret = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUnmapBuffer); ret = mSymbols.fUnmapBuffer(target); AFTER_GL_CALL; return ret; } private: GLuint raw_fCreateProgram() { GLuint ret = 0; BEFORE_GL_CALL; ret = mSymbols.fCreateProgram(); AFTER_GL_CALL; return ret; } GLuint raw_fCreateShader(GLenum t) { GLuint ret = 0; BEFORE_GL_CALL; ret = mSymbols.fCreateShader(t); AFTER_GL_CALL; return ret; } void raw_fGenBuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenBuffers(n, names); OnSyncCall(); AFTER_GL_CALL; } void raw_fGenFramebuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenFramebuffers(n, names); OnSyncCall(); AFTER_GL_CALL; } void raw_fGenRenderbuffers(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenRenderbuffers(n, names); OnSyncCall(); AFTER_GL_CALL; } void raw_fGenTextures(GLsizei n, GLuint* names) { BEFORE_GL_CALL; mSymbols.fGenTextures(n, names); OnSyncCall(); AFTER_GL_CALL; } public: GLuint fCreateProgram() { GLuint ret = raw_fCreateProgram(); TRACKING_CONTEXT(CreatedProgram(this, ret)); return ret; } GLuint fCreateShader(GLenum t) { GLuint ret = raw_fCreateShader(t); TRACKING_CONTEXT(CreatedShader(this, ret)); return ret; } void fGenBuffers(GLsizei n, GLuint* names) { raw_fGenBuffers(n, names); TRACKING_CONTEXT(CreatedBuffers(this, n, names)); } void fGenFramebuffers(GLsizei n, GLuint* names) { raw_fGenFramebuffers(n, names); TRACKING_CONTEXT(CreatedFramebuffers(this, n, names)); } void fGenRenderbuffers(GLsizei n, GLuint* names) { raw_fGenRenderbuffers(n, names); TRACKING_CONTEXT(CreatedRenderbuffers(this, n, names)); } void fGenTextures(GLsizei n, GLuint* names) { raw_fGenTextures(n, names); TRACKING_CONTEXT(CreatedTextures(this, n, names)); } private: void raw_fDeleteProgram(GLuint program) { BEFORE_GL_CALL; mSymbols.fDeleteProgram(program); AFTER_GL_CALL; } void raw_fDeleteShader(GLuint shader) { BEFORE_GL_CALL; mSymbols.fDeleteShader(shader); AFTER_GL_CALL; } void raw_fDeleteBuffers(GLsizei n, const GLuint* names) { BEFORE_GL_CALL; mSymbols.fDeleteBuffers(n, names); AFTER_GL_CALL; } void raw_fDeleteFramebuffers(GLsizei n, const GLuint* names) { BEFORE_GL_CALL; mSymbols.fDeleteFramebuffers(n, names); AFTER_GL_CALL; for (const auto i : IntegerRange(n)) { const auto fb = names[i]; if (mCachedDrawFb == fb) { mCachedDrawFb = 0; } if (mCachedReadFb == fb) { mCachedReadFb = 0; } } } void raw_fDeleteRenderbuffers(GLsizei n, const GLuint* names) { BEFORE_GL_CALL; mSymbols.fDeleteRenderbuffers(n, names); AFTER_GL_CALL; } void raw_fDeleteTextures(GLsizei n, const GLuint* names) { BEFORE_GL_CALL; mSymbols.fDeleteTextures(n, names); AFTER_GL_CALL; } public: void fDeleteProgram(GLuint program) { raw_fDeleteProgram(program); TRACKING_CONTEXT(DeletedProgram(this, program)); } void fDeleteShader(GLuint shader) { raw_fDeleteShader(shader); TRACKING_CONTEXT(DeletedShader(this, shader)); } void fDeleteBuffers(GLsizei n, const GLuint* names) { raw_fDeleteBuffers(n, names); TRACKING_CONTEXT(DeletedBuffers(this, n, names)); } void fDeleteFramebuffers(GLsizei n, const GLuint* names); void fDeleteRenderbuffers(GLsizei n, const GLuint* names) { raw_fDeleteRenderbuffers(n, names); TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names)); } void fDeleteTextures(GLsizei n, const GLuint* names) { #ifdef XP_MACOSX // On the Mac the call to fDeleteTextures() triggers a flush. But it // happens at the wrong time, which can lead to crashes. To work around // this we call fFlush() explicitly ourselves, before the call to // fDeleteTextures(). This fixes bug 1666293. fFlush(); #endif raw_fDeleteTextures(n, names); TRACKING_CONTEXT(DeletedTextures(this, n, names)); } // ----------------------------------------------------------------------------- // Extension ARB_sync (GL) public: GLsync fFenceSync(GLenum condition, GLbitfield flags) { GLsync ret = 0; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fFenceSync); ret = mSymbols.fFenceSync(condition, flags); OnSyncCall(); AFTER_GL_CALL; return ret; } realGLboolean fIsSync(GLsync sync) { realGLboolean ret = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsSync); ret = mSymbols.fIsSync(sync); OnSyncCall(); AFTER_GL_CALL; return ret; } void fDeleteSync(GLsync sync) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteSync); mSymbols.fDeleteSync(sync); AFTER_GL_CALL; } GLenum fClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { GLenum ret = 0; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fClientWaitSync); ret = mSymbols.fClientWaitSync(sync, flags, timeout); OnSyncCall(); AFTER_GL_CALL; return ret; } void fWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fWaitSync); mSymbols.fWaitSync(sync, flags, timeout); AFTER_GL_CALL; } void fGetInteger64v(GLenum pname, GLint64* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetInteger64v); mSymbols.fGetInteger64v(pname, params); AFTER_GL_CALL; } void fGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetSynciv); mSymbols.fGetSynciv(sync, pname, bufSize, length, values); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Extension OES_EGL_image (GLES) public: void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D); mSymbols.fEGLImageTargetTexture2D(target, image); AFTER_GL_CALL; mHeavyGLCallsSinceLastFlush = true; } void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage); mSymbols.fEGLImageTargetRenderbufferStorage(target, image); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_bind_buffer_offset public: void fBindBufferOffset(GLenum target, GLuint index, GLuint buffer, GLintptr offset) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindBufferOffset); mSymbols.fBindBufferOffset(target, index, buffer, offset); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_draw_buffers public: void fDrawBuffers(GLsizei n, const GLenum* bufs) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDrawBuffers); mSymbols.fDrawBuffers(n, bufs); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_draw_instanced public: void fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { BeforeGLDrawCall(); raw_fDrawArraysInstanced(mode, first, count, primcount); AfterGLDrawCall(); } void fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei primcount) { BeforeGLDrawCall(); raw_fDrawElementsInstanced(mode, count, type, indices, primcount); AfterGLDrawCall(); } private: void raw_fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDrawArraysInstanced); mSymbols.fDrawArraysInstanced(mode, first, count, primcount); AFTER_GL_CALL; } void raw_fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei primcount) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDrawElementsInstanced); mSymbols.fDrawElementsInstanced(mode, count, type, indices, primcount); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_framebuffer_blit public: // Draw/Read void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { BeforeGLDrawCall(); BeforeGLReadCall(); raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); AfterGLReadCall(); AfterGLDrawCall(); } private: void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBlitFramebuffer); mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_framebuffer_multisample public: void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample); mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // GL 3.0, GL ES 3.0 & EXT_gpu_shader4 public: void fGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) { ASSERT_SYMBOL_PRESENT(fGetVertexAttribIiv); BEFORE_GL_CALL; mSymbols.fGetVertexAttribIiv(index, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) { ASSERT_SYMBOL_PRESENT(fGetVertexAttribIuiv); BEFORE_GL_CALL; mSymbols.fGetVertexAttribIuiv(index, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribI4i); mSymbols.fVertexAttribI4i(index, x, y, z, w); AFTER_GL_CALL; } void fVertexAttribI4iv(GLuint index, const GLint* v) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribI4iv); mSymbols.fVertexAttribI4iv(index, v); AFTER_GL_CALL; } void fVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribI4ui); mSymbols.fVertexAttribI4ui(index, x, y, z, w); AFTER_GL_CALL; } void fVertexAttribI4uiv(GLuint index, const GLuint* v) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribI4uiv); mSymbols.fVertexAttribI4uiv(index, v); AFTER_GL_CALL; } void fVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* offset) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribIPointer); mSymbols.fVertexAttribIPointer(index, size, type, stride, offset); AFTER_GL_CALL; } void fUniform1ui(GLint location, GLuint v0) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform1ui); mSymbols.fUniform1ui(location, v0); AFTER_GL_CALL; } void fUniform2ui(GLint location, GLuint v0, GLuint v1) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform2ui); mSymbols.fUniform2ui(location, v0, v1); AFTER_GL_CALL; } void fUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform3ui); mSymbols.fUniform3ui(location, v0, v1, v2); AFTER_GL_CALL; } void fUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform4ui); mSymbols.fUniform4ui(location, v0, v1, v2, v3); AFTER_GL_CALL; } void fUniform1uiv(GLint location, GLsizei count, const GLuint* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform1uiv); mSymbols.fUniform1uiv(location, count, value); AFTER_GL_CALL; } void fUniform2uiv(GLint location, GLsizei count, const GLuint* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform2uiv); mSymbols.fUniform2uiv(location, count, value); AFTER_GL_CALL; } void fUniform3uiv(GLint location, GLsizei count, const GLuint* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform3uiv); mSymbols.fUniform3uiv(location, count, value); AFTER_GL_CALL; } void fUniform4uiv(GLint location, GLsizei count, const GLuint* value) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fUniform4uiv); mSymbols.fUniform4uiv(location, count, value); AFTER_GL_CALL; } GLint fGetFragDataLocation(GLuint program, const GLchar* name) { GLint result = 0; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetFragDataLocation); result = mSymbols.fGetFragDataLocation(program, name); OnSyncCall(); AFTER_GL_CALL; return result; } // ----------------------------------------------------------------------------- // Package XXX_instanced_arrays public: void fVertexAttribDivisor(GLuint index, GLuint divisor) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fVertexAttribDivisor); mSymbols.fVertexAttribDivisor(index, divisor); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Feature internalformat_query public: void fGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetInternalformativ); mSymbols.fGetInternalformativ(target, internalformat, pname, bufSize, params); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_query_counter /** * XXX_query_counter: * - depends on XXX_query_objects * - provide all followed entry points * - provide GL_TIMESTAMP */ public: void fQueryCounter(GLuint id, GLenum target) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fQueryCounter); mSymbols.fQueryCounter(id, target); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_query_objects /** * XXX_query_objects: * - provide all followed entry points * * XXX_occlusion_query2: * - depends on XXX_query_objects * - provide ANY_SAMPLES_PASSED * * XXX_occlusion_query_boolean: * - depends on XXX_occlusion_query2 * - provide ANY_SAMPLES_PASSED_CONSERVATIVE */ public: void fDeleteQueries(GLsizei n, const GLuint* names) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteQueries); mSymbols.fDeleteQueries(n, names); AFTER_GL_CALL; TRACKING_CONTEXT(DeletedQueries(this, n, names)); } void fGenQueries(GLsizei n, GLuint* names) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGenQueries); mSymbols.fGenQueries(n, names); AFTER_GL_CALL; TRACKING_CONTEXT(CreatedQueries(this, n, names)); } void fGetQueryiv(GLenum target, GLenum pname, GLint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryiv); mSymbols.fGetQueryiv(target, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjectuiv); mSymbols.fGetQueryObjectuiv(id, pname, params); OnSyncCall(); AFTER_GL_CALL; } realGLboolean fIsQuery(GLuint query) { realGLboolean retval = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsQuery); retval = mSymbols.fIsQuery(query); OnSyncCall(); AFTER_GL_CALL; return retval; } // ----------------------------------------------------------------------------- // Package XXX_get_query_object_i64v /** * XXX_get_query_object_i64v: * - depends on XXX_query_objects * - provide the followed entry point */ public: void fGetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjecti64v); mSymbols.fGetQueryObjecti64v(id, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjectui64v); mSymbols.fGetQueryObjectui64v(id, pname, params); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_get_query_object_iv /** * XXX_get_query_object_iv: * - depends on XXX_query_objects * - provide the followed entry point * * XXX_occlusion_query: * - depends on XXX_get_query_object_iv * - provide LOCAL_GL_SAMPLES_PASSED */ public: void fGetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetQueryObjectiv); mSymbols.fGetQueryObjectiv(id, pname, params); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // GL 4.0, GL ES 3.0, ARB_transform_feedback2, NV_transform_feedback2 public: void fBindBufferBase(GLenum target, GLuint index, GLuint buffer) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindBufferBase); mSymbols.fBindBufferBase(target, index, buffer); AFTER_GL_CALL; } void fBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindBufferRange); mSymbols.fBindBufferRange(target, index, buffer, offset, size); AFTER_GL_CALL; } void fGenTransformFeedbacks(GLsizei n, GLuint* ids) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGenTransformFeedbacks); mSymbols.fGenTransformFeedbacks(n, ids); OnSyncCall(); AFTER_GL_CALL; } void fDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteTransformFeedbacks); mSymbols.fDeleteTransformFeedbacks(n, ids); AFTER_GL_CALL; } realGLboolean fIsTransformFeedback(GLuint id) { realGLboolean result = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsTransformFeedback); result = mSymbols.fIsTransformFeedback(id); OnSyncCall(); AFTER_GL_CALL; return result; } void fBindTransformFeedback(GLenum target, GLuint id) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindTransformFeedback); mSymbols.fBindTransformFeedback(target, id); AFTER_GL_CALL; } void fBeginTransformFeedback(GLenum primitiveMode) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBeginTransformFeedback); mSymbols.fBeginTransformFeedback(primitiveMode); AFTER_GL_CALL; } void fEndTransformFeedback() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fEndTransformFeedback); mSymbols.fEndTransformFeedback(); AFTER_GL_CALL; } void fTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTransformFeedbackVaryings); mSymbols.fTransformFeedbackVaryings(program, count, varyings, bufferMode); AFTER_GL_CALL; } void fGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetTransformFeedbackVarying); mSymbols.fGetTransformFeedbackVarying(program, index, bufSize, length, size, type, name); OnSyncCall(); AFTER_GL_CALL; } void fPauseTransformFeedback() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fPauseTransformFeedback); mSymbols.fPauseTransformFeedback(); AFTER_GL_CALL; } void fResumeTransformFeedback() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fResumeTransformFeedback); mSymbols.fResumeTransformFeedback(); AFTER_GL_CALL; } void fGetIntegeri_v(GLenum param, GLuint index, GLint* values) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetIntegeri_v); mSymbols.fGetIntegeri_v(param, index, values); OnSyncCall(); AFTER_GL_CALL; } void fGetInteger64i_v(GLenum target, GLuint index, GLint64* data) { ASSERT_SYMBOL_PRESENT(fGetInteger64i_v); BEFORE_GL_CALL; mSymbols.fGetInteger64i_v(target, index, data); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Package XXX_vertex_array_object public: void fBindVertexArray(GLuint array) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindVertexArray); mSymbols.fBindVertexArray(array); AFTER_GL_CALL; } void fDeleteVertexArrays(GLsizei n, const GLuint* arrays) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteVertexArrays); mSymbols.fDeleteVertexArrays(n, arrays); AFTER_GL_CALL; } void fGenVertexArrays(GLsizei n, GLuint* arrays) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGenVertexArrays); mSymbols.fGenVertexArrays(n, arrays); AFTER_GL_CALL; } realGLboolean fIsVertexArray(GLuint array) { realGLboolean ret = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsVertexArray); ret = mSymbols.fIsVertexArray(array); OnSyncCall(); AFTER_GL_CALL; return ret; } // ----------------------------------------------------------------------------- // Extension NV_fence public: void fGenFences(GLsizei n, GLuint* fences) { ASSERT_SYMBOL_PRESENT(fGenFences); BEFORE_GL_CALL; mSymbols.fGenFences(n, fences); AFTER_GL_CALL; } void fDeleteFences(GLsizei n, const GLuint* fences) { ASSERT_SYMBOL_PRESENT(fDeleteFences); BEFORE_GL_CALL; mSymbols.fDeleteFences(n, fences); AFTER_GL_CALL; } void fSetFence(GLuint fence, GLenum condition) { ASSERT_SYMBOL_PRESENT(fSetFence); BEFORE_GL_CALL; mSymbols.fSetFence(fence, condition); AFTER_GL_CALL; } realGLboolean fTestFence(GLuint fence) { realGLboolean ret = false; ASSERT_SYMBOL_PRESENT(fTestFence); BEFORE_GL_CALL; ret = mSymbols.fTestFence(fence); OnSyncCall(); AFTER_GL_CALL; return ret; } void fFinishFence(GLuint fence) { ASSERT_SYMBOL_PRESENT(fFinishFence); BEFORE_GL_CALL; mSymbols.fFinishFence(fence); OnSyncCall(); AFTER_GL_CALL; } realGLboolean fIsFence(GLuint fence) { realGLboolean ret = false; ASSERT_SYMBOL_PRESENT(fIsFence); BEFORE_GL_CALL; ret = mSymbols.fIsFence(fence); OnSyncCall(); AFTER_GL_CALL; return ret; } void fGetFenceiv(GLuint fence, GLenum pname, GLint* params) { ASSERT_SYMBOL_PRESENT(fGetFenceiv); BEFORE_GL_CALL; mSymbols.fGetFenceiv(fence, pname, params); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Extension NV_texture_barrier public: void fTextureBarrier() { ASSERT_SYMBOL_PRESENT(fTextureBarrier); BEFORE_GL_CALL; mSymbols.fTextureBarrier(); AFTER_GL_CALL; } // Core GL & Extension ARB_copy_buffer public: void fCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fCopyBufferSubData); mSymbols.fCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Core GL & Extension ARB_map_buffer_range public: void* fMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { void* data = nullptr; ASSERT_SYMBOL_PRESENT(fMapBufferRange); BEFORE_GL_CALL; data = mSymbols.fMapBufferRange(target, offset, length, access); OnSyncCall(); AFTER_GL_CALL; return data; } void fFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { ASSERT_SYMBOL_PRESENT(fFlushMappedBufferRange); BEFORE_GL_CALL; mSymbols.fFlushMappedBufferRange(target, offset, length); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Core GL & Extension ARB_sampler_objects public: void fGenSamplers(GLsizei count, GLuint* samplers) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGenSamplers); mSymbols.fGenSamplers(count, samplers); AFTER_GL_CALL; } void fDeleteSamplers(GLsizei count, const GLuint* samplers) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteSamplers); mSymbols.fDeleteSamplers(count, samplers); AFTER_GL_CALL; } realGLboolean fIsSampler(GLuint sampler) { realGLboolean result = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fIsSampler); result = mSymbols.fIsSampler(sampler); OnSyncCall(); AFTER_GL_CALL; return result; } void fBindSampler(GLuint unit, GLuint sampler) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fBindSampler); mSymbols.fBindSampler(unit, sampler); AFTER_GL_CALL; } void fSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fSamplerParameteri); mSymbols.fSamplerParameteri(sampler, pname, param); AFTER_GL_CALL; } void fSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fSamplerParameteriv); mSymbols.fSamplerParameteriv(sampler, pname, param); AFTER_GL_CALL; } void fSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fSamplerParameterf); mSymbols.fSamplerParameterf(sampler, pname, param); AFTER_GL_CALL; } void fSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fSamplerParameterfv); mSymbols.fSamplerParameterfv(sampler, pname, param); AFTER_GL_CALL; } void fGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetSamplerParameteriv); mSymbols.fGetSamplerParameteriv(sampler, pname, params); AFTER_GL_CALL; } void fGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetSamplerParameterfv); mSymbols.fGetSamplerParameterfv(sampler, pname, params); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Core GL & Extension ARB_uniform_buffer_object public: void fGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) { ASSERT_SYMBOL_PRESENT(fGetUniformIndices); BEFORE_GL_CALL; mSymbols.fGetUniformIndices(program, uniformCount, uniformNames, uniformIndices); OnSyncCall(); AFTER_GL_CALL; } void fGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) { ASSERT_SYMBOL_PRESENT(fGetActiveUniformsiv); BEFORE_GL_CALL; mSymbols.fGetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); OnSyncCall(); AFTER_GL_CALL; } GLuint fGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) { GLuint result = 0; ASSERT_SYMBOL_PRESENT(fGetUniformBlockIndex); BEFORE_GL_CALL; result = mSymbols.fGetUniformBlockIndex(program, uniformBlockName); OnSyncCall(); AFTER_GL_CALL; return result; } void fGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) { ASSERT_SYMBOL_PRESENT(fGetActiveUniformBlockiv); BEFORE_GL_CALL; mSymbols.fGetActiveUniformBlockiv(program, uniformBlockIndex, pname, params); OnSyncCall(); AFTER_GL_CALL; } void fGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) { ASSERT_SYMBOL_PRESENT(fGetActiveUniformBlockName); BEFORE_GL_CALL; mSymbols.fGetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName); OnSyncCall(); AFTER_GL_CALL; } void fUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { ASSERT_SYMBOL_PRESENT(fUniformBlockBinding); BEFORE_GL_CALL; mSymbols.fUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // Core GL 4.2, GL ES 3.0 & Extension ARB_texture_storage/EXT_texture_storage void fTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTexStorage2D); mSymbols.fTexStorage2D(target, levels, internalformat, width, height); OnSyncCall(); AFTER_GL_CALL; } void fTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTexStorage3D); mSymbols.fTexStorage3D(target, levels, internalformat, width, height, depth); OnSyncCall(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // 3D Textures void fTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* data) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTexImage3D); mSymbols.fTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, data); OnSyncCall(); AFTER_GL_CALL; } void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTexSubImage3D); mSymbols.fTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); OnSyncCall(); AFTER_GL_CALL; } void fCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { BeforeGLReadCall(); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fCopyTexSubImage3D); mSymbols.fCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); AFTER_GL_CALL; AfterGLReadCall(); } void fCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fCompressedTexImage3D); mSymbols.fCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); AFTER_GL_CALL; } void fCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fCompressedTexSubImage3D); mSymbols.fCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // GL3+, ES3+ const GLubyte* fGetStringi(GLenum name, GLuint index) { const GLubyte* ret = nullptr; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fGetStringi); ret = mSymbols.fGetStringi(name, index); OnSyncCall(); AFTER_GL_CALL; return ret; } // ----------------------------------------------------------------------------- // APPLE_framebuffer_multisample void fResolveMultisampleFramebufferAPPLE() { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE); mSymbols.fResolveMultisampleFramebufferAPPLE(); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // APPLE_fence void fFinishObjectAPPLE(GLenum object, GLint name) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fFinishObjectAPPLE); mSymbols.fFinishObjectAPPLE(object, name); AFTER_GL_CALL; } realGLboolean fTestObjectAPPLE(GLenum object, GLint name) { realGLboolean ret = false; BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fTestObjectAPPLE); ret = mSymbols.fTestObjectAPPLE(object, name); AFTER_GL_CALL; return ret; } // ----------------------------------------------------------------------------- // prim_restart void fPrimitiveRestartIndex(GLuint index) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fPrimitiveRestartIndex); mSymbols.fPrimitiveRestartIndex(index); AFTER_GL_CALL; } // ----------------------------------------------------------------------------- // multiview void fFramebufferTextureMultiview(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews) const { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fFramebufferTextureMultiview); mSymbols.fFramebufferTextureMultiview(target, attachment, texture, level, baseViewIndex, numViews); AFTER_GL_CALL; } // - // draw_buffers_indexed void fBlendEquationSeparatei(GLuint i, GLenum modeRGB, GLenum modeAlpha) const { BEFORE_GL_CALL; mSymbols.fBlendEquationSeparatei(i, modeRGB, modeAlpha); AFTER_GL_CALL; } void fBlendFuncSeparatei(GLuint i, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) const { BEFORE_GL_CALL; mSymbols.fBlendFuncSeparatei(i, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); AFTER_GL_CALL; } void fColorMaski(GLuint i, realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha) const { BEFORE_GL_CALL; mSymbols.fColorMaski(i, red, green, blue, alpha); AFTER_GL_CALL; } void fDisablei(GLenum capability, GLuint i) const { BEFORE_GL_CALL; mSymbols.fDisablei(capability, i); AFTER_GL_CALL; } void fEnablei(GLenum capability, GLuint i) const { BEFORE_GL_CALL; mSymbols.fEnablei(capability, i); AFTER_GL_CALL; } // - void fProvokingVertex(GLenum mode) const { BEFORE_GL_CALL; mSymbols.fProvokingVertex(mode); AFTER_GL_CALL; } // - #undef BEFORE_GL_CALL #undef AFTER_GL_CALL #undef ASSERT_SYMBOL_PRESENT // #undef TRACKING_CONTEXT // Needed in GLContext.cpp #undef ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL // ----------------------------------------------------------------------------- // Constructor protected: explicit GLContext(const GLContextDesc&, GLContext* sharedContext = nullptr, bool canUseTLSIsCurrent = false); // ----------------------------------------------------------------------------- // Destructor public: virtual ~GLContext(); // Mark this context as destroyed. This will nullptr out all // the GL function pointers! void MarkDestroyed(); protected: virtual void OnMarkDestroyed() {} // ----------------------------------------------------------------------------- // Everything that isn't standard GL APIs protected: typedef gfx::SurfaceFormat SurfaceFormat; public: virtual void ReleaseSurface() {} bool IsDestroyed() const { // MarkDestroyed will mark all these as null. return mContextLost && mSymbols.fUseProgram == nullptr; } GLContext* GetSharedContext() { return mSharedContext; } /** * Returns true if the thread on which this context was created is the * currently executing thread. */ bool IsValidOwningThread() const; static void PlatformStartup(); public: /** * If this context wraps a double-buffered target, swap the back * and front buffers. It should be assumed that after a swap, the * contents of the new back buffer are undefined. */ virtual bool SwapBuffers() { return false; } /** * Stores a damage region (in origin bottom left coordinates), which * makes the next SwapBuffers call do eglSwapBuffersWithDamage if supported. * * Note that even if only part of the context is damaged, the entire buffer * needs to be filled with up-to-date contents. This region is only a hint * telling the system compositor which parts of the buffer were updated. */ virtual void SetDamage(const nsIntRegion& aDamageRegion) {} /** * Get the buffer age. If it returns 0, that indicates the buffer state is * unknown and the entire frame should be redrawn. */ virtual GLint GetBufferAge() const { return 0; } /** * Defines a two-dimensional texture image for context target surface */ virtual bool BindTexImage() { return false; } /* * Releases a color buffer that is being used as a texture */ virtual bool ReleaseTexImage() { return false; } virtual Maybe GetSymbolLoader() const = 0; void BindFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); MOZ_GL_ASSERT(this, !fb || fIsFramebuffer(fb)); } void BindDrawFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); } void BindReadFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); } GLuint GetDrawFB() const { return GetIntAs(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT); } GLuint GetReadFB() const { auto bindEnum = LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT; if (!IsSupported(GLFeature::split_framebuffer)) { bindEnum = LOCAL_GL_FRAMEBUFFER_BINDING; } return GetIntAs(bindEnum); } GLuint GetFB() const { const auto ret = GetDrawFB(); MOZ_ASSERT(ret == GetReadFB()); return ret; } private: void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { switch (precisiontype) { case LOCAL_GL_LOW_FLOAT: case LOCAL_GL_MEDIUM_FLOAT: case LOCAL_GL_HIGH_FLOAT: // Assume IEEE 754 precision range[0] = 127; range[1] = 127; *precision = 23; break; case LOCAL_GL_LOW_INT: case LOCAL_GL_MEDIUM_INT: case LOCAL_GL_HIGH_INT: // Some (most) hardware only supports single-precision floating-point // numbers, which can accurately represent integers up to +/-16777216 range[0] = 24; range[1] = 24; *precision = 0; break; } } public: virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; } virtual GLenum GetPreferredEGLImageTextureTarget() const { #ifdef MOZ_WAYLAND return LOCAL_GL_TEXTURE_2D; #else return IsExtensionSupported(OES_EGL_image_external) ? LOCAL_GL_TEXTURE_EXTERNAL : LOCAL_GL_TEXTURE_2D; #endif } virtual bool RenewSurface(widget::CompositorWidget* aWidget) { return false; } // Shared code for GL extensions and GLX extensions. static bool ListHasExtension(const GLubyte* extensions, const char* extension); public: enum { DebugFlagEnabled = 1 << 0, DebugFlagTrace = 1 << 1, DebugFlagAbortOnError = 1 << 2 }; const uint8_t mDebugFlags; static uint8_t ChooseDebugFlags(CreateContextFlags createFlags); protected: RefPtr mSharedContext; public: // The thread id which this context was created. Maybe mOwningThreadId; protected: GLContextSymbols mSymbols = {}; UniquePtr mBlitHelper; UniquePtr mReadTexImageHelper; public: GLBlitHelper* BlitHelper(); GLReadTexImageHelper* ReadTexImageHelper(); // Assumes shares are created by all sharing with the same global context. bool SharesWith(const GLContext* other) const { MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext); MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext); MOZ_ASSERT(!this->mSharedContext || !other->mSharedContext || this->mSharedContext == other->mSharedContext); const GLContext* thisShared = this->mSharedContext ? this->mSharedContext : this; const GLContext* otherShared = other->mSharedContext ? other->mSharedContext : other; return thisShared == otherShared; } bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); // Does not check completeness. void AttachBuffersToFB(GLuint colorTex, GLuint colorRB, GLuint depthRB, GLuint stencilRB, GLuint fb, GLenum target = LOCAL_GL_TEXTURE_2D); // Passing null is fine if the value you'd get is 0. bool AssembleOffscreenFBs(const GLuint colorMSRB, const GLuint depthRB, const GLuint stencilRB, const GLuint texture, GLuint* drawFB, GLuint* readFB); protected: SharedSurface* mLockedSurface = nullptr; public: void LockSurface(SharedSurface* surf) { mLockedSurface = surf; } void UnlockSurface(SharedSurface* surf) { MOZ_ASSERT(mLockedSurface == surf); mLockedSurface = nullptr; } SharedSurface* GetLockedSurface() const { return mLockedSurface; } bool IsOffscreen() const { return mDesc.isOffscreen; } bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; virtual bool Init(); private: bool InitImpl(); void LoadMoreSymbols(const SymbolLoader& loader); bool LoadExtSymbols(const SymbolLoader& loader, const SymLoadStruct* list, GLExtensions ext); bool LoadFeatureSymbols(const SymbolLoader& loader, const SymLoadStruct* list, GLFeature feature); protected: void InitExtensions(); GLint mViewportRect[4] = {}; GLint mScissorRect[4] = {}; uint32_t mMaxTexOrRbSize = 0; GLint mMaxTextureSize = 0; GLint mMaxCubeMapTextureSize = 0; GLint mMaxRenderbufferSize = 0; GLint mMaxViewportDims[2] = {}; GLsizei mMaxSamples = 0; bool mNeedsTextureSizeChecks = false; bool mNeedsFlushBeforeDeleteFB = false; bool mTextureAllocCrashesOnMapFailure = false; bool mNeedsCheckAfterAttachTextureToFb = false; const bool mWorkAroundDriverBugs; mutable uint64_t mSyncGLCallCount = 0; bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const { if (mNeedsTextureSizeChecks) { // some drivers incorrectly handle some large texture sizes that are below // the max texture size that they report. So we check ourselves against // our own values (mMax[CubeMap]TextureSize). see bug 737182 for Mac Intel // 2D textures see bug 684882 for Mac Intel cube map textures see bug // 814716 for Mesa Nouveau GLsizei maxSize = target == LOCAL_GL_TEXTURE_CUBE_MAP || (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? mMaxCubeMapTextureSize : mMaxTextureSize; return width <= maxSize && height <= maxSize; } return true; } public: auto MaxSamples() const { return uint32_t(mMaxSamples); } auto MaxTextureSize() const { return uint32_t(mMaxTextureSize); } auto MaxRenderbufferSize() const { return uint32_t(mMaxRenderbufferSize); } auto MaxTexOrRbSize() const { return mMaxTexOrRbSize; } #ifdef MOZ_GL_DEBUG_BUILD void CreatedProgram(GLContext* aOrigin, GLuint aName); void CreatedShader(GLContext* aOrigin, GLuint aName); void CreatedBuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); void CreatedQueries(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); void CreatedTextures(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); void CreatedFramebuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); void CreatedRenderbuffers(GLContext* aOrigin, GLsizei aCount, GLuint* aNames); void DeletedProgram(GLContext* aOrigin, GLuint aName); void DeletedShader(GLContext* aOrigin, GLuint aName); void DeletedBuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); void DeletedQueries(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); void DeletedTextures(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); void DeletedFramebuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); void DeletedRenderbuffers(GLContext* aOrigin, GLsizei aCount, const GLuint* aNames); void SharedContextDestroyed(GLContext* aChild); void ReportOutstandingNames(); struct NamedResource { NamedResource() : origin(nullptr), name(0), originDeleted(false) {} NamedResource(GLContext* aOrigin, GLuint aName) : origin(aOrigin), name(aName), originDeleted(false) {} GLContext* origin; GLuint name; bool originDeleted; // for sorting bool operator<(const NamedResource& aOther) const { if (intptr_t(origin) < intptr_t(aOther.origin)) return true; if (name < aOther.name) return true; return false; } bool operator==(const NamedResource& aOther) const { return origin == aOther.origin && name == aOther.name && originDeleted == aOther.originDeleted; } }; nsTArray mTrackedPrograms; nsTArray mTrackedShaders; nsTArray mTrackedTextures; nsTArray mTrackedFramebuffers; nsTArray mTrackedRenderbuffers; nsTArray mTrackedBuffers; nsTArray mTrackedQueries; #endif protected: bool mHeavyGLCallsSinceLastFlush = false; public: void FlushIfHeavyGLCallsSinceLastFlush(); static bool ShouldSpew(); static bool ShouldDumpExts(); // -- void TexParams_SetClampNoMips(GLenum target = LOCAL_GL_TEXTURE_2D) { fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); } // -- GLuint CreateFramebuffer() { GLuint x = 0; fGenFramebuffers(1, &x); return x; } GLuint CreateRenderbuffer() { GLuint x = 0; fGenRenderbuffers(1, &x); return x; } GLuint CreateTexture() { GLuint x = 0; fGenTextures(1, &x); return x; } void DeleteFramebuffer(const GLuint x) { fDeleteFramebuffers(1, &x); } void DeleteRenderbuffer(const GLuint x) { fDeleteRenderbuffers(1, &x); } void DeleteTexture(const GLuint x) { fDeleteTextures(1, &x); } }; bool DoesStringMatch(const char* aString, const char* aWantedString); void SplitByChar(const nsACString& str, const char delim, std::vector* const out); template bool MarkBitfieldByString(const nsACString& str, const char* const (&markStrList)[N], std::bitset* 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 void MarkBitfieldByStrings(const std::vector& strList, bool dumpStrings, const char* const (&markStrList)[N], std::bitset* const out_markList) { for (auto itr = strList.begin(); itr != strList.end(); ++itr) { const nsACString& str = *itr; const bool wasMarked = MarkBitfieldByString(str, markStrList, out_markList); if (dumpStrings) printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : ""); } } // - class Renderbuffer final { public: const WeakPtr weakGl; const GLuint name; private: static GLuint Create(GLContext& gl) { GLuint ret = 0; gl.fGenRenderbuffers(1, &ret); return ret; } public: explicit Renderbuffer(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} ~Renderbuffer() { const RefPtr gl = weakGl.get(); if (!gl || !gl->MakeCurrent()) return; gl->fDeleteRenderbuffers(1, &name); } }; // - class Texture final { public: const WeakPtr weakGl; const GLuint name; private: static GLuint Create(GLContext& gl) { GLuint ret = 0; gl.fGenTextures(1, &ret); return ret; } public: explicit Texture(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} ~Texture() { const RefPtr gl = weakGl.get(); if (!gl || !gl->MakeCurrent()) return; gl->fDeleteTextures(1, &name); } }; /** * Helper function that creates a 2D texture aSize.width x aSize.height with * storage type specified by aFormats. Returns GL texture object id. * * See mozilla::gl::CreateTexture. */ UniquePtr CreateTexture(GLContext&, const gfx::IntSize& size); /** * Helper function that calculates the number of bytes required per * texel for a texture from its format and type. */ uint32_t GetBytesPerTexel(GLenum format, GLenum type); void MesaMemoryLeakWorkaround(); } /* namespace gl */ } /* namespace mozilla */ #endif /* GLCONTEXT_H_ */