/src/mozilla-central/gfx/layers/client/SingleTiledContentClient.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/SingleTiledContentClient.h" |
8 | | |
9 | | #include "ClientTiledPaintedLayer.h" |
10 | | #include "mozilla/Maybe.h" |
11 | | #include "mozilla/UniquePtr.h" |
12 | | |
13 | | namespace mozilla { |
14 | | namespace layers { |
15 | | |
16 | | |
17 | | SingleTiledContentClient::SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer, |
18 | | ClientLayerManager* aManager) |
19 | | : TiledContentClient(aManager, "Single") |
20 | 0 | { |
21 | 0 | MOZ_COUNT_CTOR(SingleTiledContentClient); |
22 | 0 |
|
23 | 0 | mTiledBuffer = new ClientSingleTiledLayerBuffer(aPaintedLayer, *this, aManager); |
24 | 0 | } |
25 | | |
26 | | void |
27 | | SingleTiledContentClient::ClearCachedResources() |
28 | 0 | { |
29 | 0 | CompositableClient::ClearCachedResources(); |
30 | 0 | mTiledBuffer->DiscardBuffers(); |
31 | 0 | } |
32 | | |
33 | | void |
34 | | SingleTiledContentClient::UpdatedBuffer(TiledBufferType aType) |
35 | 0 | { |
36 | 0 | mForwarder->UseTiledLayerBuffer(this, mTiledBuffer->GetSurfaceDescriptorTiles()); |
37 | 0 | } |
38 | | |
39 | | /* static */ bool |
40 | | SingleTiledContentClient::ClientSupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) |
41 | 0 | { |
42 | 0 | int32_t maxTextureSize = aManager->GetMaxTextureSize(); |
43 | 0 | return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize; |
44 | 0 | } |
45 | | |
46 | | ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer, |
47 | | CompositableClient& aCompositableClient, |
48 | | ClientLayerManager* aManager) |
49 | | : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient) |
50 | | , mManager(aManager) |
51 | | , mWasLastPaintProgressive(false) |
52 | | , mFormat(gfx::SurfaceFormat::UNKNOWN) |
53 | 0 | { |
54 | 0 | } |
55 | | |
56 | | void |
57 | | ClientSingleTiledLayerBuffer::ReleaseTiles() |
58 | 0 | { |
59 | 0 | if (!mTile.IsPlaceholderTile()) { |
60 | 0 | mTile.DiscardBuffers(); |
61 | 0 | } |
62 | 0 | mTile.SetTextureAllocator(nullptr); |
63 | 0 | } |
64 | | |
65 | | void |
66 | | ClientSingleTiledLayerBuffer::DiscardBuffers() |
67 | 0 | { |
68 | 0 | if (!mTile.IsPlaceholderTile()) { |
69 | 0 | mTile.DiscardFrontBuffer(); |
70 | 0 | mTile.DiscardBackBuffer(); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | SurfaceDescriptorTiles |
75 | | ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles() |
76 | 0 | { |
77 | 0 | InfallibleTArray<TileDescriptor> tiles; |
78 | 0 |
|
79 | 0 | TileDescriptor tileDesc = mTile.GetTileDescriptor(); |
80 | 0 | tiles.AppendElement(tileDesc); |
81 | 0 | mTile.mUpdateRect = gfx::IntRect(); |
82 | 0 |
|
83 | 0 | return SurfaceDescriptorTiles(mValidRegion, |
84 | 0 | tiles, |
85 | 0 | mTilingOrigin, |
86 | 0 | mSize, |
87 | 0 | 0, 0, 1, 1, |
88 | 0 | 1.0, |
89 | 0 | mFrameResolution.xScale, |
90 | 0 | mFrameResolution.yScale, |
91 | 0 | mWasLastPaintProgressive); |
92 | 0 | } |
93 | | |
94 | | already_AddRefed<TextureClient> |
95 | | ClientSingleTiledLayerBuffer::GetTextureClient() |
96 | 0 | { |
97 | 0 | MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN); |
98 | 0 | return mCompositableClient.CreateTextureClientForDrawing( |
99 | 0 | gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content, |
100 | 0 | TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::NON_BLOCKING_READ_LOCK); |
101 | 0 | } |
102 | | |
103 | | void |
104 | | ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, |
105 | | const nsIntRegion& aPaintRegion, |
106 | | const nsIntRegion& aDirtyRegion, |
107 | | LayerManager::DrawPaintedLayerCallback aCallback, |
108 | | void* aCallbackData, |
109 | | TilePaintFlags aFlags) |
110 | 0 | { |
111 | 0 | mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive); |
112 | 0 | bool asyncPaint = !!(aFlags & TilePaintFlags::Async); |
113 | 0 |
|
114 | 0 | // Compare layer valid region size to current backbuffer size, discard if not matching. |
115 | 0 | gfx::IntSize size = aNewValidRegion.GetBounds().Size(); |
116 | 0 | gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); |
117 | 0 | nsIntRegion paintRegion = aPaintRegion; |
118 | 0 |
|
119 | 0 | RefPtr<TextureClient> discardedFrontBuffer = nullptr; |
120 | 0 | RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr; |
121 | 0 | nsIntRegion discardedValidRegion; |
122 | 0 |
|
123 | 0 | if (mSize != size || |
124 | 0 | mTilingOrigin != origin) { |
125 | 0 | discardedFrontBuffer = mTile.mFrontBuffer; |
126 | 0 | discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite; |
127 | 0 | discardedValidRegion = mValidRegion; |
128 | 0 |
|
129 | 0 | TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer); |
130 | 0 | ResetPaintedAndValidState(); |
131 | 0 | mSize = size; |
132 | 0 | mTilingOrigin = origin; |
133 | 0 | paintRegion = aNewValidRegion; |
134 | 0 | } |
135 | 0 |
|
136 | 0 | SurfaceMode mode; |
137 | 0 | gfxContentType content = GetContentType(&mode); |
138 | 0 | mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); |
139 | 0 |
|
140 | 0 | if (mTile.IsPlaceholderTile()) { |
141 | 0 | mTile.SetTextureAllocator(this); |
142 | 0 | } |
143 | 0 |
|
144 | 0 |
|
145 | 0 | if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) { |
146 | 0 | AutoTArray<uint64_t, 2> syncTextureSerials; |
147 | 0 | mTile.GetSyncTextureSerials(mode, syncTextureSerials); |
148 | 0 | if (syncTextureSerials.Length() > 0) { |
149 | 0 | mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials); |
150 | 0 | } |
151 | 0 | } |
152 | 0 |
|
153 | 0 | // The dirty region relative to the top-left of the tile. |
154 | 0 | nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin); |
155 | 0 | nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); |
156 | 0 |
|
157 | 0 | Maybe<AcquiredBackBuffer> backBuffer = |
158 | 0 | mTile.AcquireBackBuffer(mCompositableClient, |
159 | 0 | tileDirtyRegion, |
160 | 0 | tileVisibleRegion, |
161 | 0 | content, |
162 | 0 | mode, |
163 | 0 | aFlags); |
164 | 0 |
|
165 | 0 | if (!backBuffer) { |
166 | 0 | return; |
167 | 0 | } |
168 | 0 | |
169 | 0 | // Mark the area we need to paint in the back buffer as invalid in the |
170 | 0 | // front buffer as they will become out of sync. |
171 | 0 | mTile.mInvalidFront.OrWith(tileDirtyRegion); |
172 | 0 |
|
173 | 0 | // Add backbuffer's invalid region to the dirty region to be painted. |
174 | 0 | // This will be empty if we were able to copy from the front in to the back. |
175 | 0 | nsIntRegion tileInvalidRegion = mTile.mInvalidBack; |
176 | 0 | tileInvalidRegion.AndWith(tileVisibleRegion); |
177 | 0 |
|
178 | 0 | paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin)); |
179 | 0 | tileDirtyRegion.OrWith(tileInvalidRegion); |
180 | 0 |
|
181 | 0 | // Mark the region we will be painting and the region we copied from the front buffer as |
182 | 0 | // needing to be uploaded to the compositor |
183 | 0 | mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect); |
184 | 0 |
|
185 | 0 | // If the old frontbuffer was discarded then attempt to copy what we |
186 | 0 | // can from it to the new backbuffer. |
187 | 0 | if (discardedFrontBuffer) { |
188 | 0 | nsIntRegion copyableRegion; |
189 | 0 | copyableRegion.And(aNewValidRegion, discardedValidRegion); |
190 | 0 | copyableRegion.SubOut(aDirtyRegion); |
191 | 0 |
|
192 | 0 | OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC |
193 | 0 | : OpenMode::OPEN_READ; |
194 | 0 |
|
195 | 0 | DualTextureClientAutoLock discardedBuffer(discardedFrontBuffer, discardedFrontBufferOnWhite, readMode); |
196 | 0 |
|
197 | 0 | if (discardedBuffer.Succeeded()) { |
198 | 0 | RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot(); |
199 | 0 |
|
200 | 0 | for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { |
201 | 0 | const gfx::IntRect src = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); |
202 | 0 | const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; |
203 | 0 |
|
204 | 0 | backBuffer->mTarget->CopySurface(discardedSurface, src, dest); |
205 | 0 | } |
206 | 0 |
|
207 | 0 | TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str()); |
208 | 0 |
|
209 | 0 | // We don't need to repaint valid content that was just copied. |
210 | 0 | paintRegion.SubOut(copyableRegion); |
211 | 0 | copyableRegion.MoveBy(-mTilingOrigin); |
212 | 0 | tileDirtyRegion.SubOut(copyableRegion); |
213 | 0 | } else { |
214 | 0 | gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target"; |
215 | 0 | } |
216 | 0 | } |
217 | 0 |
|
218 | 0 | if (mode != SurfaceMode::SURFACE_OPAQUE) { |
219 | 0 | for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { |
220 | 0 | const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(), |
221 | 0 | iter.Get().Width(), iter.Get().Height()); |
222 | 0 | backBuffer->mTarget->ClearRect(drawRect); |
223 | 0 | } |
224 | 0 | } |
225 | 0 |
|
226 | 0 | // Paint into the target |
227 | 0 | { |
228 | 0 | RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget); |
229 | 0 | if (!ctx) { |
230 | 0 | gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(backBuffer->mTarget); |
231 | 0 | return; |
232 | 0 | } |
233 | 0 | ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y)); |
234 | 0 |
|
235 | 0 | aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); |
236 | 0 | } |
237 | 0 |
|
238 | 0 | if (asyncPaint) { |
239 | 0 | if (!backBuffer->mCapture->IsEmpty()) { |
240 | 0 | UniquePtr<PaintTask> task(new PaintTask()); |
241 | 0 | task->mCapture = backBuffer->mCapture; |
242 | 0 | task->mTarget = backBuffer->mBackBuffer; |
243 | 0 | task->mClients = std::move(backBuffer->mTextureClients); |
244 | 0 |
|
245 | 0 | // The target is an alias for the capture, and the paint thread expects |
246 | 0 | // to be the only one with a reference to the capture |
247 | 0 | backBuffer->mTarget = nullptr; |
248 | 0 | backBuffer->mCapture = nullptr; |
249 | 0 |
|
250 | 0 | PaintThread::Get()->QueuePaintTask(std::move(task)); |
251 | 0 | mManager->SetQueuedAsyncPaints(); |
252 | 0 | } |
253 | 0 | } else { |
254 | 0 | MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer); |
255 | 0 | MOZ_ASSERT(!backBuffer->mCapture); |
256 | 0 | } |
257 | 0 |
|
258 | 0 | // The new buffer is now validated, remove the dirty region from it. |
259 | 0 | mTile.mInvalidBack.SubOut(tileDirtyRegion); |
260 | 0 |
|
261 | 0 | backBuffer = Nothing(); |
262 | 0 |
|
263 | 0 | mTile.Flip(); |
264 | 0 | UnlockTile(mTile); |
265 | 0 |
|
266 | 0 | mValidRegion = aNewValidRegion; |
267 | 0 | mLastPaintSurfaceMode = mode; |
268 | 0 | mLastPaintContentType = content; |
269 | 0 | } |
270 | | |
271 | | } // namespace layers |
272 | | } // namespace mozilla |