1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/opengl/CompositorOGL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1621 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "CompositorOGL.h" 1.10 +#include <stddef.h> // for size_t 1.11 +#include <stdint.h> // for uint32_t, uint8_t 1.12 +#include <stdlib.h> // for free, malloc 1.13 +#include "GLContextProvider.h" // for GLContextProvider 1.14 +#include "GLContext.h" // for GLContext 1.15 +#include "GLUploadHelpers.h" 1.16 +#include "Layers.h" // for WriteSnapshotToDumpFile 1.17 +#include "LayerScope.h" // for LayerScope 1.18 +#include "gfx2DGlue.h" // for ThebesFilter 1.19 +#include "gfx3DMatrix.h" // for gfx3DMatrix 1.20 +#include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter 1.21 +#include "gfxImageSurface.h" // for gfxImageSurface 1.22 +#include "gfxMatrix.h" // for gfxMatrix 1.23 +#include "GraphicsFilter.h" // for GraphicsFilter 1.24 +#include "gfxPlatform.h" // for gfxPlatform 1.25 +#include "gfxPrefs.h" // for gfxPrefs 1.26 +#include "gfxRect.h" // for gfxRect 1.27 +#include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc 1.28 +#include "mozilla/ArrayUtils.h" // for ArrayLength 1.29 +#include "mozilla/Preferences.h" // for Preferences 1.30 +#include "mozilla/gfx/BasePoint.h" // for BasePoint 1.31 +#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix 1.32 +#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc 1.33 +#include "mozilla/layers/CompositingRenderTargetOGL.h" 1.34 +#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc 1.35 +#include "mozilla/layers/TextureHost.h" // for TextureSource, etc 1.36 +#include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc 1.37 +#include "mozilla/mozalloc.h" // for operator delete, etc 1.38 +#include "nsAString.h" 1.39 +#include "nsIConsoleService.h" // for nsIConsoleService, etc 1.40 +#include "nsIWidget.h" // for nsIWidget 1.41 +#include "nsLiteralString.h" // for NS_LITERAL_STRING 1.42 +#include "nsMathUtils.h" // for NS_roundf 1.43 +#include "nsRect.h" // for nsIntRect 1.44 +#include "nsServiceManagerUtils.h" // for do_GetService 1.45 +#include "nsString.h" // for nsString, nsAutoCString, etc 1.46 +#include "DecomposeIntoNoRepeatTriangles.h" 1.47 +#include "ScopedGLHelpers.h" 1.48 +#include "GLReadTexImageHelper.h" 1.49 +#include "TiledLayerBuffer.h" // for TiledLayerComposer 1.50 + 1.51 +#if MOZ_ANDROID_OMTC 1.52 +#include "TexturePoolOGL.h" 1.53 +#endif 1.54 + 1.55 +#ifdef XP_MACOSX 1.56 +#include "nsCocoaFeatures.h" 1.57 +#endif 1.58 + 1.59 +#include "GeckoProfiler.h" 1.60 + 1.61 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.62 +#include "libdisplay/GonkDisplay.h" // for GonkDisplay 1.63 +#include <ui/Fence.h> 1.64 +#endif 1.65 + 1.66 +#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) 1.67 + 1.68 +namespace mozilla { 1.69 + 1.70 +using namespace std; 1.71 +using namespace gfx; 1.72 + 1.73 +namespace layers { 1.74 + 1.75 +using namespace mozilla::gl; 1.76 + 1.77 +static inline IntSize ns2gfxSize(const nsIntSize& s) { 1.78 + return IntSize(s.width, s.height); 1.79 +} 1.80 + 1.81 +static void 1.82 +BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask, 1.83 + GLenum aTexUnit, const gfx::Matrix4x4& aTransform) 1.84 +{ 1.85 + MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31); 1.86 + aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR); 1.87 + aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0); 1.88 + aProgram->SetMaskLayerTransform(aTransform); 1.89 +} 1.90 + 1.91 +// Draw the given quads with the already selected shader. Texture coordinates 1.92 +// are supplied if the shader requires them. 1.93 +static void 1.94 +DrawQuads(GLContext *aGLContext, 1.95 + VBOArena &aVBOs, 1.96 + ShaderProgramOGL *aProg, 1.97 + GLenum aMode, 1.98 + RectTriangles &aRects) 1.99 +{ 1.100 + NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); 1.101 + GLuint vertAttribIndex = 1.102 + aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); 1.103 + GLuint texCoordAttribIndex = 1.104 + aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib); 1.105 + bool texCoords = (texCoordAttribIndex != GLuint(-1)); 1.106 + 1.107 + GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat); 1.108 + 1.109 + GLsizei total = bytes; 1.110 + if (texCoords) { 1.111 + total *= 2; 1.112 + } 1.113 + 1.114 + aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 1.115 + aVBOs.Allocate(aGLContext)); 1.116 + aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, 1.117 + total, 1.118 + nullptr, 1.119 + LOCAL_GL_STREAM_DRAW); 1.120 + 1.121 + aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, 1.122 + 0, 1.123 + bytes, 1.124 + aRects.vertCoords().Elements()); 1.125 + aGLContext->fEnableVertexAttribArray(vertAttribIndex); 1.126 + aGLContext->fVertexAttribPointer(vertAttribIndex, 1.127 + 2, LOCAL_GL_FLOAT, 1.128 + LOCAL_GL_FALSE, 1.129 + 0, BUFFER_OFFSET(0)); 1.130 + 1.131 + if (texCoords) { 1.132 + aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, 1.133 + bytes, 1.134 + bytes, 1.135 + aRects.texCoords().Elements()); 1.136 + aGLContext->fEnableVertexAttribArray(texCoordAttribIndex); 1.137 + aGLContext->fVertexAttribPointer(texCoordAttribIndex, 1.138 + 2, LOCAL_GL_FLOAT, 1.139 + LOCAL_GL_FALSE, 1.140 + 0, BUFFER_OFFSET(bytes)); 1.141 + } else { 1.142 + aGLContext->fDisableVertexAttribArray(texCoordAttribIndex); 1.143 + } 1.144 + 1.145 + aGLContext->fDrawArrays(aMode, 0, aRects.elements()); 1.146 + 1.147 + aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.148 +} 1.149 + 1.150 +CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth, 1.151 + int aSurfaceHeight, bool aUseExternalSurfaceSize) 1.152 + : mWidget(aWidget) 1.153 + , mWidgetSize(-1, -1) 1.154 + , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) 1.155 + , mHasBGRA(0) 1.156 + , mUseExternalSurfaceSize(aUseExternalSurfaceSize) 1.157 + , mFrameInProgress(false) 1.158 + , mDestroyed(false) 1.159 + , mHeight(0) 1.160 +{ 1.161 + MOZ_COUNT_CTOR(CompositorOGL); 1.162 + SetBackend(LayersBackend::LAYERS_OPENGL); 1.163 +} 1.164 + 1.165 +CompositorOGL::~CompositorOGL() 1.166 +{ 1.167 + MOZ_COUNT_DTOR(CompositorOGL); 1.168 + Destroy(); 1.169 +} 1.170 + 1.171 +already_AddRefed<mozilla::gl::GLContext> 1.172 +CompositorOGL::CreateContext() 1.173 +{ 1.174 + nsRefPtr<GLContext> context; 1.175 + 1.176 +#ifdef XP_WIN 1.177 + if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) { 1.178 + printf_stderr("Trying GL layers...\n"); 1.179 + context = gl::GLContextProviderEGL::CreateForWindow(mWidget); 1.180 + } 1.181 +#endif 1.182 + 1.183 + if (!context) 1.184 + context = gl::GLContextProvider::CreateForWindow(mWidget); 1.185 + 1.186 + if (!context) { 1.187 + NS_WARNING("Failed to create CompositorOGL context"); 1.188 + } 1.189 + 1.190 + return context.forget(); 1.191 +} 1.192 + 1.193 +void 1.194 +CompositorOGL::Destroy() 1.195 +{ 1.196 + if (gl() && gl()->MakeCurrent()) { 1.197 + mVBOs.Flush(gl()); 1.198 + } 1.199 + 1.200 + if (mTexturePool) { 1.201 + mTexturePool->Clear(); 1.202 + mTexturePool = nullptr; 1.203 + } 1.204 + 1.205 + if (!mDestroyed) { 1.206 + mDestroyed = true; 1.207 + CleanupResources(); 1.208 + } 1.209 +} 1.210 + 1.211 +void 1.212 +CompositorOGL::CleanupResources() 1.213 +{ 1.214 + if (!mGLContext) 1.215 + return; 1.216 + 1.217 + nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext(); 1.218 + if (!ctx) { 1.219 + ctx = mGLContext; 1.220 + } 1.221 + 1.222 + for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin(); 1.223 + iter != mPrograms.end(); 1.224 + iter++) { 1.225 + delete iter->second; 1.226 + } 1.227 + mPrograms.clear(); 1.228 + 1.229 + if (!ctx->MakeCurrent()) { 1.230 + mQuadVBO = 0; 1.231 + mGLContext = nullptr; 1.232 + return; 1.233 + } 1.234 + 1.235 + ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); 1.236 + 1.237 + if (mQuadVBO) { 1.238 + ctx->fDeleteBuffers(1, &mQuadVBO); 1.239 + mQuadVBO = 0; 1.240 + } 1.241 + 1.242 + mGLContext = nullptr; 1.243 +} 1.244 + 1.245 +bool 1.246 +CompositorOGL::Initialize() 1.247 +{ 1.248 + ScopedGfxFeatureReporter reporter("GL Layers", true); 1.249 + 1.250 + // Do not allow double initialization 1.251 + NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL"); 1.252 + 1.253 + mGLContext = CreateContext(); 1.254 + 1.255 +#ifdef MOZ_WIDGET_ANDROID 1.256 + if (!mGLContext) 1.257 + NS_RUNTIMEABORT("We need a context on Android"); 1.258 +#endif 1.259 + 1.260 + if (!mGLContext) 1.261 + return false; 1.262 + 1.263 + MakeCurrent(); 1.264 + 1.265 + mHasBGRA = 1.266 + mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) || 1.267 + mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra); 1.268 + 1.269 + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.270 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.271 + mGLContext->fEnable(LOCAL_GL_BLEND); 1.272 + 1.273 + // initialise a common shader to check that we can actually compile a shader 1.274 + RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0)); 1.275 + ShaderConfigOGL config = GetShaderConfigFor(effect); 1.276 + if (!GetShaderProgramFor(config)) { 1.277 + return false; 1.278 + } 1.279 + 1.280 + if (mGLContext->WorkAroundDriverBugs()) { 1.281 + /** 1.282 + * We'll test the ability here to bind NPOT textures to a framebuffer, if 1.283 + * this fails we'll try ARB_texture_rectangle. 1.284 + */ 1.285 + 1.286 + GLenum textureTargets[] = { 1.287 + LOCAL_GL_TEXTURE_2D, 1.288 + LOCAL_GL_NONE 1.289 + }; 1.290 + 1.291 + if (!mGLContext->IsGLES()) { 1.292 + // No TEXTURE_RECTANGLE_ARB available on ES2 1.293 + textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB; 1.294 + } 1.295 + 1.296 + mFBOTextureTarget = LOCAL_GL_NONE; 1.297 + 1.298 + GLuint testFBO = 0; 1.299 + mGLContext->fGenFramebuffers(1, &testFBO); 1.300 + GLuint testTexture = 0; 1.301 + 1.302 + for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) { 1.303 + GLenum target = textureTargets[i]; 1.304 + if (!target) 1.305 + continue; 1.306 + 1.307 + mGLContext->fGenTextures(1, &testTexture); 1.308 + mGLContext->fBindTexture(target, testTexture); 1.309 + mGLContext->fTexParameteri(target, 1.310 + LOCAL_GL_TEXTURE_MIN_FILTER, 1.311 + LOCAL_GL_NEAREST); 1.312 + mGLContext->fTexParameteri(target, 1.313 + LOCAL_GL_TEXTURE_MAG_FILTER, 1.314 + LOCAL_GL_NEAREST); 1.315 + mGLContext->fTexImage2D(target, 1.316 + 0, 1.317 + LOCAL_GL_RGBA, 1.318 + 5, 3, /* sufficiently NPOT */ 1.319 + 0, 1.320 + LOCAL_GL_RGBA, 1.321 + LOCAL_GL_UNSIGNED_BYTE, 1.322 + nullptr); 1.323 + 1.324 + // unbind this texture, in preparation for binding it to the FBO 1.325 + mGLContext->fBindTexture(target, 0); 1.326 + 1.327 + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO); 1.328 + mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, 1.329 + LOCAL_GL_COLOR_ATTACHMENT0, 1.330 + target, 1.331 + testTexture, 1.332 + 0); 1.333 + 1.334 + if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == 1.335 + LOCAL_GL_FRAMEBUFFER_COMPLETE) 1.336 + { 1.337 + mFBOTextureTarget = target; 1.338 + mGLContext->fDeleteTextures(1, &testTexture); 1.339 + break; 1.340 + } 1.341 + 1.342 + mGLContext->fDeleteTextures(1, &testTexture); 1.343 + } 1.344 + 1.345 + if (testFBO) { 1.346 + mGLContext->fDeleteFramebuffers(1, &testFBO); 1.347 + } 1.348 + 1.349 + if (mFBOTextureTarget == LOCAL_GL_NONE) { 1.350 + /* Unable to find a texture target that works with FBOs and NPOT textures */ 1.351 + return false; 1.352 + } 1.353 + } else { 1.354 + // not trying to work around driver bugs, so TEXTURE_2D should just work 1.355 + mFBOTextureTarget = LOCAL_GL_TEXTURE_2D; 1.356 + } 1.357 + 1.358 + // back to default framebuffer, to avoid confusion 1.359 + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); 1.360 + 1.361 + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { 1.362 + /* If we're using TEXTURE_RECTANGLE, then we must have the ARB 1.363 + * extension -- the EXT variant does not provide support for 1.364 + * texture rectangle access inside GLSL (sampler2DRect, 1.365 + * texture2DRect). 1.366 + */ 1.367 + if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)) 1.368 + return false; 1.369 + } 1.370 + 1.371 + /* Create a simple quad VBO */ 1.372 + 1.373 + mGLContext->fGenBuffers(1, &mQuadVBO); 1.374 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 1.375 + 1.376 + GLfloat vertices[] = { 1.377 + /* First quad vertices */ 1.378 + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.379 + /* Then quad texcoords */ 1.380 + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.381 + }; 1.382 + mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); 1.383 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.384 + 1.385 + nsCOMPtr<nsIConsoleService> 1.386 + console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); 1.387 + 1.388 + if (console) { 1.389 + nsString msg; 1.390 + msg += 1.391 + NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: "); 1.392 + msg += NS_ConvertUTF8toUTF16( 1.393 + nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION))); 1.394 + msg += NS_LITERAL_STRING("\nVendor: "); 1.395 + msg += NS_ConvertUTF8toUTF16( 1.396 + nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR))); 1.397 + msg += NS_LITERAL_STRING("\nRenderer: "); 1.398 + msg += NS_ConvertUTF8toUTF16( 1.399 + nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); 1.400 + msg += NS_LITERAL_STRING("\nFBO Texture Target: "); 1.401 + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) 1.402 + msg += NS_LITERAL_STRING("TEXTURE_2D"); 1.403 + else 1.404 + msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE"); 1.405 + console->LogStringMessage(msg.get()); 1.406 + } 1.407 + 1.408 + reporter.SetSuccessful(); 1.409 + return true; 1.410 +} 1.411 + 1.412 +// |aTextureTransform| is the texture transform that will be set on 1.413 +// aProg, possibly multiplied with another texture transform of our 1.414 +// own. 1.415 +// |aTexCoordRect| is the rectangle from the texture that we want to 1.416 +// draw using the given program. The program already has a necessary 1.417 +// offset and scale, so the geometry that needs to be drawn is a unit 1.418 +// square from 0,0 to 1,1. 1.419 +// 1.420 +// |aTexture| is the texture we are drawing. Its actual size can be 1.421 +// larger than the rectangle given by |aTexCoordRect|. 1.422 +void 1.423 +CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, 1.424 + const gfx3DMatrix& aTextureTransform, 1.425 + const Rect& aTexCoordRect, 1.426 + TextureSource *aTexture) 1.427 +{ 1.428 + // Given what we know about these textures and coordinates, we can 1.429 + // compute fmod(t, 1.0f) to get the same texture coordinate out. If 1.430 + // the texCoordRect dimension is < 0 or > width/height, then we have 1.431 + // wraparound that we need to deal with by drawing multiple quads, 1.432 + // because we can't rely on full non-power-of-two texture support 1.433 + // (which is required for the REPEAT wrap mode). 1.434 + 1.435 + RectTriangles rects; 1.436 + 1.437 + GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode(); 1.438 + 1.439 + IntSize realTexSize = aTexture->GetSize(); 1.440 + if (!CanUploadNonPowerOfTwo(mGLContext)) { 1.441 + realTexSize = IntSize(NextPowerOfTwo(realTexSize.width), 1.442 + NextPowerOfTwo(realTexSize.height)); 1.443 + } 1.444 + 1.445 + // We need to convert back to actual texels here to get proper behaviour with 1.446 + // our GL helper functions. Should fix this sometime. 1.447 + // I want to vomit. 1.448 + IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width), 1.449 + NS_roundf(aTexCoordRect.y * aTexture->GetSize().height), 1.450 + NS_roundf(aTexCoordRect.width * aTexture->GetSize().width), 1.451 + NS_roundf(aTexCoordRect.height * aTexture->GetSize().height)); 1.452 + 1.453 + // This is fairly disgusting - if the texture should be flipped it will have a 1.454 + // negative height, in which case we un-invert the texture coords and pass the 1.455 + // flipped 'flag' to the functions below. We can't just use the inverted coords 1.456 + // because our GL funtions use an explicit flag. 1.457 + bool flipped = false; 1.458 + if (texCoordRect.height < 0) { 1.459 + flipped = true; 1.460 + texCoordRect.y = texCoordRect.YMost(); 1.461 + texCoordRect.height = -texCoordRect.height; 1.462 + } 1.463 + 1.464 + if (wrapMode == LOCAL_GL_REPEAT) { 1.465 + rects.addRect(/* dest rectangle */ 1.466 + 0.0f, 0.0f, 1.0f, 1.0f, 1.467 + /* tex coords */ 1.468 + texCoordRect.x / GLfloat(realTexSize.width), 1.469 + texCoordRect.y / GLfloat(realTexSize.height), 1.470 + texCoordRect.XMost() / GLfloat(realTexSize.width), 1.471 + texCoordRect.YMost() / GLfloat(realTexSize.height), 1.472 + flipped); 1.473 + } else { 1.474 + nsIntRect tcRect(texCoordRect.x, texCoordRect.y, 1.475 + texCoordRect.width, texCoordRect.height); 1.476 + DecomposeIntoNoRepeatTriangles(tcRect, 1.477 + nsIntSize(realTexSize.width, realTexSize.height), 1.478 + rects, flipped); 1.479 + } 1.480 + 1.481 + gfx3DMatrix textureTransform; 1.482 + if (rects.isSimpleQuad(textureTransform)) { 1.483 + Matrix4x4 transform; 1.484 + ToMatrix4x4(aTextureTransform * textureTransform, transform); 1.485 + aProg->SetTextureTransform(transform); 1.486 + BindAndDrawQuad(aProg); 1.487 + } else { 1.488 + Matrix4x4 transform; 1.489 + ToMatrix4x4(aTextureTransform, transform); 1.490 + aProg->SetTextureTransform(transform); 1.491 + DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects); 1.492 + } 1.493 +} 1.494 + 1.495 +void 1.496 +CompositorOGL::PrepareViewport(const gfx::IntSize& aSize, 1.497 + const Matrix& aWorldTransform) 1.498 +{ 1.499 + // Set the viewport correctly. 1.500 + mGLContext->fViewport(0, 0, aSize.width, aSize.height); 1.501 + 1.502 + mHeight = aSize.height; 1.503 + 1.504 + // We flip the view matrix around so that everything is right-side up; we're 1.505 + // drawing directly into the window's back buffer, so this keeps things 1.506 + // looking correct. 1.507 + // XXX: We keep track of whether the window size changed, so we could skip 1.508 + // this update if it hadn't changed since the last call. We will need to 1.509 + // track changes to aTransformPolicy and aWorldTransform for this to work 1.510 + // though. 1.511 + 1.512 + // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0, 1.513 + // 2, 2) and flip the contents. 1.514 + Matrix viewMatrix; 1.515 + viewMatrix.Translate(-1.0, 1.0); 1.516 + viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height)); 1.517 + viewMatrix.Scale(1.0f, -1.0f); 1.518 + if (!mTarget) { 1.519 + viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y); 1.520 + } 1.521 + 1.522 + viewMatrix = aWorldTransform * viewMatrix; 1.523 + 1.524 + Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix); 1.525 + matrix3d._33 = 0.0f; 1.526 + 1.527 + mProjMatrix = matrix3d; 1.528 +} 1.529 + 1.530 +TemporaryRef<CompositingRenderTarget> 1.531 +CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit) 1.532 +{ 1.533 + GLuint tex = 0; 1.534 + GLuint fbo = 0; 1.535 + CreateFBOWithTexture(aRect, false, 0, &fbo, &tex); 1.536 + RefPtr<CompositingRenderTargetOGL> surface 1.537 + = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); 1.538 + surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit); 1.539 + return surface.forget(); 1.540 +} 1.541 + 1.542 +TemporaryRef<CompositingRenderTarget> 1.543 +CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect, 1.544 + const CompositingRenderTarget *aSource, 1.545 + const IntPoint &aSourcePoint) 1.546 +{ 1.547 + GLuint tex = 0; 1.548 + GLuint fbo = 0; 1.549 + const CompositingRenderTargetOGL* sourceSurface 1.550 + = static_cast<const CompositingRenderTargetOGL*>(aSource); 1.551 + IntRect sourceRect(aSourcePoint, aRect.Size()); 1.552 + if (aSource) { 1.553 + CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(), 1.554 + &fbo, &tex); 1.555 + } else { 1.556 + CreateFBOWithTexture(sourceRect, true, 0, 1.557 + &fbo, &tex); 1.558 + } 1.559 + 1.560 + RefPtr<CompositingRenderTargetOGL> surface 1.561 + = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); 1.562 + surface->Initialize(aRect.Size(), 1.563 + mFBOTextureTarget, 1.564 + INIT_MODE_NONE); 1.565 + return surface.forget(); 1.566 +} 1.567 + 1.568 +void 1.569 +CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface) 1.570 +{ 1.571 + MOZ_ASSERT(aSurface); 1.572 + CompositingRenderTargetOGL* surface 1.573 + = static_cast<CompositingRenderTargetOGL*>(aSurface); 1.574 + if (mCurrentRenderTarget != surface) { 1.575 + surface->BindRenderTarget(); 1.576 + mCurrentRenderTarget = surface; 1.577 + } 1.578 +} 1.579 + 1.580 +CompositingRenderTarget* 1.581 +CompositorOGL::GetCurrentRenderTarget() const 1.582 +{ 1.583 + return mCurrentRenderTarget; 1.584 +} 1.585 + 1.586 +static GLenum 1.587 +GetFrameBufferInternalFormat(GLContext* gl, 1.588 + GLuint aFrameBuffer, 1.589 + nsIWidget* aWidget) 1.590 +{ 1.591 + if (aFrameBuffer == 0) { // default framebuffer 1.592 + return aWidget->GetGLFrameBufferFormat(); 1.593 + } 1.594 + return LOCAL_GL_RGBA; 1.595 +} 1.596 + 1.597 +/* 1.598 + * Returns a size that is larger than and closest to aSize where both 1.599 + * width and height are powers of two. 1.600 + * If the OpenGL setup is capable of using non-POT textures, then it 1.601 + * will just return aSize. 1.602 + */ 1.603 +static IntSize 1.604 +CalculatePOTSize(const IntSize& aSize, GLContext* gl) 1.605 +{ 1.606 + if (CanUploadNonPowerOfTwo(gl)) 1.607 + return aSize; 1.608 + 1.609 + return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height)); 1.610 +} 1.611 + 1.612 +void 1.613 +CompositorOGL::ClearRect(const gfx::Rect& aRect) 1.614 +{ 1.615 + // Map aRect to OGL coordinates, origin:bottom-left 1.616 + GLint y = mHeight - (aRect.y + aRect.height); 1.617 + 1.618 + ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); 1.619 + ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height); 1.620 + mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); 1.621 + mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); 1.622 +} 1.623 + 1.624 +void 1.625 +CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, 1.626 + const Rect *aClipRectIn, 1.627 + const gfx::Matrix& aTransform, 1.628 + const Rect& aRenderBounds, 1.629 + Rect *aClipRectOut, 1.630 + Rect *aRenderBoundsOut) 1.631 +{ 1.632 + PROFILER_LABEL("CompositorOGL", "BeginFrame"); 1.633 + MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); 1.634 + 1.635 + LayerScope::BeginFrame(mGLContext, PR_Now()); 1.636 + 1.637 + mVBOs.Reset(); 1.638 + 1.639 + mFrameInProgress = true; 1.640 + gfx::Rect rect; 1.641 + if (mUseExternalSurfaceSize) { 1.642 + rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height); 1.643 + } else { 1.644 + rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height); 1.645 + // If render bounds is not updated explicitly, try to infer it from widget 1.646 + if (rect.width == 0 || rect.height == 0) { 1.647 + // FIXME/bug XXXXXX this races with rotation changes on the main 1.648 + // thread, and undoes all the care we take with layers txns being 1.649 + // sent atomically with rotation changes 1.650 + nsIntRect intRect; 1.651 + mWidget->GetClientBounds(intRect); 1.652 + rect = gfx::Rect(0, 0, intRect.width, intRect.height); 1.653 + } 1.654 + } 1.655 + 1.656 + rect = aTransform.TransformBounds(rect); 1.657 + if (aRenderBoundsOut) { 1.658 + *aRenderBoundsOut = rect; 1.659 + } 1.660 + 1.661 + GLint width = rect.width; 1.662 + GLint height = rect.height; 1.663 + 1.664 + // We can't draw anything to something with no area 1.665 + // so just return 1.666 + if (width == 0 || height == 0) 1.667 + return; 1.668 + 1.669 + // If the widget size changed, we have to force a MakeCurrent 1.670 + // to make sure that GL sees the updated widget size. 1.671 + if (mWidgetSize.width != width || 1.672 + mWidgetSize.height != height) 1.673 + { 1.674 + MakeCurrent(ForceMakeCurrent); 1.675 + 1.676 + mWidgetSize.width = width; 1.677 + mWidgetSize.height = height; 1.678 + } else { 1.679 + MakeCurrent(); 1.680 + } 1.681 + 1.682 + mPixelsPerFrame = width * height; 1.683 + mPixelsFilled = 0; 1.684 + 1.685 +#if MOZ_ANDROID_OMTC 1.686 + TexturePoolOGL::Fill(gl()); 1.687 +#endif 1.688 + 1.689 + mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this, 1.690 + IntSize(width, height), 1.691 + aTransform); 1.692 + mCurrentRenderTarget->BindRenderTarget(); 1.693 +#ifdef DEBUG 1.694 + mWindowRenderTarget = mCurrentRenderTarget; 1.695 +#endif 1.696 + 1.697 + // Default blend function implements "OVER" 1.698 + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.699 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.700 + mGLContext->fEnable(LOCAL_GL_BLEND); 1.701 + 1.702 + mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); 1.703 + 1.704 + if (aClipRectOut && !aClipRectIn) { 1.705 + aClipRectOut->SetRect(0, 0, width, height); 1.706 + } 1.707 + 1.708 + // If the Android compositor is being used, this clear will be done in 1.709 + // DrawWindowUnderlay. Make sure the bits used here match up with those used 1.710 + // in mobile/android/base/gfx/LayerRenderer.java 1.711 +#ifndef MOZ_ANDROID_OMTC 1.712 + mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); 1.713 + mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); 1.714 +#endif 1.715 +} 1.716 + 1.717 +void 1.718 +CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource, 1.719 + GLuint aSourceFrameBuffer, 1.720 + GLuint *aFBO, GLuint *aTexture) 1.721 +{ 1.722 + GLuint tex, fbo; 1.723 + 1.724 + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); 1.725 + mGLContext->fGenTextures(1, &tex); 1.726 + mGLContext->fBindTexture(mFBOTextureTarget, tex); 1.727 + 1.728 + if (aCopyFromSource) { 1.729 + GLuint curFBO = mCurrentRenderTarget->GetFBO(); 1.730 + if (curFBO != aSourceFrameBuffer) { 1.731 + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer); 1.732 + } 1.733 + 1.734 + // We're going to create an RGBA temporary fbo. But to 1.735 + // CopyTexImage() from the current framebuffer, the framebuffer's 1.736 + // format has to be compatible with the new texture's. So we 1.737 + // check the format of the framebuffer here and take a slow path 1.738 + // if it's incompatible. 1.739 + GLenum format = 1.740 + GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget); 1.741 + 1.742 + bool isFormatCompatibleWithRGBA 1.743 + = gl()->IsGLES() ? (format == LOCAL_GL_RGBA) 1.744 + : true; 1.745 + 1.746 + if (isFormatCompatibleWithRGBA) { 1.747 + mGLContext->fCopyTexImage2D(mFBOTextureTarget, 1.748 + 0, 1.749 + LOCAL_GL_RGBA, 1.750 + aRect.x, FlipY(aRect.y + aRect.height), 1.751 + aRect.width, aRect.height, 1.752 + 0); 1.753 + } else { 1.754 + // Curses, incompatible formats. Take a slow path. 1.755 + 1.756 + // RGBA 1.757 + size_t bufferSize = aRect.width * aRect.height * 4; 1.758 + nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]); 1.759 + 1.760 + mGLContext->fReadPixels(aRect.x, aRect.y, 1.761 + aRect.width, aRect.height, 1.762 + LOCAL_GL_RGBA, 1.763 + LOCAL_GL_UNSIGNED_BYTE, 1.764 + buf); 1.765 + mGLContext->fTexImage2D(mFBOTextureTarget, 1.766 + 0, 1.767 + LOCAL_GL_RGBA, 1.768 + aRect.width, aRect.height, 1.769 + 0, 1.770 + LOCAL_GL_RGBA, 1.771 + LOCAL_GL_UNSIGNED_BYTE, 1.772 + buf); 1.773 + } 1.774 + GLenum error = mGLContext->GetAndClearError(); 1.775 + if (error != LOCAL_GL_NO_ERROR) { 1.776 + nsAutoCString msg; 1.777 + msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d", 1.778 + error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA); 1.779 + NS_ERROR(msg.get()); 1.780 + } 1.781 + } else { 1.782 + mGLContext->fTexImage2D(mFBOTextureTarget, 1.783 + 0, 1.784 + LOCAL_GL_RGBA, 1.785 + aRect.width, aRect.height, 1.786 + 0, 1.787 + LOCAL_GL_RGBA, 1.788 + LOCAL_GL_UNSIGNED_BYTE, 1.789 + nullptr); 1.790 + } 1.791 + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, 1.792 + LOCAL_GL_LINEAR); 1.793 + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, 1.794 + LOCAL_GL_LINEAR); 1.795 + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, 1.796 + LOCAL_GL_CLAMP_TO_EDGE); 1.797 + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, 1.798 + LOCAL_GL_CLAMP_TO_EDGE); 1.799 + mGLContext->fBindTexture(mFBOTextureTarget, 0); 1.800 + 1.801 + mGLContext->fGenFramebuffers(1, &fbo); 1.802 + 1.803 + *aFBO = fbo; 1.804 + *aTexture = tex; 1.805 +} 1.806 + 1.807 +ShaderConfigOGL 1.808 +CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const 1.809 +{ 1.810 + ShaderConfigOGL config; 1.811 + 1.812 + switch(aEffect->mType) { 1.813 + case EFFECT_SOLID_COLOR: 1.814 + config.SetRenderColor(true); 1.815 + break; 1.816 + case EFFECT_YCBCR: 1.817 + config.SetYCbCr(true); 1.818 + break; 1.819 + case EFFECT_COMPONENT_ALPHA: 1.820 + { 1.821 + config.SetComponentAlpha(true); 1.822 + EffectComponentAlpha* effectComponentAlpha = 1.823 + static_cast<EffectComponentAlpha*>(aEffect); 1.824 + gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat(); 1.825 + config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 || 1.826 + format == gfx::SurfaceFormat::B8G8R8X8); 1.827 + break; 1.828 + } 1.829 + case EFFECT_RENDER_TARGET: 1.830 + config.SetTextureTarget(mFBOTextureTarget); 1.831 + break; 1.832 + default: 1.833 + { 1.834 + MOZ_ASSERT(aEffect->mType == EFFECT_RGB); 1.835 + TexturedEffect* texturedEffect = 1.836 + static_cast<TexturedEffect*>(aEffect); 1.837 + TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); 1.838 + MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL, 1.839 + source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8); 1.840 + MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB, 1.841 + source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || 1.842 + source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || 1.843 + source->GetFormat() == gfx::SurfaceFormat::R5G6B5); 1.844 + config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(), 1.845 + source->GetFormat()); 1.846 + break; 1.847 + } 1.848 + } 1.849 + config.SetMask2D(aMask == Mask2d); 1.850 + config.SetMask3D(aMask == Mask3d); 1.851 + return config; 1.852 +} 1.853 + 1.854 +ShaderProgramOGL* 1.855 +CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig) 1.856 +{ 1.857 + std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig); 1.858 + if (iter != mPrograms.end()) 1.859 + return iter->second; 1.860 + 1.861 + ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig); 1.862 + ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile); 1.863 + if (!shader->Initialize()) { 1.864 + delete shader; 1.865 + return nullptr; 1.866 + } 1.867 + 1.868 + mPrograms[aConfig] = shader; 1.869 + return shader; 1.870 +} 1.871 + 1.872 +void 1.873 +CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect, 1.874 + const gfx::Color& aColor, 1.875 + gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) 1.876 +{ 1.877 + mGLContext->fLineWidth(2.0); 1.878 + 1.879 + EffectChain effects; 1.880 + effects.mPrimaryEffect = new EffectSolidColor(aColor); 1.881 + 1.882 + for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) { 1.883 + const gfx::Point& p1 = aLines[i]; 1.884 + const gfx::Point& p2 = aLines[i+1]; 1.885 + DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y), 1.886 + aClipRect, effects, aOpacity, aTransform, 1.887 + LOCAL_GL_LINE_STRIP); 1.888 + } 1.889 +} 1.890 + 1.891 +void 1.892 +CompositorOGL::DrawQuadInternal(const Rect& aRect, 1.893 + const Rect& aClipRect, 1.894 + const EffectChain &aEffectChain, 1.895 + Float aOpacity, 1.896 + const gfx::Matrix4x4 &aTransform, 1.897 + GLuint aDrawMode) 1.898 +{ 1.899 + PROFILER_LABEL("CompositorOGL", "DrawQuad"); 1.900 + MOZ_ASSERT(mFrameInProgress, "frame not started"); 1.901 + 1.902 + Rect clipRect = aClipRect; 1.903 + if (!mTarget) { 1.904 + clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y); 1.905 + } 1.906 + IntRect intClipRect; 1.907 + clipRect.ToIntRect(&intClipRect); 1.908 + 1.909 + gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height), 1.910 + intClipRect.width, intClipRect.height); 1.911 + 1.912 + LayerScope::SendEffectChain(mGLContext, aEffectChain, 1.913 + aRect.width, aRect.height); 1.914 + 1.915 + MaskType maskType; 1.916 + EffectMask* effectMask; 1.917 + TextureSourceOGL* sourceMask = nullptr; 1.918 + gfx::Matrix4x4 maskQuadTransform; 1.919 + if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) { 1.920 + effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); 1.921 + sourceMask = effectMask->mMaskTexture->AsSourceOGL(); 1.922 + 1.923 + // NS_ASSERTION(textureMask->IsAlpha(), 1.924 + // "OpenGL mask layers must be backed by alpha surfaces"); 1.925 + 1.926 + // We're assuming that the gl backend won't cheat and use NPOT 1.927 + // textures when glContext says it can't (which seems to happen 1.928 + // on a mac when you force POT textures) 1.929 + IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext); 1.930 + 1.931 + const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform; 1.932 + NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); 1.933 + Rect bounds = Rect(Point(), Size(maskSize)); 1.934 + bounds = maskTransform.As2D().TransformBounds(bounds); 1.935 + 1.936 + maskQuadTransform._11 = 1.0f/bounds.width; 1.937 + maskQuadTransform._22 = 1.0f/bounds.height; 1.938 + maskQuadTransform._41 = float(-bounds.x)/bounds.width; 1.939 + maskQuadTransform._42 = float(-bounds.y)/bounds.height; 1.940 + 1.941 + maskType = effectMask->mIs3D 1.942 + ? Mask3d 1.943 + : Mask2d; 1.944 + } else { 1.945 + maskType = MaskNone; 1.946 + } 1.947 + 1.948 + mPixelsFilled += aRect.width * aRect.height; 1.949 + 1.950 + // Determine the color if this is a color shader and fold the opacity into 1.951 + // the color since color shaders don't have an opacity uniform. 1.952 + Color color; 1.953 + if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) { 1.954 + EffectSolidColor* effectSolidColor = 1.955 + static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); 1.956 + color = effectSolidColor->mColor; 1.957 + 1.958 + Float opacity = aOpacity * color.a; 1.959 + color.r *= opacity; 1.960 + color.g *= opacity; 1.961 + color.b *= opacity; 1.962 + color.a = opacity; 1.963 + 1.964 + // We can fold opacity into the color, so no need to consider it further. 1.965 + aOpacity = 1.f; 1.966 + } 1.967 + 1.968 + ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType); 1.969 + config.SetOpacity(aOpacity != 1.f); 1.970 + ShaderProgramOGL *program = GetShaderProgramFor(config); 1.971 + program->Activate(); 1.972 + program->SetProjectionMatrix(mProjMatrix); 1.973 + program->SetLayerQuadRect(aRect); 1.974 + program->SetLayerTransform(aTransform); 1.975 + IntPoint offset = mCurrentRenderTarget->GetOrigin(); 1.976 + program->SetRenderOffset(offset.x, offset.y); 1.977 + if (aOpacity != 1.f) 1.978 + program->SetLayerOpacity(aOpacity); 1.979 + if (config.mFeatures & ENABLE_TEXTURE_RECT) { 1.980 + TexturedEffect* texturedEffect = 1.981 + static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); 1.982 + TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); 1.983 + // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. 1.984 + program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height); 1.985 + } 1.986 + 1.987 + switch (aEffectChain.mPrimaryEffect->mType) { 1.988 + case EFFECT_SOLID_COLOR: { 1.989 + program->SetRenderColor(color); 1.990 + 1.991 + if (maskType != MaskNone) { 1.992 + BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform); 1.993 + } 1.994 + 1.995 + BindAndDrawQuad(program, aDrawMode); 1.996 + } 1.997 + break; 1.998 + 1.999 + case EFFECT_RGB: { 1.1000 + TexturedEffect* texturedEffect = 1.1001 + static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); 1.1002 + TextureSource *source = texturedEffect->mTexture; 1.1003 + 1.1004 + if (!texturedEffect->mPremultiplied) { 1.1005 + mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.1006 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.1007 + } 1.1008 + 1.1009 + gfx::Filter filter = texturedEffect->mFilter; 1.1010 + gfx3DMatrix textureTransform; 1.1011 + gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform); 1.1012 + 1.1013 +#ifdef MOZ_WIDGET_ANDROID 1.1014 + gfxMatrix textureTransform2D; 1.1015 + if (filter != gfx::Filter::POINT && 1.1016 + aTransform.Is2DIntegerTranslation() && 1.1017 + textureTransform.Is2D(&textureTransform2D) && 1.1018 + textureTransform2D.HasOnlyIntegerTranslation()) { 1.1019 + // On Android we encounter small resampling errors in what should be 1.1020 + // pixel-aligned compositing operations. This works around them. This 1.1021 + // code should not be needed! 1.1022 + filter = gfx::Filter::POINT; 1.1023 + } 1.1024 +#endif 1.1025 + source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter); 1.1026 + 1.1027 + program->SetTextureUnit(0); 1.1028 + 1.1029 + if (maskType != MaskNone) { 1.1030 + BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform); 1.1031 + } 1.1032 + 1.1033 + BindAndDrawQuadWithTextureRect(program, textureTransform, 1.1034 + texturedEffect->mTextureCoords, source); 1.1035 + 1.1036 + if (!texturedEffect->mPremultiplied) { 1.1037 + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.1038 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.1039 + } 1.1040 + } 1.1041 + break; 1.1042 + case EFFECT_YCBCR: { 1.1043 + EffectYCbCr* effectYCbCr = 1.1044 + static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get()); 1.1045 + TextureSource* sourceYCbCr = effectYCbCr->mTexture; 1.1046 + const int Y = 0, Cb = 1, Cr = 2; 1.1047 + TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); 1.1048 + TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); 1.1049 + TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); 1.1050 + 1.1051 + if (!sourceY && !sourceCb && !sourceCr) { 1.1052 + NS_WARNING("Invalid layer texture."); 1.1053 + return; 1.1054 + } 1.1055 + 1.1056 + sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter); 1.1057 + sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter); 1.1058 + sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter); 1.1059 + 1.1060 + program->SetYCbCrTextureUnits(Y, Cb, Cr); 1.1061 + 1.1062 + if (maskType != MaskNone) { 1.1063 + BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform); 1.1064 + } 1.1065 + BindAndDrawQuadWithTextureRect(program, 1.1066 + gfx3DMatrix(), 1.1067 + effectYCbCr->mTextureCoords, 1.1068 + sourceYCbCr->GetSubSource(Y)); 1.1069 + } 1.1070 + break; 1.1071 + case EFFECT_RENDER_TARGET: { 1.1072 + EffectRenderTarget* effectRenderTarget = 1.1073 + static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); 1.1074 + RefPtr<CompositingRenderTargetOGL> surface 1.1075 + = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get()); 1.1076 + 1.1077 + surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget); 1.1078 + 1.1079 + // Drawing is always flipped, but when copying between surfaces we want to avoid 1.1080 + // this, so apply a flip here to cancel the other one out. 1.1081 + Matrix transform; 1.1082 + transform.Translate(0.0, 1.0); 1.1083 + transform.Scale(1.0f, -1.0f); 1.1084 + program->SetTextureTransform(Matrix4x4::From2D(transform)); 1.1085 + program->SetTextureUnit(0); 1.1086 + 1.1087 + if (maskType != MaskNone) { 1.1088 + sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR); 1.1089 + program->SetMaskTextureUnit(1); 1.1090 + program->SetMaskLayerTransform(maskQuadTransform); 1.1091 + } 1.1092 + 1.1093 + if (config.mFeatures & ENABLE_TEXTURE_RECT) { 1.1094 + // 2DRect case, get the multiplier right for a sampler2DRect 1.1095 + program->SetTexCoordMultiplier(aRect.width, aRect.height); 1.1096 + } 1.1097 + 1.1098 + // Drawing is always flipped, but when copying between surfaces we want to avoid 1.1099 + // this. Pass true for the flip parameter to introduce a second flip 1.1100 + // that cancels the other one out. 1.1101 + BindAndDrawQuad(program); 1.1102 + } 1.1103 + break; 1.1104 + case EFFECT_COMPONENT_ALPHA: { 1.1105 + MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); 1.1106 + EffectComponentAlpha* effectComponentAlpha = 1.1107 + static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get()); 1.1108 + TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL(); 1.1109 + TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL(); 1.1110 + 1.1111 + if (!sourceOnBlack->IsValid() || 1.1112 + !sourceOnWhite->IsValid()) { 1.1113 + NS_WARNING("Invalid layer texture for component alpha"); 1.1114 + return; 1.1115 + } 1.1116 + 1.1117 + sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter); 1.1118 + sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter); 1.1119 + 1.1120 + program->SetBlackTextureUnit(0); 1.1121 + program->SetWhiteTextureUnit(1); 1.1122 + program->SetTextureTransform(gfx::Matrix4x4()); 1.1123 + 1.1124 + if (maskType != MaskNone) { 1.1125 + BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform); 1.1126 + } 1.1127 + // Pass 1. 1.1128 + gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR, 1.1129 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.1130 + program->SetTexturePass2(false); 1.1131 + BindAndDrawQuadWithTextureRect(program, 1.1132 + gfx3DMatrix(), 1.1133 + effectComponentAlpha->mTextureCoords, 1.1134 + effectComponentAlpha->mOnBlack); 1.1135 + 1.1136 + // Pass 2. 1.1137 + gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, 1.1138 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.1139 + 1.1140 +#ifdef XP_MACOSX 1.1141 + if (gl()->WorkAroundDriverBugs() && 1.1142 + gl()->Vendor() == GLVendor::NVIDIA && 1.1143 + !nsCocoaFeatures::OnMavericksOrLater()) { 1.1144 + // Bug 987497: With some GPUs the nvidia driver on 10.8 and below 1.1145 + // won't pick up the TexturePass2 uniform change below if we don't do 1.1146 + // something to force it. Re-activating the shader seems to be one way 1.1147 + // of achieving that. 1.1148 + program->Activate(); 1.1149 + } 1.1150 +#endif 1.1151 + 1.1152 + program->SetTexturePass2(true); 1.1153 + BindAndDrawQuadWithTextureRect(program, 1.1154 + gfx3DMatrix(), 1.1155 + effectComponentAlpha->mTextureCoords, 1.1156 + effectComponentAlpha->mOnBlack); 1.1157 + 1.1158 + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.1159 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.1160 + } 1.1161 + break; 1.1162 + default: 1.1163 + MOZ_ASSERT(false, "Unhandled effect type"); 1.1164 + break; 1.1165 + } 1.1166 + 1.1167 + // in case rendering has used some other GL context 1.1168 + MakeCurrent(); 1.1169 +} 1.1170 + 1.1171 +void 1.1172 +CompositorOGL::EndFrame() 1.1173 +{ 1.1174 + PROFILER_LABEL("CompositorOGL", "EndFrame"); 1.1175 + MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored"); 1.1176 + 1.1177 +#ifdef MOZ_DUMP_PAINTING 1.1178 + if (gfxUtils::sDumpPainting) { 1.1179 + nsIntRect rect; 1.1180 + if (mUseExternalSurfaceSize) { 1.1181 + rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); 1.1182 + } else { 1.1183 + mWidget->GetBounds(rect); 1.1184 + } 1.1185 + RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8); 1.1186 + CopyToTarget(target, mCurrentRenderTarget->GetTransform()); 1.1187 + 1.1188 + WriteSnapshotToDumpFile(this, target); 1.1189 + } 1.1190 +#endif 1.1191 + 1.1192 + mFrameInProgress = false; 1.1193 + 1.1194 + LayerScope::EndFrame(mGLContext); 1.1195 + 1.1196 + if (mTarget) { 1.1197 + CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform()); 1.1198 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.1199 + mCurrentRenderTarget = nullptr; 1.1200 + return; 1.1201 + } 1.1202 + 1.1203 + mCurrentRenderTarget = nullptr; 1.1204 + 1.1205 + if (mTexturePool) { 1.1206 + mTexturePool->EndFrame(); 1.1207 + } 1.1208 + 1.1209 + mGLContext->SwapBuffers(); 1.1210 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.1211 + 1.1212 + // Unbind all textures 1.1213 + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); 1.1214 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); 1.1215 + if (!mGLContext->IsGLES()) { 1.1216 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); 1.1217 + } 1.1218 + 1.1219 + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1); 1.1220 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); 1.1221 + if (!mGLContext->IsGLES()) { 1.1222 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); 1.1223 + } 1.1224 + 1.1225 + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2); 1.1226 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); 1.1227 + if (!mGLContext->IsGLES()) { 1.1228 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); 1.1229 + } 1.1230 +} 1.1231 + 1.1232 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.1233 +void 1.1234 +CompositorOGL::SetFBAcquireFence(Layer* aLayer) 1.1235 +{ 1.1236 + // OpenGL does not provide ReleaseFence for rendering. 1.1237 + // Instead use FBAcquireFence as layer buffer's ReleaseFence 1.1238 + // to prevent flickering and tearing. 1.1239 + // FBAcquireFence is FramebufferSurface's AcquireFence. 1.1240 + // AcquireFence will be signaled when a buffer's content is available. 1.1241 + // See Bug 974152. 1.1242 + 1.1243 + if (!aLayer) { 1.1244 + return; 1.1245 + } 1.1246 + 1.1247 + const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); 1.1248 + if (visibleRegion.IsEmpty()) { 1.1249 + return; 1.1250 + } 1.1251 + 1.1252 + // Set FBAcquireFence on ContainerLayer's childs 1.1253 + ContainerLayer* container = aLayer->AsContainerLayer(); 1.1254 + if (container) { 1.1255 + for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { 1.1256 + SetFBAcquireFence(child); 1.1257 + } 1.1258 + return; 1.1259 + } 1.1260 + 1.1261 + // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer. 1.1262 + TiledLayerComposer* composer = nullptr; 1.1263 + LayerComposite* shadow = aLayer->AsLayerComposite(); 1.1264 + if (shadow) { 1.1265 + composer = shadow->GetTiledLayerComposer(); 1.1266 + if (composer) { 1.1267 + composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); 1.1268 + return; 1.1269 + } 1.1270 + } 1.1271 + 1.1272 + // Set FBAcquireFence as layer buffer's ReleaseFence 1.1273 + LayerRenderState state = aLayer->GetRenderState(); 1.1274 + if (!state.mTexture) { 1.1275 + return; 1.1276 + } 1.1277 + TextureHostOGL* texture = state.mTexture->AsHostOGL(); 1.1278 + if (!texture) { 1.1279 + return; 1.1280 + } 1.1281 + texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); 1.1282 +} 1.1283 +#else 1.1284 +void 1.1285 +CompositorOGL::SetFBAcquireFence(Layer* aLayer) 1.1286 +{ 1.1287 +} 1.1288 +#endif 1.1289 + 1.1290 +void 1.1291 +CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform) 1.1292 +{ 1.1293 + // This lets us reftest and screenshot content rendered externally 1.1294 + if (mTarget) { 1.1295 + MakeCurrent(); 1.1296 + CopyToTarget(mTarget, aTransform); 1.1297 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.1298 + } 1.1299 + if (mTexturePool) { 1.1300 + mTexturePool->EndFrame(); 1.1301 + } 1.1302 +} 1.1303 + 1.1304 +void 1.1305 +CompositorOGL::AbortFrame() 1.1306 +{ 1.1307 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.1308 + mFrameInProgress = false; 1.1309 + mCurrentRenderTarget = nullptr; 1.1310 + 1.1311 + if (mTexturePool) { 1.1312 + mTexturePool->EndFrame(); 1.1313 + } 1.1314 +} 1.1315 + 1.1316 +void 1.1317 +CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize) 1.1318 +{ 1.1319 + mSurfaceSize.width = aSize.width; 1.1320 + mSurfaceSize.height = aSize.height; 1.1321 +} 1.1322 + 1.1323 +void 1.1324 +CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform) 1.1325 +{ 1.1326 + IntRect rect; 1.1327 + if (mUseExternalSurfaceSize) { 1.1328 + rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); 1.1329 + } else { 1.1330 + rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height); 1.1331 + } 1.1332 + GLint width = rect.width; 1.1333 + GLint height = rect.height; 1.1334 + 1.1335 + if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) { 1.1336 + NS_ERROR("Widget size too big - integer overflow!"); 1.1337 + return; 1.1338 + } 1.1339 + 1.1340 + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); 1.1341 + 1.1342 + if (!mGLContext->IsGLES()) { 1.1343 + // GLES2 promises that binding to any custom FBO will attach 1.1344 + // to GL_COLOR_ATTACHMENT0 attachment point. 1.1345 + mGLContext->fReadBuffer(LOCAL_GL_BACK); 1.1346 + } 1.1347 + 1.1348 + RefPtr<DataSourceSurface> source = 1.1349 + Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8); 1.1350 + 1.1351 + DataSourceSurface::MappedSurface map; 1.1352 + source->Map(DataSourceSurface::MapType::WRITE, &map); 1.1353 + // XXX we should do this properly one day without using the gfxImageSurface 1.1354 + nsRefPtr<gfxImageSurface> surf = 1.1355 + new gfxImageSurface(map.mData, 1.1356 + gfxIntSize(width, height), 1.1357 + map.mStride, 1.1358 + gfxImageFormat::ARGB32); 1.1359 + ReadPixelsIntoImageSurface(mGLContext, surf); 1.1360 + source->Unmap(); 1.1361 + 1.1362 + // Map from GL space to Cairo space and reverse the world transform. 1.1363 + Matrix glToCairoTransform = aTransform; 1.1364 + glToCairoTransform.Invert(); 1.1365 + glToCairoTransform.Scale(1.0, -1.0); 1.1366 + glToCairoTransform.Translate(0.0, -height); 1.1367 + 1.1368 + Matrix oldMatrix = aTarget->GetTransform(); 1.1369 + aTarget->SetTransform(glToCairoTransform); 1.1370 + Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height); 1.1371 + aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); 1.1372 + aTarget->SetTransform(oldMatrix); 1.1373 + aTarget->Flush(); 1.1374 +} 1.1375 + 1.1376 +void 1.1377 +CompositorOGL::Pause() 1.1378 +{ 1.1379 +#ifdef MOZ_WIDGET_ANDROID 1.1380 + if (!gl() || gl()->IsDestroyed()) 1.1381 + return; 1.1382 + 1.1383 + // ReleaseSurface internally calls MakeCurrent. 1.1384 + gl()->ReleaseSurface(); 1.1385 +#endif 1.1386 +} 1.1387 + 1.1388 +bool 1.1389 +CompositorOGL::Resume() 1.1390 +{ 1.1391 +#ifdef MOZ_WIDGET_ANDROID 1.1392 + if (!gl() || gl()->IsDestroyed()) 1.1393 + return false; 1.1394 + 1.1395 + // RenewSurface internally calls MakeCurrent. 1.1396 + return gl()->RenewSurface(); 1.1397 +#endif 1.1398 + return true; 1.1399 +} 1.1400 + 1.1401 +TemporaryRef<DataTextureSource> 1.1402 +CompositorOGL::CreateDataTextureSource(TextureFlags aFlags) 1.1403 +{ 1.1404 + RefPtr<DataTextureSource> result = 1.1405 + new TextureImageTextureSourceOGL(mGLContext, aFlags); 1.1406 + return result; 1.1407 +} 1.1408 + 1.1409 +bool 1.1410 +CompositorOGL::SupportsPartialTextureUpdate() 1.1411 +{ 1.1412 + return CanUploadSubTextures(mGLContext); 1.1413 +} 1.1414 + 1.1415 +int32_t 1.1416 +CompositorOGL::GetMaxTextureSize() const 1.1417 +{ 1.1418 + MOZ_ASSERT(mGLContext); 1.1419 + GLint texSize = 0; 1.1420 + mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, 1.1421 + &texSize); 1.1422 + MOZ_ASSERT(texSize != 0); 1.1423 + return texSize; 1.1424 +} 1.1425 + 1.1426 +void 1.1427 +CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) { 1.1428 + if (mDestroyed) { 1.1429 + NS_WARNING("Call on destroyed layer manager"); 1.1430 + return; 1.1431 + } 1.1432 + mGLContext->MakeCurrent(aFlags & ForceMakeCurrent); 1.1433 +} 1.1434 + 1.1435 +void 1.1436 +CompositorOGL::BindQuadVBO() { 1.1437 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 1.1438 +} 1.1439 + 1.1440 +void 1.1441 +CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) { 1.1442 + mGLContext->fVertexAttribPointer(aAttribIndex, 2, 1.1443 + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 1.1444 + (GLvoid*) QuadVBOVertexOffset()); 1.1445 +} 1.1446 + 1.1447 +void 1.1448 +CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) { 1.1449 + mGLContext->fVertexAttribPointer(aAttribIndex, 2, 1.1450 + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 1.1451 + (GLvoid*) QuadVBOTexCoordOffset()); 1.1452 +} 1.1453 + 1.1454 +void 1.1455 +CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex, 1.1456 + GLuint aTexCoordAttribIndex, 1.1457 + GLuint aDrawMode) 1.1458 +{ 1.1459 + BindQuadVBO(); 1.1460 + QuadVBOVerticesAttrib(aVertAttribIndex); 1.1461 + 1.1462 + if (aTexCoordAttribIndex != GLuint(-1)) { 1.1463 + QuadVBOTexCoordsAttrib(aTexCoordAttribIndex); 1.1464 + mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex); 1.1465 + } 1.1466 + 1.1467 + mGLContext->fEnableVertexAttribArray(aVertAttribIndex); 1.1468 + if (aDrawMode == LOCAL_GL_LINE_STRIP) { 1.1469 + mGLContext->fDrawArrays(aDrawMode, 1, 2); 1.1470 + } else { 1.1471 + mGLContext->fDrawArrays(aDrawMode, 0, 4); 1.1472 + } 1.1473 +} 1.1474 + 1.1475 +void 1.1476 +CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg, 1.1477 + GLuint aDrawMode) 1.1478 +{ 1.1479 + NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); 1.1480 + BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib), 1.1481 + aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib), 1.1482 + aDrawMode); 1.1483 +} 1.1484 + 1.1485 +GLuint 1.1486 +CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) 1.1487 +{ 1.1488 + if (!mTexturePool) { 1.1489 +#ifdef MOZ_WIDGET_GONK 1.1490 + mTexturePool = new PerFrameTexturePoolOGL(gl()); 1.1491 +#else 1.1492 + mTexturePool = new PerUnitTexturePoolOGL(gl()); 1.1493 +#endif 1.1494 + } 1.1495 + return mTexturePool->GetTexture(aTarget, aUnit); 1.1496 +} 1.1497 + 1.1498 +GLuint 1.1499 +PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) 1.1500 +{ 1.1501 + if (mTextureTarget == 0) { 1.1502 + mTextureTarget = aTarget; 1.1503 + } 1.1504 + MOZ_ASSERT(mTextureTarget == aTarget); 1.1505 + 1.1506 + size_t index = aTextureUnit - LOCAL_GL_TEXTURE0; 1.1507 + // lazily grow the array of temporary textures 1.1508 + if (mTextures.Length() <= index) { 1.1509 + size_t prevLength = mTextures.Length(); 1.1510 + mTextures.SetLength(index + 1); 1.1511 + for(unsigned int i = prevLength; i <= index; ++i) { 1.1512 + mTextures[i] = 0; 1.1513 + } 1.1514 + } 1.1515 + // lazily initialize the temporary textures 1.1516 + if (!mTextures[index]) { 1.1517 + if (!mGL->MakeCurrent()) { 1.1518 + return 0; 1.1519 + } 1.1520 + mGL->fGenTextures(1, &mTextures[index]); 1.1521 + mGL->fBindTexture(aTarget, mTextures[index]); 1.1522 + mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); 1.1523 + mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); 1.1524 + } 1.1525 + return mTextures[index]; 1.1526 +} 1.1527 + 1.1528 +void 1.1529 +PerUnitTexturePoolOGL::DestroyTextures() 1.1530 +{ 1.1531 + if (mGL && mGL->MakeCurrent()) { 1.1532 + if (mTextures.Length() > 0) { 1.1533 + mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]); 1.1534 + } 1.1535 + } 1.1536 + mTextures.SetLength(0); 1.1537 +} 1.1538 + 1.1539 +void 1.1540 +PerFrameTexturePoolOGL::DestroyTextures() 1.1541 +{ 1.1542 + if (!mGL->MakeCurrent()) { 1.1543 + return; 1.1544 + } 1.1545 + 1.1546 + if (mUnusedTextures.Length() > 0) { 1.1547 + mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]); 1.1548 + mUnusedTextures.Clear(); 1.1549 + } 1.1550 + 1.1551 + if (mCreatedTextures.Length() > 0) { 1.1552 + mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]); 1.1553 + mCreatedTextures.Clear(); 1.1554 + } 1.1555 +} 1.1556 + 1.1557 +GLuint 1.1558 +PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum) 1.1559 +{ 1.1560 + if (mTextureTarget == 0) { 1.1561 + mTextureTarget = aTarget; 1.1562 + } 1.1563 + 1.1564 + // The pool should always use the same texture target because it is illegal 1.1565 + // to change the target of an already exisiting gl texture. 1.1566 + // If we need to use several targets, a pool with several sub-pools (one per 1.1567 + // target) will have to be implemented. 1.1568 + // At the moment this pool is only used with tiling on b2g so we always need 1.1569 + // the same target. 1.1570 + MOZ_ASSERT(mTextureTarget == aTarget); 1.1571 + 1.1572 + GLuint texture = 0; 1.1573 + 1.1574 + if (!mUnusedTextures.IsEmpty()) { 1.1575 + // Try to reuse one from the unused pile first 1.1576 + texture = mUnusedTextures[0]; 1.1577 + mUnusedTextures.RemoveElementAt(0); 1.1578 + } else if (mGL->MakeCurrent()) { 1.1579 + // There isn't one to reuse, create one. 1.1580 + mGL->fGenTextures(1, &texture); 1.1581 + mGL->fBindTexture(aTarget, texture); 1.1582 + mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); 1.1583 + mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); 1.1584 + } 1.1585 + 1.1586 + if (texture) { 1.1587 + mCreatedTextures.AppendElement(texture); 1.1588 + } 1.1589 + 1.1590 + return texture; 1.1591 +} 1.1592 + 1.1593 +void 1.1594 +PerFrameTexturePoolOGL::EndFrame() 1.1595 +{ 1.1596 + if (!mGL->MakeCurrent()) { 1.1597 + // this means the context got destroyed underneith us somehow, and the driver 1.1598 + // already has destroyed the textures. 1.1599 + mCreatedTextures.Clear(); 1.1600 + mUnusedTextures.Clear(); 1.1601 + return; 1.1602 + } 1.1603 + 1.1604 + // Some platforms have issues unlocking Gralloc buffers even when they're 1.1605 + // rebound. 1.1606 + if (gfxPrefs::OverzealousGrallocUnlocking()) { 1.1607 + mUnusedTextures.AppendElements(mCreatedTextures); 1.1608 + mCreatedTextures.Clear(); 1.1609 + } 1.1610 + 1.1611 + // Delete unused textures 1.1612 + for (size_t i = 0; i < mUnusedTextures.Length(); i++) { 1.1613 + GLuint texture = mUnusedTextures[i]; 1.1614 + mGL->fDeleteTextures(1, &texture); 1.1615 + } 1.1616 + mUnusedTextures.Clear(); 1.1617 + 1.1618 + // Move all created textures into the unused pile 1.1619 + mUnusedTextures.AppendElements(mCreatedTextures); 1.1620 + mCreatedTextures.Clear(); 1.1621 +} 1.1622 + 1.1623 +} /* layers */ 1.1624 +} /* mozilla */