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