/src/mozilla-central/gfx/layers/Compositor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "mozilla/layers/Compositor.h" |
8 | | #include "base/message_loop.h" // for MessageLoop |
9 | | #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent |
10 | | #include "mozilla/layers/Diagnostics.h" |
11 | | #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc |
12 | | #include "mozilla/layers/TextureClient.h" |
13 | | #include "mozilla/layers/TextureHost.h" |
14 | | #include "mozilla/layers/CompositorThread.h" |
15 | | #include "mozilla/mozalloc.h" // for operator delete, etc |
16 | | #include "gfx2DGlue.h" |
17 | | #include "nsAppRunner.h" |
18 | | #include "LayersHelpers.h" |
19 | | |
20 | | namespace mozilla { |
21 | | |
22 | | namespace layers { |
23 | | |
24 | | Compositor::Compositor(widget::CompositorWidget* aWidget, |
25 | | CompositorBridgeParent* aParent) |
26 | | : mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC) |
27 | | , mParent(aParent) |
28 | | , mPixelsPerFrame(0) |
29 | | , mPixelsFilled(0) |
30 | | , mScreenRotation(ROTATION_0) |
31 | | , mWidget(aWidget) |
32 | | , mIsDestroyed(false) |
33 | | #if defined(MOZ_WIDGET_ANDROID) |
34 | | // If the default color isn't white for Fennec, there is a black |
35 | | // flash before the first page of a tab is loaded. |
36 | | , mClearColor(1.0, 1.0, 1.0, 1.0) |
37 | | , mDefaultClearColor(1.0, 1.0, 1.0, 1.0) |
38 | | #else |
39 | | , mClearColor(0.0, 0.0, 0.0, 0.0) |
40 | | , mDefaultClearColor(0.0, 0.0, 0.0, 0.0) |
41 | | #endif |
42 | 0 | { |
43 | 0 | } |
44 | | |
45 | | Compositor::~Compositor() |
46 | 0 | { |
47 | 0 | ReadUnlockTextures(); |
48 | 0 | } |
49 | | |
50 | | void |
51 | | Compositor::Destroy() |
52 | 0 | { |
53 | 0 | TextureSourceProvider::Destroy(); |
54 | 0 | mIsDestroyed = true; |
55 | 0 | } |
56 | | |
57 | | void |
58 | | Compositor::EndFrame() |
59 | 0 | { |
60 | 0 | ReadUnlockTextures(); |
61 | 0 | mLastCompositionEndTime = TimeStamp::Now(); |
62 | 0 | } |
63 | | |
64 | | bool |
65 | | Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags) |
66 | 0 | { |
67 | 0 | if ((aFlags & DiagnosticFlags::TILE) && !(mDiagnosticTypes & DiagnosticTypes::TILE_BORDERS)) { |
68 | 0 | return false; |
69 | 0 | } |
70 | 0 | if ((aFlags & DiagnosticFlags::BIGIMAGE) && |
71 | 0 | !(mDiagnosticTypes & DiagnosticTypes::BIGIMAGE_BORDERS)) { |
72 | 0 | return false; |
73 | 0 | } |
74 | 0 | if (mDiagnosticTypes == DiagnosticTypes::NO_DIAGNOSTIC) { |
75 | 0 | return false; |
76 | 0 | } |
77 | 0 | return true; |
78 | 0 | } |
79 | | |
80 | | void |
81 | | Compositor::DrawDiagnostics(DiagnosticFlags aFlags, |
82 | | const nsIntRegion& aVisibleRegion, |
83 | | const gfx::IntRect& aClipRect, |
84 | | const gfx::Matrix4x4& aTransform, |
85 | | uint32_t aFlashCounter) |
86 | 0 | { |
87 | 0 | if (!ShouldDrawDiagnostics(aFlags)) { |
88 | 0 | return; |
89 | 0 | } |
90 | 0 | |
91 | 0 | if (aVisibleRegion.GetNumRects() > 1) { |
92 | 0 | for (auto iter = aVisibleRegion.RectIter(); !iter.Done(); iter.Next()) { |
93 | 0 | DrawDiagnostics(aFlags | DiagnosticFlags::REGION_RECT, |
94 | 0 | IntRectToRect(iter.Get()), aClipRect, aTransform, |
95 | 0 | aFlashCounter); |
96 | 0 | } |
97 | 0 | } |
98 | 0 |
|
99 | 0 | DrawDiagnostics(aFlags, IntRectToRect(aVisibleRegion.GetBounds()), |
100 | 0 | aClipRect, aTransform, aFlashCounter); |
101 | 0 | } |
102 | | |
103 | | void |
104 | | Compositor::DrawDiagnostics(DiagnosticFlags aFlags, |
105 | | const gfx::Rect& aVisibleRect, |
106 | | const gfx::IntRect& aClipRect, |
107 | | const gfx::Matrix4x4& aTransform, |
108 | | uint32_t aFlashCounter) |
109 | 0 | { |
110 | 0 | if (!ShouldDrawDiagnostics(aFlags)) { |
111 | 0 | return; |
112 | 0 | } |
113 | 0 | |
114 | 0 | DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform, |
115 | 0 | aFlashCounter); |
116 | 0 | } |
117 | | |
118 | | void |
119 | | Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags, |
120 | | const gfx::Rect& aVisibleRect, |
121 | | const gfx::IntRect& aClipRect, |
122 | | const gfx::Matrix4x4& aTransform, |
123 | | uint32_t aFlashCounter) |
124 | 0 | { |
125 | | #ifdef ANDROID |
126 | | int lWidth = 10; |
127 | | #else |
128 | | int lWidth = 2; |
129 | 0 | #endif |
130 | 0 |
|
131 | 0 | gfx::Color color; |
132 | 0 | if (aFlags & DiagnosticFlags::CONTENT) { |
133 | 0 | color = gfx::Color(0.0f, 1.0f, 0.0f, 1.0f); // green |
134 | 0 | if (aFlags & DiagnosticFlags::COMPONENT_ALPHA) { |
135 | 0 | color = gfx::Color(0.0f, 1.0f, 1.0f, 1.0f); // greenish blue |
136 | 0 | } |
137 | 0 | } else if (aFlags & DiagnosticFlags::IMAGE) { |
138 | 0 | if (aFlags & DiagnosticFlags::NV12) { |
139 | 0 | color = gfx::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow |
140 | 0 | } else if (aFlags & DiagnosticFlags::YCBCR) { |
141 | 0 | color = gfx::Color(1.0f, 0.55f, 0.0f, 1.0f); // orange |
142 | 0 | } else { |
143 | 0 | color = gfx::Color(1.0f, 0.0f, 0.0f, 1.0f); // red |
144 | 0 | } |
145 | 0 | } else if (aFlags & DiagnosticFlags::COLOR) { |
146 | 0 | color = gfx::Color(0.0f, 0.0f, 1.0f, 1.0f); // blue |
147 | 0 | } else if (aFlags & DiagnosticFlags::CONTAINER) { |
148 | 0 | color = gfx::Color(0.8f, 0.0f, 0.8f, 1.0f); // purple |
149 | 0 | } |
150 | 0 |
|
151 | 0 | // make tile borders a bit more transparent to keep layer borders readable. |
152 | 0 | if (aFlags & DiagnosticFlags::TILE || |
153 | 0 | aFlags & DiagnosticFlags::BIGIMAGE || |
154 | 0 | aFlags & DiagnosticFlags::REGION_RECT) { |
155 | 0 | lWidth = 1; |
156 | 0 | color.r *= 0.7f; |
157 | 0 | color.g *= 0.7f; |
158 | 0 | color.b *= 0.7f; |
159 | 0 | color.a = color.a * 0.5f; |
160 | 0 | } else { |
161 | 0 | color.a = color.a * 0.7f; |
162 | 0 | } |
163 | 0 |
|
164 | 0 |
|
165 | 0 | if (mDiagnosticTypes & DiagnosticTypes::FLASH_BORDERS) { |
166 | 0 | float flash = (float)aFlashCounter / (float)DIAGNOSTIC_FLASH_COUNTER_MAX; |
167 | 0 | color.r *= flash; |
168 | 0 | color.g *= flash; |
169 | 0 | color.b *= flash; |
170 | 0 | } |
171 | 0 |
|
172 | 0 | SlowDrawRect(aVisibleRect, color, aClipRect, aTransform, lWidth); |
173 | 0 | } |
174 | | |
175 | | static void |
176 | | UpdateTextureCoordinates(gfx::TexturedTriangle& aTriangle, |
177 | | const gfx::Rect& aRect, |
178 | | const gfx::Rect& aIntersection, |
179 | | const gfx::Rect& aTextureCoords) |
180 | 0 | { |
181 | 0 | // Calculate the relative offset of the intersection within the layer. |
182 | 0 | float dx = (aIntersection.X() - aRect.X()) / aRect.Width(); |
183 | 0 | float dy = (aIntersection.Y() - aRect.Y()) / aRect.Height(); |
184 | 0 |
|
185 | 0 | // Update the texture offset. |
186 | 0 | float x = aTextureCoords.X() + dx * aTextureCoords.Width(); |
187 | 0 | float y = aTextureCoords.Y() + dy * aTextureCoords.Height(); |
188 | 0 |
|
189 | 0 | // Scale the texture width and height. |
190 | 0 | float w = aTextureCoords.Width() * aIntersection.Width() / aRect.Width(); |
191 | 0 | float h = aTextureCoords.Height() * aIntersection.Height() / aRect.Height(); |
192 | 0 |
|
193 | 0 | static const auto Clamp = [](float& f) |
194 | 0 | { |
195 | 0 | if (f >= 1.0f) f = 1.0f; |
196 | 0 | if (f <= 0.0f) f = 0.0f; |
197 | 0 | }; |
198 | 0 |
|
199 | 0 | auto UpdatePoint = [&](const gfx::Point& p, gfx::Point& t) |
200 | 0 | { |
201 | 0 | t.x = x + (p.x - aIntersection.X()) / aIntersection.Width() * w; |
202 | 0 | t.y = y + (p.y - aIntersection.Y()) / aIntersection.Height() * h; |
203 | 0 |
|
204 | 0 | Clamp(t.x); |
205 | 0 | Clamp(t.y); |
206 | 0 | }; |
207 | 0 |
|
208 | 0 | UpdatePoint(aTriangle.p1, aTriangle.textureCoords.p1); |
209 | 0 | UpdatePoint(aTriangle.p2, aTriangle.textureCoords.p2); |
210 | 0 | UpdatePoint(aTriangle.p3, aTriangle.textureCoords.p3); |
211 | 0 | } |
212 | | |
213 | | void |
214 | | Compositor::DrawGeometry(const gfx::Rect& aRect, |
215 | | const gfx::IntRect& aClipRect, |
216 | | const EffectChain& aEffectChain, |
217 | | gfx::Float aOpacity, |
218 | | const gfx::Matrix4x4& aTransform, |
219 | | const gfx::Rect& aVisibleRect, |
220 | | const Maybe<gfx::Polygon>& aGeometry) |
221 | 0 | { |
222 | 0 | if (aRect.IsEmpty()) { |
223 | 0 | return; |
224 | 0 | } |
225 | 0 | |
226 | 0 | if (!aGeometry || !SupportsLayerGeometry()) { |
227 | 0 | DrawQuad(aRect, aClipRect, aEffectChain, |
228 | 0 | aOpacity, aTransform, aVisibleRect); |
229 | 0 | return; |
230 | 0 | } |
231 | 0 | |
232 | 0 | // Cull completely invisible polygons. |
233 | 0 | if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) { |
234 | 0 | return; |
235 | 0 | } |
236 | 0 | |
237 | 0 | const gfx::Polygon clipped = aGeometry->ClipPolygon(aRect); |
238 | 0 |
|
239 | 0 | // Cull polygons with no area. |
240 | 0 | if (clipped.IsEmpty()) { |
241 | 0 | return; |
242 | 0 | } |
243 | 0 | |
244 | 0 | DrawPolygon(clipped, aRect, aClipRect, aEffectChain, |
245 | 0 | aOpacity, aTransform, aVisibleRect); |
246 | 0 | } |
247 | | |
248 | | void |
249 | | Compositor::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles, |
250 | | const gfx::Rect& aRect, |
251 | | const gfx::IntRect& aClipRect, |
252 | | const EffectChain& aEffectChain, |
253 | | gfx::Float aOpacity, |
254 | | const gfx::Matrix4x4& aTransform, |
255 | | const gfx::Rect& aVisibleRect) |
256 | 0 | { |
257 | 0 | for (const gfx::TexturedTriangle& triangle : aTriangles) { |
258 | 0 | DrawTriangle(triangle, aClipRect, aEffectChain, |
259 | 0 | aOpacity, aTransform, aVisibleRect); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | nsTArray<gfx::TexturedTriangle> |
264 | | GenerateTexturedTriangles(const gfx::Polygon& aPolygon, |
265 | | const gfx::Rect& aRect, |
266 | | const gfx::Rect& aTexRect) |
267 | 0 | { |
268 | 0 | nsTArray<gfx::TexturedTriangle> texturedTriangles; |
269 | 0 |
|
270 | 0 | gfx::Rect layerRects[4]; |
271 | 0 | gfx::Rect textureRects[4]; |
272 | 0 | size_t rects = DecomposeIntoNoRepeatRects(aRect, aTexRect, |
273 | 0 | &layerRects, &textureRects); |
274 | 0 | for (size_t i = 0; i < rects; ++i) { |
275 | 0 | const gfx::Rect& rect = layerRects[i]; |
276 | 0 | const gfx::Rect& texRect = textureRects[i]; |
277 | 0 | const gfx::Polygon clipped = aPolygon.ClipPolygon(rect); |
278 | 0 |
|
279 | 0 | if (clipped.IsEmpty()) { |
280 | 0 | continue; |
281 | 0 | } |
282 | 0 | |
283 | 0 | for (const gfx::Triangle& triangle : clipped.ToTriangles()) { |
284 | 0 | const gfx::Rect intersection = rect.Intersect(triangle.BoundingBox()); |
285 | 0 |
|
286 | 0 | // Cull completely invisible triangles. |
287 | 0 | if (intersection.IsEmpty()) { |
288 | 0 | continue; |
289 | 0 | } |
290 | 0 | |
291 | 0 | MOZ_ASSERT(rect.Width() > 0.0f && rect.Height() > 0.0f); |
292 | 0 | MOZ_ASSERT(intersection.Width() > 0.0f && intersection.Height() > 0.0f); |
293 | 0 |
|
294 | 0 | // Since the texture was created for non-split geometry, we need to |
295 | 0 | // update the texture coordinates to account for the split. |
296 | 0 | gfx::TexturedTriangle t(triangle); |
297 | 0 | UpdateTextureCoordinates(t, rect, intersection, texRect); |
298 | 0 | texturedTriangles.AppendElement(std::move(t)); |
299 | 0 | } |
300 | 0 | } |
301 | 0 |
|
302 | 0 | return texturedTriangles; |
303 | 0 | } |
304 | | |
305 | | nsTArray<TexturedVertex> |
306 | | TexturedTrianglesToVertexArray(const nsTArray<gfx::TexturedTriangle>& aTriangles) |
307 | 0 | { |
308 | 0 | const auto VertexFromPoints = [](const gfx::Point& p, const gfx::Point& t) { |
309 | 0 | return TexturedVertex { { p.x, p.y }, { t.x, t.y } }; |
310 | 0 | }; |
311 | 0 |
|
312 | 0 | nsTArray<TexturedVertex> vertices; |
313 | 0 |
|
314 | 0 | for (const gfx::TexturedTriangle& t : aTriangles) { |
315 | 0 | vertices.AppendElement(VertexFromPoints(t.p1, t.textureCoords.p1)); |
316 | 0 | vertices.AppendElement(VertexFromPoints(t.p2, t.textureCoords.p2)); |
317 | 0 | vertices.AppendElement(VertexFromPoints(t.p3, t.textureCoords.p3)); |
318 | 0 | } |
319 | 0 |
|
320 | 0 | return vertices; |
321 | 0 | } |
322 | | |
323 | | void |
324 | | Compositor::DrawPolygon(const gfx::Polygon& aPolygon, |
325 | | const gfx::Rect& aRect, |
326 | | const gfx::IntRect& aClipRect, |
327 | | const EffectChain& aEffectChain, |
328 | | gfx::Float aOpacity, |
329 | | const gfx::Matrix4x4& aTransform, |
330 | | const gfx::Rect& aVisibleRect) |
331 | 0 | { |
332 | 0 | nsTArray<gfx::TexturedTriangle> texturedTriangles; |
333 | 0 |
|
334 | 0 | TexturedEffect* texturedEffect = |
335 | 0 | aEffectChain.mPrimaryEffect->AsTexturedEffect(); |
336 | 0 |
|
337 | 0 | if (texturedEffect) { |
338 | 0 | texturedTriangles = |
339 | 0 | GenerateTexturedTriangles(aPolygon, aRect, texturedEffect->mTextureCoords); |
340 | 0 | } else { |
341 | 0 | for (const gfx::Triangle& triangle : aPolygon.ToTriangles()) { |
342 | 0 | texturedTriangles.AppendElement(gfx::TexturedTriangle(triangle)); |
343 | 0 | } |
344 | 0 | } |
345 | 0 |
|
346 | 0 | if (texturedTriangles.IsEmpty()) { |
347 | 0 | // Nothing to render. |
348 | 0 | return; |
349 | 0 | } |
350 | 0 | |
351 | 0 | DrawTriangles(texturedTriangles, aRect, aClipRect, aEffectChain, |
352 | 0 | aOpacity, aTransform, aVisibleRect); |
353 | 0 | } |
354 | | |
355 | | void |
356 | | Compositor::SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& aColor, |
357 | | const gfx::IntRect& aClipRect, |
358 | | const gfx::Matrix4x4& aTransform, int aStrokeWidth) |
359 | 0 | { |
360 | 0 | // TODO This should draw a rect using a single draw call but since |
361 | 0 | // this is only used for debugging overlays it's not worth optimizing ATM. |
362 | 0 | float opacity = 1.0f; |
363 | 0 | EffectChain effects; |
364 | 0 |
|
365 | 0 | effects.mPrimaryEffect = new EffectSolidColor(aColor); |
366 | 0 | // left |
367 | 0 | this->DrawQuad(gfx::Rect(aRect.X(), aRect.Y(), |
368 | 0 | aStrokeWidth, aRect.Height()), |
369 | 0 | aClipRect, effects, opacity, |
370 | 0 | aTransform); |
371 | 0 | // top |
372 | 0 | this->DrawQuad(gfx::Rect(aRect.X() + aStrokeWidth, aRect.Y(), |
373 | 0 | aRect.Width() - 2 * aStrokeWidth, aStrokeWidth), |
374 | 0 | aClipRect, effects, opacity, |
375 | 0 | aTransform); |
376 | 0 | // right |
377 | 0 | this->DrawQuad(gfx::Rect(aRect.XMost() - aStrokeWidth, aRect.Y(), |
378 | 0 | aStrokeWidth, aRect.Height()), |
379 | 0 | aClipRect, effects, opacity, |
380 | 0 | aTransform); |
381 | 0 | // bottom |
382 | 0 | this->DrawQuad(gfx::Rect(aRect.X() + aStrokeWidth, aRect.YMost() - aStrokeWidth, |
383 | 0 | aRect.Width() - 2 * aStrokeWidth, aStrokeWidth), |
384 | 0 | aClipRect, effects, opacity, |
385 | 0 | aTransform); |
386 | 0 | } |
387 | | |
388 | | void |
389 | | Compositor::FillRect(const gfx::Rect& aRect, const gfx::Color& aColor, |
390 | | const gfx::IntRect& aClipRect, |
391 | | const gfx::Matrix4x4& aTransform) |
392 | 0 | { |
393 | 0 | float opacity = 1.0f; |
394 | 0 | EffectChain effects; |
395 | 0 |
|
396 | 0 | effects.mPrimaryEffect = new EffectSolidColor(aColor); |
397 | 0 | this->DrawQuad(aRect, |
398 | 0 | aClipRect, effects, opacity, |
399 | 0 | aTransform); |
400 | 0 | } |
401 | | |
402 | | |
403 | | static float |
404 | | WrapTexCoord(float v) |
405 | 0 | { |
406 | 0 | // This should return values in range [0, 1.0) |
407 | 0 | return v - floorf(v); |
408 | 0 | } |
409 | | |
410 | | static void |
411 | | SetRects(size_t n, |
412 | | decomposedRectArrayT* aLayerRects, |
413 | | decomposedRectArrayT* aTextureRects, |
414 | | float x0, float y0, float x1, float y1, |
415 | | float tx0, float ty0, float tx1, float ty1, |
416 | | bool flip_y) |
417 | 0 | { |
418 | 0 | if (flip_y) { |
419 | 0 | std::swap(ty0, ty1); |
420 | 0 | } |
421 | 0 | (*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0); |
422 | 0 | (*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0); |
423 | 0 | } |
424 | | |
425 | | #ifdef DEBUG |
426 | | static inline bool |
427 | | FuzzyEqual(float a, float b) |
428 | | { |
429 | | return fabs(a - b) < 0.0001f; |
430 | | } |
431 | | static inline bool |
432 | | FuzzyLTE(float a, float b) |
433 | | { |
434 | | return a <= b + 0.0001f; |
435 | | } |
436 | | #endif |
437 | | |
438 | | size_t |
439 | | DecomposeIntoNoRepeatRects(const gfx::Rect& aRect, |
440 | | const gfx::Rect& aTexCoordRect, |
441 | | decomposedRectArrayT* aLayerRects, |
442 | | decomposedRectArrayT* aTextureRects) |
443 | 0 | { |
444 | 0 | gfx::Rect texCoordRect = aTexCoordRect; |
445 | 0 |
|
446 | 0 | // If the texture should be flipped, it will have negative height. Detect that |
447 | 0 | // here and compensate for it. We will flip each rect as we emit it. |
448 | 0 | bool flipped = false; |
449 | 0 | if (texCoordRect.Height() < 0) { |
450 | 0 | flipped = true; |
451 | 0 | texCoordRect.MoveByY(texCoordRect.Height()); |
452 | 0 | texCoordRect.SetHeight(-texCoordRect.Height()); |
453 | 0 | } |
454 | 0 |
|
455 | 0 | // Wrap the texture coordinates so they are within [0,1] and cap width/height |
456 | 0 | // at 1. We rely on this below. |
457 | 0 | texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.X()), |
458 | 0 | WrapTexCoord(texCoordRect.Y())), |
459 | 0 | gfx::Size(std::min(texCoordRect.Width(), 1.0f), |
460 | 0 | std::min(texCoordRect.Height(), 1.0f))); |
461 | 0 |
|
462 | 0 | NS_ASSERTION(texCoordRect.X() >= 0.0f && texCoordRect.X() <= 1.0f && |
463 | 0 | texCoordRect.Y() >= 0.0f && texCoordRect.Y() <= 1.0f && |
464 | 0 | texCoordRect.Width() >= 0.0f && texCoordRect.Width() <= 1.0f && |
465 | 0 | texCoordRect.Height() >= 0.0f && texCoordRect.Height() <= 1.0f && |
466 | 0 | texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f && |
467 | 0 | texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f, |
468 | 0 | "We just wrapped the texture coordinates, didn't we?"); |
469 | 0 |
|
470 | 0 | // Get the top left and bottom right points of the rectangle. Note that |
471 | 0 | // tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2]. |
472 | 0 | gfx::Point tl = texCoordRect.TopLeft(); |
473 | 0 | gfx::Point br = texCoordRect.BottomRight(); |
474 | 0 |
|
475 | 0 | NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f && |
476 | 0 | tl.y >= 0.0f && tl.y <= 1.0f && |
477 | 0 | br.x >= tl.x && br.x <= 2.0f && |
478 | 0 | br.y >= tl.y && br.y <= 2.0f && |
479 | 0 | FuzzyLTE(br.x - tl.x, 1.0f) && |
480 | 0 | FuzzyLTE(br.y - tl.y, 1.0f), |
481 | 0 | "Somehow generated invalid texture coordinates"); |
482 | 0 |
|
483 | 0 | // Then check if we wrap in either the x or y axis. |
484 | 0 | bool xwrap = br.x > 1.0f; |
485 | 0 | bool ywrap = br.y > 1.0f; |
486 | 0 |
|
487 | 0 | // If xwrap is false, the texture will be sampled from tl.x .. br.x. |
488 | 0 | // If xwrap is true, then it will be split into tl.x .. 1.0, and |
489 | 0 | // 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination |
490 | 0 | // rectangle is also split appropriately, according to the calculated |
491 | 0 | // xmid/ymid values. |
492 | 0 | if (!xwrap && !ywrap) { |
493 | 0 | SetRects(0, aLayerRects, aTextureRects, |
494 | 0 | aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost(), |
495 | 0 | tl.x, tl.y, br.x, br.y, |
496 | 0 | flipped); |
497 | 0 | return 1; |
498 | 0 | } |
499 | 0 | |
500 | 0 | // If we are dealing with wrapping br.x and br.y are greater than 1.0 so |
501 | 0 | // wrap them here as well. |
502 | 0 | br = gfx::Point(xwrap ? WrapTexCoord(br.x) : br.x, |
503 | 0 | ywrap ? WrapTexCoord(br.y) : br.y); |
504 | 0 |
|
505 | 0 | // If we wrap around along the x axis, we will draw first from |
506 | 0 | // tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above). |
507 | 0 | // The same applies for the Y axis. The midpoints we calculate here are |
508 | 0 | // only valid if we actually wrap around. |
509 | 0 | GLfloat xmid = aRect.X() + (1.0f - tl.x) / texCoordRect.Width() * aRect.Width(); |
510 | 0 | GLfloat ymid = aRect.Y() + (1.0f - tl.y) / texCoordRect.Height() * aRect.Height(); |
511 | 0 |
|
512 | 0 | // Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y |
513 | 0 | // to calculate width and height, respectively, to ensure that size will |
514 | 0 | // remain consistent going from absolute to relative and back again. |
515 | 0 | NS_ASSERTION(!xwrap || |
516 | 0 | (xmid >= aRect.X() && |
517 | 0 | xmid <= aRect.XMost() && |
518 | 0 | FuzzyEqual((xmid - aRect.X()) + (aRect.XMost() - xmid), aRect.XMost() - aRect.X())), |
519 | 0 | "xmid should be within [x,XMost()] and the wrapped rect should have the same width"); |
520 | 0 | NS_ASSERTION(!ywrap || |
521 | 0 | (ymid >= aRect.Y() && |
522 | 0 | ymid <= aRect.YMost() && |
523 | 0 | FuzzyEqual((ymid - aRect.Y()) + (aRect.YMost() - ymid), aRect.YMost() - aRect.Y())), |
524 | 0 | "ymid should be within [y,YMost()] and the wrapped rect should have the same height"); |
525 | 0 |
|
526 | 0 | if (!xwrap && ywrap) { |
527 | 0 | SetRects(0, aLayerRects, aTextureRects, |
528 | 0 | aRect.X(), aRect.Y(), aRect.XMost(), ymid, |
529 | 0 | tl.x, tl.y, br.x, 1.0f, |
530 | 0 | flipped); |
531 | 0 | SetRects(1, aLayerRects, aTextureRects, |
532 | 0 | aRect.X(), ymid, aRect.XMost(), aRect.YMost(), |
533 | 0 | tl.x, 0.0f, br.x, br.y, |
534 | 0 | flipped); |
535 | 0 | return 2; |
536 | 0 | } |
537 | 0 | |
538 | 0 | if (xwrap && !ywrap) { |
539 | 0 | SetRects(0, aLayerRects, aTextureRects, |
540 | 0 | aRect.X(), aRect.Y(), xmid, aRect.YMost(), |
541 | 0 | tl.x, tl.y, 1.0f, br.y, |
542 | 0 | flipped); |
543 | 0 | SetRects(1, aLayerRects, aTextureRects, |
544 | 0 | xmid, aRect.Y(), aRect.XMost(), aRect.YMost(), |
545 | 0 | 0.0f, tl.y, br.x, br.y, |
546 | 0 | flipped); |
547 | 0 | return 2; |
548 | 0 | } |
549 | 0 | |
550 | 0 | SetRects(0, aLayerRects, aTextureRects, |
551 | 0 | aRect.X(), aRect.Y(), xmid, ymid, |
552 | 0 | tl.x, tl.y, 1.0f, 1.0f, |
553 | 0 | flipped); |
554 | 0 | SetRects(1, aLayerRects, aTextureRects, |
555 | 0 | xmid, aRect.Y(), aRect.XMost(), ymid, |
556 | 0 | 0.0f, tl.y, br.x, 1.0f, |
557 | 0 | flipped); |
558 | 0 | SetRects(2, aLayerRects, aTextureRects, |
559 | 0 | aRect.X(), ymid, xmid, aRect.YMost(), |
560 | 0 | tl.x, 0.0f, 1.0f, br.y, |
561 | 0 | flipped); |
562 | 0 | SetRects(3, aLayerRects, aTextureRects, |
563 | 0 | xmid, ymid, aRect.XMost(), aRect.YMost(), |
564 | 0 | 0.0f, 0.0f, br.x, br.y, |
565 | 0 | flipped); |
566 | 0 | return 4; |
567 | 0 | } |
568 | | |
569 | | gfx::IntRect |
570 | | Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect, |
571 | | const gfx::IntRect& aClipRect, |
572 | | const gfx::Matrix4x4& aTransform, |
573 | | gfx::Matrix4x4* aOutTransform, |
574 | | gfx::Rect* aOutLayerQuad) |
575 | 0 | { |
576 | 0 | // Compute the clip. |
577 | 0 | gfx::IntPoint rtOffset = GetCurrentRenderTarget()->GetOrigin(); |
578 | 0 | gfx::IntSize rtSize = GetCurrentRenderTarget()->GetSize(); |
579 | 0 |
|
580 | 0 | return layers::ComputeBackdropCopyRect( |
581 | 0 | aRect, |
582 | 0 | aClipRect, |
583 | 0 | aTransform, |
584 | 0 | gfx::IntRect(rtOffset, rtSize), |
585 | 0 | aOutTransform, |
586 | 0 | aOutLayerQuad); |
587 | 0 | } |
588 | | |
589 | | gfx::IntRect |
590 | | Compositor::ComputeBackdropCopyRect(const gfx::Triangle& aTriangle, |
591 | | const gfx::IntRect& aClipRect, |
592 | | const gfx::Matrix4x4& aTransform, |
593 | | gfx::Matrix4x4* aOutTransform, |
594 | | gfx::Rect* aOutLayerQuad) |
595 | 0 | { |
596 | 0 | gfx::Rect boundingBox = aTriangle.BoundingBox(); |
597 | 0 | return ComputeBackdropCopyRect(boundingBox, aClipRect, aTransform, |
598 | 0 | aOutTransform, aOutLayerQuad); |
599 | 0 | } |
600 | | |
601 | | void |
602 | | Compositor::SetInvalid() |
603 | 0 | { |
604 | 0 | mParent = nullptr; |
605 | 0 | } |
606 | | |
607 | | bool |
608 | | Compositor::IsValid() const |
609 | 0 | { |
610 | 0 | return !!mParent; |
611 | 0 | } |
612 | | |
613 | | void |
614 | | Compositor::UnlockAfterComposition(TextureHost* aTexture) |
615 | 0 | { |
616 | 0 | TextureSourceProvider::UnlockAfterComposition(aTexture); |
617 | 0 |
|
618 | 0 | // If this is being called after we shutdown the compositor, we must finish |
619 | 0 | // read unlocking now to prevent a cycle. |
620 | 0 | if (IsDestroyed()) { |
621 | 0 | ReadUnlockTextures(); |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | | bool |
626 | | Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost) |
627 | 0 | { |
628 | 0 | if (IsDestroyed() || AsBasicCompositor()) { |
629 | 0 | return false; |
630 | 0 | } |
631 | 0 | return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost); |
632 | 0 | } |
633 | | |
634 | | void |
635 | | Compositor::GetFrameStats(GPUStats* aStats) |
636 | 0 | { |
637 | 0 | aStats->mInvalidPixels = mPixelsPerFrame; |
638 | 0 | aStats->mPixelsFilled = mPixelsFilled; |
639 | 0 | } |
640 | | |
641 | | } // namespace layers |
642 | | } // namespace mozilla |