Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "CompositorOGL.h"
7 : #include <stddef.h> // for size_t
8 : #include <stdint.h> // for uint32_t, uint8_t
9 : #include <stdlib.h> // for free, malloc
10 : #include "GLContextProvider.h" // for GLContextProvider
11 : #include "GLContext.h" // for GLContext
12 : #include "GLUploadHelpers.h"
13 : #include "Layers.h" // for WriteSnapshotToDumpFile
14 : #include "LayerScope.h" // for LayerScope
15 : #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
16 : #include "gfxEnv.h" // for gfxEnv
17 : #include "gfxPlatform.h" // for gfxPlatform
18 : #include "gfxPrefs.h" // for gfxPrefs
19 : #include "gfxRect.h" // for gfxRect
20 : #include "gfxUtils.h" // for gfxUtils, etc
21 : #include "mozilla/ArrayUtils.h" // for ArrayLength
22 : #include "mozilla/Preferences.h" // for Preferences
23 : #include "mozilla/gfx/BasePoint.h" // for BasePoint
24 : #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
25 : #include "mozilla/gfx/Triangle.h" // for Triangle
26 : #include "mozilla/gfx/gfxVars.h" // for gfxVars
27 : #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
28 : #include "mozilla/layers/CompositingRenderTargetOGL.h"
29 : #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
30 : #include "mozilla/layers/TextureHost.h" // for TextureSource, etc
31 : #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
32 : #include "mozilla/mozalloc.h" // for operator delete, etc
33 : #include "nsAppRunner.h"
34 : #include "nsAString.h"
35 : #include "nsIConsoleService.h" // for nsIConsoleService, etc
36 : #include "nsIWidget.h" // for nsIWidget
37 : #include "nsLiteralString.h" // for NS_LITERAL_STRING
38 : #include "nsMathUtils.h" // for NS_roundf
39 : #include "nsRect.h" // for mozilla::gfx::IntRect
40 : #include "nsServiceManagerUtils.h" // for do_GetService
41 : #include "nsString.h" // for nsString, nsAutoCString, etc
42 : #include "ScopedGLHelpers.h"
43 : #include "GLReadTexImageHelper.h"
44 : #include "GLBlitTextureImageHelper.h"
45 : #include "HeapCopyOfStackArray.h"
46 :
47 : #if MOZ_WIDGET_ANDROID
48 : #include "TexturePoolOGL.h"
49 : #endif
50 :
51 : #include "GeckoProfiler.h"
52 :
53 : namespace mozilla {
54 :
55 : using namespace std;
56 : using namespace gfx;
57 :
58 : namespace layers {
59 :
60 : using namespace mozilla::gl;
61 :
62 : static const GLuint kCoordinateAttributeIndex = 0;
63 : static const GLuint kTexCoordinateAttributeIndex = 1;
64 :
65 : static void
66 0 : BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
67 : GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
68 : {
69 0 : MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
70 0 : aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR);
71 0 : aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
72 0 : aProgram->SetMaskLayerTransform(aTransform);
73 0 : }
74 :
75 : void
76 0 : CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit)
77 : {
78 0 : MOZ_ASSERT(aBackdrop);
79 :
80 0 : mGLContext->fActiveTexture(aTexUnit);
81 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop);
82 0 : mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
83 0 : mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
84 0 : aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
85 0 : }
86 :
87 0 : CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
88 : widget::CompositorWidget* aWidget,
89 : int aSurfaceWidth, int aSurfaceHeight,
90 0 : bool aUseExternalSurfaceSize)
91 : : Compositor(aWidget, aParent)
92 : , mWidgetSize(-1, -1)
93 : , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
94 : , mHasBGRA(0)
95 : , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
96 : , mFrameInProgress(false)
97 : , mDestroyed(false)
98 : , mViewportSize(0, 0)
99 0 : , mCurrentProgram(nullptr)
100 : {
101 0 : MOZ_COUNT_CTOR(CompositorOGL);
102 0 : }
103 :
104 0 : CompositorOGL::~CompositorOGL()
105 : {
106 0 : MOZ_COUNT_DTOR(CompositorOGL);
107 0 : Destroy();
108 0 : }
109 :
110 : already_AddRefed<mozilla::gl::GLContext>
111 0 : CompositorOGL::CreateContext()
112 : {
113 0 : RefPtr<GLContext> context;
114 :
115 : // Used by mock widget to create an offscreen context
116 0 : nsIWidget* widget = mWidget->RealWidget();
117 0 : void* widgetOpenGLContext = widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr;
118 0 : if (widgetOpenGLContext) {
119 0 : GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
120 0 : return already_AddRefed<GLContext>(alreadyRefed);
121 : }
122 :
123 : #ifdef XP_WIN
124 : if (gfxEnv::LayersPreferEGL()) {
125 : printf_stderr("Trying GL layers...\n");
126 : context = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, false);
127 : }
128 : #endif
129 :
130 : // Allow to create offscreen GL context for main Layer Manager
131 0 : if (!context && gfxEnv::LayersPreferOffscreen()) {
132 0 : SurfaceCaps caps = SurfaceCaps::ForRGB();
133 0 : caps.preserve = false;
134 0 : caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
135 :
136 0 : nsCString discardFailureId;
137 0 : context = GLContextProvider::CreateOffscreen(mSurfaceSize,
138 : caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
139 0 : &discardFailureId);
140 : }
141 :
142 0 : if (!context) {
143 0 : context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
144 0 : gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
145 : }
146 :
147 0 : if (!context) {
148 0 : NS_WARNING("Failed to create CompositorOGL context");
149 : }
150 :
151 0 : return context.forget();
152 : }
153 :
154 : void
155 0 : CompositorOGL::Destroy()
156 : {
157 0 : Compositor::Destroy();
158 :
159 0 : if (mTexturePool) {
160 0 : mTexturePool->Clear();
161 0 : mTexturePool = nullptr;
162 : }
163 :
164 0 : if (!mDestroyed) {
165 0 : mDestroyed = true;
166 0 : CleanupResources();
167 : }
168 0 : }
169 :
170 : void
171 0 : CompositorOGL::CleanupResources()
172 : {
173 0 : if (!mGLContext)
174 0 : return;
175 :
176 0 : RefPtr<GLContext> ctx = mGLContext->GetSharedContext();
177 0 : if (!ctx) {
178 0 : ctx = mGLContext;
179 : }
180 :
181 0 : if (!ctx->MakeCurrent()) {
182 : // Leak resources!
183 0 : mQuadVBO = 0;
184 0 : mTriangleVBO = 0;
185 0 : mGLContext = nullptr;
186 0 : mPrograms.clear();
187 0 : return;
188 : }
189 :
190 0 : for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
191 0 : iter != mPrograms.end();
192 : iter++) {
193 0 : delete iter->second;
194 : }
195 0 : mPrograms.clear();
196 :
197 0 : ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
198 :
199 0 : if (mQuadVBO) {
200 0 : ctx->fDeleteBuffers(1, &mQuadVBO);
201 0 : mQuadVBO = 0;
202 : }
203 :
204 0 : if (mTriangleVBO) {
205 0 : ctx->fDeleteBuffers(1, &mTriangleVBO);
206 0 : mTriangleVBO = 0;
207 : }
208 :
209 0 : mGLContext->MakeCurrent();
210 :
211 0 : mBlitTextureImageHelper = nullptr;
212 :
213 0 : mContextStateTracker.DestroyOGL(mGLContext);
214 :
215 : // On the main thread the Widget will be destroyed soon and calling MakeCurrent
216 : // after that could cause a crash (at least with GLX, see bug 1059793), unless
217 : // context is marked as destroyed.
218 : // There may be some textures still alive that will try to call MakeCurrent on
219 : // the context so let's make sure it is marked destroyed now.
220 0 : mGLContext->MarkDestroyed();
221 :
222 0 : mGLContext = nullptr;
223 : }
224 :
225 : bool
226 0 : CompositorOGL::Initialize(nsCString* const out_failureReason)
227 : {
228 0 : ScopedGfxFeatureReporter reporter("GL Layers");
229 :
230 : // Do not allow double initialization
231 0 : MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
232 :
233 0 : mGLContext = CreateContext();
234 :
235 : #ifdef MOZ_WIDGET_ANDROID
236 : if (!mGLContext){
237 : *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT";
238 : MOZ_CRASH("We need a context on Android");
239 : }
240 : #endif
241 :
242 0 : if (!mGLContext){
243 0 : *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT";
244 0 : return false;
245 : }
246 :
247 0 : MakeCurrent();
248 :
249 0 : mHasBGRA =
250 0 : mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
251 0 : mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
252 :
253 0 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
254 0 : LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
255 0 : mGLContext->fEnable(LOCAL_GL_BLEND);
256 :
257 : // initialise a common shader to check that we can actually compile a shader
258 0 : RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
259 0 : ShaderConfigOGL config = GetShaderConfigFor(effect);
260 0 : if (!GetShaderProgramFor(config)) {
261 0 : *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER";
262 0 : return false;
263 : }
264 :
265 0 : if (mGLContext->WorkAroundDriverBugs()) {
266 : /**
267 : * We'll test the ability here to bind NPOT textures to a framebuffer, if
268 : * this fails we'll try ARB_texture_rectangle.
269 : */
270 :
271 : GLenum textureTargets[] = {
272 : LOCAL_GL_TEXTURE_2D,
273 : LOCAL_GL_NONE
274 0 : };
275 :
276 0 : if (!mGLContext->IsGLES()) {
277 : // No TEXTURE_RECTANGLE_ARB available on ES2
278 0 : textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
279 : }
280 :
281 0 : mFBOTextureTarget = LOCAL_GL_NONE;
282 :
283 0 : GLuint testFBO = 0;
284 0 : mGLContext->fGenFramebuffers(1, &testFBO);
285 0 : GLuint testTexture = 0;
286 :
287 0 : for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
288 0 : GLenum target = textureTargets[i];
289 0 : if (!target)
290 0 : continue;
291 :
292 0 : mGLContext->fGenTextures(1, &testTexture);
293 0 : mGLContext->fBindTexture(target, testTexture);
294 0 : mGLContext->fTexParameteri(target,
295 : LOCAL_GL_TEXTURE_MIN_FILTER,
296 0 : LOCAL_GL_NEAREST);
297 0 : mGLContext->fTexParameteri(target,
298 : LOCAL_GL_TEXTURE_MAG_FILTER,
299 0 : LOCAL_GL_NEAREST);
300 0 : mGLContext->fTexImage2D(target,
301 : 0,
302 : LOCAL_GL_RGBA,
303 : 5, 3, /* sufficiently NPOT */
304 : 0,
305 : LOCAL_GL_RGBA,
306 : LOCAL_GL_UNSIGNED_BYTE,
307 0 : nullptr);
308 :
309 : // unbind this texture, in preparation for binding it to the FBO
310 0 : mGLContext->fBindTexture(target, 0);
311 :
312 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
313 0 : mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
314 : LOCAL_GL_COLOR_ATTACHMENT0,
315 : target,
316 : testTexture,
317 0 : 0);
318 :
319 0 : if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
320 : LOCAL_GL_FRAMEBUFFER_COMPLETE)
321 : {
322 0 : mFBOTextureTarget = target;
323 0 : mGLContext->fDeleteTextures(1, &testTexture);
324 0 : break;
325 : }
326 :
327 0 : mGLContext->fDeleteTextures(1, &testTexture);
328 : }
329 :
330 0 : if (testFBO) {
331 0 : mGLContext->fDeleteFramebuffers(1, &testFBO);
332 : }
333 :
334 0 : if (mFBOTextureTarget == LOCAL_GL_NONE) {
335 : /* Unable to find a texture target that works with FBOs and NPOT textures */
336 0 : *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET";
337 0 : return false;
338 : }
339 : } else {
340 : // not trying to work around driver bugs, so TEXTURE_2D should just work
341 0 : mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
342 : }
343 :
344 : // back to default framebuffer, to avoid confusion
345 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
346 :
347 0 : if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
348 : /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
349 : * extension -- the EXT variant does not provide support for
350 : * texture rectangle access inside GLSL (sampler2DRect,
351 : * texture2DRect).
352 : */
353 0 : if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
354 0 : *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
355 0 : return false;
356 : }
357 : }
358 :
359 : // Create a VBO for triangle vertices.
360 0 : mGLContext->fGenBuffers(1, &mTriangleVBO);
361 :
362 : /* Create a simple quad VBO */
363 0 : mGLContext->fGenBuffers(1, &mQuadVBO);
364 :
365 : // 4 quads, with the number of the quad (vertexID) encoded in w.
366 : GLfloat vertices[] = {
367 : 0.0f, 0.0f, 0.0f, 0.0f,
368 : 1.0f, 0.0f, 0.0f, 0.0f,
369 : 0.0f, 1.0f, 0.0f, 0.0f,
370 : 1.0f, 0.0f, 0.0f, 0.0f,
371 : 0.0f, 1.0f, 0.0f, 0.0f,
372 : 1.0f, 1.0f, 0.0f, 0.0f,
373 :
374 : 0.0f, 0.0f, 0.0f, 1.0f,
375 : 1.0f, 0.0f, 0.0f, 1.0f,
376 : 0.0f, 1.0f, 0.0f, 1.0f,
377 : 1.0f, 0.0f, 0.0f, 1.0f,
378 : 0.0f, 1.0f, 0.0f, 1.0f,
379 : 1.0f, 1.0f, 0.0f, 1.0f,
380 :
381 : 0.0f, 0.0f, 0.0f, 2.0f,
382 : 1.0f, 0.0f, 0.0f, 2.0f,
383 : 0.0f, 1.0f, 0.0f, 2.0f,
384 : 1.0f, 0.0f, 0.0f, 2.0f,
385 : 0.0f, 1.0f, 0.0f, 2.0f,
386 : 1.0f, 1.0f, 0.0f, 2.0f,
387 :
388 : 0.0f, 0.0f, 0.0f, 3.0f,
389 : 1.0f, 0.0f, 0.0f, 3.0f,
390 : 0.0f, 1.0f, 0.0f, 3.0f,
391 : 1.0f, 0.0f, 0.0f, 3.0f,
392 : 0.0f, 1.0f, 0.0f, 3.0f,
393 : 1.0f, 1.0f, 0.0f, 3.0f,
394 0 : };
395 0 : HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
396 :
397 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
398 0 : mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
399 0 : verticesOnHeap.ByteLength(),
400 0 : verticesOnHeap.Data(),
401 0 : LOCAL_GL_STATIC_DRAW);
402 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
403 :
404 : nsCOMPtr<nsIConsoleService>
405 0 : console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
406 :
407 0 : if (console) {
408 0 : nsString msg;
409 : msg +=
410 0 : NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
411 0 : msg += NS_ConvertUTF8toUTF16(
412 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
413 0 : msg += NS_LITERAL_STRING("\nVendor: ");
414 0 : msg += NS_ConvertUTF8toUTF16(
415 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
416 0 : msg += NS_LITERAL_STRING("\nRenderer: ");
417 0 : msg += NS_ConvertUTF8toUTF16(
418 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
419 0 : msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
420 0 : if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
421 0 : msg += NS_LITERAL_STRING("TEXTURE_2D");
422 : else
423 0 : msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
424 0 : console->LogStringMessage(msg.get());
425 : }
426 :
427 0 : reporter.SetSuccessful();
428 :
429 0 : return true;
430 : }
431 :
432 : /*
433 : * Returns a size that is equal to, or larger than and closest to,
434 : * aSize where both width and height are powers of two.
435 : * If the OpenGL setup is capable of using non-POT textures,
436 : * then it will just return aSize.
437 : */
438 : static IntSize
439 0 : CalculatePOTSize(const IntSize& aSize, GLContext* gl)
440 : {
441 0 : if (CanUploadNonPowerOfTwo(gl))
442 0 : return aSize;
443 :
444 0 : return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height));
445 : }
446 :
447 : gfx::Rect
448 0 : CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, TextureSource* aTexture)
449 : {
450 : // If the OpenGL setup does not support non-power-of-two textures then the
451 : // texture's width and height will have been increased to the next
452 : // power-of-two (unless already a power of two). In that case we must scale
453 : // the texture coordinates to account for that.
454 0 : if (!CanUploadNonPowerOfTwo(mGLContext)) {
455 0 : const IntSize& textureSize = aTexture->GetSize();
456 0 : const IntSize potSize = CalculatePOTSize(textureSize, mGLContext);
457 0 : if (potSize != textureSize) {
458 0 : const float xScale = (float)textureSize.width / (float)potSize.width;
459 0 : const float yScale = (float)textureSize.height / (float)potSize.height;
460 0 : textureRect.Scale(xScale, yScale);
461 : }
462 : }
463 :
464 0 : return textureRect;
465 : }
466 :
467 : void
468 0 : CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
469 : {
470 0 : MOZ_ASSERT(aRenderTarget);
471 : // Logical surface size.
472 0 : const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
473 : // Physical surface size.
474 0 : const gfx::IntSize& phySize = aRenderTarget->mInitParams.mPhySize;
475 :
476 : // Set the viewport correctly.
477 0 : mGLContext->fViewport(0, 0, phySize.width, phySize.height);
478 :
479 0 : mViewportSize = size;
480 :
481 0 : if (!aRenderTarget->HasComplexProjection()) {
482 : // We flip the view matrix around so that everything is right-side up; we're
483 : // drawing directly into the window's back buffer, so this keeps things
484 : // looking correct.
485 : // XXX: We keep track of whether the window size changed, so we could skip
486 : // this update if it hadn't changed since the last call.
487 :
488 : // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
489 : // 2, 2) and flip the contents.
490 0 : Matrix viewMatrix;
491 0 : if (mGLContext->IsOffscreen() && !gIsGtest) {
492 : // In case of rendering via GL Offscreen context, disable Y-Flipping
493 0 : viewMatrix.PreTranslate(-1.0, -1.0);
494 0 : viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
495 : } else {
496 0 : viewMatrix.PreTranslate(-1.0, 1.0);
497 0 : viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
498 0 : viewMatrix.PreScale(1.0f, -1.0f);
499 : }
500 :
501 0 : MOZ_ASSERT(mCurrentRenderTarget, "No destination");
502 : // If we're drawing directly to the window then we want to offset
503 : // drawing by the render offset.
504 0 : if (!mTarget && mCurrentRenderTarget->IsWindow()) {
505 0 : viewMatrix.PreTranslate(mRenderOffset.x, mRenderOffset.y);
506 : }
507 :
508 0 : Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
509 0 : matrix3d._33 = 0.0f;
510 0 : mProjMatrix = matrix3d;
511 0 : mGLContext->fDepthRange(0.0f, 1.0f);
512 : } else {
513 : // XXX take into account mRenderOffset
514 : bool depthEnable;
515 : float zNear, zFar;
516 0 : aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar);
517 0 : mGLContext->fDepthRange(zNear, zFar);
518 : }
519 0 : }
520 :
521 : already_AddRefed<CompositingRenderTarget>
522 0 : CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
523 : {
524 0 : MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
525 :
526 0 : if (aRect.width * aRect.height == 0) {
527 0 : return nullptr;
528 : }
529 :
530 0 : if (!gl()) {
531 : // CompositingRenderTargetOGL does not work without a gl context.
532 0 : return nullptr;
533 : }
534 :
535 0 : GLuint tex = 0;
536 0 : GLuint fbo = 0;
537 0 : IntRect rect = aRect;
538 0 : IntSize FBOSize;
539 0 : CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &FBOSize);
540 : RefPtr<CompositingRenderTargetOGL> surface
541 0 : = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
542 0 : surface->Initialize(aRect.Size(), FBOSize, mFBOTextureTarget, aInit);
543 0 : return surface.forget();
544 : }
545 :
546 : already_AddRefed<CompositingRenderTarget>
547 0 : CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
548 : const CompositingRenderTarget *aSource,
549 : const IntPoint &aSourcePoint)
550 : {
551 0 : MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
552 :
553 0 : if (aRect.width * aRect.height == 0) {
554 0 : return nullptr;
555 : }
556 :
557 0 : if (!gl()) {
558 0 : return nullptr;
559 : }
560 :
561 0 : GLuint tex = 0;
562 0 : GLuint fbo = 0;
563 : const CompositingRenderTargetOGL* sourceSurface
564 0 : = static_cast<const CompositingRenderTargetOGL*>(aSource);
565 0 : IntRect sourceRect(aSourcePoint, aRect.Size());
566 0 : if (aSource) {
567 0 : CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
568 0 : &fbo, &tex);
569 : } else {
570 : CreateFBOWithTexture(sourceRect, true, 0,
571 0 : &fbo, &tex);
572 : }
573 :
574 : RefPtr<CompositingRenderTargetOGL> surface
575 0 : = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
576 0 : surface->Initialize(aRect.Size(),
577 0 : sourceRect.Size(),
578 : mFBOTextureTarget,
579 0 : INIT_MODE_NONE);
580 0 : return surface.forget();
581 : }
582 :
583 : void
584 0 : CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
585 : {
586 0 : MOZ_ASSERT(aSurface);
587 : CompositingRenderTargetOGL* surface
588 0 : = static_cast<CompositingRenderTargetOGL*>(aSurface);
589 0 : if (mCurrentRenderTarget != surface) {
590 0 : mCurrentRenderTarget = surface;
591 0 : if (mCurrentRenderTarget) {
592 0 : mContextStateTracker.PopOGLSection(gl(), "Frame");
593 : }
594 0 : mContextStateTracker.PushOGLSection(gl(), "Frame");
595 0 : surface->BindRenderTarget();
596 : }
597 :
598 0 : PrepareViewport(mCurrentRenderTarget);
599 0 : }
600 :
601 : CompositingRenderTarget*
602 0 : CompositorOGL::GetCurrentRenderTarget() const
603 : {
604 0 : return mCurrentRenderTarget;
605 : }
606 :
607 : static GLenum
608 0 : GetFrameBufferInternalFormat(GLContext* gl,
609 : GLuint aFrameBuffer,
610 : mozilla::widget::CompositorWidget* aWidget)
611 : {
612 0 : if (aFrameBuffer == 0) { // default framebuffer
613 0 : return aWidget->GetGLFrameBufferFormat();
614 : }
615 0 : return LOCAL_GL_RGBA;
616 : }
617 :
618 : void
619 0 : CompositorOGL::ClearRect(const gfx::Rect& aRect)
620 : {
621 : // Map aRect to OGL coordinates, origin:bottom-left
622 0 : GLint y = mViewportSize.height - (aRect.y + aRect.height);
623 :
624 0 : ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
625 0 : ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
626 0 : mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
627 0 : mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
628 0 : }
629 :
630 : void
631 0 : CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
632 : const IntRect *aClipRectIn,
633 : const IntRect& aRenderBounds,
634 : const nsIntRegion& aOpaqueRegion,
635 : IntRect *aClipRectOut,
636 : IntRect *aRenderBoundsOut)
637 : {
638 0 : AUTO_PROFILER_LABEL("CompositorOGL::BeginFrame", GRAPHICS);
639 :
640 0 : MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
641 :
642 0 : gfx::IntRect rect;
643 0 : if (mUseExternalSurfaceSize) {
644 0 : rect = gfx::IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
645 : } else {
646 0 : rect = gfx::IntRect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
647 : }
648 :
649 0 : if (aRenderBoundsOut) {
650 0 : *aRenderBoundsOut = rect;
651 : }
652 :
653 0 : GLint width = rect.width;
654 0 : GLint height = rect.height;
655 :
656 : // We can't draw anything to something with no area
657 : // so just return
658 0 : if (width == 0 || height == 0)
659 0 : return;
660 :
661 : // We're about to actually draw a frame.
662 0 : mFrameInProgress = true;
663 :
664 : // If the widget size changed, we have to force a MakeCurrent
665 : // to make sure that GL sees the updated widget size.
666 0 : if (mWidgetSize.width != width ||
667 0 : mWidgetSize.height != height)
668 : {
669 0 : MakeCurrent(ForceMakeCurrent);
670 :
671 0 : mWidgetSize.width = width;
672 0 : mWidgetSize.height = height;
673 : } else {
674 0 : MakeCurrent();
675 : }
676 :
677 0 : mPixelsPerFrame = width * height;
678 0 : mPixelsFilled = 0;
679 :
680 : #ifdef MOZ_WIDGET_ANDROID
681 : TexturePoolOGL::Fill(gl());
682 : #endif
683 :
684 : // Default blend function implements "OVER"
685 0 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
686 0 : LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
687 0 : mGLContext->fEnable(LOCAL_GL_BLEND);
688 :
689 : RefPtr<CompositingRenderTargetOGL> rt =
690 0 : CompositingRenderTargetOGL::RenderTargetForWindow(this,
691 0 : IntSize(width, height));
692 0 : SetRenderTarget(rt);
693 :
694 : #ifdef DEBUG
695 0 : mWindowRenderTarget = mCurrentRenderTarget;
696 : #endif
697 :
698 0 : if (aClipRectOut && !aClipRectIn) {
699 0 : aClipRectOut->SetRect(0, 0, width, height);
700 : }
701 :
702 0 : mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a);
703 0 : mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
704 : }
705 :
706 : void
707 0 : CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect,
708 : bool aCopyFromSource,
709 : GLuint aSourceFrameBuffer,
710 : GLuint *aFBO, GLuint *aTexture,
711 : gfx::IntSize* aAllocSize)
712 : {
713 0 : *aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer,
714 : aAllocSize);
715 0 : mGLContext->fGenFramebuffers(1, aFBO);
716 0 : }
717 :
718 : GLuint
719 0 : CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource,
720 : GLuint aSourceFrameBuffer, IntSize* aAllocSize)
721 : {
722 : // we're about to create a framebuffer backed by textures to use as an intermediate
723 : // surface. What to do if its size (as given by aRect) would exceed the
724 : // maximum texture size supported by the GL? The present code chooses the compromise
725 : // of just clamping the framebuffer's size to the max supported size.
726 : // This gives us a lower resolution rendering of the intermediate surface (children layers).
727 : // See bug 827170 for a discussion.
728 0 : IntRect clampedRect = aRect;
729 0 : int32_t maxTexSize = GetMaxTextureSize();
730 0 : clampedRect.width = std::min(clampedRect.width, maxTexSize);
731 0 : clampedRect.height = std::min(clampedRect.height, maxTexSize);
732 :
733 : GLuint tex;
734 :
735 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
736 0 : mGLContext->fGenTextures(1, &tex);
737 0 : mGLContext->fBindTexture(mFBOTextureTarget, tex);
738 :
739 0 : if (aCopyFromSource) {
740 0 : GLuint curFBO = mCurrentRenderTarget->GetFBO();
741 0 : if (curFBO != aSourceFrameBuffer) {
742 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
743 : }
744 :
745 : // We're going to create an RGBA temporary fbo. But to
746 : // CopyTexImage() from the current framebuffer, the framebuffer's
747 : // format has to be compatible with the new texture's. So we
748 : // check the format of the framebuffer here and take a slow path
749 : // if it's incompatible.
750 : GLenum format =
751 0 : GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
752 :
753 : bool isFormatCompatibleWithRGBA
754 0 : = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
755 0 : : true;
756 :
757 0 : if (isFormatCompatibleWithRGBA) {
758 0 : mGLContext->fCopyTexImage2D(mFBOTextureTarget,
759 : 0,
760 : LOCAL_GL_RGBA,
761 0 : clampedRect.x, FlipY(clampedRect.y + clampedRect.height),
762 : clampedRect.width, clampedRect.height,
763 0 : 0);
764 : } else {
765 : // Curses, incompatible formats. Take a slow path.
766 :
767 : // RGBA
768 0 : size_t bufferSize = clampedRect.width * clampedRect.height * 4;
769 0 : auto buf = MakeUnique<uint8_t[]>(bufferSize);
770 :
771 0 : mGLContext->fReadPixels(clampedRect.x, clampedRect.y,
772 : clampedRect.width, clampedRect.height,
773 : LOCAL_GL_RGBA,
774 : LOCAL_GL_UNSIGNED_BYTE,
775 0 : buf.get());
776 0 : mGLContext->fTexImage2D(mFBOTextureTarget,
777 : 0,
778 : LOCAL_GL_RGBA,
779 : clampedRect.width, clampedRect.height,
780 : 0,
781 : LOCAL_GL_RGBA,
782 : LOCAL_GL_UNSIGNED_BYTE,
783 0 : buf.get());
784 : }
785 :
786 0 : GLenum error = mGLContext->fGetError();
787 0 : if (error != LOCAL_GL_NO_ERROR) {
788 0 : nsAutoCString msg;
789 0 : msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d",
790 0 : error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
791 0 : NS_ERROR(msg.get());
792 : }
793 : } else {
794 0 : mGLContext->fTexImage2D(mFBOTextureTarget,
795 : 0,
796 : LOCAL_GL_RGBA,
797 : clampedRect.width, clampedRect.height,
798 : 0,
799 : LOCAL_GL_RGBA,
800 : LOCAL_GL_UNSIGNED_BYTE,
801 0 : nullptr);
802 : }
803 0 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
804 0 : LOCAL_GL_LINEAR);
805 0 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
806 0 : LOCAL_GL_LINEAR);
807 0 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
808 0 : LOCAL_GL_CLAMP_TO_EDGE);
809 0 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
810 0 : LOCAL_GL_CLAMP_TO_EDGE);
811 0 : mGLContext->fBindTexture(mFBOTextureTarget, 0);
812 :
813 0 : if (aAllocSize) {
814 0 : aAllocSize->width = clampedRect.width;
815 0 : aAllocSize->height = clampedRect.height;
816 : }
817 :
818 0 : return tex;
819 : }
820 :
821 : ShaderConfigOGL
822 0 : CompositorOGL::GetShaderConfigFor(Effect *aEffect,
823 : MaskType aMask,
824 : gfx::CompositionOp aOp,
825 : bool aColorMatrix,
826 : bool aDEAAEnabled) const
827 : {
828 0 : ShaderConfigOGL config;
829 :
830 0 : switch(aEffect->mType) {
831 : case EffectTypes::SOLID_COLOR:
832 0 : config.SetRenderColor(true);
833 0 : break;
834 : case EffectTypes::YCBCR:
835 0 : config.SetYCbCr(true);
836 0 : break;
837 : case EffectTypes::NV12:
838 0 : config.SetNV12(true);
839 0 : config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
840 0 : break;
841 : case EffectTypes::COMPONENT_ALPHA:
842 : {
843 0 : config.SetComponentAlpha(true);
844 : EffectComponentAlpha* effectComponentAlpha =
845 0 : static_cast<EffectComponentAlpha*>(aEffect);
846 0 : gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
847 0 : config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
848 0 : format == gfx::SurfaceFormat::B8G8R8X8);
849 0 : TextureSourceOGL* source = effectComponentAlpha->mOnWhite->AsSourceOGL();
850 0 : config.SetTextureTarget(source->GetTextureTarget());
851 0 : break;
852 : }
853 : case EffectTypes::RENDER_TARGET:
854 0 : config.SetTextureTarget(mFBOTextureTarget);
855 0 : break;
856 : default:
857 : {
858 0 : MOZ_ASSERT(aEffect->mType == EffectTypes::RGB);
859 : TexturedEffect* texturedEffect =
860 0 : static_cast<TexturedEffect*>(aEffect);
861 0 : TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
862 0 : MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
863 : source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
864 : source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8);
865 0 : MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
866 : source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
867 : source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
868 : source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 ||
869 : source->GetFormat() == gfx::SurfaceFormat::YUV422 );
870 0 : config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
871 0 : source->GetFormat());
872 0 : if (!texturedEffect->mPremultiplied) {
873 0 : config.SetNoPremultipliedAlpha();
874 : }
875 0 : break;
876 : }
877 : }
878 0 : config.SetColorMatrix(aColorMatrix);
879 0 : config.SetMask(aMask == MaskType::Mask);
880 0 : config.SetDEAA(aDEAAEnabled);
881 0 : config.SetCompositionOp(aOp);
882 0 : return config;
883 : }
884 :
885 : ShaderProgramOGL*
886 0 : CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
887 : {
888 0 : std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
889 0 : if (iter != mPrograms.end())
890 0 : return iter->second;
891 :
892 0 : ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
893 0 : ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
894 0 : if (!shader->Initialize()) {
895 0 : delete shader;
896 0 : return nullptr;
897 : }
898 :
899 0 : mPrograms[aConfig] = shader;
900 0 : return shader;
901 : }
902 :
903 : void
904 0 : CompositorOGL::ActivateProgram(ShaderProgramOGL* aProg)
905 : {
906 0 : if (mCurrentProgram != aProg) {
907 0 : gl()->fUseProgram(aProg->GetProgram());
908 0 : mCurrentProgram = aProg;
909 : }
910 0 : }
911 :
912 : void
913 0 : CompositorOGL::ResetProgram()
914 : {
915 0 : mCurrentProgram = nullptr;
916 0 : }
917 :
918 0 : static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
919 : {
920 0 : if (BlendOpIsMixBlendMode(aBlendMode)) {
921 : // Mix-blend modes require an extra step (or more) that cannot be expressed
922 : // in the fixed-function blending capabilities of opengl. We handle them
923 : // separately in shaders, and the shaders assume we will use our default
924 : // blend function for compositing (premultiplied OP_OVER).
925 0 : return false;
926 : }
927 0 : if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
928 0 : return false;
929 : }
930 :
931 : GLenum srcBlend;
932 : GLenum dstBlend;
933 0 : GLenum srcAlphaBlend = LOCAL_GL_ONE;
934 0 : GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
935 :
936 0 : switch (aBlendMode) {
937 : case gfx::CompositionOp::OP_OVER:
938 0 : MOZ_ASSERT(!aIsPremultiplied);
939 0 : srcBlend = LOCAL_GL_SRC_ALPHA;
940 0 : dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
941 0 : break;
942 : case gfx::CompositionOp::OP_SOURCE:
943 0 : srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA;
944 0 : dstBlend = LOCAL_GL_ZERO;
945 0 : srcAlphaBlend = LOCAL_GL_ONE;
946 0 : dstAlphaBlend = LOCAL_GL_ZERO;
947 0 : break;
948 : default:
949 0 : MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!");
950 : return false;
951 : }
952 :
953 : aGL->fBlendFuncSeparate(srcBlend, dstBlend,
954 0 : srcAlphaBlend, dstAlphaBlend);
955 0 : return true;
956 : }
957 :
958 : gfx::Point3D
959 0 : CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
960 : const gfx::Point& aPoint2)
961 : {
962 : // Return standard coefficients for a line between aPoint1 and aPoint2
963 : // for standard line equation:
964 : //
965 : // Ax + By + C = 0
966 : //
967 : // A = (p1.y – p2.y)
968 : // B = (p2.x – p1.x)
969 : // C = (p1.x * p2.y) – (p2.x * p1.y)
970 :
971 0 : gfx::Point3D coeffecients;
972 0 : coeffecients.x = aPoint1.y - aPoint2.y;
973 0 : coeffecients.y = aPoint2.x - aPoint1.x;
974 0 : coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
975 :
976 0 : coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
977 0 : coeffecients.y * coeffecients.y);
978 :
979 : // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
980 : // wide and included within the interior of the polygon
981 0 : coeffecients.z += 0.5f;
982 :
983 0 : return coeffecients;
984 : }
985 :
986 : void
987 0 : CompositorOGL::DrawQuad(const Rect& aRect,
988 : const IntRect& aClipRect,
989 : const EffectChain &aEffectChain,
990 : Float aOpacity,
991 : const gfx::Matrix4x4& aTransform,
992 : const gfx::Rect& aVisibleRect)
993 : {
994 0 : AUTO_PROFILER_LABEL("CompositorOGL::DrawQuad", GRAPHICS);
995 :
996 : DrawGeometry(aRect, aRect, aClipRect, aEffectChain,
997 0 : aOpacity, aTransform, aVisibleRect);
998 0 : }
999 :
1000 : void
1001 0 : CompositorOGL::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
1002 : const gfx::Rect& aRect,
1003 : const gfx::IntRect& aClipRect,
1004 : const EffectChain& aEffectChain,
1005 : gfx::Float aOpacity,
1006 : const gfx::Matrix4x4& aTransform,
1007 : const gfx::Rect& aVisibleRect)
1008 : {
1009 0 : AUTO_PROFILER_LABEL("CompositorOGL::DrawTriangles", GRAPHICS);
1010 :
1011 : DrawGeometry(aTriangles, aRect, aClipRect, aEffectChain,
1012 0 : aOpacity, aTransform, aVisibleRect);
1013 0 : }
1014 :
1015 : template<typename Geometry>
1016 : void
1017 0 : CompositorOGL::DrawGeometry(const Geometry& aGeometry,
1018 : const gfx::Rect& aRect,
1019 : const gfx::IntRect& aClipRect,
1020 : const EffectChain& aEffectChain,
1021 : gfx::Float aOpacity,
1022 : const gfx::Matrix4x4& aTransform,
1023 : const gfx::Rect& aVisibleRect)
1024 : {
1025 0 : MOZ_ASSERT(mFrameInProgress, "frame not started");
1026 0 : MOZ_ASSERT(mCurrentRenderTarget, "No destination");
1027 :
1028 0 : MakeCurrent();
1029 :
1030 0 : IntPoint offset = mCurrentRenderTarget->GetOrigin();
1031 0 : IntSize size = mCurrentRenderTarget->GetSize();
1032 :
1033 0 : Rect renderBound(0, 0, size.width, size.height);
1034 0 : renderBound.IntersectRect(renderBound, Rect(aClipRect));
1035 0 : renderBound.MoveBy(offset);
1036 :
1037 0 : Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound);
1038 :
1039 : // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
1040 : // quads. Fix me.
1041 0 : mPixelsFilled += destRect.width * destRect.height;
1042 :
1043 : // Do a simple culling if this rect is out of target buffer.
1044 : // Inflate a small size to avoid some numerical imprecision issue.
1045 0 : destRect.Inflate(1, 1);
1046 0 : destRect.MoveBy(-offset);
1047 0 : renderBound = Rect(0, 0, size.width, size.height);
1048 0 : if (!renderBound.Intersects(destRect)) {
1049 0 : return;
1050 : }
1051 :
1052 0 : LayerScope::DrawBegin();
1053 :
1054 0 : IntRect clipRect = aClipRect;
1055 : // aClipRect is in destination coordinate space (after all
1056 : // transforms and offsets have been applied) so if our
1057 : // drawing is going to be shifted by mRenderOffset then we need
1058 : // to shift the clip rect by the same amount.
1059 0 : if (!mTarget && mCurrentRenderTarget->IsWindow()) {
1060 0 : clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
1061 : }
1062 :
1063 0 : ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
1064 0 : ScopedScissorRect autoScissorRect(mGLContext, clipRect.x, FlipY(clipRect.y + clipRect.height),
1065 0 : clipRect.width, clipRect.height);
1066 :
1067 : MaskType maskType;
1068 : EffectMask* effectMask;
1069 0 : TextureSourceOGL* sourceMask = nullptr;
1070 0 : gfx::Matrix4x4 maskQuadTransform;
1071 0 : if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
1072 0 : effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
1073 0 : sourceMask = effectMask->mMaskTexture->AsSourceOGL();
1074 :
1075 : // NS_ASSERTION(textureMask->IsAlpha(),
1076 : // "OpenGL mask layers must be backed by alpha surfaces");
1077 :
1078 : // We're assuming that the gl backend won't cheat and use NPOT
1079 : // textures when glContext says it can't (which seems to happen
1080 : // on a mac when you force POT textures)
1081 0 : IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
1082 :
1083 0 : const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
1084 0 : NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
1085 0 : Rect bounds = Rect(Point(), Size(maskSize));
1086 0 : bounds = maskTransform.As2D().TransformBounds(bounds);
1087 :
1088 0 : maskQuadTransform._11 = 1.0f/bounds.width;
1089 0 : maskQuadTransform._22 = 1.0f/bounds.height;
1090 0 : maskQuadTransform._41 = float(-bounds.x)/bounds.width;
1091 0 : maskQuadTransform._42 = float(-bounds.y)/bounds.height;
1092 :
1093 0 : maskType = MaskType::Mask;
1094 : } else {
1095 0 : maskType = MaskType::MaskNone;
1096 : }
1097 :
1098 : // Determine the color if this is a color shader and fold the opacity into
1099 : // the color since color shaders don't have an opacity uniform.
1100 0 : Color color;
1101 0 : if (aEffectChain.mPrimaryEffect->mType == EffectTypes::SOLID_COLOR) {
1102 : EffectSolidColor* effectSolidColor =
1103 0 : static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
1104 0 : color = effectSolidColor->mColor;
1105 :
1106 0 : Float opacity = aOpacity * color.a;
1107 0 : color.r *= opacity;
1108 0 : color.g *= opacity;
1109 0 : color.b *= opacity;
1110 0 : color.a = opacity;
1111 :
1112 : // We can fold opacity into the color, so no need to consider it further.
1113 0 : aOpacity = 1.f;
1114 : }
1115 :
1116 0 : bool createdMixBlendBackdropTexture = false;
1117 0 : GLuint mixBlendBackdrop = 0;
1118 0 : gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
1119 :
1120 0 : if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
1121 : EffectBlendMode *blendEffect =
1122 0 : static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
1123 0 : blendMode = blendEffect->mBlendMode;
1124 : }
1125 :
1126 : // Only apply DEAA to quads that have been transformed such that aliasing
1127 : // could be visible
1128 0 : bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
1129 0 : !aTransform.Is2DIntegerTranslation();
1130 :
1131 0 : bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
1132 0 : ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
1133 : maskType, blendMode, colorMatrix,
1134 0 : bEnableAA);
1135 :
1136 0 : config.SetOpacity(aOpacity != 1.f);
1137 0 : ApplyPrimitiveConfig(config, aGeometry);
1138 :
1139 0 : ShaderProgramOGL *program = GetShaderProgramFor(config);
1140 0 : ActivateProgram(program);
1141 0 : program->SetProjectionMatrix(mProjMatrix);
1142 0 : program->SetLayerTransform(aTransform);
1143 0 : LayerScope::SetLayerTransform(aTransform);
1144 :
1145 0 : if (colorMatrix) {
1146 : EffectColorMatrix* effectColorMatrix =
1147 0 : static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
1148 0 : program->SetColorMatrix(effectColorMatrix->mColorMatrix);
1149 : }
1150 :
1151 0 : if (BlendOpIsMixBlendMode(blendMode)) {
1152 0 : gfx::Matrix4x4 backdropTransform;
1153 :
1154 0 : if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) {
1155 : // The NV_texture_barrier extension lets us read directly from the
1156 : // backbuffer. Let's do that.
1157 : // We need to tell OpenGL about this, so that it can make sure everything
1158 : // on the GPU is happening in the right order.
1159 0 : gl()->fTextureBarrier();
1160 0 : mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle();
1161 : } else {
1162 0 : gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect,
1163 0 : aTransform, &backdropTransform);
1164 0 : mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
1165 0 : createdMixBlendBackdropTexture = true;
1166 : }
1167 0 : program->SetBackdropTransform(backdropTransform);
1168 : }
1169 :
1170 0 : program->SetRenderOffset(offset.x, offset.y);
1171 0 : LayerScope::SetRenderOffset(offset.x, offset.y);
1172 :
1173 0 : if (aOpacity != 1.f)
1174 0 : program->SetLayerOpacity(aOpacity);
1175 :
1176 0 : if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1177 0 : TextureSourceOGL* source = nullptr;
1178 0 : if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) {
1179 : EffectComponentAlpha* effectComponentAlpha =
1180 0 : static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1181 0 : source = effectComponentAlpha->mOnWhite->AsSourceOGL();
1182 : } else {
1183 : TexturedEffect* texturedEffect =
1184 0 : static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1185 0 : source = texturedEffect->mTexture->AsSourceOGL();
1186 : }
1187 : // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
1188 0 : program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
1189 : }
1190 :
1191 : // XXX kip - These calculations could be performed once per layer rather than
1192 : // for every tile. This might belong in Compositor.cpp once DEAA
1193 : // is implemented for DirectX.
1194 0 : if (bEnableAA) {
1195 : // Calculate the transformed vertices of aVisibleRect in screen space
1196 : // pixels, mirroring the calculations in the vertex shader
1197 0 : Matrix4x4 flatTransform = aTransform;
1198 0 : flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
1199 0 : flatTransform *= mProjMatrix;
1200 :
1201 0 : Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
1202 0 : size_t edgeCount = 0;
1203 0 : Point3D coefficients[4];
1204 :
1205 0 : Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
1206 0 : size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
1207 0 : for (size_t i = 0; i < pointCount; i++) {
1208 0 : points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
1209 0 : (points[i].y * 0.5f + 0.5f) * mViewportSize.height);
1210 : }
1211 0 : if (pointCount > 2) {
1212 : // Use shoelace formula on a triangle in the clipped quad to determine if
1213 : // winding order is reversed. Iterate through the triangles until one is
1214 : // found with a non-zero area.
1215 0 : float winding = 0.0f;
1216 0 : size_t wp = 0;
1217 0 : while (winding == 0.0f && wp < pointCount) {
1218 0 : int wp1 = (wp + 1) % pointCount;
1219 0 : int wp2 = (wp + 2) % pointCount;
1220 0 : winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
1221 0 : (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
1222 0 : (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
1223 0 : wp++;
1224 : }
1225 0 : bool frontFacing = winding >= 0.0f;
1226 :
1227 : // Calculate the line coefficients used by the DEAA shader to determine the
1228 : // sub-pixel coverage of the edge pixels
1229 0 : for (size_t i=0; i<pointCount; i++) {
1230 0 : const Point& p1 = points[i];
1231 0 : const Point& p2 = points[(i + 1) % pointCount];
1232 : // Create a DEAA edge for any non-straight lines, to a maximum of 4
1233 0 : if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
1234 0 : if (frontFacing) {
1235 0 : coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
1236 : } else {
1237 0 : coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
1238 : }
1239 : }
1240 : }
1241 : }
1242 :
1243 : // The coefficients that are not needed must not cull any fragments.
1244 : // We fill these unused coefficients with a clipping plane that has no
1245 : // effect.
1246 0 : for (size_t i = edgeCount; i < 4; i++) {
1247 0 : coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
1248 : }
1249 :
1250 : // Set uniforms required by DEAA shader
1251 0 : Matrix4x4 transformInverted = aTransform;
1252 0 : transformInverted.Invert();
1253 0 : program->SetLayerTransformInverse(transformInverted);
1254 0 : program->SetDEAAEdges(coefficients);
1255 0 : program->SetVisibleCenter(aVisibleRect.Center());
1256 0 : program->SetViewportSize(mViewportSize);
1257 : }
1258 :
1259 0 : bool didSetBlendMode = false;
1260 :
1261 0 : switch (aEffectChain.mPrimaryEffect->mType) {
1262 : case EffectTypes::SOLID_COLOR: {
1263 0 : program->SetRenderColor(color);
1264 :
1265 0 : if (maskType != MaskType::MaskNone) {
1266 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
1267 : }
1268 0 : if (mixBlendBackdrop) {
1269 0 : BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
1270 : }
1271 :
1272 0 : didSetBlendMode = SetBlendMode(gl(), blendMode);
1273 :
1274 0 : BindAndDrawGeometry(program, aGeometry);
1275 : }
1276 0 : break;
1277 :
1278 : case EffectTypes::RGB: {
1279 : TexturedEffect* texturedEffect =
1280 0 : static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1281 0 : TextureSource *source = texturedEffect->mTexture;
1282 :
1283 0 : didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
1284 :
1285 0 : gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter;
1286 :
1287 0 : source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter);
1288 :
1289 0 : program->SetTextureUnit(0);
1290 :
1291 0 : Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
1292 0 : program->SetTextureTransform(textureTransform);
1293 :
1294 0 : if (maskType != MaskType::MaskNone) {
1295 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
1296 : }
1297 0 : if (mixBlendBackdrop) {
1298 0 : BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1299 : }
1300 :
1301 0 : BindAndDrawGeometryWithTextureRect(program, aGeometry,
1302 : texturedEffect->mTextureCoords, source);
1303 : }
1304 0 : break;
1305 : case EffectTypes::YCBCR: {
1306 : EffectYCbCr* effectYCbCr =
1307 0 : static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
1308 0 : TextureSource* sourceYCbCr = effectYCbCr->mTexture;
1309 0 : const int Y = 0, Cb = 1, Cr = 2;
1310 0 : TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
1311 0 : TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
1312 0 : TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
1313 :
1314 0 : if (!sourceY || !sourceCb || !sourceCr) {
1315 0 : NS_WARNING("Invalid layer texture.");
1316 0 : return;
1317 : }
1318 :
1319 0 : sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter);
1320 0 : sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter);
1321 0 : sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter);
1322 :
1323 0 : program->SetYCbCrTextureUnits(Y, Cb, Cr);
1324 0 : program->SetTextureTransform(Matrix4x4());
1325 0 : program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace);
1326 :
1327 0 : if (maskType != MaskType::MaskNone) {
1328 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
1329 : }
1330 0 : if (mixBlendBackdrop) {
1331 0 : BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
1332 : }
1333 0 : didSetBlendMode = SetBlendMode(gl(), blendMode);
1334 0 : BindAndDrawGeometryWithTextureRect(program,
1335 : aGeometry,
1336 : effectYCbCr->mTextureCoords,
1337 : sourceYCbCr->GetSubSource(Y));
1338 : }
1339 0 : break;
1340 : case EffectTypes::NV12: {
1341 : EffectNV12* effectNV12 =
1342 0 : static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
1343 0 : TextureSource* sourceNV12 = effectNV12->mTexture;
1344 0 : const int Y = 0, CbCr = 1;
1345 0 : TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL();
1346 0 : TextureSourceOGL* sourceCbCr = sourceNV12->GetSubSource(CbCr)->AsSourceOGL();
1347 :
1348 0 : if (!sourceY || !sourceCbCr) {
1349 0 : NS_WARNING("Invalid layer texture.");
1350 0 : return;
1351 : }
1352 :
1353 0 : sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter);
1354 0 : sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter);
1355 :
1356 0 : if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1357 : // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
1358 0 : program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width, sourceCbCr->GetSize().height);
1359 : }
1360 :
1361 0 : program->SetNV12TextureUnits(Y, CbCr);
1362 0 : program->SetTextureTransform(Matrix4x4());
1363 :
1364 0 : if (maskType != MaskType::MaskNone) {
1365 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
1366 : }
1367 0 : if (mixBlendBackdrop) {
1368 0 : BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
1369 : }
1370 0 : didSetBlendMode = SetBlendMode(gl(), blendMode);
1371 0 : BindAndDrawGeometryWithTextureRect(program,
1372 : aGeometry,
1373 : effectNV12->mTextureCoords,
1374 : sourceNV12->GetSubSource(Y));
1375 : }
1376 0 : break;
1377 : case EffectTypes::RENDER_TARGET: {
1378 : EffectRenderTarget* effectRenderTarget =
1379 0 : static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
1380 : RefPtr<CompositingRenderTargetOGL> surface
1381 0 : = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
1382 :
1383 0 : surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
1384 :
1385 : // Drawing is always flipped, but when copying between surfaces we want to avoid
1386 : // this, so apply a flip here to cancel the other one out.
1387 0 : Matrix transform;
1388 0 : transform.PreTranslate(0.0, 1.0);
1389 0 : transform.PreScale(1.0f, -1.0f);
1390 0 : program->SetTextureTransform(Matrix4x4::From2D(transform));
1391 0 : program->SetTextureUnit(0);
1392 :
1393 0 : if (maskType != MaskType::MaskNone) {
1394 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
1395 : }
1396 0 : if (mixBlendBackdrop) {
1397 0 : BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1398 : }
1399 :
1400 0 : if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1401 : // 2DRect case, get the multiplier right for a sampler2DRect
1402 0 : program->SetTexCoordMultiplier(surface->GetSize().width,
1403 0 : surface->GetSize().height);
1404 : }
1405 :
1406 : // Drawing is always flipped, but when copying between surfaces we want to avoid
1407 : // this. Pass true for the flip parameter to introduce a second flip
1408 : // that cancels the other one out.
1409 0 : didSetBlendMode = SetBlendMode(gl(), blendMode);
1410 0 : BindAndDrawGeometry(program, aGeometry);
1411 : }
1412 0 : break;
1413 : case EffectTypes::COMPONENT_ALPHA: {
1414 0 : MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
1415 0 : MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!");
1416 : EffectComponentAlpha* effectComponentAlpha =
1417 0 : static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1418 0 : TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
1419 0 : TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
1420 :
1421 0 : if (!sourceOnBlack->IsValid() ||
1422 0 : !sourceOnWhite->IsValid()) {
1423 0 : NS_WARNING("Invalid layer texture for component alpha");
1424 0 : return;
1425 : }
1426 :
1427 0 : sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mSamplingFilter);
1428 0 : sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mSamplingFilter);
1429 :
1430 0 : program->SetBlackTextureUnit(0);
1431 0 : program->SetWhiteTextureUnit(1);
1432 0 : program->SetTextureTransform(Matrix4x4());
1433 :
1434 0 : if (maskType != MaskType::MaskNone) {
1435 0 : BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
1436 : }
1437 : // Pass 1.
1438 0 : gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
1439 : LOCAL_GL_ONE, LOCAL_GL_ONE);
1440 0 : program->SetTexturePass2(false);
1441 0 : BindAndDrawGeometryWithTextureRect(program,
1442 : aGeometry,
1443 : effectComponentAlpha->mTextureCoords,
1444 : effectComponentAlpha->mOnBlack);
1445 :
1446 : // Pass 2.
1447 0 : gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
1448 : LOCAL_GL_ONE, LOCAL_GL_ONE);
1449 0 : program->SetTexturePass2(true);
1450 0 : BindAndDrawGeometryWithTextureRect(program,
1451 : aGeometry,
1452 : effectComponentAlpha->mTextureCoords,
1453 : effectComponentAlpha->mOnBlack);
1454 :
1455 0 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1456 : LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1457 : }
1458 0 : break;
1459 : default:
1460 0 : MOZ_ASSERT(false, "Unhandled effect type");
1461 : break;
1462 : }
1463 :
1464 0 : if (didSetBlendMode) {
1465 0 : gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1466 : LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1467 : }
1468 0 : if (createdMixBlendBackdropTexture) {
1469 0 : gl()->fDeleteTextures(1, &mixBlendBackdrop);
1470 : }
1471 :
1472 : // in case rendering has used some other GL context
1473 0 : MakeCurrent();
1474 :
1475 0 : LayerScope::DrawEnd(mGLContext, aEffectChain,
1476 0 : aRect.width, aRect.height);
1477 : }
1478 :
1479 : void
1480 0 : CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
1481 : const gfx::Rect& aRect)
1482 : {
1483 0 : BindAndDrawQuad(aProgram, aRect);
1484 0 : }
1485 :
1486 : void
1487 0 : CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
1488 : const nsTArray<gfx::TexturedTriangle>& aTriangles)
1489 : {
1490 0 : NS_ASSERTION(aProgram->HasInitialized(), "Shader program not correctly initialized");
1491 :
1492 0 : const nsTArray<TexturedVertex> vertices = TexturedTrianglesToVertexArray(aTriangles);
1493 :
1494 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO);
1495 0 : mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
1496 0 : vertices.Length() * sizeof(TexturedVertex),
1497 0 : vertices.Elements(),
1498 0 : LOCAL_GL_STREAM_DRAW);
1499 :
1500 0 : const GLsizei stride = 4 * sizeof(GLfloat);
1501 0 : InitializeVAO(kCoordinateAttributeIndex, 2, stride, 0);
1502 0 : InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 2 * sizeof(GLfloat));
1503 :
1504 0 : mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, vertices.Length());
1505 :
1506 0 : mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1507 0 : mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex);
1508 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1509 0 : }
1510 :
1511 : // |aRect| is the rectangle we want to draw to. We will draw it with
1512 : // up to 4 draw commands if necessary to avoid wrapping.
1513 : // |aTexCoordRect| is the rectangle from the texture that we want to
1514 : // draw using the given program.
1515 : // |aTexture| is the texture we are drawing. Its actual size can be
1516 : // larger than the rectangle given by |texCoordRect|.
1517 : void
1518 0 : CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
1519 : const Rect& aRect,
1520 : const Rect& aTexCoordRect,
1521 : TextureSource *aTexture)
1522 : {
1523 0 : Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture);
1524 0 : Rect layerRects[4];
1525 0 : Rect textureRects[4];
1526 : size_t rects = DecomposeIntoNoRepeatRects(aRect,
1527 : scaledTexCoordRect,
1528 : &layerRects,
1529 0 : &textureRects);
1530 :
1531 0 : BindAndDrawQuads(aProg, rects, layerRects, textureRects);
1532 0 : }
1533 :
1534 : void
1535 0 : CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
1536 : const nsTArray<gfx::TexturedTriangle>& aTriangles,
1537 : const gfx::Rect& aTexCoordRect,
1538 : TextureSource *aTexture)
1539 : {
1540 0 : BindAndDrawGeometry(aProg, aTriangles);
1541 0 : }
1542 :
1543 : void
1544 0 : CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
1545 : int aQuads,
1546 : const Rect* aLayerRects,
1547 : const Rect* aTextureRects)
1548 : {
1549 0 : NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
1550 :
1551 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
1552 0 : InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0);
1553 :
1554 0 : aProg->SetLayerRects(aLayerRects);
1555 0 : if (aProg->GetTextureCount() > 0) {
1556 0 : aProg->SetTextureRects(aTextureRects);
1557 : }
1558 :
1559 : // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
1560 : // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
1561 0 : mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
1562 0 : mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1563 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1564 0 : LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
1565 0 : }
1566 :
1567 : void
1568 0 : CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents,
1569 : const GLsizei aStride, const size_t aOffset)
1570 : {
1571 0 : mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT,
1572 : LOCAL_GL_FALSE, aStride,
1573 0 : reinterpret_cast<GLvoid*>(aOffset));
1574 0 : mGLContext->fEnableVertexAttribArray(aAttrib);
1575 0 : }
1576 :
1577 : void
1578 0 : CompositorOGL::EndFrame()
1579 : {
1580 0 : AUTO_PROFILER_LABEL("CompositorOGL::EndFrame", GRAPHICS);
1581 :
1582 0 : MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
1583 :
1584 : #ifdef MOZ_DUMP_PAINTING
1585 0 : if (gfxEnv::DumpCompositorTextures()) {
1586 0 : LayoutDeviceIntSize size;
1587 0 : if (mUseExternalSurfaceSize) {
1588 0 : size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height);
1589 : } else {
1590 0 : size = mWidget->GetClientSize();
1591 : }
1592 0 : RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
1593 0 : if (target) {
1594 0 : CopyToTarget(target, nsIntPoint(), Matrix());
1595 0 : WriteSnapshotToDumpFile(this, target);
1596 : }
1597 : }
1598 : #endif
1599 :
1600 0 : mContextStateTracker.PopOGLSection(gl(), "Frame");
1601 :
1602 0 : mFrameInProgress = false;
1603 :
1604 0 : if (mTarget) {
1605 0 : CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
1606 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1607 0 : mCurrentRenderTarget = nullptr;
1608 0 : Compositor::EndFrame();
1609 0 : return;
1610 : }
1611 :
1612 0 : mCurrentRenderTarget = nullptr;
1613 :
1614 0 : if (mTexturePool) {
1615 0 : mTexturePool->EndFrame();
1616 : }
1617 :
1618 0 : mGLContext->SwapBuffers();
1619 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1620 :
1621 : // Unbind all textures
1622 0 : for (GLuint i = 0; i <= 4; i++) {
1623 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1624 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
1625 0 : if (!mGLContext->IsGLES()) {
1626 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
1627 : }
1628 : }
1629 :
1630 0 : Compositor::EndFrame();
1631 : }
1632 :
1633 : void
1634 0 : CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize)
1635 : {
1636 0 : mSurfaceSize.width = aSize.width;
1637 0 : mSurfaceSize.height = aSize.height;
1638 0 : }
1639 :
1640 : void
1641 0 : CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
1642 : {
1643 0 : MOZ_ASSERT(aTarget);
1644 0 : IntRect rect;
1645 0 : if (mUseExternalSurfaceSize) {
1646 0 : rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
1647 : } else {
1648 0 : rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
1649 : }
1650 0 : GLint width = rect.width;
1651 0 : GLint height = rect.height;
1652 :
1653 0 : if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
1654 0 : NS_ERROR("Widget size too big - integer overflow!");
1655 0 : return;
1656 : }
1657 :
1658 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
1659 :
1660 0 : if (!mGLContext->IsGLES()) {
1661 : // GLES2 promises that binding to any custom FBO will attach
1662 : // to GL_COLOR_ATTACHMENT0 attachment point.
1663 0 : mGLContext->fReadBuffer(LOCAL_GL_BACK);
1664 : }
1665 :
1666 : RefPtr<DataSourceSurface> source =
1667 0 : Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
1668 0 : if (NS_WARN_IF(!source)) {
1669 0 : return;
1670 : }
1671 :
1672 0 : ReadPixelsIntoDataSurface(mGLContext, source);
1673 :
1674 : // Map from GL space to Cairo space and reverse the world transform.
1675 0 : Matrix glToCairoTransform = aTransform;
1676 0 : glToCairoTransform.Invert();
1677 0 : glToCairoTransform.PreScale(1.0, -1.0);
1678 0 : glToCairoTransform.PreTranslate(0.0, -height);
1679 :
1680 0 : glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y);
1681 :
1682 0 : Matrix oldMatrix = aTarget->GetTransform();
1683 0 : aTarget->SetTransform(glToCairoTransform);
1684 0 : Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
1685 0 : aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
1686 0 : aTarget->SetTransform(oldMatrix);
1687 0 : aTarget->Flush();
1688 : }
1689 :
1690 : void
1691 0 : CompositorOGL::Pause()
1692 : {
1693 : #ifdef MOZ_WIDGET_ANDROID
1694 : if (!gl() || gl()->IsDestroyed())
1695 : return;
1696 :
1697 : // ReleaseSurface internally calls MakeCurrent.
1698 : gl()->ReleaseSurface();
1699 : #endif
1700 0 : }
1701 :
1702 : bool
1703 0 : CompositorOGL::Resume()
1704 : {
1705 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
1706 : if (!gl() || gl()->IsDestroyed())
1707 : return false;
1708 :
1709 : // RenewSurface internally calls MakeCurrent.
1710 : return gl()->RenewSurface(GetWidget());
1711 : #endif
1712 0 : return true;
1713 : }
1714 :
1715 : already_AddRefed<DataTextureSource>
1716 0 : CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
1717 : {
1718 0 : return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags);
1719 : }
1720 :
1721 : bool
1722 0 : CompositorOGL::SupportsPartialTextureUpdate()
1723 : {
1724 0 : return CanUploadSubTextures(mGLContext);
1725 : }
1726 :
1727 : int32_t
1728 0 : CompositorOGL::GetMaxTextureSize() const
1729 : {
1730 0 : MOZ_ASSERT(mGLContext);
1731 0 : GLint texSize = 0;
1732 0 : mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
1733 0 : &texSize);
1734 0 : MOZ_ASSERT(texSize != 0);
1735 0 : return texSize;
1736 : }
1737 :
1738 : void
1739 0 : CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
1740 0 : if (mDestroyed) {
1741 0 : NS_WARNING("Call on destroyed layer manager");
1742 0 : return;
1743 : }
1744 0 : mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
1745 : }
1746 :
1747 : GLBlitTextureImageHelper*
1748 0 : CompositorOGL::BlitTextureImageHelper()
1749 : {
1750 0 : if (!mBlitTextureImageHelper) {
1751 0 : mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
1752 : }
1753 :
1754 0 : return mBlitTextureImageHelper.get();
1755 : }
1756 :
1757 :
1758 :
1759 : GLuint
1760 0 : CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
1761 : {
1762 0 : if (!mTexturePool) {
1763 0 : mTexturePool = new PerUnitTexturePoolOGL(gl());
1764 : }
1765 0 : return mTexturePool->GetTexture(aTarget, aUnit);
1766 : }
1767 :
1768 : GLuint
1769 0 : PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
1770 : {
1771 0 : if (mTextureTarget == 0) {
1772 0 : mTextureTarget = aTarget;
1773 : }
1774 0 : MOZ_ASSERT(mTextureTarget == aTarget);
1775 :
1776 0 : size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
1777 : // lazily grow the array of temporary textures
1778 0 : if (mTextures.Length() <= index) {
1779 0 : size_t prevLength = mTextures.Length();
1780 0 : mTextures.SetLength(index + 1);
1781 0 : for(unsigned int i = prevLength; i <= index; ++i) {
1782 0 : mTextures[i] = 0;
1783 : }
1784 : }
1785 : // lazily initialize the temporary textures
1786 0 : if (!mTextures[index]) {
1787 0 : if (!mGL->MakeCurrent()) {
1788 0 : return 0;
1789 : }
1790 0 : mGL->fGenTextures(1, &mTextures[index]);
1791 0 : mGL->fBindTexture(aTarget, mTextures[index]);
1792 0 : mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1793 0 : mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1794 : }
1795 0 : return mTextures[index];
1796 : }
1797 :
1798 : void
1799 0 : PerUnitTexturePoolOGL::DestroyTextures()
1800 : {
1801 0 : if (mGL && mGL->MakeCurrent()) {
1802 0 : if (mTextures.Length() > 0) {
1803 0 : mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
1804 : }
1805 : }
1806 0 : mTextures.SetLength(0);
1807 0 : }
1808 :
1809 : bool
1810 0 : CompositorOGL::SupportsLayerGeometry() const
1811 : {
1812 0 : return gfxPrefs::OGLLayerGeometry();
1813 : }
1814 :
1815 : } // namespace layers
1816 : } // namespace mozilla
|