diff options
Diffstat (limited to 'gfx/gl/GLContext.h')
-rw-r--r-- | gfx/gl/GLContext.h | 3880 |
1 files changed, 3880 insertions, 0 deletions
diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h new file mode 100644 index 0000000000..d88b96019f --- /dev/null +++ b/gfx/gl/GLContext.h @@ -0,0 +1,3880 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GLCONTEXT_H_ +#define GLCONTEXT_H_ + +#include <bitset> +#include <stdint.h> +#include <stdio.h> +#include <stack> +#include <vector> + +#ifdef DEBUG +# include <string.h> +#endif + +#ifdef GetClassName +# undef GetClassName +#endif + +// Define MOZ_GL_DEBUG_BUILD unconditionally to enable GL debugging in opt +// builds. +#ifdef DEBUG +# define MOZ_GL_DEBUG_BUILD 1 +#endif + +#include "mozilla/IntegerRange.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/ThreadLocal.h" + +#include "MozFramebuffer.h" +#include "nsTArray.h" +#include "GLConsts.h" +#include "GLDefs.h" +#include "GLTypes.h" +#include "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<GLContext> 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 <profile> parameter"); + MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile"); + MOZ_ASSERT(mVersion != 0, "unknown context version"); + + if (version > mVersion) { + return false; + } + + return profile == mProfile; + } + + /** + * Return the version of the context. + * Example : + * If this a OpenGL 2.1, that will return 210 + */ + inline uint32_t Version() const { return mVersion; } + + inline uint32_t ShadingLanguageVersion() const { + return mShadingLanguageVersion; + } + + GLVendor Vendor() const { return mVendor; } + GLRenderer Renderer() const { return mRenderer; } + bool IsMesa() const { return mIsMesa; } + + bool IsContextLost() const { return mContextLost; } + + bool CheckContextLost() const { + mTopError = GetError(); + return IsContextLost(); + } + + bool HasPBOState() const { return (!IsGLES() || Version() >= 300); } + + /** + * If this context is double-buffered, returns TRUE. + */ + virtual bool IsDoubleBuffered() const { return false; } + + virtual GLContextType GetContextType() const = 0; + + virtual bool IsCurrentImpl() const = 0; + virtual bool MakeCurrentImpl() const = 0; + + bool IsCurrent() const { + if (mImplicitMakeCurrent) return MakeCurrent(); + + return IsCurrentImpl(); + } + + bool MakeCurrent(bool aForce = false) const; + + /** + * Get the default framebuffer for this context. + */ + UniquePtr<MozFramebuffer> mOffscreenDefaultFb; + + bool CreateOffscreenDefaultFb(const gfx::IntSize& size); + + virtual GLuint GetDefaultFramebuffer() { + if (mOffscreenDefaultFb) { + return mOffscreenDefaultFb->mFB; + } + return 0; + } + + /** + * mVersion store the OpenGL's version, multiplied by 100. For example, if + * the context is an OpenGL 2.1 context, mVersion value will be 210. + */ + uint32_t mVersion = 0; + ContextProfile mProfile = ContextProfile::Unknown; + + uint32_t mShadingLanguageVersion = 0; + + GLVendor mVendor = GLVendor::Other; + GLRenderer mRenderer = GLRenderer::Other; + bool mIsMesa = false; + + // ----------------------------------------------------------------------------- + // Extensions management + /** + * This mechanism is designed to know if an extension is supported. In the + * long term, we would like to only use the extension group queries XXX_* to + * have full compatibility with context version and profiles (especialy the + * core that officialy don't bring any extensions). + */ + + /** + * Known GL extensions that can be queried by + * IsExtensionSupported. The results of this are cached, and as + * such it's safe to use this even in performance critical code. + * If you add to this array, remember to add to the string names + * in GLContext.cpp. + */ + enum GLExtensions { + Extension_None = 0, + AMD_compressed_ATC_texture, + ANGLE_depth_texture, + ANGLE_framebuffer_blit, + ANGLE_framebuffer_multisample, + ANGLE_instanced_arrays, + ANGLE_multiview, + ANGLE_provoking_vertex, + ANGLE_texture_compression_dxt3, + ANGLE_texture_compression_dxt5, + ANGLE_timer_query, + APPLE_client_storage, + APPLE_fence, + APPLE_framebuffer_multisample, + APPLE_sync, + APPLE_texture_range, + APPLE_vertex_array_object, + ARB_ES2_compatibility, + ARB_ES3_compatibility, + ARB_color_buffer_float, + ARB_compatibility, + ARB_copy_buffer, + ARB_depth_texture, + ARB_draw_buffers, + ARB_draw_instanced, + ARB_framebuffer_object, + ARB_framebuffer_sRGB, + ARB_geometry_shader4, + ARB_half_float_pixel, + ARB_instanced_arrays, + ARB_internalformat_query, + ARB_invalidate_subdata, + ARB_map_buffer_range, + ARB_occlusion_query2, + ARB_pixel_buffer_object, + ARB_provoking_vertex, + ARB_robust_buffer_access_behavior, + ARB_robustness, + ARB_sampler_objects, + ARB_seamless_cube_map, + ARB_shader_texture_lod, + ARB_sync, + ARB_texture_compression, + ARB_texture_compression_bptc, + ARB_texture_compression_rgtc, + ARB_texture_float, + ARB_texture_non_power_of_two, + ARB_texture_rectangle, + ARB_texture_rg, + ARB_texture_storage, + ARB_texture_swizzle, + ARB_timer_query, + ARB_transform_feedback2, + ARB_uniform_buffer_object, + ARB_vertex_array_object, + CHROMIUM_color_buffer_float_rgb, + CHROMIUM_color_buffer_float_rgba, + EXT_bgra, + EXT_blend_minmax, + EXT_color_buffer_float, + EXT_color_buffer_half_float, + EXT_copy_texture, + EXT_disjoint_timer_query, + EXT_draw_buffers, + EXT_draw_buffers2, + EXT_draw_instanced, + EXT_float_blend, + EXT_frag_depth, + EXT_framebuffer_blit, + EXT_framebuffer_multisample, + EXT_framebuffer_object, + EXT_framebuffer_sRGB, + EXT_gpu_shader4, + EXT_map_buffer_range, + EXT_multisampled_render_to_texture, + EXT_occlusion_query_boolean, + EXT_packed_depth_stencil, + EXT_provoking_vertex, + EXT_read_format_bgra, + EXT_robustness, + EXT_sRGB, + EXT_sRGB_write_control, + EXT_shader_texture_lod, + EXT_texture_compression_bptc, + EXT_texture_compression_dxt1, + EXT_texture_compression_rgtc, + EXT_texture_compression_s3tc, + EXT_texture_compression_s3tc_srgb, + EXT_texture_filter_anisotropic, + EXT_texture_format_BGRA8888, + EXT_texture_norm16, + EXT_texture_sRGB, + EXT_texture_storage, + EXT_timer_query, + EXT_transform_feedback, + EXT_unpack_subimage, + IMG_read_format, + IMG_texture_compression_pvrtc, + IMG_texture_npot, + KHR_debug, + KHR_parallel_shader_compile, + KHR_robust_buffer_access_behavior, + KHR_robustness, + KHR_texture_compression_astc_hdr, + KHR_texture_compression_astc_ldr, + NV_draw_instanced, + NV_fence, + NV_framebuffer_blit, + NV_geometry_program4, + NV_half_float, + NV_instanced_arrays, + NV_primitive_restart, + NV_texture_barrier, + NV_transform_feedback, + NV_transform_feedback2, + OES_EGL_image, + OES_EGL_image_external, + OES_EGL_sync, + OES_compressed_ETC1_RGB8_texture, + OES_depth24, + OES_depth32, + OES_depth_texture, + OES_draw_buffers_indexed, + OES_element_index_uint, + OES_fbo_render_mipmap, + OES_framebuffer_object, + OES_packed_depth_stencil, + OES_rgb8_rgba8, + OES_standard_derivatives, + OES_stencil8, + OES_texture_3D, + OES_texture_float, + OES_texture_float_linear, + OES_texture_half_float, + OES_texture_half_float_linear, + OES_texture_npot, + OES_vertex_array_object, + OVR_multiview2, + Extensions_Max, + Extensions_End + }; + + bool IsExtensionSupported(GLExtensions aKnownExtension) const { + return mAvailableExtensions[aKnownExtension]; + } + + protected: + void MarkExtensionUnsupported(GLExtensions aKnownExtension) { + mAvailableExtensions[aKnownExtension] = 0; + } + + void MarkExtensionSupported(GLExtensions aKnownExtension) { + mAvailableExtensions[aKnownExtension] = 1; + } + + std::bitset<Extensions_Max> mAvailableExtensions; + + // ----------------------------------------------------------------------------- + // Feature queries + /* + * This mecahnism introduces a new way to check if a OpenGL feature is + * supported, regardless of whether it is supported by an extension or + * natively by the context version/profile + */ + public: + bool IsSupported(GLFeature feature) const { + return mAvailableFeatures[size_t(feature)]; + } + + static const char* GetFeatureName(GLFeature feature); + + private: + std::bitset<size_t(GLFeature::EnumMax)> mAvailableFeatures; + + /** + * Init features regarding OpenGL extension and context version and profile + */ + void InitFeatures(); + + /** + * Mark the feature and associated extensions as unsupported + */ + void MarkUnsupported(GLFeature feature); + + /** + * Is this feature supported using the core (unsuffixed) symbols? + */ + bool IsFeatureProvidedByCoreSymbols(GLFeature feature); + + // ----------------------------------------------------------------------------- + // Error handling + + private: + mutable bool mContextLost = false; + mutable GLenum mTopError = 0; + + protected: + void OnContextLostError() const; + + public: + static std::string GLErrorToString(GLenum aError); + + static bool IsBadCallError(const GLenum err) { + return !(err == 0 || err == LOCAL_GL_CONTEXT_LOST); + } + + class LocalErrorScope; + + private: + mutable std::stack<const LocalErrorScope*> mLocalErrorScopeStack; + mutable UniquePtr<LocalErrorScope> mDebugErrorScope; + + //////////////////////////////////// + // Use this safer option. + + public: + class LocalErrorScope { + const GLContext& mGL; + GLenum mOldTop; + bool mHasBeenChecked; + + public: + explicit LocalErrorScope(const GLContext& gl) + : mGL(gl), mHasBeenChecked(false) { + mGL.mLocalErrorScopeStack.push(this); + mOldTop = mGL.GetError(); + } + + /// Never returns CONTEXT_LOST. + GLenum GetError() { + MOZ_ASSERT(!mHasBeenChecked); + mHasBeenChecked = true; + + const auto ret = mGL.GetError(); + if (ret == LOCAL_GL_CONTEXT_LOST) return 0; + return ret; + } + + ~LocalErrorScope() { + MOZ_ASSERT(mHasBeenChecked); + + MOZ_ASSERT(!IsBadCallError(mGL.GetError())); + + MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this); + mGL.mLocalErrorScopeStack.pop(); + + mGL.mTopError = mOldTop; + } + }; + + // - + + bool GetPotentialInteger(GLenum pname, GLint* param) { + LocalErrorScope localError(*this); + + fGetIntegerv(pname, param); + + GLenum err = localError.GetError(); + MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_INVALID_ENUM); + return err == LOCAL_GL_NO_ERROR; + } + + void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message); + + private: + static void GLAPIENTRY StaticDebugCallback(GLenum source, GLenum type, + GLuint id, GLenum severity, + GLsizei length, + const GLchar* message, + const GLvoid* userParam); + + // ----------------------------------------------------------------------------- + // Debugging implementation + private: +#ifndef MOZ_FUNCTION_NAME +# ifdef __GNUC__ +# define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ +# elif defined(_MSC_VER) +# define MOZ_FUNCTION_NAME __FUNCTION__ +# else +# define MOZ_FUNCTION_NAME \ + __func__ // defined in C99, supported in various C++ compilers. Just raw + // function name. +# endif +#endif + +#ifdef MOZ_WIDGET_ANDROID +// Record the name of the GL call for better hang stacks on Android. +# define ANDROID_ONLY_PROFILER_LABEL AUTO_PROFILER_LABEL(__func__, GRAPHICS); +#else +# define ANDROID_ONLY_PROFILER_LABEL +#endif + +#define BEFORE_GL_CALL \ + ANDROID_ONLY_PROFILER_LABEL \ + if (MOZ_LIKELY(BeforeGLCall(MOZ_FUNCTION_NAME))) { \ + do { \ + } while (0) + +#define AFTER_GL_CALL \ + AfterGLCall(MOZ_FUNCTION_NAME); \ + } \ + do { \ + } while (0) + + void BeforeGLCall_Debug(const char* funcName) const; + void AfterGLCall_Debug(const char* funcName) const; + static void OnImplicitMakeCurrentFailure(const char* funcName); + + bool BeforeGLCall(const char* const funcName) const { + if (mImplicitMakeCurrent) { + if (MOZ_UNLIKELY(!MakeCurrent())) { + if (!mContextLost) { + OnImplicitMakeCurrentFailure(funcName); + } + return false; + } + } + MOZ_GL_ASSERT(this, IsCurrentImpl()); + + if (MOZ_UNLIKELY(mDebugFlags)) { + BeforeGLCall_Debug(funcName); + } + return true; + } + + void AfterGLCall(const char* const funcName) const { + if (MOZ_UNLIKELY(mDebugFlags)) { + AfterGLCall_Debug(funcName); + } + } + + GLContext* TrackingContext() { + GLContext* tip = this; + while (tip->mSharedContext) tip = tip->mSharedContext; + return tip; + } + + static void AssertNotPassingStackBufferToTheGL(const void* ptr); + +#ifdef MOZ_GL_DEBUG_BUILD + +# define TRACKING_CONTEXT(a) \ + do { \ + TrackingContext()->a; \ + } while (0) + +# define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ + AssertNotPassingStackBufferToTheGL(ptr) + +# define ASSERT_SYMBOL_PRESENT(func) \ + do { \ + MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, \ + "Mismatched symbol check."); \ + if (MOZ_UNLIKELY(!mSymbols.func)) { \ + printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", \ + #func); \ + MOZ_CRASH("GFX: Uninitialized GL function"); \ + } \ + } while (0) + +#else // ifdef MOZ_GL_DEBUG_BUILD + +# define TRACKING_CONTEXT(a) \ + do { \ + } while (0) +# define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) \ + do { \ + } while (0) +# define ASSERT_SYMBOL_PRESENT(func) \ + do { \ + } while (0) + +#endif // ifdef MOZ_GL_DEBUG_BUILD + + // Do whatever setup is necessary to draw to our offscreen FBO, if it's + // bound. + void BeforeGLDrawCall() {} + + // Do whatever tear-down is necessary after drawing to our offscreen FBO, + // if it's bound. + void AfterGLDrawCall() { mHeavyGLCallsSinceLastFlush = true; } + + // Do whatever setup is necessary to read from our offscreen FBO, if it's + // bound. + void BeforeGLReadCall() {} + + // Do whatever tear-down is necessary after reading from our offscreen FBO, + // if it's bound. + void AfterGLReadCall() {} + + public: + void OnSyncCall() const { mSyncGLCallCount++; } + + uint64_t GetSyncCallCount() const { return mSyncGLCallCount; } + + void ResetSyncCallCount(const char* resetReason) const; + + // ----------------------------------------------------------------------------- + // GL official entry points + public: + // We smash all errors together, so you never have to loop on this. We + // guarantee that immediately after this call, there are no errors left. + // Always returns the top-most error, except if followed by CONTEXT_LOST, then + // return that instead. + GLenum GetError() const; + + GLenum fGetError() { return GetError(); } + + GLenum fGetGraphicsResetStatus() const; + + // - + + void fActiveTexture(GLenum texture) { + BEFORE_GL_CALL; + mSymbols.fActiveTexture(texture); + AFTER_GL_CALL; + } + + void fAttachShader(GLuint program, GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fAttachShader(program, shader); + AFTER_GL_CALL; + } + + void fBeginQuery(GLenum target, GLuint id) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fBeginQuery); + mSymbols.fBeginQuery(target, id); + AFTER_GL_CALL; + } + + void fBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fBindAttribLocation(program, index, name); + AFTER_GL_CALL; + } + + void fBindBuffer(GLenum target, GLuint buffer) { + BEFORE_GL_CALL; + mSymbols.fBindBuffer(target, buffer); + AFTER_GL_CALL; + } + + void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum* attachments) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer); + mSymbols.fInvalidateFramebuffer(target, numAttachments, attachments); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum* attachments, GLint x, GLint y, + GLsizei width, GLsizei height) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer); + mSymbols.fInvalidateSubFramebuffer(target, numAttachments, attachments, x, + y, width, height); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fBindTexture(GLenum target, GLuint texture) { + BEFORE_GL_CALL; + mSymbols.fBindTexture(target, texture); + AFTER_GL_CALL; + } + + void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + BEFORE_GL_CALL; + mSymbols.fBlendColor(red, green, blue, alpha); + AFTER_GL_CALL; + } + + void fBlendEquation(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fBlendEquation(mode); + AFTER_GL_CALL; + } + + void fBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { + BEFORE_GL_CALL; + mSymbols.fBlendEquationSeparate(modeRGB, modeAlpha); + AFTER_GL_CALL; + } + + void fBlendFunc(GLenum sfactor, GLenum dfactor) { + BEFORE_GL_CALL; + mSymbols.fBlendFunc(sfactor, dfactor); + AFTER_GL_CALL; + } + + void fBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorAlpha, GLenum dfactorAlpha) { + BEFORE_GL_CALL; + mSymbols.fBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, + dfactorAlpha); + AFTER_GL_CALL; + } + + private: + void raw_fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, + GLenum usage) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); + BEFORE_GL_CALL; + mSymbols.fBufferData(target, size, data, usage); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + public: + void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, + GLenum usage) { + raw_fBufferData(target, size, data, usage); + + // bug 744888 + if (WorkAroundDriverBugs() && !data && Vendor() == GLVendor::NVIDIA) { + UniquePtr<char[]> buf = MakeUnique<char[]>(1); + buf[0] = 0; + fBufferSubData(target, size - 1, 1, buf.get()); + } + } + + void fBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, + const GLvoid* data) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(data); + BEFORE_GL_CALL; + mSymbols.fBufferSubData(target, offset, size, data); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + private: + void raw_fClear(GLbitfield mask) { + BEFORE_GL_CALL; + mSymbols.fClear(mask); + AFTER_GL_CALL; + } + + public: + void fClear(GLbitfield mask) { + BeforeGLDrawCall(); + raw_fClear(mask); + AfterGLDrawCall(); + } + + void fClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, + GLint stencil) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferfi(buffer, drawbuffer, depth, stencil); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferfv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferiv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { + BeforeGLDrawCall(); + BEFORE_GL_CALL; + mSymbols.fClearBufferuiv(buffer, drawbuffer, value); + AFTER_GL_CALL; + AfterGLDrawCall(); + } + + void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { + BEFORE_GL_CALL; + mSymbols.fClearColor(r, g, b, a); + AFTER_GL_CALL; + } + + void fClearStencil(GLint s) { + BEFORE_GL_CALL; + mSymbols.fClearStencil(s); + AFTER_GL_CALL; + } + + void fClientActiveTexture(GLenum texture) { + BEFORE_GL_CALL; + mSymbols.fClientActiveTexture(texture); + AFTER_GL_CALL; + } + + void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, + realGLboolean alpha) { + BEFORE_GL_CALL; + mSymbols.fColorMask(red, green, blue, alpha); + AFTER_GL_CALL; + } + + void fCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fCompressedTexImage2D(target, level, internalformat, width, height, + border, imageSize, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, + height, format, imageSize, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + + void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height) { + BeforeGLReadCall(); + raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, + height); + AfterGLReadCall(); + } + + void fCullFace(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fCullFace(mode); + AFTER_GL_CALL; + } + + void fDebugMessageCallback(GLDEBUGPROC callback, const GLvoid* userParam) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageCallback); + mSymbols.fDebugMessageCallback(callback, userParam); + AFTER_GL_CALL; + } + + void fDebugMessageControl(GLenum source, GLenum type, GLenum severity, + GLsizei count, const GLuint* ids, + realGLboolean enabled) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageControl); + mSymbols.fDebugMessageControl(source, type, severity, count, ids, enabled); + AFTER_GL_CALL; + } + + void fDebugMessageInsert(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* buf) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fDebugMessageInsert); + mSymbols.fDebugMessageInsert(source, type, id, severity, length, buf); + AFTER_GL_CALL; + } + + void fDetachShader(GLuint program, GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fDetachShader(program, shader); + AFTER_GL_CALL; + } + + void fDepthFunc(GLenum func) { + BEFORE_GL_CALL; + mSymbols.fDepthFunc(func); + AFTER_GL_CALL; + } + + void fDepthMask(realGLboolean flag) { + BEFORE_GL_CALL; + mSymbols.fDepthMask(flag); + AFTER_GL_CALL; + } + + void fDisable(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fDisable(capability); + AFTER_GL_CALL; + } + + void fDisableClientState(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fDisableClientState(capability); + AFTER_GL_CALL; + } + + void fDisableVertexAttribArray(GLuint index) { + BEFORE_GL_CALL; + mSymbols.fDisableVertexAttribArray(index); + AFTER_GL_CALL; + } + + void fDrawBuffer(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fDrawBuffer(mode); + AFTER_GL_CALL; + } + + private: + void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) { + BEFORE_GL_CALL; + mSymbols.fDrawArrays(mode, first, count); + AFTER_GL_CALL; + } + + void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices) { + BEFORE_GL_CALL; + mSymbols.fDrawElements(mode, count, type, indices); + AFTER_GL_CALL; + } + + public: + void fDrawArrays(GLenum mode, GLint first, GLsizei count) { + BeforeGLDrawCall(); + raw_fDrawArrays(mode, first, count); + AfterGLDrawCall(); + } + + void fDrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices) { + BeforeGLDrawCall(); + raw_fDrawElements(mode, count, type, indices); + AfterGLDrawCall(); + } + + void fEnable(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fEnable(capability); + AFTER_GL_CALL; + } + + void fEnableClientState(GLenum capability) { + BEFORE_GL_CALL; + mSymbols.fEnableClientState(capability); + AFTER_GL_CALL; + } + + void fEnableVertexAttribArray(GLuint index) { + BEFORE_GL_CALL; + mSymbols.fEnableVertexAttribArray(index); + AFTER_GL_CALL; + } + + void fEndQuery(GLenum target) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fEndQuery); + mSymbols.fEndQuery(target); + AFTER_GL_CALL; + } + + void fFinish() { + BEFORE_GL_CALL; + mSymbols.fFinish(); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = false; + } + + void fFlush() { + BEFORE_GL_CALL; + mSymbols.fFlush(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = false; + } + + void fFrontFace(GLenum face) { + BEFORE_GL_CALL; + mSymbols.fFrontFace(face); + AFTER_GL_CALL; + } + + void fGetActiveAttrib(GLuint program, GLuint index, GLsizei maxLength, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fGetActiveAttrib(program, index, maxLength, length, size, type, + name); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetActiveUniform(GLuint program, GLuint index, GLsizei maxLength, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name) { + BEFORE_GL_CALL; + mSymbols.fGetActiveUniform(program, index, maxLength, length, size, type, + name); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, + GLuint* shaders) { + BEFORE_GL_CALL; + mSymbols.fGetAttachedShaders(program, maxCount, count, shaders); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLint fGetAttribLocation(GLuint program, const GLchar* name) { + GLint retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fGetAttribLocation(program, name); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + private: + void raw_fGetIntegerv(GLenum pname, GLint* params) const { + BEFORE_GL_CALL; + mSymbols.fGetIntegerv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + public: + void fGetIntegerv(GLenum pname, GLint* params) const; + + template <typename T> + void GetInt(const GLenum pname, T* const params) const { + static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); + fGetIntegerv(pname, reinterpret_cast<GLint*>(params)); + } + + void GetUIntegerv(GLenum pname, GLuint* params) const { + GetInt(pname, params); + } + + template <typename T> + T GetIntAs(GLenum pname) const { + static_assert(sizeof(T) == sizeof(GLint), "Invalid T."); + T ret = 0; + fGetIntegerv(pname, (GLint*)&ret); + return ret; + } + + void fGetFloatv(GLenum pname, GLfloat* params) const { + BEFORE_GL_CALL; + mSymbols.fGetFloatv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetBooleanv(GLenum pname, realGLboolean* params) const { + BEFORE_GL_CALL; + mSymbols.fGetBooleanv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetBufferParameteriv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLuint fGetDebugMessageLog(GLuint count, GLsizei bufsize, GLenum* sources, + GLenum* types, GLuint* ids, GLenum* severities, + GLsizei* lengths, GLchar* messageLog) { + GLuint ret = 0; + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetDebugMessageLog); + ret = mSymbols.fGetDebugMessageLog(count, bufsize, sources, types, ids, + severities, lengths, messageLog); + OnSyncCall(); + AFTER_GL_CALL; + return ret; + } + + void fGetPointerv(GLenum pname, GLvoid** params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetPointerv); + mSymbols.fGetPointerv(pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, + GLsizei* length, GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetObjectLabel); + mSymbols.fGetObjectLabel(identifier, name, bufSize, length, label); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetObjectPtrLabel(const GLvoid* ptr, GLsizei bufSize, GLsizei* length, + GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetObjectPtrLabel); + mSymbols.fGetObjectPtrLabel(ptr, bufSize, length, label); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGenerateMipmap(GLenum target) { + BEFORE_GL_CALL; + mSymbols.fGenerateMipmap(target); + AFTER_GL_CALL; + } + + void fGetProgramiv(GLuint program, GLenum pname, GLint* param) { + BEFORE_GL_CALL; + mSymbols.fGetProgramiv(program, pname, param); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, + GLchar* infoLog) { + BEFORE_GL_CALL; + mSymbols.fGetProgramInfoLog(program, bufSize, length, infoLog); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fTexParameteri(GLenum target, GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fTexParameteri(target, pname, param); + AFTER_GL_CALL; + } + + void fTexParameteriv(GLenum target, GLenum pname, const GLint* params) { + BEFORE_GL_CALL; + mSymbols.fTexParameteriv(target, pname, params); + AFTER_GL_CALL; + } + + void fTexParameterf(GLenum target, GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fTexParameterf(target, pname, param); + AFTER_GL_CALL; + } + + const GLubyte* fGetString(GLenum name) { + const GLubyte* result = nullptr; + BEFORE_GL_CALL; + result = mSymbols.fGetString(name); + OnSyncCall(); + AFTER_GL_CALL; + return result; + } + + void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, + GLvoid* img) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetTexImage); + mSymbols.fGetTexImage(target, level, format, type, img); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, + GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv); + mSymbols.fGetTexLevelParameteriv(target, level, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fGetTexParameterfv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetTexParameteriv(target, pname, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformfv(GLuint program, GLint location, GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fGetUniformfv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformiv(GLuint program, GLint location, GLint* params) { + BEFORE_GL_CALL; + mSymbols.fGetUniformiv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetUniformuiv(GLuint program, GLint location, GLuint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetUniformuiv); + mSymbols.fGetUniformuiv(program, location, params); + OnSyncCall(); + AFTER_GL_CALL; + } + + GLint fGetUniformLocation(GLuint programObj, const GLchar* name) { + GLint retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fGetUniformLocation(programObj, name); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + void fGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribfv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetVertexAttribiv(GLuint index, GLenum pname, GLint* retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribiv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** retval) { + BEFORE_GL_CALL; + mSymbols.fGetVertexAttribPointerv(index, pname, retval); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fHint(GLenum target, GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fHint(target, mode); + AFTER_GL_CALL; + } + + realGLboolean fIsBuffer(GLuint buffer) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsBuffer(buffer); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsEnabled(GLenum capability) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsEnabled(capability); + AFTER_GL_CALL; + return retval; + } + + void SetEnabled(const GLenum cap, const bool val) { + if (val) { + fEnable(cap); + } else { + fDisable(cap); + } + } + + bool PushEnabled(const GLenum cap, const bool newVal) { + const bool oldVal = fIsEnabled(cap); + if (oldVal != newVal) { + SetEnabled(cap, newVal); + } + return oldVal; + } + + realGLboolean fIsProgram(GLuint program) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsProgram(program); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsShader(GLuint shader) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsShader(shader); + AFTER_GL_CALL; + return retval; + } + + realGLboolean fIsTexture(GLuint texture) { + realGLboolean retval = false; + BEFORE_GL_CALL; + retval = mSymbols.fIsTexture(texture); + AFTER_GL_CALL; + return retval; + } + + void fLineWidth(GLfloat width) { + BEFORE_GL_CALL; + mSymbols.fLineWidth(width); + AFTER_GL_CALL; + } + + void fLinkProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fLinkProgram(program); + AFTER_GL_CALL; + } + + void fObjectLabel(GLenum identifier, GLuint name, GLsizei length, + const GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fObjectLabel); + mSymbols.fObjectLabel(identifier, name, length, label); + AFTER_GL_CALL; + } + + void fObjectPtrLabel(const GLvoid* ptr, GLsizei length, const GLchar* label) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fObjectPtrLabel); + mSymbols.fObjectPtrLabel(ptr, length, label); + AFTER_GL_CALL; + } + + void fLoadIdentity() { + BEFORE_GL_CALL; + mSymbols.fLoadIdentity(); + AFTER_GL_CALL; + } + + void fLoadMatrixf(const GLfloat* matrix) { + BEFORE_GL_CALL; + mSymbols.fLoadMatrixf(matrix); + AFTER_GL_CALL; + } + + void fMatrixMode(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fMatrixMode(mode); + AFTER_GL_CALL; + } + + void fPixelStorei(GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fPixelStorei(pname, param); + AFTER_GL_CALL; + } + + void fTextureRangeAPPLE(GLenum target, GLsizei length, GLvoid* pointer) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pointer); + BEFORE_GL_CALL; + mSymbols.fTextureRangeAPPLE(target, length, pointer); + AFTER_GL_CALL; + } + + void fPointParameterf(GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fPointParameterf(pname, param); + AFTER_GL_CALL; + } + + void fPolygonMode(GLenum face, GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fPolygonMode(face, mode); + AFTER_GL_CALL; + } + + void fPolygonOffset(GLfloat factor, GLfloat bias) { + BEFORE_GL_CALL; + mSymbols.fPolygonOffset(factor, bias); + AFTER_GL_CALL; + } + + void fPopDebugGroup() { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPopDebugGroup); + mSymbols.fPopDebugGroup(); + AFTER_GL_CALL; + } + + void fPushDebugGroup(GLenum source, GLuint id, GLsizei length, + const GLchar* message) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fPushDebugGroup); + mSymbols.fPushDebugGroup(source, id, length, message); + AFTER_GL_CALL; + } + + void fReadBuffer(GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fReadBuffer(mode); + AFTER_GL_CALL; + } + + void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) { + BEFORE_GL_CALL; + mSymbols.fReadPixels(x, y, width, height, format, type, pixels); + OnSyncCall(); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels); + + public: + void fSampleCoverage(GLclampf value, realGLboolean invert) { + BEFORE_GL_CALL; + mSymbols.fSampleCoverage(value, invert); + AFTER_GL_CALL; + } + + void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) { + if (mScissorRect[0] == x && mScissorRect[1] == y && + mScissorRect[2] == width && mScissorRect[3] == height) { + return; + } + mScissorRect[0] = x; + mScissorRect[1] = y; + mScissorRect[2] = width; + mScissorRect[3] = height; + BEFORE_GL_CALL; + mSymbols.fScissor(x, y, width, height); + AFTER_GL_CALL; + } + + void fStencilFunc(GLenum func, GLint reference, GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilFunc(func, reference, mask); + AFTER_GL_CALL; + } + + void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint reference, + GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilFuncSeparate(frontfunc, backfunc, reference, mask); + AFTER_GL_CALL; + } + + void fStencilMask(GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilMask(mask); + AFTER_GL_CALL; + } + + void fStencilMaskSeparate(GLenum face, GLuint mask) { + BEFORE_GL_CALL; + mSymbols.fStencilMaskSeparate(face, mask); + AFTER_GL_CALL; + } + + void fStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { + BEFORE_GL_CALL; + mSymbols.fStencilOp(fail, zfail, zpass); + AFTER_GL_CALL; + } + + void fStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, + GLenum dppass) { + BEFORE_GL_CALL; + mSymbols.fStencilOpSeparate(face, sfail, dpfail, dppass); + AFTER_GL_CALL; + } + + void fTexGeni(GLenum coord, GLenum pname, GLint param) { + BEFORE_GL_CALL; + mSymbols.fTexGeni(coord, pname, param); + AFTER_GL_CALL; + } + + void fTexGenf(GLenum coord, GLenum pname, GLfloat param) { + BEFORE_GL_CALL; + mSymbols.fTexGenf(coord, pname, param); + AFTER_GL_CALL; + } + + void fTexGenfv(GLenum coord, GLenum pname, const GLfloat* params) { + BEFORE_GL_CALL; + mSymbols.fTexGenfv(coord, pname, params); + AFTER_GL_CALL; + } + + private: + void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fTexImage2D(target, level, internalformat, width, height, border, + format, type, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + public: + void fTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, GLenum format, + GLenum type, const GLvoid* pixels); + + void fTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const GLvoid* pixels) { + ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); + BEFORE_GL_CALL; + mSymbols.fTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, pixels); + AFTER_GL_CALL; + mHeavyGLCallsSinceLastFlush = true; + } + + void fUniform1f(GLint location, GLfloat v0) { + BEFORE_GL_CALL; + mSymbols.fUniform1f(location, v0); + AFTER_GL_CALL; + } + + void fUniform1fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform1fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform1i(GLint location, GLint v0) { + BEFORE_GL_CALL; + mSymbols.fUniform1i(location, v0); + AFTER_GL_CALL; + } + + void fUniform1iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform1iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform2f(GLint location, GLfloat v0, GLfloat v1) { + BEFORE_GL_CALL; + mSymbols.fUniform2f(location, v0, v1); + AFTER_GL_CALL; + } + + void fUniform2fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform2fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform2i(GLint location, GLint v0, GLint v1) { + BEFORE_GL_CALL; + mSymbols.fUniform2i(location, v0, v1); + AFTER_GL_CALL; + } + + void fUniform2iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform2iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + BEFORE_GL_CALL; + mSymbols.fUniform3f(location, v0, v1, v2); + AFTER_GL_CALL; + } + + void fUniform3fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform3fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform3i(GLint location, GLint v0, GLint v1, GLint v2) { + BEFORE_GL_CALL; + mSymbols.fUniform3i(location, v0, v1, v2); + AFTER_GL_CALL; + } + + void fUniform3iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform3iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, + GLfloat v3) { + BEFORE_GL_CALL; + mSymbols.fUniform4f(location, v0, v1, v2, v3); + AFTER_GL_CALL; + } + + void fUniform4fv(GLint location, GLsizei count, const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniform4fv(location, count, value); + AFTER_GL_CALL; + } + + void fUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + BEFORE_GL_CALL; + mSymbols.fUniform4i(location, v0, v1, v2, v3); + AFTER_GL_CALL; + } + + void fUniform4iv(GLint location, GLsizei count, const GLint* value) { + BEFORE_GL_CALL; + mSymbols.fUniform4iv(location, count, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2x3fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix2x3fv); + mSymbols.fUniformMatrix2x3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix2x4fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix2x4fv); + mSymbols.fUniformMatrix2x4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3x2fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix3x2fv); + mSymbols.fUniformMatrix3x2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix3x4fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix3x4fv); + mSymbols.fUniformMatrix3x4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4fv(GLint location, GLsizei count, realGLboolean transpose, + const GLfloat* value) { + BEFORE_GL_CALL; + mSymbols.fUniformMatrix4fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4x2fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix4x2fv); + mSymbols.fUniformMatrix4x2fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUniformMatrix4x3fv(GLint location, GLsizei count, + realGLboolean transpose, const GLfloat* value) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fUniformMatrix4x3fv); + mSymbols.fUniformMatrix4x3fv(location, count, transpose, value); + AFTER_GL_CALL; + } + + void fUseProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fUseProgram(program); + AFTER_GL_CALL; + } + + void fValidateProgram(GLuint program) { + BEFORE_GL_CALL; + mSymbols.fValidateProgram(program); + AFTER_GL_CALL; + } + + void fVertexAttribPointer(GLuint index, GLint size, GLenum type, + realGLboolean normalized, GLsizei stride, + const GLvoid* pointer) { + BEFORE_GL_CALL; + mSymbols.fVertexAttribPointer(index, size, type, normalized, stride, + pointer); + AFTER_GL_CALL; + } + + void fVertexAttrib1f(GLuint index, GLfloat x) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib1f(index, x); + AFTER_GL_CALL; + } + + void fVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib2f(index, x, y); + AFTER_GL_CALL; + } + + void fVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib3f(index, x, y, z); + AFTER_GL_CALL; + } + + void fVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, + GLfloat w) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib4f(index, x, y, z, w); + AFTER_GL_CALL; + } + + void fVertexAttrib1fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib1fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib2fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib2fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib3fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib3fv(index, v); + AFTER_GL_CALL; + } + + void fVertexAttrib4fv(GLuint index, const GLfloat* v) { + BEFORE_GL_CALL; + mSymbols.fVertexAttrib4fv(index, v); + AFTER_GL_CALL; + } + + void fVertexPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid* pointer) { + BEFORE_GL_CALL; + mSymbols.fVertexPointer(size, type, stride, pointer); + AFTER_GL_CALL; + } + + void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + if (mViewportRect[0] == x && mViewportRect[1] == y && + mViewportRect[2] == width && mViewportRect[3] == height) { + return; + } + mViewportRect[0] = x; + mViewportRect[1] = y; + mViewportRect[2] = width; + mViewportRect[3] = height; + BEFORE_GL_CALL; + mSymbols.fViewport(x, y, width, height); + AFTER_GL_CALL; + } + + void fCompileShader(GLuint shader) { + BEFORE_GL_CALL; + mSymbols.fCompileShader(shader); + AFTER_GL_CALL; + } + + private: + friend class SharedSurface_IOSurface; + + void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) { + BEFORE_GL_CALL; + mSymbols.fCopyTexImage2D(target, level, internalformat, x, y, width, height, + border); + AFTER_GL_CALL; + } + + void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height) { + BEFORE_GL_CALL; + mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, + height); + AFTER_GL_CALL; + } + + public: + void fGetShaderiv(GLuint shader, GLenum pname, GLint* param) { + BEFORE_GL_CALL; + mSymbols.fGetShaderiv(shader, pname, param); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, + GLchar* infoLog) { + BEFORE_GL_CALL; + mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog); + OnSyncCall(); + AFTER_GL_CALL; + } + + private: + void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + MOZ_ASSERT(IsGLES()); + + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat); + mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, + precision); + OnSyncCall(); + AFTER_GL_CALL; + } + + public: + void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + if (IsGLES()) { + raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, + precision); + } else { + // Fall back to automatic values because almost all desktop hardware + // supports the OpenGL standard precisions. + GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, + precision); + } + } + + void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, + GLchar* source) { + BEFORE_GL_CALL; + mSymbols.fGetShaderSource(obj, maxLength, length, source); + OnSyncCall(); + AFTER_GL_CALL; + } + + void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, + const GLint* lengths) { + BEFORE_GL_CALL; + mSymbols.fShaderSource(shader, count, strings, lengths); + AFTER_GL_CALL; + } + + private: + mutable GLuint mCachedDrawFb = 0; + mutable GLuint mCachedReadFb = 0; + + public: + bool mElideDuplicateBindFramebuffers = false; + + void fBindFramebuffer(const GLenum target, const GLuint fb) const { + if (mElideDuplicateBindFramebuffers) { + MOZ_ASSERT(mCachedDrawFb == + GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING)); + MOZ_ASSERT(mCachedReadFb == + GetIntAs<GLuint>(LOCAL_GL_READ_FRAMEBUFFER_BINDING)); + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + if (mCachedDrawFb == fb && mCachedReadFb == fb) return; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + if (mCachedDrawFb == fb) return; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + if (mCachedReadFb == fb) return; + break; + } + } + + BEFORE_GL_CALL; + mSymbols.fBindFramebuffer(target, fb); + AFTER_GL_CALL; + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + mCachedDrawFb = fb; + mCachedReadFb = fb; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + mCachedDrawFb = fb; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + mCachedReadFb = fb; + break; + } + } + + void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { + BEFORE_GL_CALL; + mSymbols.fBindRenderbuffer(target, renderbuffer); + AFTER_GL_CALL; + } + + GLenum fCheckFramebufferStatus(GLenum target) { + GLenum retval = 0; + BEFORE_GL_CALL; + retval = mSymbols.fCheckFramebufferStatus(target); + OnSyncCall(); + AFTER_GL_CALL; + return retval; + } + + void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, + GLenum renderbufferTarget, + GLuint renderbuffer) { + BEFORE_GL_CALL; + mSymbols.fFramebufferRenderbuffer(target, attachmentPoint, + renderbufferTarget, renderbuffer); + AFTER_GL_CALL; + } + + void fFramebufferTexture2D(GLenum target, GLenum attachmentPoint, + GLenum textureTarget, GLuint texture, + GLint level) { + BEFORE_GL_CALL; + mSymbols.fFramebufferTexture2D(target, attachmentPoint, textureTarget, + texture, level); + AFTER_GL_CALL; + 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<SymbolLoader> GetSymbolLoader() const = 0; + + void BindFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); + MOZ_GL_ASSERT(this, !fb || fIsFramebuffer(fb)); + } + + void BindDrawFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); + } + + void BindReadFB(GLuint fb) { + fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); + } + + GLuint GetDrawFB() const { + return GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT); + } + + GLuint GetReadFB() const { + auto bindEnum = LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT; + if (!IsSupported(GLFeature::split_framebuffer)) { + bindEnum = LOCAL_GL_FRAMEBUFFER_BINDING; + } + return GetIntAs<GLuint>(bindEnum); + } + + GLuint GetFB() const { + const auto ret = GetDrawFB(); + MOZ_ASSERT(ret == GetReadFB()); + return ret; + } + + private: + void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + switch (precisiontype) { + case LOCAL_GL_LOW_FLOAT: + case LOCAL_GL_MEDIUM_FLOAT: + case LOCAL_GL_HIGH_FLOAT: + // Assume IEEE 754 precision + range[0] = 127; + range[1] = 127; + *precision = 23; + break; + case LOCAL_GL_LOW_INT: + case LOCAL_GL_MEDIUM_INT: + case LOCAL_GL_HIGH_INT: + // Some (most) hardware only supports single-precision floating-point + // numbers, which can accurately represent integers up to +/-16777216 + range[0] = 24; + range[1] = 24; + *precision = 0; + break; + } + } + + public: + virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; } + + virtual GLenum GetPreferredEGLImageTextureTarget() const { +#ifdef MOZ_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<GLContext> mSharedContext; + + public: + // The thread id which this context was created. + Maybe<PlatformThreadId> mOwningThreadId; + + protected: + GLContextSymbols mSymbols = {}; + + UniquePtr<GLBlitHelper> mBlitHelper; + UniquePtr<GLReadTexImageHelper> mReadTexImageHelper; + + public: + GLBlitHelper* BlitHelper(); + GLReadTexImageHelper* ReadTexImageHelper(); + + // Assumes shares are created by all sharing with the same global context. + bool SharesWith(const GLContext* other) const { + MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext); + MOZ_ASSERT(!other->mSharedContext || + !other->mSharedContext->mSharedContext); + MOZ_ASSERT(!this->mSharedContext || !other->mSharedContext || + this->mSharedContext == other->mSharedContext); + + const GLContext* thisShared = + this->mSharedContext ? this->mSharedContext : this; + const GLContext* otherShared = + other->mSharedContext ? other->mSharedContext : other; + + return thisShared == otherShared; + } + + bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); + + // Does not check completeness. + void AttachBuffersToFB(GLuint colorTex, GLuint colorRB, GLuint depthRB, + GLuint stencilRB, GLuint fb, + GLenum target = LOCAL_GL_TEXTURE_2D); + + // Passing null is fine if the value you'd get is 0. + bool AssembleOffscreenFBs(const GLuint colorMSRB, const GLuint depthRB, + const GLuint stencilRB, const GLuint texture, + GLuint* drawFB, GLuint* readFB); + + protected: + SharedSurface* mLockedSurface = nullptr; + + public: + void LockSurface(SharedSurface* surf) { mLockedSurface = surf; } + + void UnlockSurface(SharedSurface* surf) { + MOZ_ASSERT(mLockedSurface == surf); + mLockedSurface = nullptr; + } + + SharedSurface* GetLockedSurface() const { return mLockedSurface; } + + bool IsOffscreen() const { return mDesc.isOffscreen; } + + bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } + + bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; + + virtual bool Init(); + + private: + bool InitImpl(); + void LoadMoreSymbols(const SymbolLoader& loader); + bool LoadExtSymbols(const SymbolLoader& loader, const SymLoadStruct* list, + GLExtensions ext); + bool LoadFeatureSymbols(const SymbolLoader& loader, const SymLoadStruct* list, + GLFeature feature); + + protected: + void InitExtensions(); + + GLint mViewportRect[4] = {}; + GLint mScissorRect[4] = {}; + + uint32_t mMaxTexOrRbSize = 0; + GLint mMaxTextureSize = 0; + GLint mMaxCubeMapTextureSize = 0; + GLint mMaxRenderbufferSize = 0; + GLint mMaxViewportDims[2] = {}; + GLsizei mMaxSamples = 0; + bool mNeedsTextureSizeChecks = false; + bool mNeedsFlushBeforeDeleteFB = false; + bool mTextureAllocCrashesOnMapFailure = false; + 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<NamedResource> mTrackedPrograms; + nsTArray<NamedResource> mTrackedShaders; + nsTArray<NamedResource> mTrackedTextures; + nsTArray<NamedResource> mTrackedFramebuffers; + nsTArray<NamedResource> mTrackedRenderbuffers; + nsTArray<NamedResource> mTrackedBuffers; + nsTArray<NamedResource> mTrackedQueries; +#endif + + protected: + bool mHeavyGLCallsSinceLastFlush = false; + + public: + void FlushIfHeavyGLCallsSinceLastFlush(); + static bool ShouldSpew(); + static bool ShouldDumpExts(); + + // -- + + void TexParams_SetClampNoMips(GLenum target = LOCAL_GL_TEXTURE_2D) { + fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); + fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); + } + + // -- + + GLuint CreateFramebuffer() { + GLuint x = 0; + fGenFramebuffers(1, &x); + return x; + } + GLuint CreateRenderbuffer() { + GLuint x = 0; + fGenRenderbuffers(1, &x); + return x; + } + GLuint CreateTexture() { + GLuint x = 0; + fGenTextures(1, &x); + return x; + } + + void DeleteFramebuffer(const GLuint x) { fDeleteFramebuffers(1, &x); } + void DeleteRenderbuffer(const GLuint x) { fDeleteRenderbuffers(1, &x); } + void DeleteTexture(const GLuint x) { fDeleteTextures(1, &x); } +}; + +bool DoesStringMatch(const char* aString, const char* aWantedString); + +void SplitByChar(const nsACString& str, const char delim, + std::vector<nsCString>* const out); + +template <size_t N> +bool MarkBitfieldByString(const nsACString& str, + const char* const (&markStrList)[N], + std::bitset<N>* const out_markList) { + for (size_t i = 0; i < N; i++) { + if (str.Equals(markStrList[i])) { + (*out_markList)[i] = 1; + return true; + } + } + return false; +} + +template <size_t N> +void MarkBitfieldByStrings(const std::vector<nsCString>& strList, + bool dumpStrings, + const char* const (&markStrList)[N], + std::bitset<N>* const out_markList) { + for (auto itr = strList.begin(); itr != strList.end(); ++itr) { + const nsACString& str = *itr; + const bool wasMarked = MarkBitfieldByString(str, markStrList, out_markList); + if (dumpStrings) + printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : ""); + } +} + +// - + +class Renderbuffer final { + public: + const WeakPtr<GLContext> weakGl; + const GLuint name; + + private: + static GLuint Create(GLContext& gl) { + GLuint ret = 0; + gl.fGenRenderbuffers(1, &ret); + return ret; + } + + public: + explicit Renderbuffer(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} + + ~Renderbuffer() { + const RefPtr<GLContext> gl = weakGl.get(); + if (!gl || !gl->MakeCurrent()) return; + gl->fDeleteRenderbuffers(1, &name); + } +}; + +// - + +class Texture final { + public: + const WeakPtr<GLContext> weakGl; + const GLuint name; + + private: + static GLuint Create(GLContext& gl) { + GLuint ret = 0; + gl.fGenTextures(1, &ret); + return ret; + } + + public: + explicit Texture(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} + + ~Texture() { + const RefPtr<GLContext> gl = weakGl.get(); + if (!gl || !gl->MakeCurrent()) return; + gl->fDeleteTextures(1, &name); + } +}; + +/** + * Helper function that creates a 2D texture aSize.width x aSize.height with + * storage type specified by aFormats. Returns GL texture object id. + * + * See mozilla::gl::CreateTexture. + */ +UniquePtr<Texture> CreateTexture(GLContext&, const gfx::IntSize& size); + +/** + * Helper function that calculates the number of bytes required per + * texel for a texture from its format and type. + */ +uint32_t GetBytesPerTexel(GLenum format, GLenum type); + +void MesaMemoryLeakWorkaround(); + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* GLCONTEXT_H_ */ |