|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "mozilla/layers/SimpleTiledContentClient.h" |
|
7 |
|
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" |
|
32 |
|
33 #define ALOG(...) __android_log_print(ANDROID_LOG_INFO, "SimpleTiles", __VA_ARGS__) |
|
34 |
|
35 using namespace mozilla::gfx; |
|
36 |
|
37 namespace mozilla { |
|
38 namespace layers { |
|
39 |
|
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; |
|
48 |
|
49 #ifdef GFX_TILEDLAYER_PREF_WARNINGS |
|
50 long start = PR_IntervalNow(); |
|
51 #endif |
|
52 |
|
53 // If this region is empty XMost() - 1 will give us a negative value. |
|
54 NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n"); |
|
55 |
|
56 PROFILER_LABEL("SimpleTiledLayerBuffer", "PaintThebesUpdate"); |
|
57 |
|
58 Update(aNewValidRegion, aPaintRegion); |
|
59 |
|
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 |
|
66 |
|
67 mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface(); |
|
68 mCallback = nullptr; |
|
69 mCallbackData = nullptr; |
|
70 } |
|
71 |
|
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()); |
|
79 |
|
80 gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType()); |
|
81 |
|
82 // if this is true, we're using a separate buffer to do our drawing first |
|
83 bool doBufferedDrawing = true; |
|
84 bool fullPaint = false; |
|
85 |
|
86 RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle(); |
|
87 |
|
88 if (!textureClient) { |
|
89 NS_WARNING("TextureClient allocation failed"); |
|
90 return SimpleTiledLayerTile(); |
|
91 } |
|
92 |
|
93 if (!textureClient->Lock(OPEN_READ_WRITE)) { |
|
94 NS_WARNING("TextureClient lock failed"); |
|
95 return SimpleTiledLayerTile(); |
|
96 } |
|
97 |
|
98 if (!textureClient->CanExposeDrawTarget()) { |
|
99 doBufferedDrawing = false; |
|
100 } |
|
101 |
|
102 RefPtr<DrawTarget> drawTarget; |
|
103 |
|
104 unsigned char *bufferData = nullptr; |
|
105 |
|
106 // these are set/updated differently based on doBufferedDrawing |
|
107 nsIntRect drawBounds; |
|
108 nsIntRegion drawRegion; |
|
109 nsIntRegion invalidateRegion; |
|
110 |
|
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; |
|
116 |
|
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(); |
|
126 |
|
127 drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData, |
|
128 kTileSize, |
|
129 srcStride, |
|
130 tileFormat); |
|
131 |
|
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 } |
|
147 |
|
148 // this might get set above if we couldn't extract out a buffer |
|
149 if (!doBufferedDrawing) { |
|
150 drawTarget = textureClient->GetAsDrawTarget(); |
|
151 |
|
152 fullPaint = true; |
|
153 drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height); |
|
154 drawRegion = nsIntRegion(drawBounds); |
|
155 |
|
156 if (GetContentType() == gfxContentType::COLOR_ALPHA) |
|
157 drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height)); |
|
158 } |
|
159 |
|
160 // do the drawing |
|
161 RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); |
|
162 |
|
163 ctxt->Scale(mResolution, mResolution); |
|
164 ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); |
|
165 |
|
166 mCallback(mThebesLayer, ctxt, |
|
167 drawRegion, |
|
168 fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED? |
|
169 invalidateRegion, |
|
170 mCallbackData); |
|
171 |
|
172 ctxt = nullptr; |
|
173 |
|
174 if (doBufferedDrawing) { |
|
175 memcpy(srcData, bufferData, srcSize.height * srcStride); |
|
176 bufferData = nullptr; |
|
177 srcDT->ReleaseBits(srcData); |
|
178 srcDT = nullptr; |
|
179 } |
|
180 |
|
181 drawTarget = nullptr; |
|
182 textureClient->Unlock(); |
|
183 |
|
184 if (!mCompositableClient->AddTextureClient(textureClient)) { |
|
185 NS_WARNING("Failed to add tile TextureClient [simple]"); |
|
186 return SimpleTiledLayerTile(); |
|
187 } |
|
188 |
|
189 // aTile.mCachedBuffer was set earlier |
|
190 aTile.mTileBuffer = textureClient; |
|
191 aTile.mManager = mManager; |
|
192 aTile.mLastUpdate = TimeStamp::Now(); |
|
193 |
|
194 return aTile; |
|
195 } |
|
196 |
|
197 SurfaceDescriptorTiles |
|
198 SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles() |
|
199 { |
|
200 InfallibleTArray<TileDescriptor> tiles; |
|
201 |
|
202 for (size_t i = 0; i < mRetainedTiles.Length(); i++) { |
|
203 tiles.AppendElement(mRetainedTiles[i].GetTileDescriptor()); |
|
204 } |
|
205 |
|
206 return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion, |
|
207 tiles, mRetainedWidth, mRetainedHeight, |
|
208 mResolution, mFrameResolution.scale); |
|
209 } |
|
210 |
|
211 bool |
|
212 SimpleTiledLayerBuffer::HasFormatChanged() const |
|
213 { |
|
214 return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque; |
|
215 } |
|
216 |
|
217 gfxContentType |
|
218 SimpleTiledLayerBuffer::GetContentType() const |
|
219 { |
|
220 if (mThebesLayer->CanUseOpaqueSurface()) |
|
221 return gfxContentType::COLOR; |
|
222 |
|
223 return gfxContentType::COLOR_ALPHA; |
|
224 } |
|
225 |
|
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 } |
|
233 |
|
234 SimpleTiledContentClient::~SimpleTiledContentClient() |
|
235 { |
|
236 MOZ_COUNT_DTOR(SimpleTiledContentClient); |
|
237 mTiledBuffer.Release(); |
|
238 } |
|
239 |
|
240 void |
|
241 SimpleTiledContentClient::UseTiledLayerBuffer() |
|
242 { |
|
243 mForwarder->UseTiledLayerBuffer(this, mTiledBuffer.GetSurfaceDescriptorTiles()); |
|
244 mTiledBuffer.ClearPaintedRegion(); |
|
245 } |
|
246 |
|
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 } |
|
254 |
|
255 SimpleClientTiledThebesLayer::~SimpleClientTiledThebesLayer() |
|
256 { |
|
257 MOZ_COUNT_DTOR(SimpleClientTiledThebesLayer); |
|
258 } |
|
259 |
|
260 void |
|
261 SimpleClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) |
|
262 { |
|
263 aAttrs = ThebesLayerAttributes(GetValidRegion()); |
|
264 } |
|
265 |
|
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 } |
|
276 |
|
277 // First time? Create a content client. |
|
278 if (!mContentClient) { |
|
279 mContentClient = new SimpleTiledContentClient(this, ClientManager()); |
|
280 |
|
281 mContentClient->Connect(); |
|
282 ClientManager()->AsShadowForwarder()->Attach(mContentClient, this); |
|
283 MOZ_ASSERT(mContentClient->GetForwarder()); |
|
284 } |
|
285 |
|
286 // If the format changed, nothing is valid |
|
287 if (mContentClient->mTiledBuffer.HasFormatChanged()) { |
|
288 mValidRegion = nsIntRegion(); |
|
289 } |
|
290 |
|
291 nsIntRegion invalidRegion = mVisibleRegion; |
|
292 invalidRegion.Sub(invalidRegion, mValidRegion); |
|
293 if (invalidRegion.IsEmpty()) { |
|
294 return; |
|
295 } |
|
296 |
|
297 // Only paint the mask layer on the first transaction. |
|
298 if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) { |
|
299 ToClientLayer(GetMaskLayer())->RenderLayer(); |
|
300 } |
|
301 |
|
302 // SimpleTiledContentClient doesn't support progressive updates or the low |
|
303 // precision buffer yet. |
|
304 MOZ_ASSERT(!gfxPrefs::UseProgressiveTilePainting() && |
|
305 !gfxPrefs::UseLowPrecisionBuffer()); |
|
306 |
|
307 mValidRegion = mVisibleRegion; |
|
308 |
|
309 NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer"); |
|
310 |
|
311 mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, |
|
312 callback, data); |
|
313 |
|
314 ClientManager()->Hold(this); |
|
315 |
|
316 mContentClient->UseTiledLayerBuffer(); |
|
317 } |
|
318 |
|
319 |
|
320 } |
|
321 } |