michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "CompositorOGL.h" michael@0: #include // for size_t michael@0: #include // for uint32_t, uint8_t michael@0: #include // for free, malloc michael@0: #include "GLContextProvider.h" // for GLContextProvider michael@0: #include "GLContext.h" // for GLContext michael@0: #include "GLUploadHelpers.h" michael@0: #include "Layers.h" // for WriteSnapshotToDumpFile michael@0: #include "LayerScope.h" // for LayerScope michael@0: #include "gfx2DGlue.h" // for ThebesFilter michael@0: #include "gfx3DMatrix.h" // for gfx3DMatrix michael@0: #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter michael@0: #include "gfxImageSurface.h" // for gfxImageSurface michael@0: #include "gfxMatrix.h" // for gfxMatrix michael@0: #include "GraphicsFilter.h" // for GraphicsFilter michael@0: #include "gfxPlatform.h" // for gfxPlatform michael@0: #include "gfxPrefs.h" // for gfxPrefs michael@0: #include "gfxRect.h" // for gfxRect michael@0: #include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc michael@0: #include "mozilla/ArrayUtils.h" // for ArrayLength michael@0: #include "mozilla/Preferences.h" // for Preferences michael@0: #include "mozilla/gfx/BasePoint.h" // for BasePoint michael@0: #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix michael@0: #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc michael@0: #include "mozilla/layers/CompositingRenderTargetOGL.h" michael@0: #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc michael@0: #include "mozilla/layers/TextureHost.h" // for TextureSource, etc michael@0: #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc michael@0: #include "mozilla/mozalloc.h" // for operator delete, etc michael@0: #include "nsAString.h" michael@0: #include "nsIConsoleService.h" // for nsIConsoleService, etc michael@0: #include "nsIWidget.h" // for nsIWidget michael@0: #include "nsLiteralString.h" // for NS_LITERAL_STRING michael@0: #include "nsMathUtils.h" // for NS_roundf michael@0: #include "nsRect.h" // for nsIntRect michael@0: #include "nsServiceManagerUtils.h" // for do_GetService michael@0: #include "nsString.h" // for nsString, nsAutoCString, etc michael@0: #include "DecomposeIntoNoRepeatTriangles.h" michael@0: #include "ScopedGLHelpers.h" michael@0: #include "GLReadTexImageHelper.h" michael@0: #include "TiledLayerBuffer.h" // for TiledLayerComposer michael@0: michael@0: #if MOZ_ANDROID_OMTC michael@0: #include "TexturePoolOGL.h" michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include "nsCocoaFeatures.h" michael@0: #endif michael@0: michael@0: #include "GeckoProfiler.h" michael@0: michael@0: #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 michael@0: #include "libdisplay/GonkDisplay.h" // for GonkDisplay michael@0: #include michael@0: #endif michael@0: michael@0: #define BUFFER_OFFSET(i) ((char *)nullptr + (i)) michael@0: michael@0: namespace mozilla { michael@0: michael@0: using namespace std; michael@0: using namespace gfx; michael@0: michael@0: namespace layers { michael@0: michael@0: using namespace mozilla::gl; michael@0: michael@0: static inline IntSize ns2gfxSize(const nsIntSize& s) { michael@0: return IntSize(s.width, s.height); michael@0: } michael@0: michael@0: static void michael@0: BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask, michael@0: GLenum aTexUnit, const gfx::Matrix4x4& aTransform) michael@0: { michael@0: MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31); michael@0: aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR); michael@0: aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0); michael@0: aProgram->SetMaskLayerTransform(aTransform); michael@0: } michael@0: michael@0: // Draw the given quads with the already selected shader. Texture coordinates michael@0: // are supplied if the shader requires them. michael@0: static void michael@0: DrawQuads(GLContext *aGLContext, michael@0: VBOArena &aVBOs, michael@0: ShaderProgramOGL *aProg, michael@0: GLenum aMode, michael@0: RectTriangles &aRects) michael@0: { michael@0: NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); michael@0: GLuint vertAttribIndex = michael@0: aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); michael@0: GLuint texCoordAttribIndex = michael@0: aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib); michael@0: bool texCoords = (texCoordAttribIndex != GLuint(-1)); michael@0: michael@0: GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat); michael@0: michael@0: GLsizei total = bytes; michael@0: if (texCoords) { michael@0: total *= 2; michael@0: } michael@0: michael@0: aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, michael@0: aVBOs.Allocate(aGLContext)); michael@0: aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, michael@0: total, michael@0: nullptr, michael@0: LOCAL_GL_STREAM_DRAW); michael@0: michael@0: aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, michael@0: 0, michael@0: bytes, michael@0: aRects.vertCoords().Elements()); michael@0: aGLContext->fEnableVertexAttribArray(vertAttribIndex); michael@0: aGLContext->fVertexAttribPointer(vertAttribIndex, michael@0: 2, LOCAL_GL_FLOAT, michael@0: LOCAL_GL_FALSE, michael@0: 0, BUFFER_OFFSET(0)); michael@0: michael@0: if (texCoords) { michael@0: aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, michael@0: bytes, michael@0: bytes, michael@0: aRects.texCoords().Elements()); michael@0: aGLContext->fEnableVertexAttribArray(texCoordAttribIndex); michael@0: aGLContext->fVertexAttribPointer(texCoordAttribIndex, michael@0: 2, LOCAL_GL_FLOAT, michael@0: LOCAL_GL_FALSE, michael@0: 0, BUFFER_OFFSET(bytes)); michael@0: } else { michael@0: aGLContext->fDisableVertexAttribArray(texCoordAttribIndex); michael@0: } michael@0: michael@0: aGLContext->fDrawArrays(aMode, 0, aRects.elements()); michael@0: michael@0: aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: } michael@0: michael@0: CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth, michael@0: int aSurfaceHeight, bool aUseExternalSurfaceSize) michael@0: : mWidget(aWidget) michael@0: , mWidgetSize(-1, -1) michael@0: , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) michael@0: , mHasBGRA(0) michael@0: , mUseExternalSurfaceSize(aUseExternalSurfaceSize) michael@0: , mFrameInProgress(false) michael@0: , mDestroyed(false) michael@0: , mHeight(0) michael@0: { michael@0: MOZ_COUNT_CTOR(CompositorOGL); michael@0: SetBackend(LayersBackend::LAYERS_OPENGL); michael@0: } michael@0: michael@0: CompositorOGL::~CompositorOGL() michael@0: { michael@0: MOZ_COUNT_DTOR(CompositorOGL); michael@0: Destroy(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: CompositorOGL::CreateContext() michael@0: { michael@0: nsRefPtr context; michael@0: michael@0: #ifdef XP_WIN michael@0: if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) { michael@0: printf_stderr("Trying GL layers...\n"); michael@0: context = gl::GLContextProviderEGL::CreateForWindow(mWidget); michael@0: } michael@0: #endif michael@0: michael@0: if (!context) michael@0: context = gl::GLContextProvider::CreateForWindow(mWidget); michael@0: michael@0: if (!context) { michael@0: NS_WARNING("Failed to create CompositorOGL context"); michael@0: } michael@0: michael@0: return context.forget(); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::Destroy() michael@0: { michael@0: if (gl() && gl()->MakeCurrent()) { michael@0: mVBOs.Flush(gl()); michael@0: } michael@0: michael@0: if (mTexturePool) { michael@0: mTexturePool->Clear(); michael@0: mTexturePool = nullptr; michael@0: } michael@0: michael@0: if (!mDestroyed) { michael@0: mDestroyed = true; michael@0: CleanupResources(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::CleanupResources() michael@0: { michael@0: if (!mGLContext) michael@0: return; michael@0: michael@0: nsRefPtr ctx = mGLContext->GetSharedContext(); michael@0: if (!ctx) { michael@0: ctx = mGLContext; michael@0: } michael@0: michael@0: for (std::map::iterator iter = mPrograms.begin(); michael@0: iter != mPrograms.end(); michael@0: iter++) { michael@0: delete iter->second; michael@0: } michael@0: mPrograms.clear(); michael@0: michael@0: if (!ctx->MakeCurrent()) { michael@0: mQuadVBO = 0; michael@0: mGLContext = nullptr; michael@0: return; michael@0: } michael@0: michael@0: ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); michael@0: michael@0: if (mQuadVBO) { michael@0: ctx->fDeleteBuffers(1, &mQuadVBO); michael@0: mQuadVBO = 0; michael@0: } michael@0: michael@0: mGLContext = nullptr; michael@0: } michael@0: michael@0: bool michael@0: CompositorOGL::Initialize() michael@0: { michael@0: ScopedGfxFeatureReporter reporter("GL Layers", true); michael@0: michael@0: // Do not allow double initialization michael@0: NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL"); michael@0: michael@0: mGLContext = CreateContext(); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (!mGLContext) michael@0: NS_RUNTIMEABORT("We need a context on Android"); michael@0: #endif michael@0: michael@0: if (!mGLContext) michael@0: return false; michael@0: michael@0: MakeCurrent(); michael@0: michael@0: mHasBGRA = michael@0: mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) || michael@0: mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra); michael@0: michael@0: mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: mGLContext->fEnable(LOCAL_GL_BLEND); michael@0: michael@0: // initialise a common shader to check that we can actually compile a shader michael@0: RefPtr effect = new EffectSolidColor(Color(0, 0, 0, 0)); michael@0: ShaderConfigOGL config = GetShaderConfigFor(effect); michael@0: if (!GetShaderProgramFor(config)) { michael@0: return false; michael@0: } michael@0: michael@0: if (mGLContext->WorkAroundDriverBugs()) { michael@0: /** michael@0: * We'll test the ability here to bind NPOT textures to a framebuffer, if michael@0: * this fails we'll try ARB_texture_rectangle. michael@0: */ michael@0: michael@0: GLenum textureTargets[] = { michael@0: LOCAL_GL_TEXTURE_2D, michael@0: LOCAL_GL_NONE michael@0: }; michael@0: michael@0: if (!mGLContext->IsGLES()) { michael@0: // No TEXTURE_RECTANGLE_ARB available on ES2 michael@0: textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB; michael@0: } michael@0: michael@0: mFBOTextureTarget = LOCAL_GL_NONE; michael@0: michael@0: GLuint testFBO = 0; michael@0: mGLContext->fGenFramebuffers(1, &testFBO); michael@0: GLuint testTexture = 0; michael@0: michael@0: for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) { michael@0: GLenum target = textureTargets[i]; michael@0: if (!target) michael@0: continue; michael@0: michael@0: mGLContext->fGenTextures(1, &testTexture); michael@0: mGLContext->fBindTexture(target, testTexture); michael@0: mGLContext->fTexParameteri(target, michael@0: LOCAL_GL_TEXTURE_MIN_FILTER, michael@0: LOCAL_GL_NEAREST); michael@0: mGLContext->fTexParameteri(target, michael@0: LOCAL_GL_TEXTURE_MAG_FILTER, michael@0: LOCAL_GL_NEAREST); michael@0: mGLContext->fTexImage2D(target, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: 5, 3, /* sufficiently NPOT */ michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: LOCAL_GL_UNSIGNED_BYTE, michael@0: nullptr); michael@0: michael@0: // unbind this texture, in preparation for binding it to the FBO michael@0: mGLContext->fBindTexture(target, 0); michael@0: michael@0: mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO); michael@0: mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, michael@0: LOCAL_GL_COLOR_ATTACHMENT0, michael@0: target, michael@0: testTexture, michael@0: 0); michael@0: michael@0: if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == michael@0: LOCAL_GL_FRAMEBUFFER_COMPLETE) michael@0: { michael@0: mFBOTextureTarget = target; michael@0: mGLContext->fDeleteTextures(1, &testTexture); michael@0: break; michael@0: } michael@0: michael@0: mGLContext->fDeleteTextures(1, &testTexture); michael@0: } michael@0: michael@0: if (testFBO) { michael@0: mGLContext->fDeleteFramebuffers(1, &testFBO); michael@0: } michael@0: michael@0: if (mFBOTextureTarget == LOCAL_GL_NONE) { michael@0: /* Unable to find a texture target that works with FBOs and NPOT textures */ michael@0: return false; michael@0: } michael@0: } else { michael@0: // not trying to work around driver bugs, so TEXTURE_2D should just work michael@0: mFBOTextureTarget = LOCAL_GL_TEXTURE_2D; michael@0: } michael@0: michael@0: // back to default framebuffer, to avoid confusion michael@0: mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); michael@0: michael@0: if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { michael@0: /* If we're using TEXTURE_RECTANGLE, then we must have the ARB michael@0: * extension -- the EXT variant does not provide support for michael@0: * texture rectangle access inside GLSL (sampler2DRect, michael@0: * texture2DRect). michael@0: */ michael@0: if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)) michael@0: return false; michael@0: } michael@0: michael@0: /* Create a simple quad VBO */ michael@0: michael@0: mGLContext->fGenBuffers(1, &mQuadVBO); michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); michael@0: michael@0: GLfloat vertices[] = { michael@0: /* First quad vertices */ michael@0: 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, michael@0: /* Then quad texcoords */ michael@0: 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, michael@0: }; michael@0: mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: michael@0: nsCOMPtr michael@0: console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); michael@0: michael@0: if (console) { michael@0: nsString msg; michael@0: msg += michael@0: NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: "); michael@0: msg += NS_ConvertUTF8toUTF16( michael@0: nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION))); michael@0: msg += NS_LITERAL_STRING("\nVendor: "); michael@0: msg += NS_ConvertUTF8toUTF16( michael@0: nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR))); michael@0: msg += NS_LITERAL_STRING("\nRenderer: "); michael@0: msg += NS_ConvertUTF8toUTF16( michael@0: nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); michael@0: msg += NS_LITERAL_STRING("\nFBO Texture Target: "); michael@0: if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) michael@0: msg += NS_LITERAL_STRING("TEXTURE_2D"); michael@0: else michael@0: msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE"); michael@0: console->LogStringMessage(msg.get()); michael@0: } michael@0: michael@0: reporter.SetSuccessful(); michael@0: return true; michael@0: } michael@0: michael@0: // |aTextureTransform| is the texture transform that will be set on michael@0: // aProg, possibly multiplied with another texture transform of our michael@0: // own. michael@0: // |aTexCoordRect| is the rectangle from the texture that we want to michael@0: // draw using the given program. The program already has a necessary michael@0: // offset and scale, so the geometry that needs to be drawn is a unit michael@0: // square from 0,0 to 1,1. michael@0: // michael@0: // |aTexture| is the texture we are drawing. Its actual size can be michael@0: // larger than the rectangle given by |aTexCoordRect|. michael@0: void michael@0: CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, michael@0: const gfx3DMatrix& aTextureTransform, michael@0: const Rect& aTexCoordRect, michael@0: TextureSource *aTexture) michael@0: { michael@0: // Given what we know about these textures and coordinates, we can michael@0: // compute fmod(t, 1.0f) to get the same texture coordinate out. If michael@0: // the texCoordRect dimension is < 0 or > width/height, then we have michael@0: // wraparound that we need to deal with by drawing multiple quads, michael@0: // because we can't rely on full non-power-of-two texture support michael@0: // (which is required for the REPEAT wrap mode). michael@0: michael@0: RectTriangles rects; michael@0: michael@0: GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode(); michael@0: michael@0: IntSize realTexSize = aTexture->GetSize(); michael@0: if (!CanUploadNonPowerOfTwo(mGLContext)) { michael@0: realTexSize = IntSize(NextPowerOfTwo(realTexSize.width), michael@0: NextPowerOfTwo(realTexSize.height)); michael@0: } michael@0: michael@0: // We need to convert back to actual texels here to get proper behaviour with michael@0: // our GL helper functions. Should fix this sometime. michael@0: // I want to vomit. michael@0: IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width), michael@0: NS_roundf(aTexCoordRect.y * aTexture->GetSize().height), michael@0: NS_roundf(aTexCoordRect.width * aTexture->GetSize().width), michael@0: NS_roundf(aTexCoordRect.height * aTexture->GetSize().height)); michael@0: michael@0: // This is fairly disgusting - if the texture should be flipped it will have a michael@0: // negative height, in which case we un-invert the texture coords and pass the michael@0: // flipped 'flag' to the functions below. We can't just use the inverted coords michael@0: // because our GL funtions use an explicit flag. michael@0: bool flipped = false; michael@0: if (texCoordRect.height < 0) { michael@0: flipped = true; michael@0: texCoordRect.y = texCoordRect.YMost(); michael@0: texCoordRect.height = -texCoordRect.height; michael@0: } michael@0: michael@0: if (wrapMode == LOCAL_GL_REPEAT) { michael@0: rects.addRect(/* dest rectangle */ michael@0: 0.0f, 0.0f, 1.0f, 1.0f, michael@0: /* tex coords */ michael@0: texCoordRect.x / GLfloat(realTexSize.width), michael@0: texCoordRect.y / GLfloat(realTexSize.height), michael@0: texCoordRect.XMost() / GLfloat(realTexSize.width), michael@0: texCoordRect.YMost() / GLfloat(realTexSize.height), michael@0: flipped); michael@0: } else { michael@0: nsIntRect tcRect(texCoordRect.x, texCoordRect.y, michael@0: texCoordRect.width, texCoordRect.height); michael@0: DecomposeIntoNoRepeatTriangles(tcRect, michael@0: nsIntSize(realTexSize.width, realTexSize.height), michael@0: rects, flipped); michael@0: } michael@0: michael@0: gfx3DMatrix textureTransform; michael@0: if (rects.isSimpleQuad(textureTransform)) { michael@0: Matrix4x4 transform; michael@0: ToMatrix4x4(aTextureTransform * textureTransform, transform); michael@0: aProg->SetTextureTransform(transform); michael@0: BindAndDrawQuad(aProg); michael@0: } else { michael@0: Matrix4x4 transform; michael@0: ToMatrix4x4(aTextureTransform, transform); michael@0: aProg->SetTextureTransform(transform); michael@0: DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::PrepareViewport(const gfx::IntSize& aSize, michael@0: const Matrix& aWorldTransform) michael@0: { michael@0: // Set the viewport correctly. michael@0: mGLContext->fViewport(0, 0, aSize.width, aSize.height); michael@0: michael@0: mHeight = aSize.height; michael@0: michael@0: // We flip the view matrix around so that everything is right-side up; we're michael@0: // drawing directly into the window's back buffer, so this keeps things michael@0: // looking correct. michael@0: // XXX: We keep track of whether the window size changed, so we could skip michael@0: // this update if it hadn't changed since the last call. We will need to michael@0: // track changes to aTransformPolicy and aWorldTransform for this to work michael@0: // though. michael@0: michael@0: // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0, michael@0: // 2, 2) and flip the contents. michael@0: Matrix viewMatrix; michael@0: viewMatrix.Translate(-1.0, 1.0); michael@0: viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height)); michael@0: viewMatrix.Scale(1.0f, -1.0f); michael@0: if (!mTarget) { michael@0: viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y); michael@0: } michael@0: michael@0: viewMatrix = aWorldTransform * viewMatrix; michael@0: michael@0: Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix); michael@0: matrix3d._33 = 0.0f; michael@0: michael@0: mProjMatrix = matrix3d; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit) michael@0: { michael@0: GLuint tex = 0; michael@0: GLuint fbo = 0; michael@0: CreateFBOWithTexture(aRect, false, 0, &fbo, &tex); michael@0: RefPtr surface michael@0: = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); michael@0: surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit); michael@0: return surface.forget(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect, michael@0: const CompositingRenderTarget *aSource, michael@0: const IntPoint &aSourcePoint) michael@0: { michael@0: GLuint tex = 0; michael@0: GLuint fbo = 0; michael@0: const CompositingRenderTargetOGL* sourceSurface michael@0: = static_cast(aSource); michael@0: IntRect sourceRect(aSourcePoint, aRect.Size()); michael@0: if (aSource) { michael@0: CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(), michael@0: &fbo, &tex); michael@0: } else { michael@0: CreateFBOWithTexture(sourceRect, true, 0, michael@0: &fbo, &tex); michael@0: } michael@0: michael@0: RefPtr surface michael@0: = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); michael@0: surface->Initialize(aRect.Size(), michael@0: mFBOTextureTarget, michael@0: INIT_MODE_NONE); michael@0: return surface.forget(); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface) michael@0: { michael@0: MOZ_ASSERT(aSurface); michael@0: CompositingRenderTargetOGL* surface michael@0: = static_cast(aSurface); michael@0: if (mCurrentRenderTarget != surface) { michael@0: surface->BindRenderTarget(); michael@0: mCurrentRenderTarget = surface; michael@0: } michael@0: } michael@0: michael@0: CompositingRenderTarget* michael@0: CompositorOGL::GetCurrentRenderTarget() const michael@0: { michael@0: return mCurrentRenderTarget; michael@0: } michael@0: michael@0: static GLenum michael@0: GetFrameBufferInternalFormat(GLContext* gl, michael@0: GLuint aFrameBuffer, michael@0: nsIWidget* aWidget) michael@0: { michael@0: if (aFrameBuffer == 0) { // default framebuffer michael@0: return aWidget->GetGLFrameBufferFormat(); michael@0: } michael@0: return LOCAL_GL_RGBA; michael@0: } michael@0: michael@0: /* michael@0: * Returns a size that is larger than and closest to aSize where both michael@0: * width and height are powers of two. michael@0: * If the OpenGL setup is capable of using non-POT textures, then it michael@0: * will just return aSize. michael@0: */ michael@0: static IntSize michael@0: CalculatePOTSize(const IntSize& aSize, GLContext* gl) michael@0: { michael@0: if (CanUploadNonPowerOfTwo(gl)) michael@0: return aSize; michael@0: michael@0: return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height)); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::ClearRect(const gfx::Rect& aRect) michael@0: { michael@0: // Map aRect to OGL coordinates, origin:bottom-left michael@0: GLint y = mHeight - (aRect.y + aRect.height); michael@0: michael@0: ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); michael@0: ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height); michael@0: mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); michael@0: mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, michael@0: const Rect *aClipRectIn, michael@0: const gfx::Matrix& aTransform, michael@0: const Rect& aRenderBounds, michael@0: Rect *aClipRectOut, michael@0: Rect *aRenderBoundsOut) michael@0: { michael@0: PROFILER_LABEL("CompositorOGL", "BeginFrame"); michael@0: MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); michael@0: michael@0: LayerScope::BeginFrame(mGLContext, PR_Now()); michael@0: michael@0: mVBOs.Reset(); michael@0: michael@0: mFrameInProgress = true; michael@0: gfx::Rect rect; michael@0: if (mUseExternalSurfaceSize) { michael@0: rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height); michael@0: } else { michael@0: rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height); michael@0: // If render bounds is not updated explicitly, try to infer it from widget michael@0: if (rect.width == 0 || rect.height == 0) { michael@0: // FIXME/bug XXXXXX this races with rotation changes on the main michael@0: // thread, and undoes all the care we take with layers txns being michael@0: // sent atomically with rotation changes michael@0: nsIntRect intRect; michael@0: mWidget->GetClientBounds(intRect); michael@0: rect = gfx::Rect(0, 0, intRect.width, intRect.height); michael@0: } michael@0: } michael@0: michael@0: rect = aTransform.TransformBounds(rect); michael@0: if (aRenderBoundsOut) { michael@0: *aRenderBoundsOut = rect; michael@0: } michael@0: michael@0: GLint width = rect.width; michael@0: GLint height = rect.height; michael@0: michael@0: // We can't draw anything to something with no area michael@0: // so just return michael@0: if (width == 0 || height == 0) michael@0: return; michael@0: michael@0: // If the widget size changed, we have to force a MakeCurrent michael@0: // to make sure that GL sees the updated widget size. michael@0: if (mWidgetSize.width != width || michael@0: mWidgetSize.height != height) michael@0: { michael@0: MakeCurrent(ForceMakeCurrent); michael@0: michael@0: mWidgetSize.width = width; michael@0: mWidgetSize.height = height; michael@0: } else { michael@0: MakeCurrent(); michael@0: } michael@0: michael@0: mPixelsPerFrame = width * height; michael@0: mPixelsFilled = 0; michael@0: michael@0: #if MOZ_ANDROID_OMTC michael@0: TexturePoolOGL::Fill(gl()); michael@0: #endif michael@0: michael@0: mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this, michael@0: IntSize(width, height), michael@0: aTransform); michael@0: mCurrentRenderTarget->BindRenderTarget(); michael@0: #ifdef DEBUG michael@0: mWindowRenderTarget = mCurrentRenderTarget; michael@0: #endif michael@0: michael@0: // Default blend function implements "OVER" michael@0: mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: mGLContext->fEnable(LOCAL_GL_BLEND); michael@0: michael@0: mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); michael@0: michael@0: if (aClipRectOut && !aClipRectIn) { michael@0: aClipRectOut->SetRect(0, 0, width, height); michael@0: } michael@0: michael@0: // If the Android compositor is being used, this clear will be done in michael@0: // DrawWindowUnderlay. Make sure the bits used here match up with those used michael@0: // in mobile/android/base/gfx/LayerRenderer.java michael@0: #ifndef MOZ_ANDROID_OMTC michael@0: mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); michael@0: mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource, michael@0: GLuint aSourceFrameBuffer, michael@0: GLuint *aFBO, GLuint *aTexture) michael@0: { michael@0: GLuint tex, fbo; michael@0: michael@0: mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); michael@0: mGLContext->fGenTextures(1, &tex); michael@0: mGLContext->fBindTexture(mFBOTextureTarget, tex); michael@0: michael@0: if (aCopyFromSource) { michael@0: GLuint curFBO = mCurrentRenderTarget->GetFBO(); michael@0: if (curFBO != aSourceFrameBuffer) { michael@0: mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer); michael@0: } michael@0: michael@0: // We're going to create an RGBA temporary fbo. But to michael@0: // CopyTexImage() from the current framebuffer, the framebuffer's michael@0: // format has to be compatible with the new texture's. So we michael@0: // check the format of the framebuffer here and take a slow path michael@0: // if it's incompatible. michael@0: GLenum format = michael@0: GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget); michael@0: michael@0: bool isFormatCompatibleWithRGBA michael@0: = gl()->IsGLES() ? (format == LOCAL_GL_RGBA) michael@0: : true; michael@0: michael@0: if (isFormatCompatibleWithRGBA) { michael@0: mGLContext->fCopyTexImage2D(mFBOTextureTarget, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: aRect.x, FlipY(aRect.y + aRect.height), michael@0: aRect.width, aRect.height, michael@0: 0); michael@0: } else { michael@0: // Curses, incompatible formats. Take a slow path. michael@0: michael@0: // RGBA michael@0: size_t bufferSize = aRect.width * aRect.height * 4; michael@0: nsAutoArrayPtr buf(new uint8_t[bufferSize]); michael@0: michael@0: mGLContext->fReadPixels(aRect.x, aRect.y, michael@0: aRect.width, aRect.height, michael@0: LOCAL_GL_RGBA, michael@0: LOCAL_GL_UNSIGNED_BYTE, michael@0: buf); michael@0: mGLContext->fTexImage2D(mFBOTextureTarget, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: aRect.width, aRect.height, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: LOCAL_GL_UNSIGNED_BYTE, michael@0: buf); michael@0: } michael@0: GLenum error = mGLContext->GetAndClearError(); michael@0: if (error != LOCAL_GL_NO_ERROR) { michael@0: nsAutoCString msg; michael@0: msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d", michael@0: error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA); michael@0: NS_ERROR(msg.get()); michael@0: } michael@0: } else { michael@0: mGLContext->fTexImage2D(mFBOTextureTarget, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: aRect.width, aRect.height, michael@0: 0, michael@0: LOCAL_GL_RGBA, michael@0: LOCAL_GL_UNSIGNED_BYTE, michael@0: nullptr); michael@0: } michael@0: mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, michael@0: LOCAL_GL_LINEAR); michael@0: mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, michael@0: LOCAL_GL_LINEAR); michael@0: mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, michael@0: LOCAL_GL_CLAMP_TO_EDGE); michael@0: mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, michael@0: LOCAL_GL_CLAMP_TO_EDGE); michael@0: mGLContext->fBindTexture(mFBOTextureTarget, 0); michael@0: michael@0: mGLContext->fGenFramebuffers(1, &fbo); michael@0: michael@0: *aFBO = fbo; michael@0: *aTexture = tex; michael@0: } michael@0: michael@0: ShaderConfigOGL michael@0: CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const michael@0: { michael@0: ShaderConfigOGL config; michael@0: michael@0: switch(aEffect->mType) { michael@0: case EFFECT_SOLID_COLOR: michael@0: config.SetRenderColor(true); michael@0: break; michael@0: case EFFECT_YCBCR: michael@0: config.SetYCbCr(true); michael@0: break; michael@0: case EFFECT_COMPONENT_ALPHA: michael@0: { michael@0: config.SetComponentAlpha(true); michael@0: EffectComponentAlpha* effectComponentAlpha = michael@0: static_cast(aEffect); michael@0: gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat(); michael@0: config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 || michael@0: format == gfx::SurfaceFormat::B8G8R8X8); michael@0: break; michael@0: } michael@0: case EFFECT_RENDER_TARGET: michael@0: config.SetTextureTarget(mFBOTextureTarget); michael@0: break; michael@0: default: michael@0: { michael@0: MOZ_ASSERT(aEffect->mType == EFFECT_RGB); michael@0: TexturedEffect* texturedEffect = michael@0: static_cast(aEffect); michael@0: TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); michael@0: MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL, michael@0: source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8); michael@0: MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB, michael@0: source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || michael@0: source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || michael@0: source->GetFormat() == gfx::SurfaceFormat::R5G6B5); michael@0: config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(), michael@0: source->GetFormat()); michael@0: break; michael@0: } michael@0: } michael@0: config.SetMask2D(aMask == Mask2d); michael@0: config.SetMask3D(aMask == Mask3d); michael@0: return config; michael@0: } michael@0: michael@0: ShaderProgramOGL* michael@0: CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig) michael@0: { michael@0: std::map::iterator iter = mPrograms.find(aConfig); michael@0: if (iter != mPrograms.end()) michael@0: return iter->second; michael@0: michael@0: ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig); michael@0: ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile); michael@0: if (!shader->Initialize()) { michael@0: delete shader; michael@0: return nullptr; michael@0: } michael@0: michael@0: mPrograms[aConfig] = shader; michael@0: return shader; michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::DrawLines(const std::vector& aLines, const gfx::Rect& aClipRect, michael@0: const gfx::Color& aColor, michael@0: gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) michael@0: { michael@0: mGLContext->fLineWidth(2.0); michael@0: michael@0: EffectChain effects; michael@0: effects.mPrimaryEffect = new EffectSolidColor(aColor); michael@0: michael@0: for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) { michael@0: const gfx::Point& p1 = aLines[i]; michael@0: const gfx::Point& p2 = aLines[i+1]; michael@0: DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y), michael@0: aClipRect, effects, aOpacity, aTransform, michael@0: LOCAL_GL_LINE_STRIP); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::DrawQuadInternal(const Rect& aRect, michael@0: const Rect& aClipRect, michael@0: const EffectChain &aEffectChain, michael@0: Float aOpacity, michael@0: const gfx::Matrix4x4 &aTransform, michael@0: GLuint aDrawMode) michael@0: { michael@0: PROFILER_LABEL("CompositorOGL", "DrawQuad"); michael@0: MOZ_ASSERT(mFrameInProgress, "frame not started"); michael@0: michael@0: Rect clipRect = aClipRect; michael@0: if (!mTarget) { michael@0: clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y); michael@0: } michael@0: IntRect intClipRect; michael@0: clipRect.ToIntRect(&intClipRect); michael@0: michael@0: gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height), michael@0: intClipRect.width, intClipRect.height); michael@0: michael@0: LayerScope::SendEffectChain(mGLContext, aEffectChain, michael@0: aRect.width, aRect.height); michael@0: michael@0: MaskType maskType; michael@0: EffectMask* effectMask; michael@0: TextureSourceOGL* sourceMask = nullptr; michael@0: gfx::Matrix4x4 maskQuadTransform; michael@0: if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) { michael@0: effectMask = static_cast(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); michael@0: sourceMask = effectMask->mMaskTexture->AsSourceOGL(); michael@0: michael@0: // NS_ASSERTION(textureMask->IsAlpha(), michael@0: // "OpenGL mask layers must be backed by alpha surfaces"); michael@0: michael@0: // We're assuming that the gl backend won't cheat and use NPOT michael@0: // textures when glContext says it can't (which seems to happen michael@0: // on a mac when you force POT textures) michael@0: IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext); michael@0: michael@0: const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform; michael@0: NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); michael@0: Rect bounds = Rect(Point(), Size(maskSize)); michael@0: bounds = maskTransform.As2D().TransformBounds(bounds); michael@0: michael@0: maskQuadTransform._11 = 1.0f/bounds.width; michael@0: maskQuadTransform._22 = 1.0f/bounds.height; michael@0: maskQuadTransform._41 = float(-bounds.x)/bounds.width; michael@0: maskQuadTransform._42 = float(-bounds.y)/bounds.height; michael@0: michael@0: maskType = effectMask->mIs3D michael@0: ? Mask3d michael@0: : Mask2d; michael@0: } else { michael@0: maskType = MaskNone; michael@0: } michael@0: michael@0: mPixelsFilled += aRect.width * aRect.height; michael@0: michael@0: // Determine the color if this is a color shader and fold the opacity into michael@0: // the color since color shaders don't have an opacity uniform. michael@0: Color color; michael@0: if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) { michael@0: EffectSolidColor* effectSolidColor = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: color = effectSolidColor->mColor; michael@0: michael@0: Float opacity = aOpacity * color.a; michael@0: color.r *= opacity; michael@0: color.g *= opacity; michael@0: color.b *= opacity; michael@0: color.a = opacity; michael@0: michael@0: // We can fold opacity into the color, so no need to consider it further. michael@0: aOpacity = 1.f; michael@0: } michael@0: michael@0: ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType); michael@0: config.SetOpacity(aOpacity != 1.f); michael@0: ShaderProgramOGL *program = GetShaderProgramFor(config); michael@0: program->Activate(); michael@0: program->SetProjectionMatrix(mProjMatrix); michael@0: program->SetLayerQuadRect(aRect); michael@0: program->SetLayerTransform(aTransform); michael@0: IntPoint offset = mCurrentRenderTarget->GetOrigin(); michael@0: program->SetRenderOffset(offset.x, offset.y); michael@0: if (aOpacity != 1.f) michael@0: program->SetLayerOpacity(aOpacity); michael@0: if (config.mFeatures & ENABLE_TEXTURE_RECT) { michael@0: TexturedEffect* texturedEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); michael@0: // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. michael@0: program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height); michael@0: } michael@0: michael@0: switch (aEffectChain.mPrimaryEffect->mType) { michael@0: case EFFECT_SOLID_COLOR: { michael@0: program->SetRenderColor(color); michael@0: michael@0: if (maskType != MaskNone) { michael@0: BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform); michael@0: } michael@0: michael@0: BindAndDrawQuad(program, aDrawMode); michael@0: } michael@0: break; michael@0: michael@0: case EFFECT_RGB: { michael@0: TexturedEffect* texturedEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: TextureSource *source = texturedEffect->mTexture; michael@0: michael@0: if (!texturedEffect->mPremultiplied) { michael@0: mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: } michael@0: michael@0: gfx::Filter filter = texturedEffect->mFilter; michael@0: gfx3DMatrix textureTransform; michael@0: gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: gfxMatrix textureTransform2D; michael@0: if (filter != gfx::Filter::POINT && michael@0: aTransform.Is2DIntegerTranslation() && michael@0: textureTransform.Is2D(&textureTransform2D) && michael@0: textureTransform2D.HasOnlyIntegerTranslation()) { michael@0: // On Android we encounter small resampling errors in what should be michael@0: // pixel-aligned compositing operations. This works around them. This michael@0: // code should not be needed! michael@0: filter = gfx::Filter::POINT; michael@0: } michael@0: #endif michael@0: source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter); michael@0: michael@0: program->SetTextureUnit(0); michael@0: michael@0: if (maskType != MaskNone) { michael@0: BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform); michael@0: } michael@0: michael@0: BindAndDrawQuadWithTextureRect(program, textureTransform, michael@0: texturedEffect->mTextureCoords, source); michael@0: michael@0: if (!texturedEffect->mPremultiplied) { michael@0: mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: } michael@0: } michael@0: break; michael@0: case EFFECT_YCBCR: { michael@0: EffectYCbCr* effectYCbCr = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: TextureSource* sourceYCbCr = effectYCbCr->mTexture; michael@0: const int Y = 0, Cb = 1, Cr = 2; michael@0: TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); michael@0: TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); michael@0: TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); michael@0: michael@0: if (!sourceY && !sourceCb && !sourceCr) { michael@0: NS_WARNING("Invalid layer texture."); michael@0: return; michael@0: } michael@0: michael@0: sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter); michael@0: sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter); michael@0: sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter); michael@0: michael@0: program->SetYCbCrTextureUnits(Y, Cb, Cr); michael@0: michael@0: if (maskType != MaskNone) { michael@0: BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform); michael@0: } michael@0: BindAndDrawQuadWithTextureRect(program, michael@0: gfx3DMatrix(), michael@0: effectYCbCr->mTextureCoords, michael@0: sourceYCbCr->GetSubSource(Y)); michael@0: } michael@0: break; michael@0: case EFFECT_RENDER_TARGET: { michael@0: EffectRenderTarget* effectRenderTarget = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: RefPtr surface michael@0: = static_cast(effectRenderTarget->mRenderTarget.get()); michael@0: michael@0: surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget); michael@0: michael@0: // Drawing is always flipped, but when copying between surfaces we want to avoid michael@0: // this, so apply a flip here to cancel the other one out. michael@0: Matrix transform; michael@0: transform.Translate(0.0, 1.0); michael@0: transform.Scale(1.0f, -1.0f); michael@0: program->SetTextureTransform(Matrix4x4::From2D(transform)); michael@0: program->SetTextureUnit(0); michael@0: michael@0: if (maskType != MaskNone) { michael@0: sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR); michael@0: program->SetMaskTextureUnit(1); michael@0: program->SetMaskLayerTransform(maskQuadTransform); michael@0: } michael@0: michael@0: if (config.mFeatures & ENABLE_TEXTURE_RECT) { michael@0: // 2DRect case, get the multiplier right for a sampler2DRect michael@0: program->SetTexCoordMultiplier(aRect.width, aRect.height); michael@0: } michael@0: michael@0: // Drawing is always flipped, but when copying between surfaces we want to avoid michael@0: // this. Pass true for the flip parameter to introduce a second flip michael@0: // that cancels the other one out. michael@0: BindAndDrawQuad(program); michael@0: } michael@0: break; michael@0: case EFFECT_COMPONENT_ALPHA: { michael@0: MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); michael@0: EffectComponentAlpha* effectComponentAlpha = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL(); michael@0: TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL(); michael@0: michael@0: if (!sourceOnBlack->IsValid() || michael@0: !sourceOnWhite->IsValid()) { michael@0: NS_WARNING("Invalid layer texture for component alpha"); michael@0: return; michael@0: } michael@0: michael@0: sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter); michael@0: sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter); michael@0: michael@0: program->SetBlackTextureUnit(0); michael@0: program->SetWhiteTextureUnit(1); michael@0: program->SetTextureTransform(gfx::Matrix4x4()); michael@0: michael@0: if (maskType != MaskNone) { michael@0: BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform); michael@0: } michael@0: // Pass 1. michael@0: gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: program->SetTexturePass2(false); michael@0: BindAndDrawQuadWithTextureRect(program, michael@0: gfx3DMatrix(), michael@0: effectComponentAlpha->mTextureCoords, michael@0: effectComponentAlpha->mOnBlack); michael@0: michael@0: // Pass 2. michael@0: gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (gl()->WorkAroundDriverBugs() && michael@0: gl()->Vendor() == GLVendor::NVIDIA && michael@0: !nsCocoaFeatures::OnMavericksOrLater()) { michael@0: // Bug 987497: With some GPUs the nvidia driver on 10.8 and below michael@0: // won't pick up the TexturePass2 uniform change below if we don't do michael@0: // something to force it. Re-activating the shader seems to be one way michael@0: // of achieving that. michael@0: program->Activate(); michael@0: } michael@0: #endif michael@0: michael@0: program->SetTexturePass2(true); michael@0: BindAndDrawQuadWithTextureRect(program, michael@0: gfx3DMatrix(), michael@0: effectComponentAlpha->mTextureCoords, michael@0: effectComponentAlpha->mOnBlack); michael@0: michael@0: mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, michael@0: LOCAL_GL_ONE, LOCAL_GL_ONE); michael@0: } michael@0: break; michael@0: default: michael@0: MOZ_ASSERT(false, "Unhandled effect type"); michael@0: break; michael@0: } michael@0: michael@0: // in case rendering has used some other GL context michael@0: MakeCurrent(); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::EndFrame() michael@0: { michael@0: PROFILER_LABEL("CompositorOGL", "EndFrame"); michael@0: MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored"); michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: if (gfxUtils::sDumpPainting) { michael@0: nsIntRect rect; michael@0: if (mUseExternalSurfaceSize) { michael@0: rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); michael@0: } else { michael@0: mWidget->GetBounds(rect); michael@0: } michael@0: RefPtr target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8); michael@0: CopyToTarget(target, mCurrentRenderTarget->GetTransform()); michael@0: michael@0: WriteSnapshotToDumpFile(this, target); michael@0: } michael@0: #endif michael@0: michael@0: mFrameInProgress = false; michael@0: michael@0: LayerScope::EndFrame(mGLContext); michael@0: michael@0: if (mTarget) { michael@0: CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform()); michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: mCurrentRenderTarget = nullptr; michael@0: return; michael@0: } michael@0: michael@0: mCurrentRenderTarget = nullptr; michael@0: michael@0: if (mTexturePool) { michael@0: mTexturePool->EndFrame(); michael@0: } michael@0: michael@0: mGLContext->SwapBuffers(); michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: michael@0: // Unbind all textures michael@0: mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); michael@0: if (!mGLContext->IsGLES()) { michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); michael@0: } michael@0: michael@0: mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1); michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); michael@0: if (!mGLContext->IsGLES()) { michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); michael@0: } michael@0: michael@0: mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2); michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); michael@0: if (!mGLContext->IsGLES()) { michael@0: mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); michael@0: } michael@0: } michael@0: michael@0: #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 michael@0: void michael@0: CompositorOGL::SetFBAcquireFence(Layer* aLayer) michael@0: { michael@0: // OpenGL does not provide ReleaseFence for rendering. michael@0: // Instead use FBAcquireFence as layer buffer's ReleaseFence michael@0: // to prevent flickering and tearing. michael@0: // FBAcquireFence is FramebufferSurface's AcquireFence. michael@0: // AcquireFence will be signaled when a buffer's content is available. michael@0: // See Bug 974152. michael@0: michael@0: if (!aLayer) { michael@0: return; michael@0: } michael@0: michael@0: const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); michael@0: if (visibleRegion.IsEmpty()) { michael@0: return; michael@0: } michael@0: michael@0: // Set FBAcquireFence on ContainerLayer's childs michael@0: ContainerLayer* container = aLayer->AsContainerLayer(); michael@0: if (container) { michael@0: for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { michael@0: SetFBAcquireFence(child); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer. michael@0: TiledLayerComposer* composer = nullptr; michael@0: LayerComposite* shadow = aLayer->AsLayerComposite(); michael@0: if (shadow) { michael@0: composer = shadow->GetTiledLayerComposer(); michael@0: if (composer) { michael@0: composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: // Set FBAcquireFence as layer buffer's ReleaseFence michael@0: LayerRenderState state = aLayer->GetRenderState(); michael@0: if (!state.mTexture) { michael@0: return; michael@0: } michael@0: TextureHostOGL* texture = state.mTexture->AsHostOGL(); michael@0: if (!texture) { michael@0: return; michael@0: } michael@0: texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); michael@0: } michael@0: #else michael@0: void michael@0: CompositorOGL::SetFBAcquireFence(Layer* aLayer) michael@0: { michael@0: } michael@0: #endif michael@0: michael@0: void michael@0: CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform) michael@0: { michael@0: // This lets us reftest and screenshot content rendered externally michael@0: if (mTarget) { michael@0: MakeCurrent(); michael@0: CopyToTarget(mTarget, aTransform); michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: } michael@0: if (mTexturePool) { michael@0: mTexturePool->EndFrame(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::AbortFrame() michael@0: { michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); michael@0: mFrameInProgress = false; michael@0: mCurrentRenderTarget = nullptr; michael@0: michael@0: if (mTexturePool) { michael@0: mTexturePool->EndFrame(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize) michael@0: { michael@0: mSurfaceSize.width = aSize.width; michael@0: mSurfaceSize.height = aSize.height; michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform) michael@0: { michael@0: IntRect rect; michael@0: if (mUseExternalSurfaceSize) { michael@0: rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); michael@0: } else { michael@0: rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height); michael@0: } michael@0: GLint width = rect.width; michael@0: GLint height = rect.height; michael@0: michael@0: if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) { michael@0: NS_ERROR("Widget size too big - integer overflow!"); michael@0: return; michael@0: } michael@0: michael@0: mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); michael@0: michael@0: if (!mGLContext->IsGLES()) { michael@0: // GLES2 promises that binding to any custom FBO will attach michael@0: // to GL_COLOR_ATTACHMENT0 attachment point. michael@0: mGLContext->fReadBuffer(LOCAL_GL_BACK); michael@0: } michael@0: michael@0: RefPtr source = michael@0: Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8); michael@0: michael@0: DataSourceSurface::MappedSurface map; michael@0: source->Map(DataSourceSurface::MapType::WRITE, &map); michael@0: // XXX we should do this properly one day without using the gfxImageSurface michael@0: nsRefPtr surf = michael@0: new gfxImageSurface(map.mData, michael@0: gfxIntSize(width, height), michael@0: map.mStride, michael@0: gfxImageFormat::ARGB32); michael@0: ReadPixelsIntoImageSurface(mGLContext, surf); michael@0: source->Unmap(); michael@0: michael@0: // Map from GL space to Cairo space and reverse the world transform. michael@0: Matrix glToCairoTransform = aTransform; michael@0: glToCairoTransform.Invert(); michael@0: glToCairoTransform.Scale(1.0, -1.0); michael@0: glToCairoTransform.Translate(0.0, -height); michael@0: michael@0: Matrix oldMatrix = aTarget->GetTransform(); michael@0: aTarget->SetTransform(glToCairoTransform); michael@0: Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height); michael@0: aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); michael@0: aTarget->SetTransform(oldMatrix); michael@0: aTarget->Flush(); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::Pause() michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (!gl() || gl()->IsDestroyed()) michael@0: return; michael@0: michael@0: // ReleaseSurface internally calls MakeCurrent. michael@0: gl()->ReleaseSurface(); michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: CompositorOGL::Resume() michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (!gl() || gl()->IsDestroyed()) michael@0: return false; michael@0: michael@0: // RenewSurface internally calls MakeCurrent. michael@0: return gl()->RenewSurface(); michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorOGL::CreateDataTextureSource(TextureFlags aFlags) michael@0: { michael@0: RefPtr result = michael@0: new TextureImageTextureSourceOGL(mGLContext, aFlags); michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: CompositorOGL::SupportsPartialTextureUpdate() michael@0: { michael@0: return CanUploadSubTextures(mGLContext); michael@0: } michael@0: michael@0: int32_t michael@0: CompositorOGL::GetMaxTextureSize() const michael@0: { michael@0: MOZ_ASSERT(mGLContext); michael@0: GLint texSize = 0; michael@0: mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, michael@0: &texSize); michael@0: MOZ_ASSERT(texSize != 0); michael@0: return texSize; michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) { michael@0: if (mDestroyed) { michael@0: NS_WARNING("Call on destroyed layer manager"); michael@0: return; michael@0: } michael@0: mGLContext->MakeCurrent(aFlags & ForceMakeCurrent); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::BindQuadVBO() { michael@0: mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) { michael@0: mGLContext->fVertexAttribPointer(aAttribIndex, 2, michael@0: LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, michael@0: (GLvoid*) QuadVBOVertexOffset()); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) { michael@0: mGLContext->fVertexAttribPointer(aAttribIndex, 2, michael@0: LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, michael@0: (GLvoid*) QuadVBOTexCoordOffset()); michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex, michael@0: GLuint aTexCoordAttribIndex, michael@0: GLuint aDrawMode) michael@0: { michael@0: BindQuadVBO(); michael@0: QuadVBOVerticesAttrib(aVertAttribIndex); michael@0: michael@0: if (aTexCoordAttribIndex != GLuint(-1)) { michael@0: QuadVBOTexCoordsAttrib(aTexCoordAttribIndex); michael@0: mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex); michael@0: } michael@0: michael@0: mGLContext->fEnableVertexAttribArray(aVertAttribIndex); michael@0: if (aDrawMode == LOCAL_GL_LINE_STRIP) { michael@0: mGLContext->fDrawArrays(aDrawMode, 1, 2); michael@0: } else { michael@0: mGLContext->fDrawArrays(aDrawMode, 0, 4); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg, michael@0: GLuint aDrawMode) michael@0: { michael@0: NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); michael@0: BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib), michael@0: aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib), michael@0: aDrawMode); michael@0: } michael@0: michael@0: GLuint michael@0: CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) michael@0: { michael@0: if (!mTexturePool) { michael@0: #ifdef MOZ_WIDGET_GONK michael@0: mTexturePool = new PerFrameTexturePoolOGL(gl()); michael@0: #else michael@0: mTexturePool = new PerUnitTexturePoolOGL(gl()); michael@0: #endif michael@0: } michael@0: return mTexturePool->GetTexture(aTarget, aUnit); michael@0: } michael@0: michael@0: GLuint michael@0: PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) michael@0: { michael@0: if (mTextureTarget == 0) { michael@0: mTextureTarget = aTarget; michael@0: } michael@0: MOZ_ASSERT(mTextureTarget == aTarget); michael@0: michael@0: size_t index = aTextureUnit - LOCAL_GL_TEXTURE0; michael@0: // lazily grow the array of temporary textures michael@0: if (mTextures.Length() <= index) { michael@0: size_t prevLength = mTextures.Length(); michael@0: mTextures.SetLength(index + 1); michael@0: for(unsigned int i = prevLength; i <= index; ++i) { michael@0: mTextures[i] = 0; michael@0: } michael@0: } michael@0: // lazily initialize the temporary textures michael@0: if (!mTextures[index]) { michael@0: if (!mGL->MakeCurrent()) { michael@0: return 0; michael@0: } michael@0: mGL->fGenTextures(1, &mTextures[index]); michael@0: mGL->fBindTexture(aTarget, mTextures[index]); michael@0: mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); michael@0: mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); michael@0: } michael@0: return mTextures[index]; michael@0: } michael@0: michael@0: void michael@0: PerUnitTexturePoolOGL::DestroyTextures() michael@0: { michael@0: if (mGL && mGL->MakeCurrent()) { michael@0: if (mTextures.Length() > 0) { michael@0: mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]); michael@0: } michael@0: } michael@0: mTextures.SetLength(0); michael@0: } michael@0: michael@0: void michael@0: PerFrameTexturePoolOGL::DestroyTextures() michael@0: { michael@0: if (!mGL->MakeCurrent()) { michael@0: return; michael@0: } michael@0: michael@0: if (mUnusedTextures.Length() > 0) { michael@0: mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]); michael@0: mUnusedTextures.Clear(); michael@0: } michael@0: michael@0: if (mCreatedTextures.Length() > 0) { michael@0: mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]); michael@0: mCreatedTextures.Clear(); michael@0: } michael@0: } michael@0: michael@0: GLuint michael@0: PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum) michael@0: { michael@0: if (mTextureTarget == 0) { michael@0: mTextureTarget = aTarget; michael@0: } michael@0: michael@0: // The pool should always use the same texture target because it is illegal michael@0: // to change the target of an already exisiting gl texture. michael@0: // If we need to use several targets, a pool with several sub-pools (one per michael@0: // target) will have to be implemented. michael@0: // At the moment this pool is only used with tiling on b2g so we always need michael@0: // the same target. michael@0: MOZ_ASSERT(mTextureTarget == aTarget); michael@0: michael@0: GLuint texture = 0; michael@0: michael@0: if (!mUnusedTextures.IsEmpty()) { michael@0: // Try to reuse one from the unused pile first michael@0: texture = mUnusedTextures[0]; michael@0: mUnusedTextures.RemoveElementAt(0); michael@0: } else if (mGL->MakeCurrent()) { michael@0: // There isn't one to reuse, create one. michael@0: mGL->fGenTextures(1, &texture); michael@0: mGL->fBindTexture(aTarget, texture); michael@0: mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); michael@0: mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); michael@0: } michael@0: michael@0: if (texture) { michael@0: mCreatedTextures.AppendElement(texture); michael@0: } michael@0: michael@0: return texture; michael@0: } michael@0: michael@0: void michael@0: PerFrameTexturePoolOGL::EndFrame() michael@0: { michael@0: if (!mGL->MakeCurrent()) { michael@0: // this means the context got destroyed underneith us somehow, and the driver michael@0: // already has destroyed the textures. michael@0: mCreatedTextures.Clear(); michael@0: mUnusedTextures.Clear(); michael@0: return; michael@0: } michael@0: michael@0: // Some platforms have issues unlocking Gralloc buffers even when they're michael@0: // rebound. michael@0: if (gfxPrefs::OverzealousGrallocUnlocking()) { michael@0: mUnusedTextures.AppendElements(mCreatedTextures); michael@0: mCreatedTextures.Clear(); michael@0: } michael@0: michael@0: // Delete unused textures michael@0: for (size_t i = 0; i < mUnusedTextures.Length(); i++) { michael@0: GLuint texture = mUnusedTextures[i]; michael@0: mGL->fDeleteTextures(1, &texture); michael@0: } michael@0: mUnusedTextures.Clear(); michael@0: michael@0: // Move all created textures into the unused pile michael@0: mUnusedTextures.AppendElements(mCreatedTextures); michael@0: mCreatedTextures.Clear(); michael@0: } michael@0: michael@0: } /* layers */ michael@0: } /* mozilla */