1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Bas Schouten <bschouten@mozilla.org>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "ContainerLayerOGL.h"
39 : #include "gfxUtils.h"
40 :
41 : namespace mozilla {
42 : namespace layers {
43 :
44 : template<class Container>
45 : static void
46 0 : ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter)
47 : {
48 0 : aChild->SetParent(aContainer);
49 0 : if (!aAfter) {
50 0 : Layer *oldFirstChild = aContainer->GetFirstChild();
51 0 : aContainer->mFirstChild = aChild;
52 0 : aChild->SetNextSibling(oldFirstChild);
53 0 : aChild->SetPrevSibling(nsnull);
54 0 : if (oldFirstChild) {
55 0 : oldFirstChild->SetPrevSibling(aChild);
56 : } else {
57 0 : aContainer->mLastChild = aChild;
58 : }
59 0 : NS_ADDREF(aChild);
60 0 : aContainer->DidInsertChild(aChild);
61 0 : return;
62 : }
63 0 : for (Layer *child = aContainer->GetFirstChild();
64 : child; child = child->GetNextSibling()) {
65 0 : if (aAfter == child) {
66 0 : Layer *oldNextSibling = child->GetNextSibling();
67 0 : child->SetNextSibling(aChild);
68 0 : aChild->SetNextSibling(oldNextSibling);
69 0 : if (oldNextSibling) {
70 0 : oldNextSibling->SetPrevSibling(aChild);
71 : } else {
72 0 : aContainer->mLastChild = aChild;
73 : }
74 0 : aChild->SetPrevSibling(child);
75 0 : NS_ADDREF(aChild);
76 0 : aContainer->DidInsertChild(aChild);
77 0 : return;
78 : }
79 : }
80 0 : NS_WARNING("Failed to find aAfter layer!");
81 : }
82 :
83 : template<class Container>
84 : static void
85 0 : ContainerRemoveChild(Container* aContainer, Layer* aChild)
86 : {
87 0 : if (aContainer->GetFirstChild() == aChild) {
88 0 : aContainer->mFirstChild = aContainer->GetFirstChild()->GetNextSibling();
89 0 : if (aContainer->mFirstChild) {
90 0 : aContainer->mFirstChild->SetPrevSibling(nsnull);
91 : } else {
92 0 : aContainer->mLastChild = nsnull;
93 : }
94 0 : aChild->SetNextSibling(nsnull);
95 0 : aChild->SetPrevSibling(nsnull);
96 0 : aChild->SetParent(nsnull);
97 0 : aContainer->DidRemoveChild(aChild);
98 0 : NS_RELEASE(aChild);
99 0 : return;
100 : }
101 0 : Layer *lastChild = nsnull;
102 0 : for (Layer *child = aContainer->GetFirstChild(); child;
103 : child = child->GetNextSibling()) {
104 0 : if (child == aChild) {
105 : // We're sure this is not our first child. So lastChild != NULL.
106 0 : lastChild->SetNextSibling(child->GetNextSibling());
107 0 : if (child->GetNextSibling()) {
108 0 : child->GetNextSibling()->SetPrevSibling(lastChild);
109 : } else {
110 0 : aContainer->mLastChild = lastChild;
111 : }
112 0 : child->SetNextSibling(nsnull);
113 0 : child->SetPrevSibling(nsnull);
114 0 : child->SetParent(nsnull);
115 0 : aContainer->DidRemoveChild(aChild);
116 0 : NS_RELEASE(aChild);
117 0 : return;
118 : }
119 0 : lastChild = child;
120 : }
121 : }
122 :
123 : template<class Container>
124 : static void
125 0 : ContainerDestroy(Container* aContainer)
126 : {
127 0 : if (!aContainer->mDestroyed) {
128 0 : while (aContainer->mFirstChild) {
129 0 : aContainer->GetFirstChildOGL()->Destroy();
130 0 : aContainer->RemoveChild(aContainer->mFirstChild);
131 : }
132 0 : aContainer->mDestroyed = true;
133 : }
134 0 : }
135 :
136 : template<class Container>
137 : static void
138 0 : ContainerCleanupResources(Container* aContainer)
139 : {
140 0 : for (Layer* l = aContainer->GetFirstChild(); l; l = l->GetNextSibling()) {
141 0 : LayerOGL* layerToRender = static_cast<LayerOGL*>(l->ImplData());
142 0 : layerToRender->CleanupResources();
143 : }
144 0 : }
145 :
146 : static inline LayerOGL*
147 : GetNextSibling(LayerOGL* aLayer)
148 : {
149 : Layer* layer = aLayer->GetLayer()->GetNextSibling();
150 : return layer ? static_cast<LayerOGL*>(layer->
151 : ImplData())
152 : : nsnull;
153 : }
154 :
155 : static bool
156 0 : HasOpaqueAncestorLayer(Layer* aLayer)
157 : {
158 0 : for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
159 0 : if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
160 0 : return true;
161 : }
162 0 : return false;
163 : }
164 :
165 : template<class Container>
166 : static void
167 : ContainerRender(Container* aContainer,
168 : int aPreviousFrameBuffer,
169 : const nsIntPoint& aOffset,
170 0 : LayerManagerOGL* aManager)
171 : {
172 : /**
173 : * Setup our temporary texture for rendering the contents of this container.
174 : */
175 : GLuint containerSurface;
176 : GLuint frameBuffer;
177 :
178 0 : nsIntPoint childOffset(aOffset);
179 0 : nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
180 :
181 0 : nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
182 0 : aContainer->gl()->PushScissorRect();
183 0 : aContainer->mSupportsComponentAlphaChildren = false;
184 :
185 0 : float opacity = aContainer->GetEffectiveOpacity();
186 0 : const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
187 0 : bool needsFramebuffer = aContainer->UseIntermediateSurface();
188 0 : if (needsFramebuffer) {
189 0 : LayerManagerOGL::InitMode mode = LayerManagerOGL::InitModeClear;
190 0 : nsIntRect framebufferRect = visibleRect;
191 0 : if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 &&
192 : (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
193 : {
194 : // don't need a background, we're going to paint all opaque stuff
195 0 : aContainer->mSupportsComponentAlphaChildren = true;
196 0 : mode = LayerManagerOGL::InitModeNone;
197 : } else {
198 0 : const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
199 0 : gfxMatrix transform;
200 : // If we have an opaque ancestor layer, then we can be sure that
201 : // all the pixels we draw into are either opaque already or will be
202 : // covered by something opaque. Otherwise copying up the background is
203 : // not safe.
204 0 : if (HasOpaqueAncestorLayer(aContainer) &&
205 : transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
206 0 : mode = LayerManagerOGL::InitModeCopy;
207 0 : framebufferRect.x += transform.x0;
208 0 : framebufferRect.y += transform.y0;
209 0 : aContainer->mSupportsComponentAlphaChildren = true;
210 : }
211 : }
212 :
213 0 : aContainer->gl()->PushViewportRect();
214 0 : framebufferRect -= childOffset;
215 0 : aManager->CreateFBOWithTexture(framebufferRect,
216 : mode,
217 : aPreviousFrameBuffer,
218 : &frameBuffer,
219 : &containerSurface);
220 0 : childOffset.x = visibleRect.x;
221 0 : childOffset.y = visibleRect.y;
222 : } else {
223 0 : frameBuffer = aPreviousFrameBuffer;
224 0 : aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
225 : (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
226 : }
227 :
228 0 : nsAutoTArray<Layer*, 12> children;
229 0 : aContainer->SortChildrenBy3DZOrder(children);
230 :
231 : /**
232 : * Render this container's contents.
233 : */
234 0 : for (PRUint32 i = 0; i < children.Length(); i++) {
235 0 : LayerOGL* layerToRender = static_cast<LayerOGL*>(children.ElementAt(i)->ImplData());
236 :
237 0 : if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) {
238 0 : continue;
239 : }
240 :
241 : nsIntRect scissorRect = layerToRender->GetLayer()->
242 0 : CalculateScissorRect(cachedScissor, &aManager->GetWorldTransform());
243 0 : if (scissorRect.IsEmpty()) {
244 0 : continue;
245 : }
246 :
247 0 : aContainer->gl()->fScissor(scissorRect.x,
248 : scissorRect.y,
249 : scissorRect.width,
250 : scissorRect.height);
251 :
252 0 : layerToRender->RenderLayer(frameBuffer, childOffset);
253 0 : aContainer->gl()->MakeCurrent();
254 : }
255 :
256 :
257 0 : if (needsFramebuffer) {
258 : // Unbind the current framebuffer and rebind the previous one.
259 : #ifdef MOZ_DUMP_PAINTING
260 0 : if (gfxUtils::sDumpPainting) {
261 : nsRefPtr<gfxImageSurface> surf =
262 0 : aContainer->gl()->GetTexImage(containerSurface, true, aManager->GetFBOLayerProgramType());
263 :
264 0 : WriteSnapshotToDumpFile(aContainer, surf);
265 : }
266 : #endif
267 :
268 : // Restore the viewport
269 0 : aContainer->gl()->PopViewportRect();
270 0 : nsIntRect viewport = aContainer->gl()->ViewportRect();
271 0 : aManager->SetupPipeline(viewport.width, viewport.height,
272 : LayerManagerOGL::ApplyWorldTransform);
273 0 : aContainer->gl()->PopScissorRect();
274 :
275 0 : aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
276 0 : aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
277 :
278 0 : aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
279 :
280 0 : aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
281 :
282 0 : ColorTextureLayerProgram *rgb = aManager->GetFBOLayerProgram();
283 :
284 0 : rgb->Activate();
285 0 : rgb->SetLayerQuadRect(visibleRect);
286 0 : rgb->SetLayerTransform(transform);
287 0 : rgb->SetLayerOpacity(opacity);
288 0 : rgb->SetRenderOffset(aOffset);
289 0 : rgb->SetTextureUnit(0);
290 :
291 0 : if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
292 : // 2DRect case, get the multiplier right for a sampler2DRect
293 0 : float f[] = { float(visibleRect.width), float(visibleRect.height) };
294 0 : rgb->SetUniform(rgb->GetTexCoordMultiplierUniformLocation(),
295 : 2, f);
296 : }
297 :
298 : // Drawing is always flipped, but when copying between surfaces we want to avoid
299 : // this. Pass true for the flip parameter to introduce a second flip
300 : // that cancels the other one out.
301 0 : aManager->BindAndDrawQuad(rgb, true);
302 :
303 : // Clean up resources. This also unbinds the texture.
304 0 : aContainer->gl()->fDeleteTextures(1, &containerSurface);
305 : } else {
306 0 : aContainer->gl()->PopScissorRect();
307 : }
308 0 : }
309 :
310 0 : ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
311 : : ContainerLayer(aManager, NULL)
312 0 : , LayerOGL(aManager)
313 : {
314 0 : mImplData = static_cast<LayerOGL*>(this);
315 0 : }
316 :
317 0 : ContainerLayerOGL::~ContainerLayerOGL()
318 : {
319 0 : Destroy();
320 0 : }
321 :
322 : void
323 0 : ContainerLayerOGL::InsertAfter(Layer* aChild, Layer* aAfter)
324 : {
325 0 : ContainerInsertAfter(this, aChild, aAfter);
326 0 : }
327 :
328 : void
329 0 : ContainerLayerOGL::RemoveChild(Layer *aChild)
330 : {
331 0 : ContainerRemoveChild(this, aChild);
332 0 : }
333 :
334 : void
335 0 : ContainerLayerOGL::Destroy()
336 : {
337 0 : ContainerDestroy(this);
338 0 : }
339 :
340 : LayerOGL*
341 0 : ContainerLayerOGL::GetFirstChildOGL()
342 : {
343 0 : if (!mFirstChild) {
344 0 : return nsnull;
345 : }
346 0 : return static_cast<LayerOGL*>(mFirstChild->ImplData());
347 : }
348 :
349 : void
350 0 : ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
351 : const nsIntPoint& aOffset)
352 : {
353 0 : ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
354 0 : }
355 :
356 : void
357 0 : ContainerLayerOGL::CleanupResources()
358 : {
359 0 : ContainerCleanupResources(this);
360 0 : }
361 :
362 0 : ShadowContainerLayerOGL::ShadowContainerLayerOGL(LayerManagerOGL *aManager)
363 : : ShadowContainerLayer(aManager, NULL)
364 0 : , LayerOGL(aManager)
365 : {
366 0 : mImplData = static_cast<LayerOGL*>(this);
367 0 : }
368 :
369 0 : ShadowContainerLayerOGL::~ShadowContainerLayerOGL()
370 : {
371 0 : Destroy();
372 0 : }
373 :
374 : void
375 0 : ShadowContainerLayerOGL::InsertAfter(Layer* aChild, Layer* aAfter)
376 : {
377 0 : ContainerInsertAfter(this, aChild, aAfter);
378 0 : }
379 :
380 : void
381 0 : ShadowContainerLayerOGL::RemoveChild(Layer *aChild)
382 : {
383 0 : ContainerRemoveChild(this, aChild);
384 0 : }
385 :
386 : void
387 0 : ShadowContainerLayerOGL::Destroy()
388 : {
389 0 : ContainerDestroy(this);
390 0 : }
391 :
392 : LayerOGL*
393 0 : ShadowContainerLayerOGL::GetFirstChildOGL()
394 : {
395 0 : if (!mFirstChild) {
396 0 : return nsnull;
397 : }
398 0 : return static_cast<LayerOGL*>(mFirstChild->ImplData());
399 : }
400 :
401 : void
402 0 : ShadowContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
403 : const nsIntPoint& aOffset)
404 : {
405 0 : ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
406 0 : }
407 :
408 : void
409 0 : ShadowContainerLayerOGL::CleanupResources()
410 : {
411 0 : ContainerCleanupResources(this);
412 0 : }
413 :
414 : } /* layers */
415 : } /* mozilla */
|