Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #include "mozilla/layers/SimpleTiledContentClient.h"
8 #include <math.h> // for ceil, ceilf, floor
9 #include "ClientTiledThebesLayer.h" // for ClientTiledThebesLayer
10 #include "GeckoProfiler.h" // for PROFILER_LABEL
11 #include "Units.h" // for ScreenIntRect, CSSPoint, etc
12 #include "UnitTransforms.h" // for TransformTo
13 #include "ClientLayerManager.h" // for ClientLayerManager
14 #include "CompositorChild.h" // for CompositorChild
15 #include "gfxContext.h" // for gfxContext, etc
16 #include "gfxPlatform.h" // for gfxPlatform
17 #include "gfxPrefs.h" // for gfxPrefs::LayersTileWidth/Height
18 #include "gfxRect.h" // for gfxRect
19 #include "mozilla/Attributes.h" // for MOZ_THIS_IN_INITIALIZER_LIST
20 #include "mozilla/MathAlgorithms.h" // for Abs
21 #include "mozilla/gfx/Point.h" // for IntSize
22 #include "mozilla/gfx/Rect.h" // for Rect
23 #include "mozilla/layers/CompositableForwarder.h"
24 #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
25 #include "SimpleTextureClientPool.h"
26 #include "nsDebug.h" // for NS_ASSERTION
27 #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
28 #include "nsSize.h" // for nsIntSize
29 #include "gfxReusableSharedImageSurfaceWrapper.h"
30 #include "nsMathUtils.h" // for NS_roundf
31 #include "gfx2DGlue.h"
33 #define ALOG(...) __android_log_print(ANDROID_LOG_INFO, "SimpleTiles", __VA_ARGS__)
35 using namespace mozilla::gfx;
37 namespace mozilla {
38 namespace layers {
40 void
41 SimpleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
42 const nsIntRegion& aPaintRegion,
43 LayerManager::DrawThebesLayerCallback aCallback,
44 void* aCallbackData)
45 {
46 mCallback = aCallback;
47 mCallbackData = aCallbackData;
49 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
50 long start = PR_IntervalNow();
51 #endif
53 // If this region is empty XMost() - 1 will give us a negative value.
54 NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n");
56 PROFILER_LABEL("SimpleTiledLayerBuffer", "PaintThebesUpdate");
58 Update(aNewValidRegion, aPaintRegion);
60 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
61 if (PR_IntervalNow() - start > 10) {
62 const nsIntRect bounds = aPaintRegion.GetBounds();
63 printf_stderr("Time to tile [%i, %i, %i, %i] -> %i\n", bounds.x, bounds.y, bounds.width, bounds.height, PR_IntervalNow() - start);
64 }
65 #endif
67 mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface();
68 mCallback = nullptr;
69 mCallbackData = nullptr;
70 }
72 SimpleTiledLayerTile
73 SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
74 const nsIntPoint& aTileOrigin,
75 const nsIntRegion& aDirtyRegion)
76 {
77 PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile");
78 static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight());
80 gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());
82 // if this is true, we're using a separate buffer to do our drawing first
83 bool doBufferedDrawing = true;
84 bool fullPaint = false;
86 RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();
88 if (!textureClient) {
89 NS_WARNING("TextureClient allocation failed");
90 return SimpleTiledLayerTile();
91 }
93 if (!textureClient->Lock(OPEN_READ_WRITE)) {
94 NS_WARNING("TextureClient lock failed");
95 return SimpleTiledLayerTile();
96 }
98 if (!textureClient->CanExposeDrawTarget()) {
99 doBufferedDrawing = false;
100 }
102 RefPtr<DrawTarget> drawTarget;
104 unsigned char *bufferData = nullptr;
106 // these are set/updated differently based on doBufferedDrawing
107 nsIntRect drawBounds;
108 nsIntRegion drawRegion;
109 nsIntRegion invalidateRegion;
111 RefPtr<DrawTarget> srcDT;
112 uint8_t* srcData = nullptr;
113 int32_t srcStride = 0;
114 gfx::IntSize srcSize;
115 gfx::SurfaceFormat srcFormat = gfx::SurfaceFormat::UNKNOWN;
117 if (doBufferedDrawing) {
118 // try to directly access the pixels of the TextureClient
119 srcDT = textureClient->GetAsDrawTarget();
120 if (srcDT->LockBits(&srcData, &srcSize, &srcStride, &srcFormat)) {
121 if (!aTile.mCachedBuffer) {
122 aTile.mCachedBuffer = SharedBuffer::Create(srcStride * srcSize.height);
123 fullPaint = true;
124 }
125 bufferData = (unsigned char*) aTile.mCachedBuffer->Data();
127 drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
128 kTileSize,
129 srcStride,
130 tileFormat);
132 if (fullPaint) {
133 drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
134 drawRegion = nsIntRegion(drawBounds);
135 } else {
136 drawBounds = aDirtyRegion.GetBounds();
137 drawRegion = nsIntRegion(drawBounds);
138 if (GetContentType() == gfxContentType::COLOR_ALPHA)
139 drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
140 drawBounds.width, drawBounds.height));
141 }
142 } else {
143 // failed to obtain the client as an ImageSurface
144 doBufferedDrawing = false;
145 }
146 }
148 // this might get set above if we couldn't extract out a buffer
149 if (!doBufferedDrawing) {
150 drawTarget = textureClient->GetAsDrawTarget();
152 fullPaint = true;
153 drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
154 drawRegion = nsIntRegion(drawBounds);
156 if (GetContentType() == gfxContentType::COLOR_ALPHA)
157 drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
158 }
160 // do the drawing
161 RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
163 ctxt->Scale(mResolution, mResolution);
164 ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
166 mCallback(mThebesLayer, ctxt,
167 drawRegion,
168 fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED?
169 invalidateRegion,
170 mCallbackData);
172 ctxt = nullptr;
174 if (doBufferedDrawing) {
175 memcpy(srcData, bufferData, srcSize.height * srcStride);
176 bufferData = nullptr;
177 srcDT->ReleaseBits(srcData);
178 srcDT = nullptr;
179 }
181 drawTarget = nullptr;
182 textureClient->Unlock();
184 if (!mCompositableClient->AddTextureClient(textureClient)) {
185 NS_WARNING("Failed to add tile TextureClient [simple]");
186 return SimpleTiledLayerTile();
187 }
189 // aTile.mCachedBuffer was set earlier
190 aTile.mTileBuffer = textureClient;
191 aTile.mManager = mManager;
192 aTile.mLastUpdate = TimeStamp::Now();
194 return aTile;
195 }
197 SurfaceDescriptorTiles
198 SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles()
199 {
200 InfallibleTArray<TileDescriptor> tiles;
202 for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
203 tiles.AppendElement(mRetainedTiles[i].GetTileDescriptor());
204 }
206 return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
207 tiles, mRetainedWidth, mRetainedHeight,
208 mResolution, mFrameResolution.scale);
209 }
211 bool
212 SimpleTiledLayerBuffer::HasFormatChanged() const
213 {
214 return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque;
215 }
217 gfxContentType
218 SimpleTiledLayerBuffer::GetContentType() const
219 {
220 if (mThebesLayer->CanUseOpaqueSurface())
221 return gfxContentType::COLOR;
223 return gfxContentType::COLOR_ALPHA;
224 }
226 SimpleTiledContentClient::SimpleTiledContentClient(SimpleClientTiledThebesLayer* aThebesLayer,
227 ClientLayerManager* aManager)
228 : CompositableClient(aManager->AsShadowForwarder())
229 , mTiledBuffer(aThebesLayer, MOZ_THIS_IN_INITIALIZER_LIST(), aManager)
230 {
231 MOZ_COUNT_CTOR(SimpleTiledContentClient);
232 }
234 SimpleTiledContentClient::~SimpleTiledContentClient()
235 {
236 MOZ_COUNT_DTOR(SimpleTiledContentClient);
237 mTiledBuffer.Release();
238 }
240 void
241 SimpleTiledContentClient::UseTiledLayerBuffer()
242 {
243 mForwarder->UseTiledLayerBuffer(this, mTiledBuffer.GetSurfaceDescriptorTiles());
244 mTiledBuffer.ClearPaintedRegion();
245 }
247 SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager)
248 : ThebesLayer(aManager,
249 static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
250 , mContentClient()
251 {
252 MOZ_COUNT_CTOR(SimpleClientTiledThebesLayer);
253 }
255 SimpleClientTiledThebesLayer::~SimpleClientTiledThebesLayer()
256 {
257 MOZ_COUNT_DTOR(SimpleClientTiledThebesLayer);
258 }
260 void
261 SimpleClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
262 {
263 aAttrs = ThebesLayerAttributes(GetValidRegion());
264 }
266 void
267 SimpleClientTiledThebesLayer::RenderLayer()
268 {
269 LayerManager::DrawThebesLayerCallback callback =
270 ClientManager()->GetThebesLayerCallback();
271 void *data = ClientManager()->GetThebesLayerCallbackData();
272 if (!callback) {
273 ClientManager()->SetTransactionIncomplete();
274 return;
275 }
277 // First time? Create a content client.
278 if (!mContentClient) {
279 mContentClient = new SimpleTiledContentClient(this, ClientManager());
281 mContentClient->Connect();
282 ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
283 MOZ_ASSERT(mContentClient->GetForwarder());
284 }
286 // If the format changed, nothing is valid
287 if (mContentClient->mTiledBuffer.HasFormatChanged()) {
288 mValidRegion = nsIntRegion();
289 }
291 nsIntRegion invalidRegion = mVisibleRegion;
292 invalidRegion.Sub(invalidRegion, mValidRegion);
293 if (invalidRegion.IsEmpty()) {
294 return;
295 }
297 // Only paint the mask layer on the first transaction.
298 if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) {
299 ToClientLayer(GetMaskLayer())->RenderLayer();
300 }
302 // SimpleTiledContentClient doesn't support progressive updates or the low
303 // precision buffer yet.
304 MOZ_ASSERT(!gfxPrefs::UseProgressiveTilePainting() &&
305 !gfxPrefs::UseLowPrecisionBuffer());
307 mValidRegion = mVisibleRegion;
309 NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
311 mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
312 callback, data);
314 ClientManager()->Hold(this);
316 mContentClient->UseTiledLayerBuffer();
317 }
320 }
321 }