/src/mozilla-central/gfx/layers/basic/BasicCompositor.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 "BasicCompositor.h" |
8 | | #include "BasicLayersImpl.h" // for FillRectWithMask |
9 | | #include "TextureHostBasic.h" |
10 | | #include "mozilla/layers/Effects.h" |
11 | | #include "nsIWidget.h" |
12 | | #include "gfx2DGlue.h" |
13 | | #include "mozilla/gfx/2D.h" |
14 | | #include "mozilla/gfx/gfxVars.h" |
15 | | #include "mozilla/gfx/Helpers.h" |
16 | | #include "mozilla/gfx/Tools.h" |
17 | | #include "mozilla/gfx/ssse3-scaler.h" |
18 | | #include "mozilla/layers/ImageDataSerializer.h" |
19 | | #include "mozilla/SSE.h" |
20 | | #include "gfxUtils.h" |
21 | | #include "YCbCrUtils.h" |
22 | | #include <algorithm> |
23 | | #include "ImageContainer.h" |
24 | | #include "gfxPrefs.h" |
25 | | |
26 | | namespace mozilla { |
27 | | using namespace mozilla::gfx; |
28 | | |
29 | | namespace layers { |
30 | | |
31 | | class DataTextureSourceBasic : public DataTextureSource |
32 | | , public TextureSourceBasic |
33 | | { |
34 | | public: |
35 | 0 | virtual const char* Name() const override { return "DataTextureSourceBasic"; } |
36 | | |
37 | | explicit DataTextureSourceBasic(DataSourceSurface* aSurface) |
38 | | : mSurface(aSurface) |
39 | | , mWrappingExistingData(!!aSurface) |
40 | 0 | {} |
41 | | |
42 | | virtual DataTextureSource* AsDataTextureSource() override |
43 | 0 | { |
44 | 0 | // If the texture wraps someone else's memory we'd rather not use it as |
45 | 0 | // a DataTextureSource per say (that is call Update on it). |
46 | 0 | return mWrappingExistingData ? nullptr : this; |
47 | 0 | } |
48 | | |
49 | 0 | virtual TextureSourceBasic* AsSourceBasic() override { return this; } |
50 | | |
51 | 0 | virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) override { return mSurface; } |
52 | | |
53 | | SurfaceFormat GetFormat() const override |
54 | 0 | { |
55 | 0 | return mSurface ? mSurface->GetFormat() : gfx::SurfaceFormat::UNKNOWN; |
56 | 0 | } |
57 | | |
58 | | virtual IntSize GetSize() const override |
59 | 0 | { |
60 | 0 | return mSurface ? mSurface->GetSize() : gfx::IntSize(0, 0); |
61 | 0 | } |
62 | | |
63 | | virtual bool Update(gfx::DataSourceSurface* aSurface, |
64 | | nsIntRegion* aDestRegion = nullptr, |
65 | | gfx::IntPoint* aSrcOffset = nullptr) override |
66 | 0 | { |
67 | 0 | MOZ_ASSERT(!mWrappingExistingData); |
68 | 0 | if (mWrappingExistingData) { |
69 | 0 | return false; |
70 | 0 | } |
71 | 0 | mSurface = aSurface; |
72 | 0 | return true; |
73 | 0 | } |
74 | | |
75 | | virtual void DeallocateDeviceData() override |
76 | 0 | { |
77 | 0 | mSurface = nullptr; |
78 | 0 | SetUpdateSerial(0); |
79 | 0 | } |
80 | | |
81 | | public: |
82 | | RefPtr<gfx::DataSourceSurface> mSurface; |
83 | | bool mWrappingExistingData; |
84 | | }; |
85 | | |
86 | | /** |
87 | | * WrappingTextureSourceYCbCrBasic wraps YUV format BufferTextureHost to defer |
88 | | * yuv->rgb conversion. The conversion happens when GetSurface is called. |
89 | | */ |
90 | | class WrappingTextureSourceYCbCrBasic : public DataTextureSource |
91 | | , public TextureSourceBasic |
92 | | { |
93 | | public: |
94 | 0 | virtual const char* Name() const override { return "WrappingTextureSourceYCbCrBasic"; } |
95 | | |
96 | | explicit WrappingTextureSourceYCbCrBasic(BufferTextureHost* aTexture) |
97 | | : mTexture(aTexture) |
98 | | , mSize(aTexture->GetSize()) |
99 | | , mNeedsUpdate(true) |
100 | 0 | { |
101 | 0 | mFromYCBCR = true; |
102 | 0 | } |
103 | | |
104 | | virtual DataTextureSource* AsDataTextureSource() override |
105 | 0 | { |
106 | 0 | return this; |
107 | 0 | } |
108 | | |
109 | 0 | virtual TextureSourceBasic* AsSourceBasic() override { return this; } |
110 | | |
111 | 0 | virtual WrappingTextureSourceYCbCrBasic* AsWrappingTextureSourceYCbCrBasic() override { return this; } |
112 | | |
113 | | virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) override |
114 | 0 | { |
115 | 0 | if (mSurface && !mNeedsUpdate) { |
116 | 0 | return mSurface; |
117 | 0 | } |
118 | 0 | MOZ_ASSERT(mTexture); |
119 | 0 | if (!mTexture) { |
120 | 0 | return nullptr; |
121 | 0 | } |
122 | 0 | |
123 | 0 | if (!mSurface) { |
124 | 0 | mSurface = Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); |
125 | 0 | } |
126 | 0 | if (!mSurface) { |
127 | 0 | return nullptr; |
128 | 0 | } |
129 | 0 | MOZ_ASSERT(mTexture->GetBufferDescriptor().type() == BufferDescriptor::TYCbCrDescriptor); |
130 | 0 | MOZ_ASSERT(mTexture->GetSize() == mSize); |
131 | 0 |
|
132 | 0 | mSurface = |
133 | 0 | ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor( |
134 | 0 | mTexture->GetBuffer(), |
135 | 0 | mTexture->GetBufferDescriptor().get_YCbCrDescriptor(), |
136 | 0 | mSurface); |
137 | 0 | mNeedsUpdate = false; |
138 | 0 | return mSurface; |
139 | 0 | } |
140 | | |
141 | | SurfaceFormat GetFormat() const override |
142 | 0 | { |
143 | 0 | return gfx::SurfaceFormat::B8G8R8X8; |
144 | 0 | } |
145 | | |
146 | | virtual IntSize GetSize() const override |
147 | 0 | { |
148 | 0 | return mSize; |
149 | 0 | } |
150 | | |
151 | | virtual bool Update(gfx::DataSourceSurface* aSurface, |
152 | | nsIntRegion* aDestRegion = nullptr, |
153 | | gfx::IntPoint* aSrcOffset = nullptr) override |
154 | 0 | { |
155 | 0 | return false; |
156 | 0 | } |
157 | | |
158 | | virtual void DeallocateDeviceData() override |
159 | 0 | { |
160 | 0 | mTexture = nullptr; |
161 | 0 | mSurface = nullptr; |
162 | 0 | SetUpdateSerial(0); |
163 | 0 | } |
164 | | |
165 | | virtual void Unbind() override |
166 | 0 | { |
167 | 0 | mNeedsUpdate = true; |
168 | 0 | } |
169 | | |
170 | | void SetBufferTextureHost(BufferTextureHost* aTexture) override |
171 | 0 | { |
172 | 0 | mTexture = aTexture; |
173 | 0 | mNeedsUpdate = true; |
174 | 0 | } |
175 | | |
176 | | void ConvertAndScale(const SurfaceFormat& aDestFormat, |
177 | | const IntSize& aDestSize, |
178 | | unsigned char* aDestBuffer, |
179 | | int32_t aStride) |
180 | 0 | { |
181 | 0 | MOZ_ASSERT(mTexture); |
182 | 0 | if (!mTexture) { |
183 | 0 | return; |
184 | 0 | } |
185 | 0 | MOZ_ASSERT(mTexture->GetBufferDescriptor().type() == BufferDescriptor::TYCbCrDescriptor); |
186 | 0 | MOZ_ASSERT(mTexture->GetSize() == mSize); |
187 | 0 | ImageDataSerializer::ConvertAndScaleFromYCbCrDescriptor( |
188 | 0 | mTexture->GetBuffer(), |
189 | 0 | mTexture->GetBufferDescriptor().get_YCbCrDescriptor(), |
190 | 0 | aDestFormat, |
191 | 0 | aDestSize, |
192 | 0 | aDestBuffer, |
193 | 0 | aStride); |
194 | 0 | } |
195 | | public: |
196 | | BufferTextureHost* mTexture; |
197 | | const gfx::IntSize mSize; |
198 | | RefPtr<gfx::DataSourceSurface> mSurface; |
199 | | bool mNeedsUpdate; |
200 | | }; |
201 | | |
202 | | BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget) |
203 | | : Compositor(aWidget, aParent) |
204 | | , mIsPendingEndRemoteDrawing(false) |
205 | 0 | { |
206 | 0 | MOZ_COUNT_CTOR(BasicCompositor); |
207 | 0 |
|
208 | 0 | mMaxTextureSize = Factory::GetMaxSurfaceSize(gfxVars::ContentBackend()); |
209 | 0 | } |
210 | | |
211 | | BasicCompositor::~BasicCompositor() |
212 | 0 | { |
213 | 0 | MOZ_COUNT_DTOR(BasicCompositor); |
214 | 0 | } |
215 | | |
216 | | bool |
217 | | BasicCompositor::Initialize(nsCString* const out_failureReason) |
218 | 0 | { |
219 | 0 | return mWidget ? mWidget->InitCompositor(this) : false; |
220 | 0 | }; |
221 | | |
222 | | int32_t |
223 | | BasicCompositor::GetMaxTextureSize() const |
224 | 0 | { |
225 | 0 | return mMaxTextureSize; |
226 | 0 | } |
227 | | |
228 | | void |
229 | | BasicCompositingRenderTarget::BindRenderTarget() |
230 | 0 | { |
231 | 0 | if (mClearOnBind) { |
232 | 0 | mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height)); |
233 | 0 | mClearOnBind = false; |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | void BasicCompositor::DetachWidget() |
238 | 0 | { |
239 | 0 | if (mWidget) { |
240 | 0 | if (mIsPendingEndRemoteDrawing) { |
241 | 0 | // Force to end previous remote drawing. |
242 | 0 | TryToEndRemoteDrawing(/* aForceToEnd */ true); |
243 | 0 | MOZ_ASSERT(!mIsPendingEndRemoteDrawing); |
244 | 0 | } |
245 | 0 | mWidget->CleanupRemoteDrawing(); |
246 | 0 | } |
247 | 0 | Compositor::DetachWidget(); |
248 | 0 | } |
249 | | |
250 | | TextureFactoryIdentifier |
251 | | BasicCompositor::GetTextureFactoryIdentifier() |
252 | 0 | { |
253 | 0 | TextureFactoryIdentifier ident(LayersBackend::LAYERS_BASIC, |
254 | 0 | XRE_GetProcessType(), |
255 | 0 | GetMaxTextureSize()); |
256 | 0 | return ident; |
257 | 0 | } |
258 | | |
259 | | already_AddRefed<CompositingRenderTarget> |
260 | | BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit) |
261 | 0 | { |
262 | 0 | MOZ_ASSERT(!aRect.IsZeroArea(), "Trying to create a render target of invalid size"); |
263 | 0 |
|
264 | 0 | if (aRect.IsZeroArea()) { |
265 | 0 | return nullptr; |
266 | 0 | } |
267 | 0 | |
268 | 0 | RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8); |
269 | 0 |
|
270 | 0 | if (!target) { |
271 | 0 | return nullptr; |
272 | 0 | } |
273 | 0 | |
274 | 0 | RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect); |
275 | 0 |
|
276 | 0 | return rt.forget(); |
277 | 0 | } |
278 | | |
279 | | already_AddRefed<CompositingRenderTarget> |
280 | | BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect, |
281 | | const CompositingRenderTarget *aSource, |
282 | | const IntPoint &aSourcePoint) |
283 | 0 | { |
284 | 0 | MOZ_CRASH("GFX: Shouldn't be called!"); |
285 | 0 | return nullptr; |
286 | 0 | } |
287 | | |
288 | | already_AddRefed<CompositingRenderTarget> |
289 | | BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, const LayoutDeviceIntRect& aClearRect, BufferMode aBufferMode) |
290 | 0 | { |
291 | 0 | MOZ_ASSERT(mDrawTarget); |
292 | 0 | MOZ_ASSERT(!aRect.IsZeroArea(), "Trying to create a render target of invalid size"); |
293 | 0 |
|
294 | 0 | if (aRect.IsZeroArea()) { |
295 | 0 | return nullptr; |
296 | 0 | } |
297 | 0 | |
298 | 0 | RefPtr<BasicCompositingRenderTarget> rt; |
299 | 0 | IntRect rect = aRect.ToUnknownRect(); |
300 | 0 |
|
301 | 0 | if (aBufferMode != BufferMode::BUFFER_NONE) { |
302 | 0 | RefPtr<DrawTarget> target = mWidget->GetBackBufferDrawTarget(mDrawTarget, aRect, aClearRect); |
303 | 0 | if (!target) { |
304 | 0 | return nullptr; |
305 | 0 | } |
306 | 0 | MOZ_ASSERT(target != mDrawTarget); |
307 | 0 | rt = new BasicCompositingRenderTarget(target, rect); |
308 | 0 | } else { |
309 | 0 | IntRect windowRect = rect; |
310 | 0 | // Adjust bounds rect to account for new origin at (0, 0). |
311 | 0 | if (windowRect.Size() != mDrawTarget->GetSize()) { |
312 | 0 | windowRect.ExpandToEnclose(IntPoint(0, 0)); |
313 | 0 | } |
314 | 0 | rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect); |
315 | 0 | if (!aClearRect.IsEmpty()) { |
316 | 0 | IntRect clearRect = aClearRect.ToUnknownRect(); |
317 | 0 | mDrawTarget->ClearRect(Rect(clearRect - rt->GetOrigin())); |
318 | 0 | } |
319 | 0 | } |
320 | 0 |
|
321 | 0 | return rt.forget(); |
322 | 0 | } |
323 | | |
324 | | already_AddRefed<DataTextureSource> |
325 | | BasicCompositor::CreateDataTextureSource(TextureFlags aFlags) |
326 | 0 | { |
327 | 0 | RefPtr<DataTextureSourceBasic> result = new DataTextureSourceBasic(nullptr); |
328 | 0 | if (aFlags & TextureFlags::RGB_FROM_YCBCR) { |
329 | 0 | result->mFromYCBCR = true; |
330 | 0 | } |
331 | 0 | return result.forget(); |
332 | 0 | } |
333 | | |
334 | | already_AddRefed<DataTextureSource> |
335 | | BasicCompositor::CreateDataTextureSourceAround(DataSourceSurface* aSurface) |
336 | 0 | { |
337 | 0 | RefPtr<DataTextureSource> result = new DataTextureSourceBasic(aSurface); |
338 | 0 | return result.forget(); |
339 | 0 | } |
340 | | |
341 | | already_AddRefed<DataTextureSource> |
342 | | BasicCompositor::CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) |
343 | 0 | { |
344 | 0 | BufferTextureHost* bufferTexture = aTexture->AsBufferTextureHost(); |
345 | 0 | MOZ_ASSERT(bufferTexture); |
346 | 0 |
|
347 | 0 | if (!bufferTexture) { |
348 | 0 | return nullptr; |
349 | 0 | } |
350 | 0 | RefPtr<DataTextureSource> result = new WrappingTextureSourceYCbCrBasic(bufferTexture); |
351 | 0 | return result.forget(); |
352 | 0 | } |
353 | | |
354 | | bool |
355 | | BasicCompositor::SupportsEffect(EffectTypes aEffect) |
356 | 0 | { |
357 | 0 | return aEffect != EffectTypes::YCBCR && aEffect != EffectTypes::COMPONENT_ALPHA; |
358 | 0 | } |
359 | | |
360 | | bool |
361 | | BasicCompositor::SupportsLayerGeometry() const |
362 | 0 | { |
363 | 0 | return gfxPrefs::BasicLayerGeometry(); |
364 | 0 | } |
365 | | |
366 | | static RefPtr<gfx::Path> |
367 | | BuildPathFromPolygon(const RefPtr<DrawTarget>& aDT, |
368 | | const gfx::Polygon& aPolygon) |
369 | 0 | { |
370 | 0 | MOZ_ASSERT(!aPolygon.IsEmpty()); |
371 | 0 |
|
372 | 0 | RefPtr<PathBuilder> pathBuilder = aDT->CreatePathBuilder(); |
373 | 0 | const nsTArray<Point4D>& points = aPolygon.GetPoints(); |
374 | 0 |
|
375 | 0 | pathBuilder->MoveTo(points[0].As2DPoint()); |
376 | 0 |
|
377 | 0 | for (size_t i = 1; i < points.Length(); ++i) { |
378 | 0 | pathBuilder->LineTo(points[i].As2DPoint()); |
379 | 0 | } |
380 | 0 |
|
381 | 0 | pathBuilder->Close(); |
382 | 0 | return pathBuilder->Finish(); |
383 | 0 | } |
384 | | |
385 | | static void |
386 | | DrawSurface(gfx::DrawTarget* aDest, |
387 | | const gfx::Rect& aDestRect, |
388 | | const gfx::Rect& /* aClipRect */, |
389 | | const gfx::Color& aColor, |
390 | | const gfx::DrawOptions& aOptions, |
391 | | gfx::SourceSurface* aMask, |
392 | | const gfx::Matrix* aMaskTransform) |
393 | 0 | { |
394 | 0 | FillRectWithMask(aDest, aDestRect, aColor, |
395 | 0 | aOptions, aMask, aMaskTransform); |
396 | 0 | } |
397 | | |
398 | | static void |
399 | | DrawSurface(gfx::DrawTarget* aDest, |
400 | | const gfx::Polygon& aPolygon, |
401 | | const gfx::Rect& aClipRect, |
402 | | const gfx::Color& aColor, |
403 | | const gfx::DrawOptions& aOptions, |
404 | | gfx::SourceSurface* aMask, |
405 | | const gfx::Matrix* aMaskTransform) |
406 | 0 | { |
407 | 0 | RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon); |
408 | 0 | FillPathWithMask(aDest, path, aClipRect, aColor, |
409 | 0 | aOptions, aMask, aMaskTransform); |
410 | 0 | } |
411 | | |
412 | | static void |
413 | | DrawTextureSurface(gfx::DrawTarget* aDest, |
414 | | const gfx::Rect& aDestRect, |
415 | | const gfx::Rect& /* aClipRect */, |
416 | | gfx::SourceSurface* aSource, |
417 | | gfx::SamplingFilter aSamplingFilter, |
418 | | const gfx::DrawOptions& aOptions, |
419 | | ExtendMode aExtendMode, |
420 | | gfx::SourceSurface* aMask, |
421 | | const gfx::Matrix* aMaskTransform, |
422 | | const Matrix* aSurfaceTransform) |
423 | 0 | { |
424 | 0 | FillRectWithMask(aDest, aDestRect, aSource, aSamplingFilter, aOptions, |
425 | 0 | aExtendMode, aMask, aMaskTransform, aSurfaceTransform); |
426 | 0 | } |
427 | | |
428 | | static void |
429 | | DrawTextureSurface(gfx::DrawTarget* aDest, |
430 | | const gfx::Polygon& aPolygon, |
431 | | const gfx::Rect& aClipRect, |
432 | | gfx::SourceSurface* aSource, |
433 | | gfx::SamplingFilter aSamplingFilter, |
434 | | const gfx::DrawOptions& aOptions, |
435 | | ExtendMode aExtendMode, |
436 | | gfx::SourceSurface* aMask, |
437 | | const gfx::Matrix* aMaskTransform, |
438 | | const Matrix* aSurfaceTransform) |
439 | 0 | { |
440 | 0 | RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon); |
441 | 0 | FillPathWithMask(aDest, path, aClipRect, aSource, aSamplingFilter, aOptions, |
442 | 0 | aExtendMode, aMask, aMaskTransform, aSurfaceTransform); |
443 | 0 | } |
444 | | |
445 | | template<typename Geometry> |
446 | | static void |
447 | | DrawSurfaceWithTextureCoords(gfx::DrawTarget* aDest, |
448 | | const Geometry& aGeometry, |
449 | | const gfx::Rect& aDestRect, |
450 | | gfx::SourceSurface* aSource, |
451 | | const gfx::Rect& aTextureCoords, |
452 | | gfx::SamplingFilter aSamplingFilter, |
453 | | const gfx::DrawOptions& aOptions, |
454 | | gfx::SourceSurface* aMask, |
455 | | const gfx::Matrix* aMaskTransform) |
456 | 0 | { |
457 | 0 | if (!aSource) { |
458 | 0 | gfxWarning() << "DrawSurfaceWithTextureCoords problem " << gfx::hexa(aSource) << " and " << gfx::hexa(aMask); |
459 | 0 | return; |
460 | 0 | } |
461 | 0 |
|
462 | 0 | // Convert aTextureCoords into aSource's coordinate space |
463 | 0 | gfxRect sourceRect(aTextureCoords.X() * aSource->GetSize().width, |
464 | 0 | aTextureCoords.Y() * aSource->GetSize().height, |
465 | 0 | aTextureCoords.Width() * aSource->GetSize().width, |
466 | 0 | aTextureCoords.Height() * aSource->GetSize().height); |
467 | 0 |
|
468 | 0 | // Floating point error can accumulate above and we know our visible region |
469 | 0 | // is integer-aligned, so round it out. |
470 | 0 | sourceRect.Round(); |
471 | 0 |
|
472 | 0 | // Compute a transform that maps sourceRect to aDestRect. |
473 | 0 | Matrix matrix = |
474 | 0 | gfxUtils::TransformRectToRect(sourceRect, |
475 | 0 | gfx::IntPoint::Truncate(aDestRect.X(), aDestRect.Y()), |
476 | 0 | gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.Y()), |
477 | 0 | gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.YMost())); |
478 | 0 |
|
479 | 0 | // Only use REPEAT if aTextureCoords is outside (0, 0, 1, 1). |
480 | 0 | gfx::Rect unitRect(0, 0, 1, 1); |
481 | 0 | ExtendMode mode = unitRect.Contains(aTextureCoords) ? ExtendMode::CLAMP : ExtendMode::REPEAT; |
482 | 0 |
|
483 | 0 | DrawTextureSurface(aDest, aGeometry, aDestRect, aSource, aSamplingFilter, |
484 | 0 | aOptions, mode, aMask, aMaskTransform, &matrix); |
485 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_layers4.cpp:void mozilla::layers::DrawSurfaceWithTextureCoords<mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> >(mozilla::gfx::DrawTarget*, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::SourceSurface*, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::SamplingFilter, mozilla::gfx::DrawOptions const&, mozilla::gfx::SourceSurface*, mozilla::gfx::BaseMatrix<float> const*) Unexecuted instantiation: Unified_cpp_gfx_layers4.cpp:void mozilla::layers::DrawSurfaceWithTextureCoords<mozilla::gfx::PolygonTyped<mozilla::gfx::UnknownUnits> >(mozilla::gfx::DrawTarget*, mozilla::gfx::PolygonTyped<mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::SourceSurface*, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::SamplingFilter, mozilla::gfx::DrawOptions const&, mozilla::gfx::SourceSurface*, mozilla::gfx::BaseMatrix<float> const*) |
486 | | |
487 | | static void |
488 | | SetupMask(const EffectChain& aEffectChain, |
489 | | DrawTarget* aDest, |
490 | | const IntPoint& aOffset, |
491 | | RefPtr<SourceSurface>& aMaskSurface, |
492 | | Matrix& aMaskTransform) |
493 | 0 | { |
494 | 0 | if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { |
495 | 0 | EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get()); |
496 | 0 | aMaskSurface = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(aDest); |
497 | 0 | if (!aMaskSurface) { |
498 | 0 | gfxWarning() << "Invalid sourceMask effect"; |
499 | 0 | } |
500 | 0 | MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!"); |
501 | 0 | aMaskTransform = effectMask->mMaskTransform.As2D(); |
502 | 0 | aMaskTransform.PostTranslate(-aOffset.x, -aOffset.y); |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | | static bool |
507 | | AttemptVideoScale(TextureSourceBasic* aSource, const SourceSurface* aSourceMask, |
508 | | gfx::Float aOpacity, CompositionOp aBlendMode, |
509 | | const TexturedEffect* aTexturedEffect, |
510 | | const Matrix& aNewTransform, const gfx::Rect& aRect, |
511 | | const gfx::Rect& aClipRect, |
512 | | DrawTarget* aDest, const DrawTarget* aBuffer) |
513 | 0 | { |
514 | 0 | #ifdef MOZILLA_SSE_HAVE_CPUID_DETECTION |
515 | 0 | if (!mozilla::supports_ssse3()) |
516 | 0 | return false; |
517 | 0 | if (aNewTransform.IsTranslation()) // unscaled painting should take the regular path |
518 | 0 | return false; |
519 | 0 | if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling()) |
520 | 0 | return false; |
521 | 0 | if (aSourceMask || aOpacity != 1.0f) |
522 | 0 | return false; |
523 | 0 | if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE) |
524 | 0 | return false; |
525 | 0 | |
526 | 0 | IntRect dstRect; |
527 | 0 | // the compiler should know a lot about aNewTransform at this point |
528 | 0 | // maybe it can do some sophisticated optimization of the following |
529 | 0 | if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect)) |
530 | 0 | return false; |
531 | 0 | |
532 | 0 | IntRect clipRect; |
533 | 0 | if (!aClipRect.ToIntRect(&clipRect)) |
534 | 0 | return false; |
535 | 0 | |
536 | 0 | if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f))) |
537 | 0 | return false; |
538 | 0 | if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16) |
539 | 0 | return false; |
540 | 0 | |
541 | 0 | uint8_t* dstData; |
542 | 0 | IntSize dstSize; |
543 | 0 | int32_t dstStride; |
544 | 0 | SurfaceFormat dstFormat; |
545 | 0 | if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) { |
546 | 0 | // If we're not painting to aBuffer the clip will |
547 | 0 | // be applied later |
548 | 0 | IntRect fillRect = dstRect; |
549 | 0 | if (aDest == aBuffer) { |
550 | 0 | // we need to clip fillRect because LockBits ignores the clip on the aDest |
551 | 0 | fillRect = fillRect.Intersect(clipRect); |
552 | 0 | } |
553 | 0 |
|
554 | 0 | fillRect = fillRect.Intersect(IntRect(IntPoint(0, 0), aDest->GetSize())); |
555 | 0 | IntPoint offset = fillRect.TopLeft() - dstRect.TopLeft(); |
556 | 0 |
|
557 | 0 | RefPtr<DataSourceSurface> srcSource = aSource->GetSurface(aDest)->GetDataSurface(); |
558 | 0 | DataSourceSurface::ScopedMap mapSrc(srcSource, DataSourceSurface::READ); |
559 | 0 |
|
560 | 0 | bool success = ssse3_scale_data((uint32_t*)mapSrc.GetData(), srcSource->GetSize().width, srcSource->GetSize().height, |
561 | 0 | mapSrc.GetStride()/4, |
562 | 0 | ((uint32_t*)dstData) + fillRect.X() + (dstStride / 4) * fillRect.Y(), dstRect.Width(), dstRect.Height(), |
563 | 0 | dstStride / 4, |
564 | 0 | offset.x, offset.y, |
565 | 0 | fillRect.Width(), fillRect.Height()); |
566 | 0 |
|
567 | 0 | aDest->ReleaseBits(dstData); |
568 | 0 | return success; |
569 | 0 | } else |
570 | 0 | #endif // MOZILLA_SSE_HAVE_CPUID_DETECTION |
571 | 0 | return false; |
572 | 0 | } |
573 | | |
574 | | static bool |
575 | | AttemptVideoConvertAndScale(TextureSource* aSource, const SourceSurface* aSourceMask, |
576 | | gfx::Float aOpacity, CompositionOp aBlendMode, |
577 | | const TexturedEffect* aTexturedEffect, |
578 | | const Matrix& aNewTransform, const gfx::Rect& aRect, |
579 | | const gfx::Rect& aClipRect, |
580 | | DrawTarget* aDest, const DrawTarget* aBuffer) |
581 | 0 | { |
582 | | #if defined(XP_WIN) && defined(_M_X64) |
583 | | // libyuv does not support SIMD scaling on win 64bit. See Bug 1295927. |
584 | | return false; |
585 | | #endif |
586 | |
|
587 | 0 | WrappingTextureSourceYCbCrBasic* wrappingSource = aSource->AsWrappingTextureSourceYCbCrBasic(); |
588 | 0 | if (!wrappingSource) |
589 | 0 | return false; |
590 | 0 | #ifdef MOZILLA_SSE_HAVE_CPUID_DETECTION |
591 | 0 | if (!mozilla::supports_ssse3()) // libyuv requests SSSE3 for fast YUV conversion. |
592 | 0 | return false; |
593 | 0 | if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling()) |
594 | 0 | return false; |
595 | 0 | if (aSourceMask || aOpacity != 1.0f) |
596 | 0 | return false; |
597 | 0 | if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE) |
598 | 0 | return false; |
599 | 0 | |
600 | 0 | IntRect dstRect; |
601 | 0 | // the compiler should know a lot about aNewTransform at this point |
602 | 0 | // maybe it can do some sophisticated optimization of the following |
603 | 0 | if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect)) |
604 | 0 | return false; |
605 | 0 | |
606 | 0 | IntRect clipRect; |
607 | 0 | if (!aClipRect.ToIntRect(&clipRect)) |
608 | 0 | return false; |
609 | 0 | |
610 | 0 | if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f))) |
611 | 0 | return false; |
612 | 0 | if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16) |
613 | 0 | return false; |
614 | 0 | |
615 | 0 | if (aDest == aBuffer && !clipRect.Contains(dstRect)) |
616 | 0 | return false; |
617 | 0 | if (!IntRect(IntPoint(0, 0), aDest->GetSize()).Contains(dstRect)) |
618 | 0 | return false; |
619 | 0 | |
620 | 0 | uint8_t* dstData; |
621 | 0 | IntSize dstSize; |
622 | 0 | int32_t dstStride; |
623 | 0 | SurfaceFormat dstFormat; |
624 | 0 | if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) { |
625 | 0 | wrappingSource->ConvertAndScale(dstFormat, |
626 | 0 | dstRect.Size(), |
627 | 0 | dstData + ptrdiff_t(dstRect.X()) * BytesPerPixel(dstFormat) + ptrdiff_t(dstRect.Y()) * dstStride, |
628 | 0 | dstStride); |
629 | 0 | aDest->ReleaseBits(dstData); |
630 | 0 | return true; |
631 | 0 | } else |
632 | 0 | #endif // MOZILLA_SSE_HAVE_CPUID_DETECTION |
633 | 0 | return false; |
634 | 0 | } |
635 | | |
636 | | void |
637 | | BasicCompositor::DrawQuad(const gfx::Rect& aRect, |
638 | | const gfx::IntRect& aClipRect, |
639 | | const EffectChain &aEffectChain, |
640 | | gfx::Float aOpacity, |
641 | | const gfx::Matrix4x4& aTransform, |
642 | | const gfx::Rect& aVisibleRect) |
643 | 0 | { |
644 | 0 | DrawGeometry(aRect, aRect, aClipRect, aEffectChain, |
645 | 0 | aOpacity, aTransform, aVisibleRect, true); |
646 | 0 | } |
647 | | |
648 | | void |
649 | | BasicCompositor::DrawPolygon(const gfx::Polygon& aPolygon, |
650 | | const gfx::Rect& aRect, |
651 | | const gfx::IntRect& aClipRect, |
652 | | const EffectChain& aEffectChain, |
653 | | gfx::Float aOpacity, |
654 | | const gfx::Matrix4x4& aTransform, |
655 | | const gfx::Rect& aVisibleRect) |
656 | 0 | { |
657 | 0 | DrawGeometry(aPolygon, aRect, aClipRect, aEffectChain, |
658 | 0 | aOpacity, aTransform, aVisibleRect, false); |
659 | 0 | } |
660 | | |
661 | | |
662 | | template<typename Geometry> |
663 | | void |
664 | | BasicCompositor::DrawGeometry(const Geometry& aGeometry, |
665 | | const gfx::Rect& aRect, |
666 | | const gfx::IntRect& aClipRect, |
667 | | const EffectChain& aEffectChain, |
668 | | gfx::Float aOpacity, |
669 | | const gfx::Matrix4x4& aTransform, |
670 | | const gfx::Rect& aVisibleRect, |
671 | | const bool aEnableAA) |
672 | 0 | { |
673 | 0 | RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget; |
674 | 0 |
|
675 | 0 | // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing, |
676 | 0 | // |dest| is a temporary surface. |
677 | 0 | RefPtr<DrawTarget> dest = buffer; |
678 | 0 |
|
679 | 0 | AutoRestoreTransform autoRestoreTransform(dest); |
680 | 0 |
|
681 | 0 | Matrix newTransform; |
682 | 0 | Rect transformBounds; |
683 | 0 | Matrix4x4 new3DTransform; |
684 | 0 | IntPoint offset = mRenderTarget->GetOrigin(); |
685 | 0 |
|
686 | 0 | if (aTransform.Is2D()) { |
687 | 0 | newTransform = aTransform.As2D(); |
688 | 0 | } else { |
689 | 0 | // Create a temporary surface for the transform. |
690 | 0 | dest = Factory::CreateDrawTarget(gfxVars::ContentBackend(), RoundedOut(aRect).Size(), SurfaceFormat::B8G8R8A8); |
691 | 0 | if (!dest) { |
692 | 0 | return; |
693 | 0 | } |
694 | 0 | |
695 | 0 | dest->SetTransform(Matrix::Translation(-aRect.X(), -aRect.Y())); |
696 | 0 |
|
697 | 0 | // Get the bounds post-transform. |
698 | 0 | transformBounds = aTransform.TransformAndClipBounds(aRect, Rect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height)); |
699 | 0 | transformBounds.RoundOut(); |
700 | 0 |
|
701 | 0 | if (transformBounds.IsEmpty()) { |
702 | 0 | return; |
703 | 0 | } |
704 | 0 | |
705 | 0 | newTransform = Matrix(); |
706 | 0 |
|
707 | 0 | // When we apply the 3D transformation, we do it against a temporary |
708 | 0 | // surface, so undo the coordinate offset. |
709 | 0 | new3DTransform = aTransform; |
710 | 0 | new3DTransform.PreTranslate(aRect.X(), aRect.Y(), 0); |
711 | 0 | } |
712 | 0 |
|
713 | 0 | // XXX the transform is probably just an integer offset so this whole |
714 | 0 | // business here is a bit silly. |
715 | 0 | Rect transformedClipRect = buffer->GetTransform().TransformBounds(Rect(aClipRect)); |
716 | 0 |
|
717 | 0 | buffer->PushClipRect(Rect(aClipRect)); |
718 | 0 |
|
719 | 0 | newTransform.PostTranslate(-offset.x, -offset.y); |
720 | 0 | buffer->SetTransform(newTransform); |
721 | 0 |
|
722 | 0 | RefPtr<SourceSurface> sourceMask; |
723 | 0 | Matrix maskTransform; |
724 | 0 | if (aTransform.Is2D()) { |
725 | 0 | SetupMask(aEffectChain, dest, offset, sourceMask, maskTransform); |
726 | 0 | } |
727 | 0 |
|
728 | 0 | CompositionOp blendMode = CompositionOp::OP_OVER; |
729 | 0 | if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) { |
730 | 0 | blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode; |
731 | 0 | } |
732 | 0 |
|
733 | 0 | const AntialiasMode aaMode = |
734 | 0 | aEnableAA ? AntialiasMode::DEFAULT : AntialiasMode::NONE; |
735 | 0 |
|
736 | 0 | DrawOptions drawOptions(aOpacity, blendMode, aaMode); |
737 | 0 |
|
738 | 0 | switch (aEffectChain.mPrimaryEffect->mType) { |
739 | 0 | case EffectTypes::SOLID_COLOR: { |
740 | 0 | EffectSolidColor* effectSolidColor = |
741 | 0 | static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); |
742 | 0 |
|
743 | 0 | bool unboundedOp = !IsOperatorBoundByMask(blendMode); |
744 | 0 | if (unboundedOp) { |
745 | 0 | dest->PushClipRect(aRect); |
746 | 0 | } |
747 | 0 |
|
748 | 0 | DrawSurface(dest, aGeometry, aRect, effectSolidColor->mColor, |
749 | 0 | drawOptions, sourceMask, &maskTransform); |
750 | 0 |
|
751 | 0 | if (unboundedOp) { |
752 | 0 | dest->PopClip(); |
753 | 0 | } |
754 | 0 | break; |
755 | 0 | } |
756 | 0 | case EffectTypes::RGB: { |
757 | 0 | TexturedEffect* texturedEffect = |
758 | 0 | static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
759 | 0 | TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic(); |
760 | 0 |
|
761 | 0 | if (source && texturedEffect->mPremultiplied) { |
762 | 0 | // we have a fast path for video here |
763 | 0 | if (source->mFromYCBCR && |
764 | 0 | AttemptVideoConvertAndScale(texturedEffect->mTexture, sourceMask, aOpacity, blendMode, |
765 | 0 | texturedEffect, |
766 | 0 | newTransform, aRect, transformedClipRect, |
767 | 0 | dest, buffer)) { |
768 | 0 | // we succeeded in convert and scaling |
769 | 0 | } else if (source->mFromYCBCR && |
770 | 0 | !source->GetSurface(dest)) { |
771 | 0 | gfxWarning() << "Failed to get YCbCr to rgb surface."; |
772 | 0 | } else if (source->mFromYCBCR && |
773 | 0 | AttemptVideoScale(source, sourceMask, aOpacity, blendMode, |
774 | 0 | texturedEffect, |
775 | 0 | newTransform, aRect, transformedClipRect, |
776 | 0 | dest, buffer)) { |
777 | 0 | // we succeeded in scaling |
778 | 0 | } else { |
779 | 0 | DrawSurfaceWithTextureCoords(dest, aGeometry, aRect, |
780 | 0 | source->GetSurface(dest), |
781 | 0 | texturedEffect->mTextureCoords, |
782 | 0 | texturedEffect->mSamplingFilter, |
783 | 0 | drawOptions, |
784 | 0 | sourceMask, &maskTransform); |
785 | 0 | } |
786 | 0 | } else if (source) { |
787 | 0 | SourceSurface* srcSurf = source->GetSurface(dest); |
788 | 0 | if (srcSurf) { |
789 | 0 | RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface(); |
790 | 0 |
|
791 | 0 | // Yes, we re-create the premultiplied data every time. |
792 | 0 | // This might be better with a cache, eventually. |
793 | 0 | RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData); |
794 | 0 |
|
795 | 0 | DrawSurfaceWithTextureCoords(dest, aGeometry, aRect, |
796 | 0 | premultData, |
797 | 0 | texturedEffect->mTextureCoords, |
798 | 0 | texturedEffect->mSamplingFilter, |
799 | 0 | drawOptions, |
800 | 0 | sourceMask, &maskTransform); |
801 | 0 | } |
802 | 0 | } else { |
803 | 0 | gfxDevCrash(LogReason::IncompatibleBasicTexturedEffect) << "Bad for basic with " << texturedEffect->mTexture->Name() << " and " << gfx::hexa(sourceMask); |
804 | 0 | } |
805 | 0 |
|
806 | 0 | break; |
807 | 0 | } |
808 | 0 | case EffectTypes::YCBCR: { |
809 | 0 | MOZ_CRASH("Can't (easily) support component alpha with BasicCompositor!"); |
810 | 0 | break; |
811 | 0 | } |
812 | 0 | case EffectTypes::RENDER_TARGET: { |
813 | 0 | EffectRenderTarget* effectRenderTarget = |
814 | 0 | static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); |
815 | 0 | RefPtr<BasicCompositingRenderTarget> surface |
816 | 0 | = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get()); |
817 | 0 | RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot(); |
818 | 0 |
|
819 | 0 | DrawSurfaceWithTextureCoords(dest, aGeometry, aRect, |
820 | 0 | sourceSurf, |
821 | 0 | effectRenderTarget->mTextureCoords, |
822 | 0 | effectRenderTarget->mSamplingFilter, |
823 | 0 | drawOptions, |
824 | 0 | sourceMask, &maskTransform); |
825 | 0 | break; |
826 | 0 | } |
827 | 0 | case EffectTypes::COMPONENT_ALPHA: { |
828 | 0 | MOZ_CRASH("Can't (easily) support component alpha with BasicCompositor!"); |
829 | 0 | break; |
830 | 0 | } |
831 | 0 | default: { |
832 | 0 | MOZ_CRASH("Invalid effect type!"); |
833 | 0 | break; |
834 | 0 | } |
835 | 0 | } |
836 | 0 | |
837 | 0 | if (!aTransform.Is2D()) { |
838 | 0 | dest->Flush(); |
839 | 0 |
|
840 | 0 | RefPtr<SourceSurface> destSnapshot = dest->Snapshot(); |
841 | 0 |
|
842 | 0 | SetupMask(aEffectChain, buffer, offset, sourceMask, maskTransform); |
843 | 0 |
|
844 | 0 | if (sourceMask) { |
845 | 0 | RefPtr<DrawTarget> transformDT = |
846 | 0 | dest->CreateSimilarDrawTarget(IntSize::Truncate(transformBounds.Width(), transformBounds.Height()), |
847 | 0 | SurfaceFormat::B8G8R8A8); |
848 | 0 | new3DTransform.PostTranslate(-transformBounds.X(), -transformBounds.Y(), 0); |
849 | 0 | if (transformDT && |
850 | 0 | transformDT->Draw3DTransformedSurface(destSnapshot, new3DTransform)) { |
851 | 0 | RefPtr<SourceSurface> transformSnapshot = transformDT->Snapshot(); |
852 | 0 |
|
853 | 0 | // Transform the source by it's normal transform, and then the inverse |
854 | 0 | // of the mask transform so that it's in the mask's untransformed |
855 | 0 | // coordinate space. |
856 | 0 | Matrix sourceTransform = newTransform; |
857 | 0 | sourceTransform.PostTranslate(transformBounds.TopLeft()); |
858 | 0 |
|
859 | 0 | Matrix inverseMask = maskTransform; |
860 | 0 | inverseMask.Invert(); |
861 | 0 |
|
862 | 0 | sourceTransform *= inverseMask; |
863 | 0 |
|
864 | 0 | SurfacePattern source(transformSnapshot, ExtendMode::CLAMP, sourceTransform); |
865 | 0 |
|
866 | 0 | buffer->PushClipRect(transformBounds); |
867 | 0 |
|
868 | 0 | // Mask in the untransformed coordinate space, and then transform |
869 | 0 | // by the mask transform to put the result back into destination |
870 | 0 | // coords. |
871 | 0 | buffer->SetTransform(maskTransform); |
872 | 0 | buffer->MaskSurface(source, sourceMask, Point(0, 0)); |
873 | 0 |
|
874 | 0 | buffer->PopClip(); |
875 | 0 | } |
876 | 0 | } else { |
877 | 0 | buffer->Draw3DTransformedSurface(destSnapshot, new3DTransform); |
878 | 0 | } |
879 | 0 | } |
880 | 0 |
|
881 | 0 | buffer->PopClip(); |
882 | 0 | } Unexecuted instantiation: void mozilla::layers::BasicCompositor::DrawGeometry<mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> >(mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::EffectChain const&, float, mozilla::gfx::Matrix4x4Typed<mozilla::gfx::UnknownUnits, mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, bool) Unexecuted instantiation: void mozilla::layers::BasicCompositor::DrawGeometry<mozilla::gfx::PolygonTyped<mozilla::gfx::UnknownUnits> >(mozilla::gfx::PolygonTyped<mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::EffectChain const&, float, mozilla::gfx::Matrix4x4Typed<mozilla::gfx::UnknownUnits, mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, bool) |
883 | | |
884 | | void |
885 | | BasicCompositor::ClearRect(const gfx::Rect& aRect) |
886 | 0 | { |
887 | 0 | mRenderTarget->mDrawTarget->ClearRect(aRect); |
888 | 0 | } |
889 | | |
890 | | void |
891 | | BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, |
892 | | const gfx::IntRect *aClipRectIn, |
893 | | const gfx::IntRect& aRenderBounds, |
894 | | const nsIntRegion& aOpaqueRegion, |
895 | | gfx::IntRect *aClipRectOut /* = nullptr */, |
896 | | gfx::IntRect *aRenderBoundsOut /* = nullptr */) |
897 | 0 | { |
898 | 0 | if (mIsPendingEndRemoteDrawing) { |
899 | 0 | // Force to end previous remote drawing. |
900 | 0 | TryToEndRemoteDrawing(/* aForceToEnd */ true); |
901 | 0 | MOZ_ASSERT(!mIsPendingEndRemoteDrawing); |
902 | 0 | } |
903 | 0 |
|
904 | 0 | LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize()); |
905 | 0 | IntRect rect = IntRect(0, 0, intRect.Width(), intRect.Height()); |
906 | 0 |
|
907 | 0 | LayoutDeviceIntRegion invalidRegionSafe; |
908 | 0 | // Sometimes the invalid region is larger than we want to draw. |
909 | 0 | invalidRegionSafe.And( |
910 | 0 | LayoutDeviceIntRegion::FromUnknownRegion(aInvalidRegion), intRect); |
911 | 0 |
|
912 | 0 | mInvalidRegion = invalidRegionSafe; |
913 | 0 | mInvalidRect = mInvalidRegion.GetBounds(); |
914 | 0 |
|
915 | 0 | if (aRenderBoundsOut) { |
916 | 0 | *aRenderBoundsOut = IntRect(); |
917 | 0 | } |
918 | 0 |
|
919 | 0 | BufferMode bufferMode = BufferMode::BUFFERED; |
920 | 0 | if (mTarget) { |
921 | 0 | // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy |
922 | 0 | // placeholder so that CreateRenderTarget() works. This is only used to create a new buffered |
923 | 0 | // draw target that we composite into, then copy the results the destination. |
924 | 0 | mDrawTarget = mTarget; |
925 | 0 | bufferMode = BufferMode::BUFFER_NONE; |
926 | 0 | } else { |
927 | 0 | // StartRemoteDrawingInRegion can mutate mInvalidRegion. |
928 | 0 | mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode); |
929 | 0 | if (!mDrawTarget) { |
930 | 0 | return; |
931 | 0 | } |
932 | 0 | mInvalidRect = mInvalidRegion.GetBounds(); |
933 | 0 | if (mInvalidRect.IsEmpty()) { |
934 | 0 | mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); |
935 | 0 | return; |
936 | 0 | } |
937 | 0 | } |
938 | 0 | |
939 | 0 | if (!mDrawTarget || mInvalidRect.IsEmpty()) { |
940 | 0 | return; |
941 | 0 | } |
942 | 0 | |
943 | 0 | LayoutDeviceIntRect clearRect; |
944 | 0 | if (!aOpaqueRegion.IsEmpty()) { |
945 | 0 | LayoutDeviceIntRegion clearRegion = mInvalidRegion; |
946 | 0 | clearRegion.SubOut(LayoutDeviceIntRegion::FromUnknownRegion(aOpaqueRegion)); |
947 | 0 | clearRect = clearRegion.GetBounds(); |
948 | 0 | } else { |
949 | 0 | clearRect = mInvalidRect; |
950 | 0 | } |
951 | 0 |
|
952 | 0 | // Prevent CreateRenderTargetForWindow from clearing unwanted area. |
953 | 0 | gfxUtils::ClipToRegion(mDrawTarget, |
954 | 0 | mInvalidRegion.ToUnknownRegion()); |
955 | 0 |
|
956 | 0 | // Setup an intermediate render target to buffer all compositing. We will |
957 | 0 | // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame() |
958 | 0 | RefPtr<CompositingRenderTarget> target = |
959 | 0 | CreateRenderTargetForWindow(mInvalidRect, |
960 | 0 | clearRect, |
961 | 0 | bufferMode); |
962 | 0 |
|
963 | 0 | mDrawTarget->PopClip(); |
964 | 0 |
|
965 | 0 | if (!target) { |
966 | 0 | if (!mTarget) { |
967 | 0 | mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); |
968 | 0 | } |
969 | 0 | return; |
970 | 0 | } |
971 | 0 | SetRenderTarget(target); |
972 | 0 |
|
973 | 0 | // We only allocate a surface sized to the invalidated region, so we need to |
974 | 0 | // translate future coordinates. |
975 | 0 | mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mRenderTarget->GetOrigin())); |
976 | 0 |
|
977 | 0 | gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget, |
978 | 0 | mInvalidRegion.ToUnknownRegion()); |
979 | 0 |
|
980 | 0 | if (aRenderBoundsOut) { |
981 | 0 | *aRenderBoundsOut = rect; |
982 | 0 | } |
983 | 0 |
|
984 | 0 | if (aClipRectIn) { |
985 | 0 | mRenderTarget->mDrawTarget->PushClipRect(Rect(*aClipRectIn)); |
986 | 0 | } else { |
987 | 0 | mRenderTarget->mDrawTarget->PushClipRect(Rect(rect)); |
988 | 0 | if (aClipRectOut) { |
989 | 0 | *aClipRectOut = rect; |
990 | 0 | } |
991 | 0 | } |
992 | 0 | } |
993 | | |
994 | | void |
995 | | BasicCompositor::EndFrame() |
996 | 0 | { |
997 | 0 | Compositor::EndFrame(); |
998 | 0 |
|
999 | 0 | // Pop aClipRectIn/bounds rect |
1000 | 0 | mRenderTarget->mDrawTarget->PopClip(); |
1001 | 0 |
|
1002 | 0 | if (gfxPrefs::WidgetUpdateFlashing()) { |
1003 | 0 | float r = float(rand()) / RAND_MAX; |
1004 | 0 | float g = float(rand()) / RAND_MAX; |
1005 | 0 | float b = float(rand()) / RAND_MAX; |
1006 | 0 | // We're still clipped to mInvalidRegion, so just fill the bounds. |
1007 | 0 | mRenderTarget->mDrawTarget->FillRect( |
1008 | 0 | IntRectToRect(mInvalidRegion.GetBounds()).ToUnknownRect(), |
1009 | 0 | ColorPattern(Color(r, g, b, 0.2f))); |
1010 | 0 | } |
1011 | 0 |
|
1012 | 0 | // Pop aInvalidregion |
1013 | 0 | mRenderTarget->mDrawTarget->PopClip(); |
1014 | 0 |
|
1015 | 0 | TryToEndRemoteDrawing(); |
1016 | 0 | } |
1017 | | |
1018 | | void |
1019 | | BasicCompositor::TryToEndRemoteDrawing(bool aForceToEnd) |
1020 | 0 | { |
1021 | 0 | if (mIsDestroyed || !mRenderTarget) { |
1022 | 0 | return; |
1023 | 0 | } |
1024 | 0 | |
1025 | 0 | // It it is not a good timing for EndRemoteDrawing, defter to call it. |
1026 | 0 | if (!aForceToEnd && !mTarget && NeedsToDeferEndRemoteDrawing()) { |
1027 | 0 | mIsPendingEndRemoteDrawing = true; |
1028 | 0 |
|
1029 | 0 | const uint32_t retryMs = 2; |
1030 | 0 | RefPtr<BasicCompositor> self = this; |
1031 | 0 | RefPtr<Runnable> runnable = |
1032 | 0 | NS_NewRunnableFunction("layers::BasicCompositor::TryToEndRemoteDrawing", |
1033 | 0 | [self]() { self->TryToEndRemoteDrawing(); }); |
1034 | 0 | MessageLoop::current()->PostDelayedTask(runnable.forget(), retryMs); |
1035 | 0 | return; |
1036 | 0 | } |
1037 | 0 |
|
1038 | 0 | if (mRenderTarget->mDrawTarget != mDrawTarget) { |
1039 | 0 | // Note: Most platforms require us to buffer drawing to the widget surface. |
1040 | 0 | // That's why we don't draw to mDrawTarget directly. |
1041 | 0 | RefPtr<SourceSurface> source = mWidget->EndBackBufferDrawing(); |
1042 | 0 |
|
1043 | 0 | nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint(); |
1044 | 0 |
|
1045 | 0 | // The source DrawTarget is clipped to the invalidation region, so we have |
1046 | 0 | // to copy the individual rectangles in the region or else we'll draw blank |
1047 | 0 | // pixels. |
1048 | 0 | for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) { |
1049 | 0 | const LayoutDeviceIntRect& r = iter.Get(); |
1050 | 0 | mDrawTarget->CopySurface(source, |
1051 | 0 | r.ToUnknownRect() - mRenderTarget->GetOrigin(), |
1052 | 0 | r.TopLeft().ToUnknownPoint() - offset); |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 |
|
1056 | 0 | if (aForceToEnd || !mTarget) { |
1057 | 0 | mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); |
1058 | 0 | } |
1059 | 0 |
|
1060 | 0 | mDrawTarget = nullptr; |
1061 | 0 | mRenderTarget = nullptr; |
1062 | 0 | mIsPendingEndRemoteDrawing = false; |
1063 | 0 | } |
1064 | | |
1065 | | bool |
1066 | | BasicCompositor::NeedsToDeferEndRemoteDrawing() |
1067 | 0 | { |
1068 | 0 | MOZ_ASSERT(mDrawTarget); |
1069 | 0 | MOZ_ASSERT(mRenderTarget); |
1070 | 0 |
|
1071 | 0 | if (mTarget || mRenderTarget->mDrawTarget == mDrawTarget) { |
1072 | 0 | return false; |
1073 | 0 | } |
1074 | 0 | |
1075 | 0 | return mWidget->NeedsToDeferEndRemoteDrawing(); |
1076 | 0 | } |
1077 | | |
1078 | | void |
1079 | | BasicCompositor::FinishPendingComposite() |
1080 | 0 | { |
1081 | 0 | TryToEndRemoteDrawing(/* aForceToEnd */ true); |
1082 | 0 | } |
1083 | | |
1084 | | } // namespace layers |
1085 | | } // namespace mozilla |