gfx/layers/opengl/CompositorOGL.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "CompositorOGL.h"
michael@0 7 #include <stddef.h> // for size_t
michael@0 8 #include <stdint.h> // for uint32_t, uint8_t
michael@0 9 #include <stdlib.h> // for free, malloc
michael@0 10 #include "GLContextProvider.h" // for GLContextProvider
michael@0 11 #include "GLContext.h" // for GLContext
michael@0 12 #include "GLUploadHelpers.h"
michael@0 13 #include "Layers.h" // for WriteSnapshotToDumpFile
michael@0 14 #include "LayerScope.h" // for LayerScope
michael@0 15 #include "gfx2DGlue.h" // for ThebesFilter
michael@0 16 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 17 #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
michael@0 18 #include "gfxImageSurface.h" // for gfxImageSurface
michael@0 19 #include "gfxMatrix.h" // for gfxMatrix
michael@0 20 #include "GraphicsFilter.h" // for GraphicsFilter
michael@0 21 #include "gfxPlatform.h" // for gfxPlatform
michael@0 22 #include "gfxPrefs.h" // for gfxPrefs
michael@0 23 #include "gfxRect.h" // for gfxRect
michael@0 24 #include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc
michael@0 25 #include "mozilla/ArrayUtils.h" // for ArrayLength
michael@0 26 #include "mozilla/Preferences.h" // for Preferences
michael@0 27 #include "mozilla/gfx/BasePoint.h" // for BasePoint
michael@0 28 #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
michael@0 29 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
michael@0 30 #include "mozilla/layers/CompositingRenderTargetOGL.h"
michael@0 31 #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
michael@0 32 #include "mozilla/layers/TextureHost.h" // for TextureSource, etc
michael@0 33 #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
michael@0 34 #include "mozilla/mozalloc.h" // for operator delete, etc
michael@0 35 #include "nsAString.h"
michael@0 36 #include "nsIConsoleService.h" // for nsIConsoleService, etc
michael@0 37 #include "nsIWidget.h" // for nsIWidget
michael@0 38 #include "nsLiteralString.h" // for NS_LITERAL_STRING
michael@0 39 #include "nsMathUtils.h" // for NS_roundf
michael@0 40 #include "nsRect.h" // for nsIntRect
michael@0 41 #include "nsServiceManagerUtils.h" // for do_GetService
michael@0 42 #include "nsString.h" // for nsString, nsAutoCString, etc
michael@0 43 #include "DecomposeIntoNoRepeatTriangles.h"
michael@0 44 #include "ScopedGLHelpers.h"
michael@0 45 #include "GLReadTexImageHelper.h"
michael@0 46 #include "TiledLayerBuffer.h" // for TiledLayerComposer
michael@0 47
michael@0 48 #if MOZ_ANDROID_OMTC
michael@0 49 #include "TexturePoolOGL.h"
michael@0 50 #endif
michael@0 51
michael@0 52 #ifdef XP_MACOSX
michael@0 53 #include "nsCocoaFeatures.h"
michael@0 54 #endif
michael@0 55
michael@0 56 #include "GeckoProfiler.h"
michael@0 57
michael@0 58 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
michael@0 59 #include "libdisplay/GonkDisplay.h" // for GonkDisplay
michael@0 60 #include <ui/Fence.h>
michael@0 61 #endif
michael@0 62
michael@0 63 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
michael@0 64
michael@0 65 namespace mozilla {
michael@0 66
michael@0 67 using namespace std;
michael@0 68 using namespace gfx;
michael@0 69
michael@0 70 namespace layers {
michael@0 71
michael@0 72 using namespace mozilla::gl;
michael@0 73
michael@0 74 static inline IntSize ns2gfxSize(const nsIntSize& s) {
michael@0 75 return IntSize(s.width, s.height);
michael@0 76 }
michael@0 77
michael@0 78 static void
michael@0 79 BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
michael@0 80 GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
michael@0 81 {
michael@0 82 MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
michael@0 83 aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
michael@0 84 aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
michael@0 85 aProgram->SetMaskLayerTransform(aTransform);
michael@0 86 }
michael@0 87
michael@0 88 // Draw the given quads with the already selected shader. Texture coordinates
michael@0 89 // are supplied if the shader requires them.
michael@0 90 static void
michael@0 91 DrawQuads(GLContext *aGLContext,
michael@0 92 VBOArena &aVBOs,
michael@0 93 ShaderProgramOGL *aProg,
michael@0 94 GLenum aMode,
michael@0 95 RectTriangles &aRects)
michael@0 96 {
michael@0 97 NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
michael@0 98 GLuint vertAttribIndex =
michael@0 99 aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
michael@0 100 GLuint texCoordAttribIndex =
michael@0 101 aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
michael@0 102 bool texCoords = (texCoordAttribIndex != GLuint(-1));
michael@0 103
michael@0 104 GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
michael@0 105
michael@0 106 GLsizei total = bytes;
michael@0 107 if (texCoords) {
michael@0 108 total *= 2;
michael@0 109 }
michael@0 110
michael@0 111 aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
michael@0 112 aVBOs.Allocate(aGLContext));
michael@0 113 aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
michael@0 114 total,
michael@0 115 nullptr,
michael@0 116 LOCAL_GL_STREAM_DRAW);
michael@0 117
michael@0 118 aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
michael@0 119 0,
michael@0 120 bytes,
michael@0 121 aRects.vertCoords().Elements());
michael@0 122 aGLContext->fEnableVertexAttribArray(vertAttribIndex);
michael@0 123 aGLContext->fVertexAttribPointer(vertAttribIndex,
michael@0 124 2, LOCAL_GL_FLOAT,
michael@0 125 LOCAL_GL_FALSE,
michael@0 126 0, BUFFER_OFFSET(0));
michael@0 127
michael@0 128 if (texCoords) {
michael@0 129 aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
michael@0 130 bytes,
michael@0 131 bytes,
michael@0 132 aRects.texCoords().Elements());
michael@0 133 aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
michael@0 134 aGLContext->fVertexAttribPointer(texCoordAttribIndex,
michael@0 135 2, LOCAL_GL_FLOAT,
michael@0 136 LOCAL_GL_FALSE,
michael@0 137 0, BUFFER_OFFSET(bytes));
michael@0 138 } else {
michael@0 139 aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
michael@0 140 }
michael@0 141
michael@0 142 aGLContext->fDrawArrays(aMode, 0, aRects.elements());
michael@0 143
michael@0 144 aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 145 }
michael@0 146
michael@0 147 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
michael@0 148 int aSurfaceHeight, bool aUseExternalSurfaceSize)
michael@0 149 : mWidget(aWidget)
michael@0 150 , mWidgetSize(-1, -1)
michael@0 151 , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
michael@0 152 , mHasBGRA(0)
michael@0 153 , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
michael@0 154 , mFrameInProgress(false)
michael@0 155 , mDestroyed(false)
michael@0 156 , mHeight(0)
michael@0 157 {
michael@0 158 MOZ_COUNT_CTOR(CompositorOGL);
michael@0 159 SetBackend(LayersBackend::LAYERS_OPENGL);
michael@0 160 }
michael@0 161
michael@0 162 CompositorOGL::~CompositorOGL()
michael@0 163 {
michael@0 164 MOZ_COUNT_DTOR(CompositorOGL);
michael@0 165 Destroy();
michael@0 166 }
michael@0 167
michael@0 168 already_AddRefed<mozilla::gl::GLContext>
michael@0 169 CompositorOGL::CreateContext()
michael@0 170 {
michael@0 171 nsRefPtr<GLContext> context;
michael@0 172
michael@0 173 #ifdef XP_WIN
michael@0 174 if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
michael@0 175 printf_stderr("Trying GL layers...\n");
michael@0 176 context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
michael@0 177 }
michael@0 178 #endif
michael@0 179
michael@0 180 if (!context)
michael@0 181 context = gl::GLContextProvider::CreateForWindow(mWidget);
michael@0 182
michael@0 183 if (!context) {
michael@0 184 NS_WARNING("Failed to create CompositorOGL context");
michael@0 185 }
michael@0 186
michael@0 187 return context.forget();
michael@0 188 }
michael@0 189
michael@0 190 void
michael@0 191 CompositorOGL::Destroy()
michael@0 192 {
michael@0 193 if (gl() && gl()->MakeCurrent()) {
michael@0 194 mVBOs.Flush(gl());
michael@0 195 }
michael@0 196
michael@0 197 if (mTexturePool) {
michael@0 198 mTexturePool->Clear();
michael@0 199 mTexturePool = nullptr;
michael@0 200 }
michael@0 201
michael@0 202 if (!mDestroyed) {
michael@0 203 mDestroyed = true;
michael@0 204 CleanupResources();
michael@0 205 }
michael@0 206 }
michael@0 207
michael@0 208 void
michael@0 209 CompositorOGL::CleanupResources()
michael@0 210 {
michael@0 211 if (!mGLContext)
michael@0 212 return;
michael@0 213
michael@0 214 nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
michael@0 215 if (!ctx) {
michael@0 216 ctx = mGLContext;
michael@0 217 }
michael@0 218
michael@0 219 for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
michael@0 220 iter != mPrograms.end();
michael@0 221 iter++) {
michael@0 222 delete iter->second;
michael@0 223 }
michael@0 224 mPrograms.clear();
michael@0 225
michael@0 226 if (!ctx->MakeCurrent()) {
michael@0 227 mQuadVBO = 0;
michael@0 228 mGLContext = nullptr;
michael@0 229 return;
michael@0 230 }
michael@0 231
michael@0 232 ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
michael@0 233
michael@0 234 if (mQuadVBO) {
michael@0 235 ctx->fDeleteBuffers(1, &mQuadVBO);
michael@0 236 mQuadVBO = 0;
michael@0 237 }
michael@0 238
michael@0 239 mGLContext = nullptr;
michael@0 240 }
michael@0 241
michael@0 242 bool
michael@0 243 CompositorOGL::Initialize()
michael@0 244 {
michael@0 245 ScopedGfxFeatureReporter reporter("GL Layers", true);
michael@0 246
michael@0 247 // Do not allow double initialization
michael@0 248 NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
michael@0 249
michael@0 250 mGLContext = CreateContext();
michael@0 251
michael@0 252 #ifdef MOZ_WIDGET_ANDROID
michael@0 253 if (!mGLContext)
michael@0 254 NS_RUNTIMEABORT("We need a context on Android");
michael@0 255 #endif
michael@0 256
michael@0 257 if (!mGLContext)
michael@0 258 return false;
michael@0 259
michael@0 260 MakeCurrent();
michael@0 261
michael@0 262 mHasBGRA =
michael@0 263 mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
michael@0 264 mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
michael@0 265
michael@0 266 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
michael@0 267 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 268 mGLContext->fEnable(LOCAL_GL_BLEND);
michael@0 269
michael@0 270 // initialise a common shader to check that we can actually compile a shader
michael@0 271 RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
michael@0 272 ShaderConfigOGL config = GetShaderConfigFor(effect);
michael@0 273 if (!GetShaderProgramFor(config)) {
michael@0 274 return false;
michael@0 275 }
michael@0 276
michael@0 277 if (mGLContext->WorkAroundDriverBugs()) {
michael@0 278 /**
michael@0 279 * We'll test the ability here to bind NPOT textures to a framebuffer, if
michael@0 280 * this fails we'll try ARB_texture_rectangle.
michael@0 281 */
michael@0 282
michael@0 283 GLenum textureTargets[] = {
michael@0 284 LOCAL_GL_TEXTURE_2D,
michael@0 285 LOCAL_GL_NONE
michael@0 286 };
michael@0 287
michael@0 288 if (!mGLContext->IsGLES()) {
michael@0 289 // No TEXTURE_RECTANGLE_ARB available on ES2
michael@0 290 textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
michael@0 291 }
michael@0 292
michael@0 293 mFBOTextureTarget = LOCAL_GL_NONE;
michael@0 294
michael@0 295 GLuint testFBO = 0;
michael@0 296 mGLContext->fGenFramebuffers(1, &testFBO);
michael@0 297 GLuint testTexture = 0;
michael@0 298
michael@0 299 for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
michael@0 300 GLenum target = textureTargets[i];
michael@0 301 if (!target)
michael@0 302 continue;
michael@0 303
michael@0 304 mGLContext->fGenTextures(1, &testTexture);
michael@0 305 mGLContext->fBindTexture(target, testTexture);
michael@0 306 mGLContext->fTexParameteri(target,
michael@0 307 LOCAL_GL_TEXTURE_MIN_FILTER,
michael@0 308 LOCAL_GL_NEAREST);
michael@0 309 mGLContext->fTexParameteri(target,
michael@0 310 LOCAL_GL_TEXTURE_MAG_FILTER,
michael@0 311 LOCAL_GL_NEAREST);
michael@0 312 mGLContext->fTexImage2D(target,
michael@0 313 0,
michael@0 314 LOCAL_GL_RGBA,
michael@0 315 5, 3, /* sufficiently NPOT */
michael@0 316 0,
michael@0 317 LOCAL_GL_RGBA,
michael@0 318 LOCAL_GL_UNSIGNED_BYTE,
michael@0 319 nullptr);
michael@0 320
michael@0 321 // unbind this texture, in preparation for binding it to the FBO
michael@0 322 mGLContext->fBindTexture(target, 0);
michael@0 323
michael@0 324 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
michael@0 325 mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
michael@0 326 LOCAL_GL_COLOR_ATTACHMENT0,
michael@0 327 target,
michael@0 328 testTexture,
michael@0 329 0);
michael@0 330
michael@0 331 if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
michael@0 332 LOCAL_GL_FRAMEBUFFER_COMPLETE)
michael@0 333 {
michael@0 334 mFBOTextureTarget = target;
michael@0 335 mGLContext->fDeleteTextures(1, &testTexture);
michael@0 336 break;
michael@0 337 }
michael@0 338
michael@0 339 mGLContext->fDeleteTextures(1, &testTexture);
michael@0 340 }
michael@0 341
michael@0 342 if (testFBO) {
michael@0 343 mGLContext->fDeleteFramebuffers(1, &testFBO);
michael@0 344 }
michael@0 345
michael@0 346 if (mFBOTextureTarget == LOCAL_GL_NONE) {
michael@0 347 /* Unable to find a texture target that works with FBOs and NPOT textures */
michael@0 348 return false;
michael@0 349 }
michael@0 350 } else {
michael@0 351 // not trying to work around driver bugs, so TEXTURE_2D should just work
michael@0 352 mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
michael@0 353 }
michael@0 354
michael@0 355 // back to default framebuffer, to avoid confusion
michael@0 356 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
michael@0 357
michael@0 358 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
michael@0 359 /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
michael@0 360 * extension -- the EXT variant does not provide support for
michael@0 361 * texture rectangle access inside GLSL (sampler2DRect,
michael@0 362 * texture2DRect).
michael@0 363 */
michael@0 364 if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
michael@0 365 return false;
michael@0 366 }
michael@0 367
michael@0 368 /* Create a simple quad VBO */
michael@0 369
michael@0 370 mGLContext->fGenBuffers(1, &mQuadVBO);
michael@0 371 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
michael@0 372
michael@0 373 GLfloat vertices[] = {
michael@0 374 /* First quad vertices */
michael@0 375 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
michael@0 376 /* Then quad texcoords */
michael@0 377 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
michael@0 378 };
michael@0 379 mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
michael@0 380 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 381
michael@0 382 nsCOMPtr<nsIConsoleService>
michael@0 383 console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
michael@0 384
michael@0 385 if (console) {
michael@0 386 nsString msg;
michael@0 387 msg +=
michael@0 388 NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
michael@0 389 msg += NS_ConvertUTF8toUTF16(
michael@0 390 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
michael@0 391 msg += NS_LITERAL_STRING("\nVendor: ");
michael@0 392 msg += NS_ConvertUTF8toUTF16(
michael@0 393 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
michael@0 394 msg += NS_LITERAL_STRING("\nRenderer: ");
michael@0 395 msg += NS_ConvertUTF8toUTF16(
michael@0 396 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
michael@0 397 msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
michael@0 398 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
michael@0 399 msg += NS_LITERAL_STRING("TEXTURE_2D");
michael@0 400 else
michael@0 401 msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
michael@0 402 console->LogStringMessage(msg.get());
michael@0 403 }
michael@0 404
michael@0 405 reporter.SetSuccessful();
michael@0 406 return true;
michael@0 407 }
michael@0 408
michael@0 409 // |aTextureTransform| is the texture transform that will be set on
michael@0 410 // aProg, possibly multiplied with another texture transform of our
michael@0 411 // own.
michael@0 412 // |aTexCoordRect| is the rectangle from the texture that we want to
michael@0 413 // draw using the given program. The program already has a necessary
michael@0 414 // offset and scale, so the geometry that needs to be drawn is a unit
michael@0 415 // square from 0,0 to 1,1.
michael@0 416 //
michael@0 417 // |aTexture| is the texture we are drawing. Its actual size can be
michael@0 418 // larger than the rectangle given by |aTexCoordRect|.
michael@0 419 void
michael@0 420 CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
michael@0 421 const gfx3DMatrix& aTextureTransform,
michael@0 422 const Rect& aTexCoordRect,
michael@0 423 TextureSource *aTexture)
michael@0 424 {
michael@0 425 // Given what we know about these textures and coordinates, we can
michael@0 426 // compute fmod(t, 1.0f) to get the same texture coordinate out. If
michael@0 427 // the texCoordRect dimension is < 0 or > width/height, then we have
michael@0 428 // wraparound that we need to deal with by drawing multiple quads,
michael@0 429 // because we can't rely on full non-power-of-two texture support
michael@0 430 // (which is required for the REPEAT wrap mode).
michael@0 431
michael@0 432 RectTriangles rects;
michael@0 433
michael@0 434 GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
michael@0 435
michael@0 436 IntSize realTexSize = aTexture->GetSize();
michael@0 437 if (!CanUploadNonPowerOfTwo(mGLContext)) {
michael@0 438 realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
michael@0 439 NextPowerOfTwo(realTexSize.height));
michael@0 440 }
michael@0 441
michael@0 442 // We need to convert back to actual texels here to get proper behaviour with
michael@0 443 // our GL helper functions. Should fix this sometime.
michael@0 444 // I want to vomit.
michael@0 445 IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
michael@0 446 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
michael@0 447 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
michael@0 448 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
michael@0 449
michael@0 450 // This is fairly disgusting - if the texture should be flipped it will have a
michael@0 451 // negative height, in which case we un-invert the texture coords and pass the
michael@0 452 // flipped 'flag' to the functions below. We can't just use the inverted coords
michael@0 453 // because our GL funtions use an explicit flag.
michael@0 454 bool flipped = false;
michael@0 455 if (texCoordRect.height < 0) {
michael@0 456 flipped = true;
michael@0 457 texCoordRect.y = texCoordRect.YMost();
michael@0 458 texCoordRect.height = -texCoordRect.height;
michael@0 459 }
michael@0 460
michael@0 461 if (wrapMode == LOCAL_GL_REPEAT) {
michael@0 462 rects.addRect(/* dest rectangle */
michael@0 463 0.0f, 0.0f, 1.0f, 1.0f,
michael@0 464 /* tex coords */
michael@0 465 texCoordRect.x / GLfloat(realTexSize.width),
michael@0 466 texCoordRect.y / GLfloat(realTexSize.height),
michael@0 467 texCoordRect.XMost() / GLfloat(realTexSize.width),
michael@0 468 texCoordRect.YMost() / GLfloat(realTexSize.height),
michael@0 469 flipped);
michael@0 470 } else {
michael@0 471 nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
michael@0 472 texCoordRect.width, texCoordRect.height);
michael@0 473 DecomposeIntoNoRepeatTriangles(tcRect,
michael@0 474 nsIntSize(realTexSize.width, realTexSize.height),
michael@0 475 rects, flipped);
michael@0 476 }
michael@0 477
michael@0 478 gfx3DMatrix textureTransform;
michael@0 479 if (rects.isSimpleQuad(textureTransform)) {
michael@0 480 Matrix4x4 transform;
michael@0 481 ToMatrix4x4(aTextureTransform * textureTransform, transform);
michael@0 482 aProg->SetTextureTransform(transform);
michael@0 483 BindAndDrawQuad(aProg);
michael@0 484 } else {
michael@0 485 Matrix4x4 transform;
michael@0 486 ToMatrix4x4(aTextureTransform, transform);
michael@0 487 aProg->SetTextureTransform(transform);
michael@0 488 DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
michael@0 489 }
michael@0 490 }
michael@0 491
michael@0 492 void
michael@0 493 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
michael@0 494 const Matrix& aWorldTransform)
michael@0 495 {
michael@0 496 // Set the viewport correctly.
michael@0 497 mGLContext->fViewport(0, 0, aSize.width, aSize.height);
michael@0 498
michael@0 499 mHeight = aSize.height;
michael@0 500
michael@0 501 // We flip the view matrix around so that everything is right-side up; we're
michael@0 502 // drawing directly into the window's back buffer, so this keeps things
michael@0 503 // looking correct.
michael@0 504 // XXX: We keep track of whether the window size changed, so we could skip
michael@0 505 // this update if it hadn't changed since the last call. We will need to
michael@0 506 // track changes to aTransformPolicy and aWorldTransform for this to work
michael@0 507 // though.
michael@0 508
michael@0 509 // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
michael@0 510 // 2, 2) and flip the contents.
michael@0 511 Matrix viewMatrix;
michael@0 512 viewMatrix.Translate(-1.0, 1.0);
michael@0 513 viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
michael@0 514 viewMatrix.Scale(1.0f, -1.0f);
michael@0 515 if (!mTarget) {
michael@0 516 viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y);
michael@0 517 }
michael@0 518
michael@0 519 viewMatrix = aWorldTransform * viewMatrix;
michael@0 520
michael@0 521 Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
michael@0 522 matrix3d._33 = 0.0f;
michael@0 523
michael@0 524 mProjMatrix = matrix3d;
michael@0 525 }
michael@0 526
michael@0 527 TemporaryRef<CompositingRenderTarget>
michael@0 528 CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
michael@0 529 {
michael@0 530 GLuint tex = 0;
michael@0 531 GLuint fbo = 0;
michael@0 532 CreateFBOWithTexture(aRect, false, 0, &fbo, &tex);
michael@0 533 RefPtr<CompositingRenderTargetOGL> surface
michael@0 534 = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
michael@0 535 surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit);
michael@0 536 return surface.forget();
michael@0 537 }
michael@0 538
michael@0 539 TemporaryRef<CompositingRenderTarget>
michael@0 540 CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
michael@0 541 const CompositingRenderTarget *aSource,
michael@0 542 const IntPoint &aSourcePoint)
michael@0 543 {
michael@0 544 GLuint tex = 0;
michael@0 545 GLuint fbo = 0;
michael@0 546 const CompositingRenderTargetOGL* sourceSurface
michael@0 547 = static_cast<const CompositingRenderTargetOGL*>(aSource);
michael@0 548 IntRect sourceRect(aSourcePoint, aRect.Size());
michael@0 549 if (aSource) {
michael@0 550 CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
michael@0 551 &fbo, &tex);
michael@0 552 } else {
michael@0 553 CreateFBOWithTexture(sourceRect, true, 0,
michael@0 554 &fbo, &tex);
michael@0 555 }
michael@0 556
michael@0 557 RefPtr<CompositingRenderTargetOGL> surface
michael@0 558 = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
michael@0 559 surface->Initialize(aRect.Size(),
michael@0 560 mFBOTextureTarget,
michael@0 561 INIT_MODE_NONE);
michael@0 562 return surface.forget();
michael@0 563 }
michael@0 564
michael@0 565 void
michael@0 566 CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
michael@0 567 {
michael@0 568 MOZ_ASSERT(aSurface);
michael@0 569 CompositingRenderTargetOGL* surface
michael@0 570 = static_cast<CompositingRenderTargetOGL*>(aSurface);
michael@0 571 if (mCurrentRenderTarget != surface) {
michael@0 572 surface->BindRenderTarget();
michael@0 573 mCurrentRenderTarget = surface;
michael@0 574 }
michael@0 575 }
michael@0 576
michael@0 577 CompositingRenderTarget*
michael@0 578 CompositorOGL::GetCurrentRenderTarget() const
michael@0 579 {
michael@0 580 return mCurrentRenderTarget;
michael@0 581 }
michael@0 582
michael@0 583 static GLenum
michael@0 584 GetFrameBufferInternalFormat(GLContext* gl,
michael@0 585 GLuint aFrameBuffer,
michael@0 586 nsIWidget* aWidget)
michael@0 587 {
michael@0 588 if (aFrameBuffer == 0) { // default framebuffer
michael@0 589 return aWidget->GetGLFrameBufferFormat();
michael@0 590 }
michael@0 591 return LOCAL_GL_RGBA;
michael@0 592 }
michael@0 593
michael@0 594 /*
michael@0 595 * Returns a size that is larger than and closest to aSize where both
michael@0 596 * width and height are powers of two.
michael@0 597 * If the OpenGL setup is capable of using non-POT textures, then it
michael@0 598 * will just return aSize.
michael@0 599 */
michael@0 600 static IntSize
michael@0 601 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
michael@0 602 {
michael@0 603 if (CanUploadNonPowerOfTwo(gl))
michael@0 604 return aSize;
michael@0 605
michael@0 606 return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
michael@0 607 }
michael@0 608
michael@0 609 void
michael@0 610 CompositorOGL::ClearRect(const gfx::Rect& aRect)
michael@0 611 {
michael@0 612 // Map aRect to OGL coordinates, origin:bottom-left
michael@0 613 GLint y = mHeight - (aRect.y + aRect.height);
michael@0 614
michael@0 615 ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
michael@0 616 ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
michael@0 617 mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
michael@0 618 mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
michael@0 619 }
michael@0 620
michael@0 621 void
michael@0 622 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
michael@0 623 const Rect *aClipRectIn,
michael@0 624 const gfx::Matrix& aTransform,
michael@0 625 const Rect& aRenderBounds,
michael@0 626 Rect *aClipRectOut,
michael@0 627 Rect *aRenderBoundsOut)
michael@0 628 {
michael@0 629 PROFILER_LABEL("CompositorOGL", "BeginFrame");
michael@0 630 MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
michael@0 631
michael@0 632 LayerScope::BeginFrame(mGLContext, PR_Now());
michael@0 633
michael@0 634 mVBOs.Reset();
michael@0 635
michael@0 636 mFrameInProgress = true;
michael@0 637 gfx::Rect rect;
michael@0 638 if (mUseExternalSurfaceSize) {
michael@0 639 rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
michael@0 640 } else {
michael@0 641 rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
michael@0 642 // If render bounds is not updated explicitly, try to infer it from widget
michael@0 643 if (rect.width == 0 || rect.height == 0) {
michael@0 644 // FIXME/bug XXXXXX this races with rotation changes on the main
michael@0 645 // thread, and undoes all the care we take with layers txns being
michael@0 646 // sent atomically with rotation changes
michael@0 647 nsIntRect intRect;
michael@0 648 mWidget->GetClientBounds(intRect);
michael@0 649 rect = gfx::Rect(0, 0, intRect.width, intRect.height);
michael@0 650 }
michael@0 651 }
michael@0 652
michael@0 653 rect = aTransform.TransformBounds(rect);
michael@0 654 if (aRenderBoundsOut) {
michael@0 655 *aRenderBoundsOut = rect;
michael@0 656 }
michael@0 657
michael@0 658 GLint width = rect.width;
michael@0 659 GLint height = rect.height;
michael@0 660
michael@0 661 // We can't draw anything to something with no area
michael@0 662 // so just return
michael@0 663 if (width == 0 || height == 0)
michael@0 664 return;
michael@0 665
michael@0 666 // If the widget size changed, we have to force a MakeCurrent
michael@0 667 // to make sure that GL sees the updated widget size.
michael@0 668 if (mWidgetSize.width != width ||
michael@0 669 mWidgetSize.height != height)
michael@0 670 {
michael@0 671 MakeCurrent(ForceMakeCurrent);
michael@0 672
michael@0 673 mWidgetSize.width = width;
michael@0 674 mWidgetSize.height = height;
michael@0 675 } else {
michael@0 676 MakeCurrent();
michael@0 677 }
michael@0 678
michael@0 679 mPixelsPerFrame = width * height;
michael@0 680 mPixelsFilled = 0;
michael@0 681
michael@0 682 #if MOZ_ANDROID_OMTC
michael@0 683 TexturePoolOGL::Fill(gl());
michael@0 684 #endif
michael@0 685
michael@0 686 mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
michael@0 687 IntSize(width, height),
michael@0 688 aTransform);
michael@0 689 mCurrentRenderTarget->BindRenderTarget();
michael@0 690 #ifdef DEBUG
michael@0 691 mWindowRenderTarget = mCurrentRenderTarget;
michael@0 692 #endif
michael@0 693
michael@0 694 // Default blend function implements "OVER"
michael@0 695 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
michael@0 696 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 697 mGLContext->fEnable(LOCAL_GL_BLEND);
michael@0 698
michael@0 699 mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
michael@0 700
michael@0 701 if (aClipRectOut && !aClipRectIn) {
michael@0 702 aClipRectOut->SetRect(0, 0, width, height);
michael@0 703 }
michael@0 704
michael@0 705 // If the Android compositor is being used, this clear will be done in
michael@0 706 // DrawWindowUnderlay. Make sure the bits used here match up with those used
michael@0 707 // in mobile/android/base/gfx/LayerRenderer.java
michael@0 708 #ifndef MOZ_ANDROID_OMTC
michael@0 709 mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
michael@0 710 mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
michael@0 711 #endif
michael@0 712 }
michael@0 713
michael@0 714 void
michael@0 715 CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
michael@0 716 GLuint aSourceFrameBuffer,
michael@0 717 GLuint *aFBO, GLuint *aTexture)
michael@0 718 {
michael@0 719 GLuint tex, fbo;
michael@0 720
michael@0 721 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
michael@0 722 mGLContext->fGenTextures(1, &tex);
michael@0 723 mGLContext->fBindTexture(mFBOTextureTarget, tex);
michael@0 724
michael@0 725 if (aCopyFromSource) {
michael@0 726 GLuint curFBO = mCurrentRenderTarget->GetFBO();
michael@0 727 if (curFBO != aSourceFrameBuffer) {
michael@0 728 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
michael@0 729 }
michael@0 730
michael@0 731 // We're going to create an RGBA temporary fbo. But to
michael@0 732 // CopyTexImage() from the current framebuffer, the framebuffer's
michael@0 733 // format has to be compatible with the new texture's. So we
michael@0 734 // check the format of the framebuffer here and take a slow path
michael@0 735 // if it's incompatible.
michael@0 736 GLenum format =
michael@0 737 GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
michael@0 738
michael@0 739 bool isFormatCompatibleWithRGBA
michael@0 740 = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
michael@0 741 : true;
michael@0 742
michael@0 743 if (isFormatCompatibleWithRGBA) {
michael@0 744 mGLContext->fCopyTexImage2D(mFBOTextureTarget,
michael@0 745 0,
michael@0 746 LOCAL_GL_RGBA,
michael@0 747 aRect.x, FlipY(aRect.y + aRect.height),
michael@0 748 aRect.width, aRect.height,
michael@0 749 0);
michael@0 750 } else {
michael@0 751 // Curses, incompatible formats. Take a slow path.
michael@0 752
michael@0 753 // RGBA
michael@0 754 size_t bufferSize = aRect.width * aRect.height * 4;
michael@0 755 nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]);
michael@0 756
michael@0 757 mGLContext->fReadPixels(aRect.x, aRect.y,
michael@0 758 aRect.width, aRect.height,
michael@0 759 LOCAL_GL_RGBA,
michael@0 760 LOCAL_GL_UNSIGNED_BYTE,
michael@0 761 buf);
michael@0 762 mGLContext->fTexImage2D(mFBOTextureTarget,
michael@0 763 0,
michael@0 764 LOCAL_GL_RGBA,
michael@0 765 aRect.width, aRect.height,
michael@0 766 0,
michael@0 767 LOCAL_GL_RGBA,
michael@0 768 LOCAL_GL_UNSIGNED_BYTE,
michael@0 769 buf);
michael@0 770 }
michael@0 771 GLenum error = mGLContext->GetAndClearError();
michael@0 772 if (error != LOCAL_GL_NO_ERROR) {
michael@0 773 nsAutoCString msg;
michael@0 774 msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d",
michael@0 775 error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
michael@0 776 NS_ERROR(msg.get());
michael@0 777 }
michael@0 778 } else {
michael@0 779 mGLContext->fTexImage2D(mFBOTextureTarget,
michael@0 780 0,
michael@0 781 LOCAL_GL_RGBA,
michael@0 782 aRect.width, aRect.height,
michael@0 783 0,
michael@0 784 LOCAL_GL_RGBA,
michael@0 785 LOCAL_GL_UNSIGNED_BYTE,
michael@0 786 nullptr);
michael@0 787 }
michael@0 788 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
michael@0 789 LOCAL_GL_LINEAR);
michael@0 790 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
michael@0 791 LOCAL_GL_LINEAR);
michael@0 792 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
michael@0 793 LOCAL_GL_CLAMP_TO_EDGE);
michael@0 794 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
michael@0 795 LOCAL_GL_CLAMP_TO_EDGE);
michael@0 796 mGLContext->fBindTexture(mFBOTextureTarget, 0);
michael@0 797
michael@0 798 mGLContext->fGenFramebuffers(1, &fbo);
michael@0 799
michael@0 800 *aFBO = fbo;
michael@0 801 *aTexture = tex;
michael@0 802 }
michael@0 803
michael@0 804 ShaderConfigOGL
michael@0 805 CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
michael@0 806 {
michael@0 807 ShaderConfigOGL config;
michael@0 808
michael@0 809 switch(aEffect->mType) {
michael@0 810 case EFFECT_SOLID_COLOR:
michael@0 811 config.SetRenderColor(true);
michael@0 812 break;
michael@0 813 case EFFECT_YCBCR:
michael@0 814 config.SetYCbCr(true);
michael@0 815 break;
michael@0 816 case EFFECT_COMPONENT_ALPHA:
michael@0 817 {
michael@0 818 config.SetComponentAlpha(true);
michael@0 819 EffectComponentAlpha* effectComponentAlpha =
michael@0 820 static_cast<EffectComponentAlpha*>(aEffect);
michael@0 821 gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
michael@0 822 config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
michael@0 823 format == gfx::SurfaceFormat::B8G8R8X8);
michael@0 824 break;
michael@0 825 }
michael@0 826 case EFFECT_RENDER_TARGET:
michael@0 827 config.SetTextureTarget(mFBOTextureTarget);
michael@0 828 break;
michael@0 829 default:
michael@0 830 {
michael@0 831 MOZ_ASSERT(aEffect->mType == EFFECT_RGB);
michael@0 832 TexturedEffect* texturedEffect =
michael@0 833 static_cast<TexturedEffect*>(aEffect);
michael@0 834 TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
michael@0 835 MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
michael@0 836 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8);
michael@0 837 MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
michael@0 838 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
michael@0 839 source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
michael@0 840 source->GetFormat() == gfx::SurfaceFormat::R5G6B5);
michael@0 841 config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
michael@0 842 source->GetFormat());
michael@0 843 break;
michael@0 844 }
michael@0 845 }
michael@0 846 config.SetMask2D(aMask == Mask2d);
michael@0 847 config.SetMask3D(aMask == Mask3d);
michael@0 848 return config;
michael@0 849 }
michael@0 850
michael@0 851 ShaderProgramOGL*
michael@0 852 CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
michael@0 853 {
michael@0 854 std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
michael@0 855 if (iter != mPrograms.end())
michael@0 856 return iter->second;
michael@0 857
michael@0 858 ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
michael@0 859 ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
michael@0 860 if (!shader->Initialize()) {
michael@0 861 delete shader;
michael@0 862 return nullptr;
michael@0 863 }
michael@0 864
michael@0 865 mPrograms[aConfig] = shader;
michael@0 866 return shader;
michael@0 867 }
michael@0 868
michael@0 869 void
michael@0 870 CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect,
michael@0 871 const gfx::Color& aColor,
michael@0 872 gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform)
michael@0 873 {
michael@0 874 mGLContext->fLineWidth(2.0);
michael@0 875
michael@0 876 EffectChain effects;
michael@0 877 effects.mPrimaryEffect = new EffectSolidColor(aColor);
michael@0 878
michael@0 879 for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) {
michael@0 880 const gfx::Point& p1 = aLines[i];
michael@0 881 const gfx::Point& p2 = aLines[i+1];
michael@0 882 DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y),
michael@0 883 aClipRect, effects, aOpacity, aTransform,
michael@0 884 LOCAL_GL_LINE_STRIP);
michael@0 885 }
michael@0 886 }
michael@0 887
michael@0 888 void
michael@0 889 CompositorOGL::DrawQuadInternal(const Rect& aRect,
michael@0 890 const Rect& aClipRect,
michael@0 891 const EffectChain &aEffectChain,
michael@0 892 Float aOpacity,
michael@0 893 const gfx::Matrix4x4 &aTransform,
michael@0 894 GLuint aDrawMode)
michael@0 895 {
michael@0 896 PROFILER_LABEL("CompositorOGL", "DrawQuad");
michael@0 897 MOZ_ASSERT(mFrameInProgress, "frame not started");
michael@0 898
michael@0 899 Rect clipRect = aClipRect;
michael@0 900 if (!mTarget) {
michael@0 901 clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
michael@0 902 }
michael@0 903 IntRect intClipRect;
michael@0 904 clipRect.ToIntRect(&intClipRect);
michael@0 905
michael@0 906 gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
michael@0 907 intClipRect.width, intClipRect.height);
michael@0 908
michael@0 909 LayerScope::SendEffectChain(mGLContext, aEffectChain,
michael@0 910 aRect.width, aRect.height);
michael@0 911
michael@0 912 MaskType maskType;
michael@0 913 EffectMask* effectMask;
michael@0 914 TextureSourceOGL* sourceMask = nullptr;
michael@0 915 gfx::Matrix4x4 maskQuadTransform;
michael@0 916 if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
michael@0 917 effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
michael@0 918 sourceMask = effectMask->mMaskTexture->AsSourceOGL();
michael@0 919
michael@0 920 // NS_ASSERTION(textureMask->IsAlpha(),
michael@0 921 // "OpenGL mask layers must be backed by alpha surfaces");
michael@0 922
michael@0 923 // We're assuming that the gl backend won't cheat and use NPOT
michael@0 924 // textures when glContext says it can't (which seems to happen
michael@0 925 // on a mac when you force POT textures)
michael@0 926 IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
michael@0 927
michael@0 928 const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
michael@0 929 NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
michael@0 930 Rect bounds = Rect(Point(), Size(maskSize));
michael@0 931 bounds = maskTransform.As2D().TransformBounds(bounds);
michael@0 932
michael@0 933 maskQuadTransform._11 = 1.0f/bounds.width;
michael@0 934 maskQuadTransform._22 = 1.0f/bounds.height;
michael@0 935 maskQuadTransform._41 = float(-bounds.x)/bounds.width;
michael@0 936 maskQuadTransform._42 = float(-bounds.y)/bounds.height;
michael@0 937
michael@0 938 maskType = effectMask->mIs3D
michael@0 939 ? Mask3d
michael@0 940 : Mask2d;
michael@0 941 } else {
michael@0 942 maskType = MaskNone;
michael@0 943 }
michael@0 944
michael@0 945 mPixelsFilled += aRect.width * aRect.height;
michael@0 946
michael@0 947 // Determine the color if this is a color shader and fold the opacity into
michael@0 948 // the color since color shaders don't have an opacity uniform.
michael@0 949 Color color;
michael@0 950 if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) {
michael@0 951 EffectSolidColor* effectSolidColor =
michael@0 952 static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
michael@0 953 color = effectSolidColor->mColor;
michael@0 954
michael@0 955 Float opacity = aOpacity * color.a;
michael@0 956 color.r *= opacity;
michael@0 957 color.g *= opacity;
michael@0 958 color.b *= opacity;
michael@0 959 color.a = opacity;
michael@0 960
michael@0 961 // We can fold opacity into the color, so no need to consider it further.
michael@0 962 aOpacity = 1.f;
michael@0 963 }
michael@0 964
michael@0 965 ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
michael@0 966 config.SetOpacity(aOpacity != 1.f);
michael@0 967 ShaderProgramOGL *program = GetShaderProgramFor(config);
michael@0 968 program->Activate();
michael@0 969 program->SetProjectionMatrix(mProjMatrix);
michael@0 970 program->SetLayerQuadRect(aRect);
michael@0 971 program->SetLayerTransform(aTransform);
michael@0 972 IntPoint offset = mCurrentRenderTarget->GetOrigin();
michael@0 973 program->SetRenderOffset(offset.x, offset.y);
michael@0 974 if (aOpacity != 1.f)
michael@0 975 program->SetLayerOpacity(aOpacity);
michael@0 976 if (config.mFeatures & ENABLE_TEXTURE_RECT) {
michael@0 977 TexturedEffect* texturedEffect =
michael@0 978 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
michael@0 979 TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
michael@0 980 // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
michael@0 981 program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
michael@0 982 }
michael@0 983
michael@0 984 switch (aEffectChain.mPrimaryEffect->mType) {
michael@0 985 case EFFECT_SOLID_COLOR: {
michael@0 986 program->SetRenderColor(color);
michael@0 987
michael@0 988 if (maskType != MaskNone) {
michael@0 989 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
michael@0 990 }
michael@0 991
michael@0 992 BindAndDrawQuad(program, aDrawMode);
michael@0 993 }
michael@0 994 break;
michael@0 995
michael@0 996 case EFFECT_RGB: {
michael@0 997 TexturedEffect* texturedEffect =
michael@0 998 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
michael@0 999 TextureSource *source = texturedEffect->mTexture;
michael@0 1000
michael@0 1001 if (!texturedEffect->mPremultiplied) {
michael@0 1002 mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
michael@0 1003 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 1004 }
michael@0 1005
michael@0 1006 gfx::Filter filter = texturedEffect->mFilter;
michael@0 1007 gfx3DMatrix textureTransform;
michael@0 1008 gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform);
michael@0 1009
michael@0 1010 #ifdef MOZ_WIDGET_ANDROID
michael@0 1011 gfxMatrix textureTransform2D;
michael@0 1012 if (filter != gfx::Filter::POINT &&
michael@0 1013 aTransform.Is2DIntegerTranslation() &&
michael@0 1014 textureTransform.Is2D(&textureTransform2D) &&
michael@0 1015 textureTransform2D.HasOnlyIntegerTranslation()) {
michael@0 1016 // On Android we encounter small resampling errors in what should be
michael@0 1017 // pixel-aligned compositing operations. This works around them. This
michael@0 1018 // code should not be needed!
michael@0 1019 filter = gfx::Filter::POINT;
michael@0 1020 }
michael@0 1021 #endif
michael@0 1022 source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
michael@0 1023
michael@0 1024 program->SetTextureUnit(0);
michael@0 1025
michael@0 1026 if (maskType != MaskNone) {
michael@0 1027 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
michael@0 1028 }
michael@0 1029
michael@0 1030 BindAndDrawQuadWithTextureRect(program, textureTransform,
michael@0 1031 texturedEffect->mTextureCoords, source);
michael@0 1032
michael@0 1033 if (!texturedEffect->mPremultiplied) {
michael@0 1034 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
michael@0 1035 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 1036 }
michael@0 1037 }
michael@0 1038 break;
michael@0 1039 case EFFECT_YCBCR: {
michael@0 1040 EffectYCbCr* effectYCbCr =
michael@0 1041 static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
michael@0 1042 TextureSource* sourceYCbCr = effectYCbCr->mTexture;
michael@0 1043 const int Y = 0, Cb = 1, Cr = 2;
michael@0 1044 TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
michael@0 1045 TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
michael@0 1046 TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
michael@0 1047
michael@0 1048 if (!sourceY && !sourceCb && !sourceCr) {
michael@0 1049 NS_WARNING("Invalid layer texture.");
michael@0 1050 return;
michael@0 1051 }
michael@0 1052
michael@0 1053 sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
michael@0 1054 sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
michael@0 1055 sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
michael@0 1056
michael@0 1057 program->SetYCbCrTextureUnits(Y, Cb, Cr);
michael@0 1058
michael@0 1059 if (maskType != MaskNone) {
michael@0 1060 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
michael@0 1061 }
michael@0 1062 BindAndDrawQuadWithTextureRect(program,
michael@0 1063 gfx3DMatrix(),
michael@0 1064 effectYCbCr->mTextureCoords,
michael@0 1065 sourceYCbCr->GetSubSource(Y));
michael@0 1066 }
michael@0 1067 break;
michael@0 1068 case EFFECT_RENDER_TARGET: {
michael@0 1069 EffectRenderTarget* effectRenderTarget =
michael@0 1070 static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
michael@0 1071 RefPtr<CompositingRenderTargetOGL> surface
michael@0 1072 = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
michael@0 1073
michael@0 1074 surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
michael@0 1075
michael@0 1076 // Drawing is always flipped, but when copying between surfaces we want to avoid
michael@0 1077 // this, so apply a flip here to cancel the other one out.
michael@0 1078 Matrix transform;
michael@0 1079 transform.Translate(0.0, 1.0);
michael@0 1080 transform.Scale(1.0f, -1.0f);
michael@0 1081 program->SetTextureTransform(Matrix4x4::From2D(transform));
michael@0 1082 program->SetTextureUnit(0);
michael@0 1083
michael@0 1084 if (maskType != MaskNone) {
michael@0 1085 sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
michael@0 1086 program->SetMaskTextureUnit(1);
michael@0 1087 program->SetMaskLayerTransform(maskQuadTransform);
michael@0 1088 }
michael@0 1089
michael@0 1090 if (config.mFeatures & ENABLE_TEXTURE_RECT) {
michael@0 1091 // 2DRect case, get the multiplier right for a sampler2DRect
michael@0 1092 program->SetTexCoordMultiplier(aRect.width, aRect.height);
michael@0 1093 }
michael@0 1094
michael@0 1095 // Drawing is always flipped, but when copying between surfaces we want to avoid
michael@0 1096 // this. Pass true for the flip parameter to introduce a second flip
michael@0 1097 // that cancels the other one out.
michael@0 1098 BindAndDrawQuad(program);
michael@0 1099 }
michael@0 1100 break;
michael@0 1101 case EFFECT_COMPONENT_ALPHA: {
michael@0 1102 MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
michael@0 1103 EffectComponentAlpha* effectComponentAlpha =
michael@0 1104 static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
michael@0 1105 TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
michael@0 1106 TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
michael@0 1107
michael@0 1108 if (!sourceOnBlack->IsValid() ||
michael@0 1109 !sourceOnWhite->IsValid()) {
michael@0 1110 NS_WARNING("Invalid layer texture for component alpha");
michael@0 1111 return;
michael@0 1112 }
michael@0 1113
michael@0 1114 sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
michael@0 1115 sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
michael@0 1116
michael@0 1117 program->SetBlackTextureUnit(0);
michael@0 1118 program->SetWhiteTextureUnit(1);
michael@0 1119 program->SetTextureTransform(gfx::Matrix4x4());
michael@0 1120
michael@0 1121 if (maskType != MaskNone) {
michael@0 1122 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
michael@0 1123 }
michael@0 1124 // Pass 1.
michael@0 1125 gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
michael@0 1126 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 1127 program->SetTexturePass2(false);
michael@0 1128 BindAndDrawQuadWithTextureRect(program,
michael@0 1129 gfx3DMatrix(),
michael@0 1130 effectComponentAlpha->mTextureCoords,
michael@0 1131 effectComponentAlpha->mOnBlack);
michael@0 1132
michael@0 1133 // Pass 2.
michael@0 1134 gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
michael@0 1135 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 1136
michael@0 1137 #ifdef XP_MACOSX
michael@0 1138 if (gl()->WorkAroundDriverBugs() &&
michael@0 1139 gl()->Vendor() == GLVendor::NVIDIA &&
michael@0 1140 !nsCocoaFeatures::OnMavericksOrLater()) {
michael@0 1141 // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
michael@0 1142 // won't pick up the TexturePass2 uniform change below if we don't do
michael@0 1143 // something to force it. Re-activating the shader seems to be one way
michael@0 1144 // of achieving that.
michael@0 1145 program->Activate();
michael@0 1146 }
michael@0 1147 #endif
michael@0 1148
michael@0 1149 program->SetTexturePass2(true);
michael@0 1150 BindAndDrawQuadWithTextureRect(program,
michael@0 1151 gfx3DMatrix(),
michael@0 1152 effectComponentAlpha->mTextureCoords,
michael@0 1153 effectComponentAlpha->mOnBlack);
michael@0 1154
michael@0 1155 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
michael@0 1156 LOCAL_GL_ONE, LOCAL_GL_ONE);
michael@0 1157 }
michael@0 1158 break;
michael@0 1159 default:
michael@0 1160 MOZ_ASSERT(false, "Unhandled effect type");
michael@0 1161 break;
michael@0 1162 }
michael@0 1163
michael@0 1164 // in case rendering has used some other GL context
michael@0 1165 MakeCurrent();
michael@0 1166 }
michael@0 1167
michael@0 1168 void
michael@0 1169 CompositorOGL::EndFrame()
michael@0 1170 {
michael@0 1171 PROFILER_LABEL("CompositorOGL", "EndFrame");
michael@0 1172 MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
michael@0 1173
michael@0 1174 #ifdef MOZ_DUMP_PAINTING
michael@0 1175 if (gfxUtils::sDumpPainting) {
michael@0 1176 nsIntRect rect;
michael@0 1177 if (mUseExternalSurfaceSize) {
michael@0 1178 rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
michael@0 1179 } else {
michael@0 1180 mWidget->GetBounds(rect);
michael@0 1181 }
michael@0 1182 RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8);
michael@0 1183 CopyToTarget(target, mCurrentRenderTarget->GetTransform());
michael@0 1184
michael@0 1185 WriteSnapshotToDumpFile(this, target);
michael@0 1186 }
michael@0 1187 #endif
michael@0 1188
michael@0 1189 mFrameInProgress = false;
michael@0 1190
michael@0 1191 LayerScope::EndFrame(mGLContext);
michael@0 1192
michael@0 1193 if (mTarget) {
michael@0 1194 CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
michael@0 1195 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 1196 mCurrentRenderTarget = nullptr;
michael@0 1197 return;
michael@0 1198 }
michael@0 1199
michael@0 1200 mCurrentRenderTarget = nullptr;
michael@0 1201
michael@0 1202 if (mTexturePool) {
michael@0 1203 mTexturePool->EndFrame();
michael@0 1204 }
michael@0 1205
michael@0 1206 mGLContext->SwapBuffers();
michael@0 1207 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 1208
michael@0 1209 // Unbind all textures
michael@0 1210 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
michael@0 1211 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
michael@0 1212 if (!mGLContext->IsGLES()) {
michael@0 1213 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
michael@0 1214 }
michael@0 1215
michael@0 1216 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
michael@0 1217 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
michael@0 1218 if (!mGLContext->IsGLES()) {
michael@0 1219 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
michael@0 1220 }
michael@0 1221
michael@0 1222 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
michael@0 1223 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
michael@0 1224 if (!mGLContext->IsGLES()) {
michael@0 1225 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
michael@0 1226 }
michael@0 1227 }
michael@0 1228
michael@0 1229 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
michael@0 1230 void
michael@0 1231 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
michael@0 1232 {
michael@0 1233 // OpenGL does not provide ReleaseFence for rendering.
michael@0 1234 // Instead use FBAcquireFence as layer buffer's ReleaseFence
michael@0 1235 // to prevent flickering and tearing.
michael@0 1236 // FBAcquireFence is FramebufferSurface's AcquireFence.
michael@0 1237 // AcquireFence will be signaled when a buffer's content is available.
michael@0 1238 // See Bug 974152.
michael@0 1239
michael@0 1240 if (!aLayer) {
michael@0 1241 return;
michael@0 1242 }
michael@0 1243
michael@0 1244 const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
michael@0 1245 if (visibleRegion.IsEmpty()) {
michael@0 1246 return;
michael@0 1247 }
michael@0 1248
michael@0 1249 // Set FBAcquireFence on ContainerLayer's childs
michael@0 1250 ContainerLayer* container = aLayer->AsContainerLayer();
michael@0 1251 if (container) {
michael@0 1252 for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
michael@0 1253 SetFBAcquireFence(child);
michael@0 1254 }
michael@0 1255 return;
michael@0 1256 }
michael@0 1257
michael@0 1258 // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
michael@0 1259 TiledLayerComposer* composer = nullptr;
michael@0 1260 LayerComposite* shadow = aLayer->AsLayerComposite();
michael@0 1261 if (shadow) {
michael@0 1262 composer = shadow->GetTiledLayerComposer();
michael@0 1263 if (composer) {
michael@0 1264 composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
michael@0 1265 return;
michael@0 1266 }
michael@0 1267 }
michael@0 1268
michael@0 1269 // Set FBAcquireFence as layer buffer's ReleaseFence
michael@0 1270 LayerRenderState state = aLayer->GetRenderState();
michael@0 1271 if (!state.mTexture) {
michael@0 1272 return;
michael@0 1273 }
michael@0 1274 TextureHostOGL* texture = state.mTexture->AsHostOGL();
michael@0 1275 if (!texture) {
michael@0 1276 return;
michael@0 1277 }
michael@0 1278 texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
michael@0 1279 }
michael@0 1280 #else
michael@0 1281 void
michael@0 1282 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
michael@0 1283 {
michael@0 1284 }
michael@0 1285 #endif
michael@0 1286
michael@0 1287 void
michael@0 1288 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
michael@0 1289 {
michael@0 1290 // This lets us reftest and screenshot content rendered externally
michael@0 1291 if (mTarget) {
michael@0 1292 MakeCurrent();
michael@0 1293 CopyToTarget(mTarget, aTransform);
michael@0 1294 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 1295 }
michael@0 1296 if (mTexturePool) {
michael@0 1297 mTexturePool->EndFrame();
michael@0 1298 }
michael@0 1299 }
michael@0 1300
michael@0 1301 void
michael@0 1302 CompositorOGL::AbortFrame()
michael@0 1303 {
michael@0 1304 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
michael@0 1305 mFrameInProgress = false;
michael@0 1306 mCurrentRenderTarget = nullptr;
michael@0 1307
michael@0 1308 if (mTexturePool) {
michael@0 1309 mTexturePool->EndFrame();
michael@0 1310 }
michael@0 1311 }
michael@0 1312
michael@0 1313 void
michael@0 1314 CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
michael@0 1315 {
michael@0 1316 mSurfaceSize.width = aSize.width;
michael@0 1317 mSurfaceSize.height = aSize.height;
michael@0 1318 }
michael@0 1319
michael@0 1320 void
michael@0 1321 CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
michael@0 1322 {
michael@0 1323 IntRect rect;
michael@0 1324 if (mUseExternalSurfaceSize) {
michael@0 1325 rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
michael@0 1326 } else {
michael@0 1327 rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
michael@0 1328 }
michael@0 1329 GLint width = rect.width;
michael@0 1330 GLint height = rect.height;
michael@0 1331
michael@0 1332 if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
michael@0 1333 NS_ERROR("Widget size too big - integer overflow!");
michael@0 1334 return;
michael@0 1335 }
michael@0 1336
michael@0 1337 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
michael@0 1338
michael@0 1339 if (!mGLContext->IsGLES()) {
michael@0 1340 // GLES2 promises that binding to any custom FBO will attach
michael@0 1341 // to GL_COLOR_ATTACHMENT0 attachment point.
michael@0 1342 mGLContext->fReadBuffer(LOCAL_GL_BACK);
michael@0 1343 }
michael@0 1344
michael@0 1345 RefPtr<DataSourceSurface> source =
michael@0 1346 Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
michael@0 1347
michael@0 1348 DataSourceSurface::MappedSurface map;
michael@0 1349 source->Map(DataSourceSurface::MapType::WRITE, &map);
michael@0 1350 // XXX we should do this properly one day without using the gfxImageSurface
michael@0 1351 nsRefPtr<gfxImageSurface> surf =
michael@0 1352 new gfxImageSurface(map.mData,
michael@0 1353 gfxIntSize(width, height),
michael@0 1354 map.mStride,
michael@0 1355 gfxImageFormat::ARGB32);
michael@0 1356 ReadPixelsIntoImageSurface(mGLContext, surf);
michael@0 1357 source->Unmap();
michael@0 1358
michael@0 1359 // Map from GL space to Cairo space and reverse the world transform.
michael@0 1360 Matrix glToCairoTransform = aTransform;
michael@0 1361 glToCairoTransform.Invert();
michael@0 1362 glToCairoTransform.Scale(1.0, -1.0);
michael@0 1363 glToCairoTransform.Translate(0.0, -height);
michael@0 1364
michael@0 1365 Matrix oldMatrix = aTarget->GetTransform();
michael@0 1366 aTarget->SetTransform(glToCairoTransform);
michael@0 1367 Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
michael@0 1368 aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
michael@0 1369 aTarget->SetTransform(oldMatrix);
michael@0 1370 aTarget->Flush();
michael@0 1371 }
michael@0 1372
michael@0 1373 void
michael@0 1374 CompositorOGL::Pause()
michael@0 1375 {
michael@0 1376 #ifdef MOZ_WIDGET_ANDROID
michael@0 1377 if (!gl() || gl()->IsDestroyed())
michael@0 1378 return;
michael@0 1379
michael@0 1380 // ReleaseSurface internally calls MakeCurrent.
michael@0 1381 gl()->ReleaseSurface();
michael@0 1382 #endif
michael@0 1383 }
michael@0 1384
michael@0 1385 bool
michael@0 1386 CompositorOGL::Resume()
michael@0 1387 {
michael@0 1388 #ifdef MOZ_WIDGET_ANDROID
michael@0 1389 if (!gl() || gl()->IsDestroyed())
michael@0 1390 return false;
michael@0 1391
michael@0 1392 // RenewSurface internally calls MakeCurrent.
michael@0 1393 return gl()->RenewSurface();
michael@0 1394 #endif
michael@0 1395 return true;
michael@0 1396 }
michael@0 1397
michael@0 1398 TemporaryRef<DataTextureSource>
michael@0 1399 CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
michael@0 1400 {
michael@0 1401 RefPtr<DataTextureSource> result =
michael@0 1402 new TextureImageTextureSourceOGL(mGLContext, aFlags);
michael@0 1403 return result;
michael@0 1404 }
michael@0 1405
michael@0 1406 bool
michael@0 1407 CompositorOGL::SupportsPartialTextureUpdate()
michael@0 1408 {
michael@0 1409 return CanUploadSubTextures(mGLContext);
michael@0 1410 }
michael@0 1411
michael@0 1412 int32_t
michael@0 1413 CompositorOGL::GetMaxTextureSize() const
michael@0 1414 {
michael@0 1415 MOZ_ASSERT(mGLContext);
michael@0 1416 GLint texSize = 0;
michael@0 1417 mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
michael@0 1418 &texSize);
michael@0 1419 MOZ_ASSERT(texSize != 0);
michael@0 1420 return texSize;
michael@0 1421 }
michael@0 1422
michael@0 1423 void
michael@0 1424 CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
michael@0 1425 if (mDestroyed) {
michael@0 1426 NS_WARNING("Call on destroyed layer manager");
michael@0 1427 return;
michael@0 1428 }
michael@0 1429 mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
michael@0 1430 }
michael@0 1431
michael@0 1432 void
michael@0 1433 CompositorOGL::BindQuadVBO() {
michael@0 1434 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
michael@0 1435 }
michael@0 1436
michael@0 1437 void
michael@0 1438 CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
michael@0 1439 mGLContext->fVertexAttribPointer(aAttribIndex, 2,
michael@0 1440 LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
michael@0 1441 (GLvoid*) QuadVBOVertexOffset());
michael@0 1442 }
michael@0 1443
michael@0 1444 void
michael@0 1445 CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
michael@0 1446 mGLContext->fVertexAttribPointer(aAttribIndex, 2,
michael@0 1447 LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
michael@0 1448 (GLvoid*) QuadVBOTexCoordOffset());
michael@0 1449 }
michael@0 1450
michael@0 1451 void
michael@0 1452 CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
michael@0 1453 GLuint aTexCoordAttribIndex,
michael@0 1454 GLuint aDrawMode)
michael@0 1455 {
michael@0 1456 BindQuadVBO();
michael@0 1457 QuadVBOVerticesAttrib(aVertAttribIndex);
michael@0 1458
michael@0 1459 if (aTexCoordAttribIndex != GLuint(-1)) {
michael@0 1460 QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
michael@0 1461 mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
michael@0 1462 }
michael@0 1463
michael@0 1464 mGLContext->fEnableVertexAttribArray(aVertAttribIndex);
michael@0 1465 if (aDrawMode == LOCAL_GL_LINE_STRIP) {
michael@0 1466 mGLContext->fDrawArrays(aDrawMode, 1, 2);
michael@0 1467 } else {
michael@0 1468 mGLContext->fDrawArrays(aDrawMode, 0, 4);
michael@0 1469 }
michael@0 1470 }
michael@0 1471
michael@0 1472 void
michael@0 1473 CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
michael@0 1474 GLuint aDrawMode)
michael@0 1475 {
michael@0 1476 NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
michael@0 1477 BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
michael@0 1478 aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
michael@0 1479 aDrawMode);
michael@0 1480 }
michael@0 1481
michael@0 1482 GLuint
michael@0 1483 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
michael@0 1484 {
michael@0 1485 if (!mTexturePool) {
michael@0 1486 #ifdef MOZ_WIDGET_GONK
michael@0 1487 mTexturePool = new PerFrameTexturePoolOGL(gl());
michael@0 1488 #else
michael@0 1489 mTexturePool = new PerUnitTexturePoolOGL(gl());
michael@0 1490 #endif
michael@0 1491 }
michael@0 1492 return mTexturePool->GetTexture(aTarget, aUnit);
michael@0 1493 }
michael@0 1494
michael@0 1495 GLuint
michael@0 1496 PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
michael@0 1497 {
michael@0 1498 if (mTextureTarget == 0) {
michael@0 1499 mTextureTarget = aTarget;
michael@0 1500 }
michael@0 1501 MOZ_ASSERT(mTextureTarget == aTarget);
michael@0 1502
michael@0 1503 size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
michael@0 1504 // lazily grow the array of temporary textures
michael@0 1505 if (mTextures.Length() <= index) {
michael@0 1506 size_t prevLength = mTextures.Length();
michael@0 1507 mTextures.SetLength(index + 1);
michael@0 1508 for(unsigned int i = prevLength; i <= index; ++i) {
michael@0 1509 mTextures[i] = 0;
michael@0 1510 }
michael@0 1511 }
michael@0 1512 // lazily initialize the temporary textures
michael@0 1513 if (!mTextures[index]) {
michael@0 1514 if (!mGL->MakeCurrent()) {
michael@0 1515 return 0;
michael@0 1516 }
michael@0 1517 mGL->fGenTextures(1, &mTextures[index]);
michael@0 1518 mGL->fBindTexture(aTarget, mTextures[index]);
michael@0 1519 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 1520 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 1521 }
michael@0 1522 return mTextures[index];
michael@0 1523 }
michael@0 1524
michael@0 1525 void
michael@0 1526 PerUnitTexturePoolOGL::DestroyTextures()
michael@0 1527 {
michael@0 1528 if (mGL && mGL->MakeCurrent()) {
michael@0 1529 if (mTextures.Length() > 0) {
michael@0 1530 mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
michael@0 1531 }
michael@0 1532 }
michael@0 1533 mTextures.SetLength(0);
michael@0 1534 }
michael@0 1535
michael@0 1536 void
michael@0 1537 PerFrameTexturePoolOGL::DestroyTextures()
michael@0 1538 {
michael@0 1539 if (!mGL->MakeCurrent()) {
michael@0 1540 return;
michael@0 1541 }
michael@0 1542
michael@0 1543 if (mUnusedTextures.Length() > 0) {
michael@0 1544 mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
michael@0 1545 mUnusedTextures.Clear();
michael@0 1546 }
michael@0 1547
michael@0 1548 if (mCreatedTextures.Length() > 0) {
michael@0 1549 mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
michael@0 1550 mCreatedTextures.Clear();
michael@0 1551 }
michael@0 1552 }
michael@0 1553
michael@0 1554 GLuint
michael@0 1555 PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
michael@0 1556 {
michael@0 1557 if (mTextureTarget == 0) {
michael@0 1558 mTextureTarget = aTarget;
michael@0 1559 }
michael@0 1560
michael@0 1561 // The pool should always use the same texture target because it is illegal
michael@0 1562 // to change the target of an already exisiting gl texture.
michael@0 1563 // If we need to use several targets, a pool with several sub-pools (one per
michael@0 1564 // target) will have to be implemented.
michael@0 1565 // At the moment this pool is only used with tiling on b2g so we always need
michael@0 1566 // the same target.
michael@0 1567 MOZ_ASSERT(mTextureTarget == aTarget);
michael@0 1568
michael@0 1569 GLuint texture = 0;
michael@0 1570
michael@0 1571 if (!mUnusedTextures.IsEmpty()) {
michael@0 1572 // Try to reuse one from the unused pile first
michael@0 1573 texture = mUnusedTextures[0];
michael@0 1574 mUnusedTextures.RemoveElementAt(0);
michael@0 1575 } else if (mGL->MakeCurrent()) {
michael@0 1576 // There isn't one to reuse, create one.
michael@0 1577 mGL->fGenTextures(1, &texture);
michael@0 1578 mGL->fBindTexture(aTarget, texture);
michael@0 1579 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 1580 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 1581 }
michael@0 1582
michael@0 1583 if (texture) {
michael@0 1584 mCreatedTextures.AppendElement(texture);
michael@0 1585 }
michael@0 1586
michael@0 1587 return texture;
michael@0 1588 }
michael@0 1589
michael@0 1590 void
michael@0 1591 PerFrameTexturePoolOGL::EndFrame()
michael@0 1592 {
michael@0 1593 if (!mGL->MakeCurrent()) {
michael@0 1594 // this means the context got destroyed underneith us somehow, and the driver
michael@0 1595 // already has destroyed the textures.
michael@0 1596 mCreatedTextures.Clear();
michael@0 1597 mUnusedTextures.Clear();
michael@0 1598 return;
michael@0 1599 }
michael@0 1600
michael@0 1601 // Some platforms have issues unlocking Gralloc buffers even when they're
michael@0 1602 // rebound.
michael@0 1603 if (gfxPrefs::OverzealousGrallocUnlocking()) {
michael@0 1604 mUnusedTextures.AppendElements(mCreatedTextures);
michael@0 1605 mCreatedTextures.Clear();
michael@0 1606 }
michael@0 1607
michael@0 1608 // Delete unused textures
michael@0 1609 for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
michael@0 1610 GLuint texture = mUnusedTextures[i];
michael@0 1611 mGL->fDeleteTextures(1, &texture);
michael@0 1612 }
michael@0 1613 mUnusedTextures.Clear();
michael@0 1614
michael@0 1615 // Move all created textures into the unused pile
michael@0 1616 mUnusedTextures.AppendElements(mCreatedTextures);
michael@0 1617 mCreatedTextures.Clear();
michael@0 1618 }
michael@0 1619
michael@0 1620 } /* layers */
michael@0 1621 } /* mozilla */

mercurial