Line data Source code
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/TextureClient.h"
7 : #include <stdint.h> // for uint8_t, uint32_t, etc
8 : #include "Layers.h" // for Layer, etc
9 : #include "gfx2DGlue.h"
10 : #include "gfxPlatform.h" // for gfxPlatform
11 : #include "mozilla/Atomics.h"
12 : #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
13 : #include "mozilla/layers/CompositableForwarder.h"
14 : #include "mozilla/layers/ISurfaceAllocator.h"
15 : #include "mozilla/layers/ImageBridgeChild.h"
16 : #include "mozilla/layers/ImageDataSerializer.h"
17 : #include "mozilla/layers/TextureClientRecycleAllocator.h"
18 : #include "mozilla/Mutex.h"
19 : #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
20 : #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
21 : #include "ImageContainer.h" // for PlanarYCbCrData, etc
22 : #include "mozilla/gfx/2D.h"
23 : #include "mozilla/gfx/Logging.h" // for gfxDebug
24 : #include "mozilla/layers/TextureClientOGL.h"
25 : #include "mozilla/layers/PTextureChild.h"
26 : #include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
27 : #include "nsPrintfCString.h" // for nsPrintfCString
28 : #include "LayersLogging.h" // for AppendToString
29 : #include "gfxUtils.h" // for gfxUtils::GetAsLZ4Base64Str
30 : #include "IPDLActor.h"
31 : #include "BufferTexture.h"
32 : #include "gfxPrefs.h"
33 : #include "mozilla/layers/ShadowLayers.h"
34 : #include "mozilla/ipc/CrossProcessSemaphore.h"
35 :
36 : #ifdef XP_WIN
37 : #include "mozilla/gfx/DeviceManagerDx.h"
38 : #include "mozilla/layers/TextureD3D11.h"
39 : #include "mozilla/layers/TextureDIB.h"
40 : #include "gfxWindowsPlatform.h"
41 : #include "gfx2DGlue.h"
42 : #endif
43 : #ifdef MOZ_X11
44 : #include "mozilla/layers/TextureClientX11.h"
45 : #ifdef GL_PROVIDER_GLX
46 : #include "GLXLibrary.h"
47 : #endif
48 : #endif
49 :
50 : #ifdef XP_MACOSX
51 : #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
52 : #endif
53 :
54 : #if 0
55 : #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
56 : #else
57 : #define RECYCLE_LOG(...) do { } while (0)
58 : #endif
59 :
60 : namespace mozilla {
61 : namespace layers {
62 :
63 : using namespace mozilla::ipc;
64 : using namespace mozilla::gl;
65 : using namespace mozilla::gfx;
66 :
67 24 : struct TextureDeallocParams
68 : {
69 : TextureData* data;
70 : RefPtr<TextureChild> actor;
71 : RefPtr<LayersIPCChannel> allocator;
72 : bool clientDeallocation;
73 : bool syncDeallocation;
74 : bool workAroundSharedSurfaceOwnershipIssue;
75 : };
76 :
77 : void DeallocateTextureClient(TextureDeallocParams params);
78 :
79 : /**
80 : * TextureChild is the content-side incarnation of the PTexture IPDL actor.
81 : *
82 : * TextureChild is used to synchronize a texture client and its corresponding
83 : * TextureHost if needed (a TextureClient that is not shared with the compositor
84 : * does not have a TextureChild)
85 : *
86 : * During the deallocation phase, a TextureChild may hold its recently destroyed
87 : * TextureClient's data until the compositor side confirmed that it is safe to
88 : * deallocte or recycle the it.
89 : */
90 : class TextureChild final : PTextureChild
91 : {
92 12 : ~TextureChild()
93 12 : {
94 : // We should have deallocated mTextureData in ActorDestroy
95 6 : MOZ_ASSERT(!mTextureData);
96 6 : MOZ_ASSERT_IF(!mOwnerCalledDestroy, !mTextureClient);
97 18 : }
98 : public:
99 66 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
100 :
101 9 : TextureChild()
102 9 : : mCompositableForwarder(nullptr)
103 : , mTextureForwarder(nullptr)
104 : , mTextureClient(nullptr)
105 : , mTextureData(nullptr)
106 : , mDestroyed(false)
107 : , mMainThreadOnly(false)
108 : , mIPCOpen(false)
109 : , mOwnsTextureData(false)
110 9 : , mOwnerCalledDestroy(false)
111 9 : {}
112 :
113 6 : mozilla::ipc::IPCResult Recv__delete__() override { return IPC_OK(); }
114 :
115 6 : LayersIPCChannel* GetAllocator() { return mTextureForwarder; }
116 :
117 : void ActorDestroy(ActorDestroyReason why) override;
118 :
119 15 : bool IPCOpen() const { return mIPCOpen; }
120 :
121 53 : void Lock() const { if (mCompositableForwarder && mCompositableForwarder->GetTextureForwarder()->UsesImageBridge()) { mLock.Enter(); } }
122 :
123 53 : void Unlock() const { if (mCompositableForwarder && mCompositableForwarder->GetTextureForwarder()->UsesImageBridge()) { mLock.Leave(); } }
124 :
125 : private:
126 :
127 : // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
128 : // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
129 : // The purpose of these methods is to be aware of when the IPC system around this
130 : // actor goes down: mIPCOpen is then set to false.
131 9 : void AddIPDLReference() {
132 9 : MOZ_ASSERT(mIPCOpen == false);
133 9 : mIPCOpen = true;
134 9 : AddRef();
135 9 : }
136 6 : void ReleaseIPDLReference() {
137 6 : MOZ_ASSERT(mIPCOpen == false);
138 6 : Release();
139 6 : }
140 :
141 : /// The normal way to destroy the actor.
142 : ///
143 : /// This will asynchronously send a Destroy message to the parent actor, whom
144 : /// will send the delete message.
145 : void Destroy(const TextureDeallocParams& aParams);
146 :
147 : // This lock is used order to prevent several threads to access the
148 : // TextureClient's data concurrently. In particular, it prevents shutdown
149 : // code to destroy a texture while another thread is reading or writing into
150 : // it.
151 : // In most places, the lock is held in short and bounded scopes in which we
152 : // don't block on any other resource. There are few exceptions to this, which
153 : // are discussed below.
154 : //
155 : // The locking pattern of TextureClient may in some case upset deadlock detection
156 : // tools such as TSan.
157 : // Typically our tile rendering code will lock all of its tiles, render into them
158 : // and unlock them all right after that, which looks something like:
159 : //
160 : // Lock tile A
161 : // Lock tile B
162 : // Lock tile C
163 : // Apply drawing commands to tiles A, B and C
164 : // Unlock tile A
165 : // Unlock tile B
166 : // Unlock tile C
167 : //
168 : // And later, we may end up rendering a tile buffer that has the same tiles,
169 : // in a different order, for example:
170 : //
171 : // Lock tile B
172 : // Lock tile A
173 : // Lock tile D
174 : // Apply drawing commands to tiles A, B and D
175 : // Unlock tile B
176 : // Unlock tile A
177 : // Unlock tile D
178 : //
179 : // This is because textures being expensive to create, we recycle them as much
180 : // as possible and they may reappear in the tile buffer in a different order.
181 : //
182 : // Unfortunately this is not very friendly to TSan's analysis, which will see
183 : // that B was once locked while A was locked, and then A locked while B was
184 : // locked. TSan identifies this as a potential dead-lock which would be the
185 : // case if this kind of inconsistent and dependent locking order was happening
186 : // concurrently.
187 : // In the case of TextureClient, dependent locking only ever happens on the
188 : // thread that draws into the texture (let's call it the producer thread). Other
189 : // threads may call into a method that can lock the texture in a short and
190 : // bounded scope inside of which it is not allowed to do anything that could
191 : // cause the thread to block. A given texture can only have one producer thread.
192 : //
193 : // Another example of TSan-unfriendly locking pattern is when copying a texture
194 : // into another, which also never happens outside of the producer thread.
195 : // Copying A into B looks like this:
196 : //
197 : // Lock texture B
198 : // Lock texture A
199 : // Copy A into B
200 : // Unlock A
201 : // Unlock B
202 : //
203 : // In a given frame we may need to copy A into B and in another frame copy
204 : // B into A. For example A and B can be the Front and Back buffers, alternating
205 : // roles and the copy is needed to avoid the cost of re-drawing the valid
206 : // region.
207 : //
208 : // The important rule is that all of the dependent locking must occur only
209 : // in the texture's producer thread to avoid deadlocks.
210 : mutable gfx::CriticalSection mLock;
211 :
212 : RefPtr<CompositableForwarder> mCompositableForwarder;
213 : RefPtr<TextureForwarder> mTextureForwarder;
214 :
215 : TextureClient* mTextureClient;
216 : TextureData* mTextureData;
217 : Atomic<bool> mDestroyed;
218 : bool mMainThreadOnly;
219 : bool mIPCOpen;
220 : bool mOwnsTextureData;
221 : bool mOwnerCalledDestroy;
222 :
223 : friend class TextureClient;
224 : friend void DeallocateTextureClient(TextureDeallocParams params);
225 : };
226 :
227 :
228 6 : static void DestroyTextureData(TextureData* aTextureData, LayersIPCChannel* aAllocator,
229 : bool aDeallocate, bool aMainThreadOnly)
230 : {
231 6 : if (!aTextureData) {
232 0 : return;
233 : }
234 :
235 6 : if (aMainThreadOnly && !NS_IsMainThread()) {
236 0 : RefPtr<LayersIPCChannel> allocatorRef = aAllocator;
237 0 : NS_DispatchToMainThread(NS_NewRunnableFunction(
238 : "layers::DestroyTextureData",
239 0 : [aTextureData, allocatorRef, aDeallocate]() -> void {
240 0 : DestroyTextureData(aTextureData, allocatorRef, aDeallocate, true);
241 0 : }));
242 0 : return;
243 : }
244 :
245 6 : if (aDeallocate) {
246 0 : aTextureData->Deallocate(aAllocator);
247 : } else {
248 6 : aTextureData->Forget(aAllocator);
249 : }
250 6 : delete aTextureData;
251 : }
252 :
253 : void
254 6 : TextureChild::ActorDestroy(ActorDestroyReason why)
255 : {
256 12 : AUTO_PROFILER_LABEL("TextureChild::ActorDestroy", GRAPHICS);
257 6 : MOZ_ASSERT(mIPCOpen);
258 6 : mIPCOpen = false;
259 :
260 6 : if (mTextureData) {
261 6 : DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
262 6 : mTextureData = nullptr;
263 : }
264 6 : }
265 :
266 : void
267 6 : TextureChild::Destroy(const TextureDeallocParams& aParams)
268 : {
269 6 : MOZ_ASSERT(!mOwnerCalledDestroy);
270 6 : if (mOwnerCalledDestroy) {
271 0 : return;
272 : }
273 :
274 6 : mOwnerCalledDestroy = true;
275 :
276 6 : if (!IPCOpen()) {
277 0 : DestroyTextureData(
278 0 : aParams.data,
279 : aParams.allocator,
280 0 : aParams.clientDeallocation,
281 0 : mMainThreadOnly);
282 0 : return;
283 : }
284 :
285 : // DestroyTextureData will be called by TextureChild::ActorDestroy
286 6 : mTextureData = aParams.data;
287 6 : mOwnsTextureData = aParams.clientDeallocation;
288 :
289 12 : if (!mCompositableForwarder ||
290 6 : !mCompositableForwarder->DestroyInTransaction(this))
291 : {
292 4 : this->SendDestroy();
293 : }
294 : }
295 :
296 : /* static */ Atomic<uint64_t> TextureClient::sSerialCounter(0);
297 :
298 0 : void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
299 : ReentrantMonitor* aBarrier, bool* aDone)
300 : {
301 0 : DeallocateTextureClient(params);
302 0 : ReentrantMonitorAutoEnter autoMon(*aBarrier);
303 0 : *aDone = true;
304 0 : aBarrier->NotifyAll();
305 0 : }
306 :
307 : /// The logic for synchronizing a TextureClient's deallocation goes here.
308 : ///
309 : /// This funciton takes care of dispatching work to the right thread using
310 : /// a synchronous proxy if needed, and handles client/host deallocation.
311 : void
312 6 : DeallocateTextureClient(TextureDeallocParams params)
313 : {
314 6 : if (!params.actor && !params.data) {
315 : // Nothing to do
316 0 : return;
317 : }
318 :
319 6 : TextureChild* actor = params.actor;
320 6 : MessageLoop* ipdlMsgLoop = nullptr;
321 :
322 6 : if (params.allocator) {
323 6 : ipdlMsgLoop = params.allocator->GetMessageLoop();
324 6 : if (!ipdlMsgLoop) {
325 : // An allocator with no message loop means we are too late in the shutdown
326 : // sequence.
327 0 : gfxCriticalError() << "Texture deallocated too late during shutdown";
328 0 : return;
329 : }
330 : }
331 :
332 : // First make sure that the work is happening on the IPDL thread.
333 6 : if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
334 0 : if (params.syncDeallocation) {
335 0 : bool done = false;
336 0 : ReentrantMonitor barrier("DeallocateTextureClient");
337 0 : ReentrantMonitorAutoEnter autoMon(barrier);
338 0 : ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClientSyncProxy,
339 0 : params, &barrier, &done));
340 0 : while (!done) {
341 0 : barrier.Wait();
342 : }
343 : } else {
344 0 : ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClient,
345 0 : params));
346 : }
347 : // The work has been forwarded to the IPDL thread, we are done.
348 0 : return;
349 : }
350 :
351 : // Below this line, we are either in the IPDL thread or ther is no IPDL
352 : // thread anymore.
353 :
354 6 : if (!ipdlMsgLoop) {
355 : // If we don't have a message loop we can't know for sure that we are in
356 : // the IPDL thread and use the LayersIPCChannel.
357 : // This should ideally not happen outside of gtest, but some shutdown raciness
358 : // could put us in this situation.
359 0 : params.allocator = nullptr;
360 : }
361 :
362 6 : if (!actor) {
363 : // We don't have an IPDL actor, probably because we destroyed the TextureClient
364 : // before sharing it with the compositor. It means the data cannot be owned by
365 : // the TextureHost since we never created the TextureHost...
366 : // ..except if the lovely mWorkaroundAnnoyingSharedSurfaceOwnershipIssues member
367 : // is set to true. In this case we are in a special situation where this
368 : // TextureClient is in wrapped into another TextureClient which assumes it owns
369 : // our data.
370 0 : bool shouldDeallocate = !params.workAroundSharedSurfaceOwnershipIssue;
371 0 : DestroyTextureData(params.data, params.allocator,
372 : shouldDeallocate,
373 0 : false); // main-thread deallocation
374 0 : return;
375 : }
376 :
377 6 : actor->Destroy(params);
378 : }
379 :
380 6 : void TextureClient::Destroy()
381 : {
382 6 : if (mActor && !mIsLocked) {
383 6 : mActor->Lock();
384 : }
385 :
386 6 : mBorrowedDrawTarget = nullptr;
387 6 : mReadLock = nullptr;
388 :
389 12 : RefPtr<TextureChild> actor = mActor;
390 6 : mActor = nullptr;
391 :
392 6 : if (actor && !actor->mDestroyed.compareExchange(false, true)) {
393 0 : actor->Unlock();
394 0 : actor = nullptr;
395 : }
396 :
397 6 : TextureData* data = mData;
398 6 : if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
399 6 : mData = nullptr;
400 : }
401 :
402 6 : if (data || actor) {
403 12 : TextureDeallocParams params;
404 6 : params.actor = actor;
405 6 : params.allocator = mAllocator;
406 6 : params.clientDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
407 6 : params.workAroundSharedSurfaceOwnershipIssue = mWorkaroundAnnoyingSharedSurfaceOwnershipIssues;
408 6 : if (mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
409 0 : params.data = nullptr;
410 : } else {
411 6 : params.data = data;
412 : }
413 : // At the moment we always deallocate synchronously when deallocating on the
414 : // client side, but having asynchronous deallocate in some of the cases will
415 : // be a worthwhile optimization.
416 6 : params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
417 :
418 : // Release the lock before calling DeallocateTextureClient because the latter
419 : // may wait for the main thread which could create a dead-lock.
420 :
421 6 : if (actor) {
422 6 : actor->Unlock();
423 : }
424 :
425 6 : DeallocateTextureClient(params);
426 : }
427 6 : }
428 :
429 : void
430 47 : TextureClient::LockActor() const
431 : {
432 47 : if (mActor) {
433 47 : mActor->Lock();
434 : }
435 47 : }
436 :
437 : void
438 47 : TextureClient::UnlockActor() const
439 : {
440 47 : if (mActor) {
441 47 : mActor->Unlock();
442 : }
443 47 : }
444 :
445 : bool
446 0 : TextureClient::IsReadLocked() const
447 : {
448 0 : if (!mReadLock) {
449 0 : return false;
450 : }
451 0 : MOZ_ASSERT(mReadLock->AsNonBlockingLock(), "Can only check locked for non-blocking locks!");
452 0 : return mReadLock->AsNonBlockingLock()->GetReadCount() > 1;
453 : }
454 :
455 : bool
456 34 : TextureClient::TryReadLock()
457 : {
458 34 : if (!mReadLock || mIsReadLocked) {
459 0 : return true;
460 : }
461 :
462 34 : if (mReadLock->AsNonBlockingLock()) {
463 0 : if (IsReadLocked()) {
464 0 : return false;
465 : }
466 : }
467 :
468 34 : if (!mReadLock->TryReadLock(TimeDuration::FromMilliseconds(500))) {
469 0 : return false;
470 : }
471 :
472 34 : mIsReadLocked = true;
473 34 : return true;
474 : }
475 :
476 : void
477 47 : TextureClient::ReadUnlock()
478 : {
479 47 : if (!mIsReadLocked) {
480 13 : return;
481 : }
482 34 : MOZ_ASSERT(mReadLock);
483 34 : mReadLock->ReadUnlock();
484 34 : mIsReadLocked = false;
485 : }
486 :
487 : bool
488 47 : TextureClient::Lock(OpenMode aMode)
489 : {
490 47 : MOZ_ASSERT(IsValid());
491 47 : MOZ_ASSERT(!mIsLocked);
492 47 : if (!IsValid()) {
493 0 : return false;
494 : }
495 47 : if (mIsLocked) {
496 0 : return mOpenMode == aMode;
497 : }
498 :
499 47 : if (aMode & OpenMode::OPEN_WRITE && !TryReadLock()) {
500 0 : NS_WARNING("Attempt to Lock a texture that is being read by the compositor!");
501 0 : return false;
502 : }
503 :
504 47 : LockActor();
505 :
506 47 : mIsLocked = mData->Lock(aMode);
507 47 : mOpenMode = aMode;
508 :
509 47 : auto format = GetFormat();
510 141 : if (mIsLocked && CanExposeDrawTarget() &&
511 34 : aMode == OpenMode::OPEN_READ_WRITE &&
512 149 : NS_IsMainThread() &&
513 : // the formats that we apparently expect, in the cairo backend. Any other
514 : // format will trigger an assertion in GfxFormatToCairoFormat.
515 18 : (format == SurfaceFormat::A8R8G8B8_UINT32 ||
516 0 : format == SurfaceFormat::X8R8G8B8_UINT32 ||
517 0 : format == SurfaceFormat::A8 ||
518 : format == SurfaceFormat::R5G6B5_UINT16)) {
519 34 : if (!BorrowDrawTarget()) {
520 : // Failed to get a DrawTarget, means we won't be able to write into the
521 : // texture, might as well fail now.
522 0 : Unlock();
523 0 : return false;
524 : }
525 : }
526 :
527 47 : if (!mIsLocked) {
528 0 : UnlockActor();
529 0 : ReadUnlock();
530 : }
531 :
532 47 : return mIsLocked;
533 : }
534 :
535 : void
536 47 : TextureClient::Unlock()
537 : {
538 47 : MOZ_ASSERT(IsValid());
539 47 : MOZ_ASSERT(mIsLocked);
540 47 : if (!IsValid() || !mIsLocked) {
541 0 : return;
542 : }
543 :
544 47 : if (mBorrowedDrawTarget) {
545 47 : if (mOpenMode & OpenMode::OPEN_WRITE) {
546 34 : mBorrowedDrawTarget->Flush();
547 34 : if (mReadbackSink && !mData->ReadBack(mReadbackSink)) {
548 : // Fallback implementation for reading back, because mData does not
549 : // have a backend-specific implementation and returned false.
550 0 : RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
551 0 : RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
552 0 : mReadbackSink->ProcessReadback(dataSurf);
553 : }
554 : }
555 :
556 47 : mBorrowedDrawTarget->DetachAllSnapshots();
557 : // If this assertion is hit, it means something is holding a strong reference
558 : // to our DrawTarget externally, which is not allowed.
559 47 : MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
560 :
561 47 : mBorrowedDrawTarget = nullptr;
562 : }
563 :
564 47 : if (mOpenMode & OpenMode::OPEN_WRITE) {
565 34 : mUpdated = true;
566 : }
567 :
568 47 : if (mData) {
569 47 : mData->Unlock();
570 : }
571 47 : mIsLocked = false;
572 47 : mOpenMode = OpenMode::OPEN_NONE;
573 :
574 47 : UnlockActor();
575 47 : ReadUnlock();
576 : }
577 :
578 : void
579 0 : TextureClient::EnableReadLock()
580 : {
581 0 : if (!mReadLock) {
582 0 : mReadLock = NonBlockingTextureReadLock::Create(mAllocator);
583 : }
584 0 : }
585 :
586 : bool
587 33 : TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor)
588 : {
589 33 : if (mReadLock && mUpdated) {
590 : // Take a read lock on behalf of the TextureHost. The latter will unlock
591 : // after the shared data is available again for drawing.
592 33 : mReadLock->ReadLock();
593 33 : mUpdated = false;
594 33 : if (mReadLock->Serialize(aDescriptor, GetAllocator()->GetParentPid())) {
595 33 : return true;
596 : }
597 : }
598 :
599 0 : aDescriptor = null_t();
600 0 : return false;
601 : }
602 :
603 18 : TextureClient::~TextureClient()
604 : {
605 6 : mReadLock = nullptr;
606 6 : Destroy();
607 18 : }
608 :
609 : void
610 0 : TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
611 : {
612 0 : MOZ_ASSERT(IsValid());
613 0 : MOZ_ASSERT(mIsLocked);
614 0 : MOZ_ASSERT(aSurface);
615 : // If you run into this assertion, make sure the texture was locked write-only
616 : // rather than read-write.
617 0 : MOZ_ASSERT(!mBorrowedDrawTarget);
618 :
619 : // XXX - It would be better to first try the DrawTarget approach and fallback
620 : // to the backend-specific implementation because the latter will usually do
621 : // an expensive read-back + cpu-side copy if the texture is on the gpu.
622 : // There is a bug with the DrawTarget approach, though specific to reading back
623 : // from WebGL (where R and B channel end up inverted) to figure out first.
624 0 : if (mData->UpdateFromSurface(aSurface)) {
625 0 : return;
626 : }
627 0 : if (CanExposeDrawTarget() && NS_IsMainThread()) {
628 0 : RefPtr<DrawTarget> dt = BorrowDrawTarget();
629 :
630 0 : MOZ_ASSERT(dt);
631 0 : if (dt) {
632 0 : dt->CopySurface(aSurface,
633 0 : gfx::IntRect(gfx::IntPoint(0, 0), aSurface->GetSize()),
634 0 : gfx::IntPoint(0, 0));
635 0 : return;
636 : }
637 : }
638 0 : NS_WARNING("TextureClient::UpdateFromSurface failed");
639 : }
640 :
641 :
642 : already_AddRefed<TextureClient>
643 0 : TextureClient::CreateSimilar(LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
644 : {
645 0 : MOZ_ASSERT(IsValid());
646 :
647 0 : MOZ_ASSERT(!mIsLocked);
648 0 : if (mIsLocked) {
649 0 : return nullptr;
650 : }
651 :
652 0 : LockActor();
653 0 : TextureData* data = mData->CreateSimilar(mAllocator, aLayersBackend, aFlags, aAllocFlags);
654 0 : UnlockActor();
655 :
656 0 : if (!data) {
657 0 : return nullptr;
658 : }
659 :
660 0 : return MakeAndAddRef<TextureClient>(data, aFlags, mAllocator);
661 : }
662 :
663 : gfx::DrawTarget*
664 81 : TextureClient::BorrowDrawTarget()
665 : {
666 81 : MOZ_ASSERT(IsValid());
667 81 : MOZ_ASSERT(mIsLocked);
668 : // TODO- We can't really assert that at the moment because there is code that Borrows
669 : // the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
670 : // but we should have a way to get a SourceSurface directly instead.
671 : //MOZ_ASSERT(mOpenMode & OpenMode::OPEN_WRITE);
672 :
673 81 : if (!IsValid() || !mIsLocked) {
674 0 : return nullptr;
675 : }
676 :
677 81 : if (!NS_IsMainThread()) {
678 0 : return nullptr;
679 : }
680 :
681 81 : if (!mBorrowedDrawTarget) {
682 47 : mBorrowedDrawTarget = mData->BorrowDrawTarget();
683 : #ifdef DEBUG
684 47 : mExpectedDtRefs = mBorrowedDrawTarget ? mBorrowedDrawTarget->refCount() : 0;
685 : #endif
686 : }
687 :
688 81 : return mBorrowedDrawTarget;
689 : }
690 :
691 : bool
692 0 : TextureClient::BorrowMappedData(MappedTextureData& aMap)
693 : {
694 0 : MOZ_ASSERT(IsValid());
695 :
696 : // TODO - SharedRGBImage just accesses the buffer without properly locking
697 : // the texture. It's bad.
698 : //MOZ_ASSERT(mIsLocked);
699 : //if (!mIsLocked) {
700 : // return nullptr;
701 : //}
702 :
703 0 : return mData ? mData->BorrowMappedData(aMap) : false;
704 : }
705 :
706 : bool
707 0 : TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
708 : {
709 0 : MOZ_ASSERT(IsValid());
710 :
711 0 : return mData ? mData->BorrowMappedYCbCrData(aMap) : false;
712 : }
713 :
714 : bool
715 9 : TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
716 : {
717 9 : MOZ_ASSERT(IsValid());
718 :
719 9 : return mData ? mData->Serialize(aOutDescriptor) : false;
720 : }
721 :
722 : // static
723 : PTextureChild*
724 9 : TextureClient::CreateIPDLActor()
725 : {
726 9 : TextureChild* c = new TextureChild();
727 9 : c->AddIPDLReference();
728 9 : return c;
729 : }
730 :
731 : // static
732 : bool
733 6 : TextureClient::DestroyIPDLActor(PTextureChild* actor)
734 : {
735 6 : static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
736 6 : return true;
737 : }
738 :
739 : // static
740 : already_AddRefed<TextureClient>
741 0 : TextureClient::AsTextureClient(PTextureChild* actor)
742 : {
743 0 : if (!actor) {
744 0 : return nullptr;
745 : }
746 :
747 0 : TextureChild* tc = static_cast<TextureChild*>(actor);
748 :
749 0 : tc->Lock();
750 :
751 : // Since TextureClient may be destroyed asynchronously with respect to its
752 : // IPDL actor, we must acquire a reference within a lock. The mDestroyed bit
753 : // tells us whether or not the main thread has disconnected the TextureClient
754 : // from its actor.
755 0 : if (tc->mDestroyed) {
756 0 : tc->Unlock();
757 0 : return nullptr;
758 : }
759 :
760 0 : RefPtr<TextureClient> texture = tc->mTextureClient;
761 0 : tc->Unlock();
762 :
763 0 : return texture.forget();
764 : }
765 :
766 : bool
767 0 : TextureClient::IsSharedWithCompositor() const {
768 0 : return mActor && mActor->IPCOpen();
769 : }
770 :
771 : void
772 0 : TextureClient::AddFlags(TextureFlags aFlags)
773 : {
774 0 : MOZ_ASSERT(!IsSharedWithCompositor() ||
775 : ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
776 0 : mFlags |= aFlags;
777 0 : }
778 :
779 : void
780 0 : TextureClient::RemoveFlags(TextureFlags aFlags)
781 : {
782 0 : MOZ_ASSERT(!IsSharedWithCompositor() ||
783 : ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
784 0 : mFlags &= ~aFlags;
785 0 : }
786 :
787 : void
788 0 : TextureClient::RecycleTexture(TextureFlags aFlags)
789 : {
790 0 : MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
791 0 : MOZ_ASSERT(!mIsLocked);
792 :
793 0 : mAddedToCompositableClient = false;
794 0 : if (mFlags != aFlags) {
795 0 : mFlags = aFlags;
796 : }
797 0 : }
798 :
799 : void
800 9 : TextureClient::SetAddedToCompositableClient()
801 : {
802 9 : if (!mAddedToCompositableClient) {
803 9 : mAddedToCompositableClient = true;
804 9 : if(!(GetFlags() & TextureFlags::RECYCLE)) {
805 9 : return;
806 : }
807 0 : MOZ_ASSERT(!mIsLocked);
808 0 : LockActor();
809 0 : if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
810 0 : mActor->SendRecycleTexture(mFlags);
811 : }
812 0 : UnlockActor();
813 : }
814 : }
815 :
816 0 : void CancelTextureClientRecycle(uint64_t aTextureId, LayersIPCChannel* aAllocator)
817 : {
818 0 : if (!aAllocator) {
819 0 : return;
820 : }
821 0 : MessageLoop* msgLoop = nullptr;
822 0 : msgLoop = aAllocator->GetMessageLoop();
823 0 : if (!msgLoop) {
824 0 : return;
825 : }
826 0 : if (MessageLoop::current() == msgLoop) {
827 0 : aAllocator->CancelWaitForRecycle(aTextureId);
828 : } else {
829 0 : msgLoop->PostTask(NewRunnableFunction(CancelTextureClientRecycle,
830 0 : aTextureId, aAllocator));
831 : }
832 : }
833 :
834 : void
835 0 : TextureClient::CancelWaitForRecycle()
836 : {
837 0 : if (GetFlags() & TextureFlags::RECYCLE) {
838 0 : CancelTextureClientRecycle(mSerial, GetAllocator());
839 0 : return;
840 : }
841 : }
842 :
843 : /* static */ void
844 0 : TextureClient::TextureClientRecycleCallback(TextureClient* aClient, void* aClosure)
845 : {
846 0 : MOZ_ASSERT(aClient->GetRecycleAllocator());
847 0 : aClient->GetRecycleAllocator()->RecycleTextureClient(aClient);
848 0 : }
849 :
850 : void
851 0 : TextureClient::SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator)
852 : {
853 0 : mRecycleAllocator = aAllocator;
854 0 : if (aAllocator) {
855 0 : SetRecycleCallback(TextureClientRecycleCallback, nullptr);
856 : } else {
857 0 : ClearRecycleCallback();
858 : }
859 0 : }
860 :
861 : bool
862 9 : TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
863 : {
864 9 : MOZ_ASSERT(aForwarder && aForwarder->GetTextureForwarder()->GetMessageLoop() == mAllocator->GetMessageLoop());
865 :
866 9 : if (mActor && !mActor->IPCOpen()) {
867 0 : return false;
868 : }
869 :
870 9 : if (mActor && !mActor->mDestroyed) {
871 0 : CompositableForwarder* currentFwd = mActor->mCompositableForwarder;
872 0 : TextureForwarder* currentTexFwd = mActor->mTextureForwarder;
873 0 : if (currentFwd != aForwarder) {
874 : // It's a bit iffy but right now ShadowLayerForwarder inherits TextureForwarder
875 : // even though it should not. ShadowLayerForwarder::GetTextureForwarder actually
876 : // returns a pointer to the CompositorBridgeChild.
877 : // It's Ok for a texture to move from a ShadowLayerForwarder to another, but
878 : // not form a CompositorBridgeChild to another (they use different channels).
879 0 : if (currentTexFwd && currentTexFwd != aForwarder->GetTextureForwarder()) {
880 0 : gfxCriticalError() << "Attempt to move a texture to a different channel CF.";
881 0 : return false;
882 : }
883 0 : if (currentFwd && currentFwd->GetCompositorBackendType() != aForwarder->GetCompositorBackendType()) {
884 0 : gfxCriticalError() << "Attempt to move a texture to different compositor backend.";
885 0 : return false;
886 : }
887 0 : if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
888 : // Do the DOM labeling.
889 0 : if (nsIEventTarget* target = forwarder->GetEventTarget()) {
890 0 : forwarder->GetCompositorBridgeChild()->ReplaceEventTargetForActor(
891 0 : mActor, target);
892 : }
893 : }
894 0 : mActor->mCompositableForwarder = aForwarder;
895 : }
896 0 : return true;
897 : }
898 9 : MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
899 :
900 18 : SurfaceDescriptor desc;
901 9 : if (!ToSurfaceDescriptor(desc)) {
902 0 : return false;
903 : }
904 :
905 : // Try external image id allocation.
906 9 : mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
907 :
908 9 : nsIEventTarget* target = nullptr;
909 : // Get the layers id if the forwarder is a ShadowLayerForwarder.
910 9 : if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
911 9 : target = forwarder->GetEventTarget();
912 : }
913 :
914 27 : PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture(
915 : desc,
916 : aForwarder->GetCompositorBackendType(),
917 : GetFlags(),
918 9 : mSerial,
919 : mExternalImageId,
920 18 : target);
921 :
922 9 : if (!actor) {
923 0 : gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
924 0 : << static_cast<int32_t>(aForwarder->GetCompositorBackendType()) << ", "
925 0 : << static_cast<uint32_t>(GetFlags())
926 0 : << ", " << mSerial;
927 0 : return false;
928 : }
929 :
930 9 : mActor = static_cast<TextureChild*>(actor);
931 9 : mActor->mCompositableForwarder = aForwarder;
932 9 : mActor->mTextureForwarder = aForwarder->GetTextureForwarder();
933 9 : mActor->mTextureClient = this;
934 9 : mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
935 :
936 : // If the TextureClient is already locked, we have to lock TextureChild's mutex
937 : // since it will be unlocked in TextureClient::Unlock.
938 9 : if (mIsLocked) {
939 0 : LockActor();
940 : }
941 :
942 9 : return mActor->IPCOpen();
943 : }
944 :
945 : bool
946 0 : TextureClient::InitIPDLActor(KnowsCompositor* aForwarder)
947 : {
948 0 : MOZ_ASSERT(aForwarder && aForwarder->GetTextureForwarder()->GetMessageLoop() == mAllocator->GetMessageLoop());
949 0 : TextureForwarder* fwd = aForwarder->GetTextureForwarder();
950 0 : if (mActor && !mActor->mDestroyed) {
951 0 : CompositableForwarder* currentFwd = mActor->mCompositableForwarder;
952 0 : TextureForwarder* currentTexFwd = mActor->mTextureForwarder;
953 :
954 0 : if (currentFwd) {
955 0 : gfxCriticalError() << "Attempt to remove a texture from a CompositableForwarder.";
956 0 : return false;
957 : }
958 :
959 0 : if (currentTexFwd && currentTexFwd != fwd) {
960 0 : gfxCriticalError() << "Attempt to move a texture to a different channel TF.";
961 0 : return false;
962 : }
963 0 : mActor->mTextureForwarder = fwd;
964 0 : return true;
965 : }
966 0 : MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
967 :
968 0 : SurfaceDescriptor desc;
969 0 : if (!ToSurfaceDescriptor(desc)) {
970 0 : return false;
971 : }
972 :
973 : // Try external image id allocation.
974 0 : mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
975 :
976 0 : PTextureChild* actor = fwd->CreateTexture(
977 : desc,
978 : aForwarder->GetCompositorBackendType(),
979 : GetFlags(),
980 0 : mSerial,
981 0 : mExternalImageId);
982 0 : if (!actor) {
983 0 : gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
984 0 : << static_cast<int32_t>(aForwarder->GetCompositorBackendType()) << ", "
985 0 : << static_cast<uint32_t>(GetFlags())
986 0 : << ", " << mSerial;
987 0 : return false;
988 : }
989 :
990 0 : mActor = static_cast<TextureChild*>(actor);
991 0 : mActor->mTextureForwarder = fwd;
992 0 : mActor->mTextureClient = this;
993 0 : mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
994 :
995 : // If the TextureClient is already locked, we have to lock TextureChild's mutex
996 : // since it will be unlocked in TextureClient::Unlock.
997 0 : if (mIsLocked) {
998 0 : LockActor();
999 : }
1000 :
1001 0 : return mActor->IPCOpen();
1002 : }
1003 :
1004 : PTextureChild*
1005 99 : TextureClient::GetIPDLActor()
1006 : {
1007 99 : return mActor;
1008 : }
1009 :
1010 : static inline gfx::BackendType
1011 9 : BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
1012 : {
1013 9 : switch (aSelector) {
1014 : case BackendSelector::Canvas:
1015 0 : return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
1016 : case BackendSelector::Content:
1017 9 : return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
1018 : default:
1019 0 : MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
1020 : return gfx::BackendType::NONE;
1021 : }
1022 : };
1023 :
1024 : // static
1025 : already_AddRefed<TextureClient>
1026 9 : TextureClient::CreateForDrawing(KnowsCompositor* aAllocator,
1027 : gfx::SurfaceFormat aFormat,
1028 : gfx::IntSize aSize,
1029 : BackendSelector aSelector,
1030 : TextureFlags aTextureFlags,
1031 : TextureAllocationFlags aAllocFlags)
1032 : {
1033 9 : LayersBackend layersBackend = aAllocator->GetCompositorBackendType();
1034 9 : return TextureClient::CreateForDrawing(aAllocator->GetTextureForwarder(),
1035 : aFormat, aSize,
1036 : layersBackend,
1037 : aAllocator->GetMaxTextureSize(),
1038 : aSelector,
1039 : aTextureFlags,
1040 18 : aAllocFlags);
1041 : }
1042 :
1043 : // static
1044 : already_AddRefed<TextureClient>
1045 9 : TextureClient::CreateForDrawing(TextureForwarder* aAllocator,
1046 : gfx::SurfaceFormat aFormat,
1047 : gfx::IntSize aSize,
1048 : LayersBackend aLayersBackend,
1049 : int32_t aMaxTextureSize,
1050 : BackendSelector aSelector,
1051 : TextureFlags aTextureFlags,
1052 : TextureAllocationFlags aAllocFlags)
1053 : {
1054 9 : gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(aLayersBackend, aSelector);
1055 :
1056 : // also test the validity of aAllocator
1057 9 : if (!aAllocator || !aAllocator->IPCOpen()) {
1058 0 : return nullptr;
1059 : }
1060 :
1061 9 : if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
1062 0 : return nullptr;
1063 : }
1064 :
1065 9 : TextureData* data = nullptr;
1066 :
1067 : #ifdef XP_WIN
1068 : if (aLayersBackend == LayersBackend::LAYERS_D3D11 &&
1069 : (moz2DBackend == gfx::BackendType::DIRECT2D ||
1070 : moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
1071 : (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
1072 : DeviceManagerDx::Get()->GetContentDevice())) &&
1073 : aSize.width <= aMaxTextureSize &&
1074 : aSize.height <= aMaxTextureSize &&
1075 : !(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE))
1076 : {
1077 : data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
1078 : }
1079 :
1080 : if (aLayersBackend != LayersBackend::LAYERS_WR &&
1081 : !data && aFormat == SurfaceFormat::B8G8R8X8 &&
1082 : moz2DBackend == gfx::BackendType::CAIRO &&
1083 : NS_IsMainThread()) {
1084 : data = DIBTextureData::Create(aSize, aFormat, aAllocator);
1085 : }
1086 : #endif
1087 :
1088 : #ifdef MOZ_X11
1089 : gfxSurfaceType type =
1090 9 : gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
1091 :
1092 9 : if (!data && aLayersBackend == LayersBackend::LAYERS_BASIC &&
1093 0 : moz2DBackend == gfx::BackendType::CAIRO &&
1094 : type == gfxSurfaceType::Xlib)
1095 : {
1096 0 : data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
1097 : }
1098 : #ifdef GL_PROVIDER_GLX
1099 27 : if (!data && aLayersBackend == LayersBackend::LAYERS_OPENGL &&
1100 0 : type == gfxSurfaceType::Xlib &&
1101 9 : aFormat != SurfaceFormat::A8 &&
1102 0 : gl::sGLXLibrary.UseTextureFromPixmap())
1103 : {
1104 0 : data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
1105 : }
1106 : #endif
1107 : #endif
1108 :
1109 : #ifdef XP_MACOSX
1110 : if (!data && gfxPrefs::UseIOSurfaceTextures()) {
1111 : data = MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
1112 : }
1113 : #endif
1114 :
1115 9 : if (data) {
1116 0 : return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
1117 : }
1118 :
1119 9 : if (moz2DBackend == BackendType::SKIA && aFormat == SurfaceFormat::B8G8R8X8) {
1120 : // Skia doesn't support RGBX, so ensure we clear the buffer for the proper alpha values.
1121 5 : aAllocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_CLEAR_BUFFER);
1122 : }
1123 :
1124 : // Can't do any better than a buffer texture client.
1125 : return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,
1126 : moz2DBackend, aLayersBackend,
1127 9 : aTextureFlags, aAllocFlags);
1128 : }
1129 :
1130 : // static
1131 : already_AddRefed<TextureClient>
1132 0 : TextureClient::CreateFromSurface(KnowsCompositor* aAllocator,
1133 : gfx::SourceSurface* aSurface,
1134 : BackendSelector aSelector,
1135 : TextureFlags aTextureFlags,
1136 : TextureAllocationFlags aAllocFlags)
1137 : {
1138 : // also test the validity of aAllocator
1139 0 : if (!aAllocator || !aAllocator->GetTextureForwarder()->IPCOpen()) {
1140 0 : return nullptr;
1141 : }
1142 :
1143 0 : gfx::IntSize size = aSurface->GetSize();
1144 :
1145 0 : if (!gfx::Factory::AllowedSurfaceSize(size)) {
1146 0 : return nullptr;
1147 : }
1148 :
1149 0 : TextureData* data = nullptr;
1150 : #if defined(XP_WIN)
1151 : LayersBackend layersBackend = aAllocator->GetCompositorBackendType();
1152 : gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(layersBackend, aSelector);
1153 :
1154 : int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
1155 :
1156 : if (layersBackend == LayersBackend::LAYERS_D3D11 &&
1157 : (moz2DBackend == gfx::BackendType::DIRECT2D ||
1158 : moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
1159 : (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
1160 : DeviceManagerDx::Get()->GetContentDevice())) &&
1161 : size.width <= maxTextureSize &&
1162 : size.height <= maxTextureSize)
1163 : {
1164 : data = D3D11TextureData::Create(aSurface, aAllocFlags);
1165 : }
1166 : #endif
1167 :
1168 0 : if (data) {
1169 0 : return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator->GetTextureForwarder());
1170 : }
1171 :
1172 : // Fall back to using UpdateFromSurface
1173 :
1174 0 : TextureAllocationFlags allocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_UPDATE_FROM_SURFACE);
1175 0 : RefPtr<TextureClient> client = CreateForDrawing(aAllocator, aSurface->GetFormat(), size,
1176 0 : aSelector, aTextureFlags, allocFlags);
1177 0 : if (!client) {
1178 0 : return nullptr;
1179 : }
1180 :
1181 0 : TextureClientAutoLock autoLock(client, OpenMode::OPEN_WRITE_ONLY);
1182 0 : if (!autoLock.Succeeded()) {
1183 0 : return nullptr;
1184 : }
1185 :
1186 0 : client->UpdateFromSurface(aSurface);
1187 0 : return client.forget();
1188 : }
1189 :
1190 : // static
1191 : already_AddRefed<TextureClient>
1192 0 : TextureClient::CreateForRawBufferAccess(KnowsCompositor* aAllocator,
1193 : gfx::SurfaceFormat aFormat,
1194 : gfx::IntSize aSize,
1195 : gfx::BackendType aMoz2DBackend,
1196 : TextureFlags aTextureFlags,
1197 : TextureAllocationFlags aAllocFlags)
1198 : {
1199 0 : return CreateForRawBufferAccess(aAllocator->GetTextureForwarder(),
1200 : aFormat, aSize, aMoz2DBackend,
1201 : aAllocator->GetCompositorBackendType(),
1202 0 : aTextureFlags, aAllocFlags);
1203 : }
1204 :
1205 : // static
1206 : already_AddRefed<TextureClient>
1207 9 : TextureClient::CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
1208 : gfx::SurfaceFormat aFormat,
1209 : gfx::IntSize aSize,
1210 : gfx::BackendType aMoz2DBackend,
1211 : LayersBackend aLayersBackend,
1212 : TextureFlags aTextureFlags,
1213 : TextureAllocationFlags aAllocFlags)
1214 : {
1215 : // also test the validity of aAllocator
1216 9 : if (!aAllocator || !aAllocator->IPCOpen()) {
1217 0 : return nullptr;
1218 : }
1219 :
1220 9 : if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
1221 0 : return nullptr;
1222 : }
1223 :
1224 9 : if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
1225 0 : return nullptr;
1226 : }
1227 :
1228 : // D2D backend does not support CreateDrawTargetForData(). Use CAIRO instead.
1229 9 : if (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
1230 : aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) {
1231 0 : aMoz2DBackend = gfx::BackendType::CAIRO;
1232 : }
1233 :
1234 9 : TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
1235 : aLayersBackend, aTextureFlags,
1236 9 : aAllocFlags, aAllocator);
1237 9 : if (!texData) {
1238 0 : return nullptr;
1239 : }
1240 :
1241 9 : return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
1242 : }
1243 :
1244 : // static
1245 : already_AddRefed<TextureClient>
1246 0 : TextureClient::CreateForYCbCr(KnowsCompositor* aAllocator,
1247 : gfx::IntSize aYSize,
1248 : gfx::IntSize aCbCrSize,
1249 : StereoMode aStereoMode,
1250 : YUVColorSpace aYUVColorSpace,
1251 : TextureFlags aTextureFlags)
1252 : {
1253 0 : if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
1254 0 : return nullptr;
1255 : }
1256 :
1257 0 : if (!gfx::Factory::AllowedSurfaceSize(aYSize)) {
1258 0 : return nullptr;
1259 : }
1260 :
1261 0 : TextureData* data = BufferTextureData::CreateForYCbCr(aAllocator, aYSize, aCbCrSize,
1262 : aStereoMode, aYUVColorSpace,
1263 0 : aTextureFlags);
1264 0 : if (!data) {
1265 0 : return nullptr;
1266 : }
1267 :
1268 : return MakeAndAddRef<TextureClient>(data, aTextureFlags,
1269 0 : aAllocator->GetTextureForwarder());
1270 : }
1271 :
1272 : // static
1273 : already_AddRefed<TextureClient>
1274 0 : TextureClient::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
1275 : size_t aSize,
1276 : YUVColorSpace aYUVColorSpace,
1277 : TextureFlags aTextureFlags)
1278 : {
1279 0 : if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
1280 0 : return nullptr;
1281 : }
1282 :
1283 : TextureData* data =
1284 0 : BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aSize, aYUVColorSpace,
1285 0 : aTextureFlags);
1286 0 : if (!data) {
1287 0 : return nullptr;
1288 : }
1289 :
1290 : return MakeAndAddRef<TextureClient>(data, aTextureFlags,
1291 0 : aAllocator->GetTextureForwarder());
1292 : }
1293 :
1294 9 : TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
1295 : : AtomicRefCountedWithFinalize("TextureClient")
1296 : , mAllocator(aAllocator)
1297 : , mActor(nullptr)
1298 : , mData(aData)
1299 : , mFlags(aFlags)
1300 : , mOpenMode(OpenMode::OPEN_NONE)
1301 : #ifdef DEBUG
1302 : , mExpectedDtRefs(0)
1303 : #endif
1304 : , mIsLocked(false)
1305 : , mIsReadLocked(false)
1306 : , mUpdated(false)
1307 : , mAddedToCompositableClient(false)
1308 : , mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
1309 : , mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
1310 : , mFwdTransactionId(0)
1311 9 : , mSerial(++sSerialCounter)
1312 : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
1313 18 : , mPoolTracker(nullptr)
1314 : #endif
1315 : {
1316 9 : mData->FillInfo(mInfo);
1317 9 : mFlags |= mData->GetTextureFlags();
1318 9 : }
1319 :
1320 0 : bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
1321 : const gfx::IntRect* aRect,
1322 : const gfx::IntPoint* aPoint)
1323 : {
1324 0 : MOZ_ASSERT(IsLocked());
1325 0 : MOZ_ASSERT(aTarget->IsLocked());
1326 :
1327 0 : if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) {
1328 0 : return false;
1329 : }
1330 :
1331 0 : RefPtr<DrawTarget> destinationTarget = aTarget->BorrowDrawTarget();
1332 0 : if (!destinationTarget) {
1333 0 : gfxWarning() << "TextureClient::CopyToTextureClient (dest) failed in BorrowDrawTarget";
1334 0 : return false;
1335 : }
1336 :
1337 0 : RefPtr<DrawTarget> sourceTarget = BorrowDrawTarget();
1338 0 : if (!sourceTarget) {
1339 0 : gfxWarning() << "TextureClient::CopyToTextureClient (src) failed in BorrowDrawTarget";
1340 0 : return false;
1341 : }
1342 :
1343 0 : RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
1344 0 : destinationTarget->CopySurface(source,
1345 0 : aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
1346 0 : aPoint ? *aPoint : gfx::IntPoint(0, 0));
1347 0 : return true;
1348 : }
1349 :
1350 : already_AddRefed<gfx::DataSourceSurface>
1351 0 : TextureClient::GetAsSurface()
1352 : {
1353 0 : if (!Lock(OpenMode::OPEN_READ)) {
1354 0 : return nullptr;
1355 : }
1356 0 : RefPtr<gfx::DataSourceSurface> data;
1357 : { // scope so that the DrawTarget is destroyed before Unlock()
1358 0 : RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
1359 0 : if (dt) {
1360 0 : RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
1361 0 : if (surf) {
1362 0 : data = surf->GetDataSurface();
1363 : }
1364 : }
1365 : }
1366 0 : Unlock();
1367 0 : return data.forget();
1368 : }
1369 :
1370 : void
1371 0 : TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1372 : {
1373 0 : aStream << aPrefix;
1374 0 : aStream << nsPrintfCString("TextureClient (0x%p)", this).get();
1375 0 : AppendToString(aStream, GetSize(), " [size=", "]");
1376 0 : AppendToString(aStream, GetFormat(), " [format=", "]");
1377 0 : AppendToString(aStream, mFlags, " [flags=", "]");
1378 :
1379 : #ifdef MOZ_DUMP_PAINTING
1380 0 : if (gfxPrefs::LayersDumpTexture() ||
1381 0 : profiler_feature_active(ProfilerFeature::LayersDump)) {
1382 0 : nsAutoCString pfx(aPrefix);
1383 0 : pfx += " ";
1384 :
1385 0 : aStream << "\n" << pfx.get() << "Surface: ";
1386 0 : RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
1387 0 : if (dSurf) {
1388 0 : aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
1389 : }
1390 : }
1391 : #endif
1392 0 : }
1393 :
1394 : class MemoryTextureReadLock : public NonBlockingTextureReadLock {
1395 : public:
1396 : MemoryTextureReadLock();
1397 :
1398 : ~MemoryTextureReadLock();
1399 :
1400 : virtual bool ReadLock() override;
1401 :
1402 : virtual int32_t ReadUnlock() override;
1403 :
1404 : virtual int32_t GetReadCount() override;
1405 :
1406 0 : virtual LockType GetType() override { return TYPE_NONBLOCKING_MEMORY; }
1407 :
1408 0 : virtual bool IsValid() const override { return true; };
1409 :
1410 : virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
1411 :
1412 : int32_t mReadCount;
1413 : };
1414 :
1415 : // The cross-prcess implementation of TextureReadLock.
1416 : //
1417 : // Since we don't use cross-process reference counting for the ReadLock objects,
1418 : // we use the lock's internal counter as a way to know when to deallocate the
1419 : // underlying shmem section: when the counter is equal to 1, it means that the
1420 : // lock is not "held" (the texture is writable), when the counter is equal to 0
1421 : // it means that we can safely deallocate the shmem section without causing a race
1422 : // condition with the other process.
1423 : class ShmemTextureReadLock : public NonBlockingTextureReadLock {
1424 : public:
1425 : struct ShmReadLockInfo {
1426 : int32_t readCount;
1427 : };
1428 :
1429 : explicit ShmemTextureReadLock(LayersIPCChannel* aAllocator);
1430 :
1431 : ~ShmemTextureReadLock();
1432 :
1433 : virtual bool ReadLock() override;
1434 :
1435 : virtual int32_t ReadUnlock() override;
1436 :
1437 : virtual int32_t GetReadCount() override;
1438 :
1439 0 : virtual bool IsValid() const override { return mAllocSuccess; };
1440 :
1441 0 : virtual LockType GetType() override { return TYPE_NONBLOCKING_SHMEM; }
1442 :
1443 : virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
1444 :
1445 0 : mozilla::layers::ShmemSection& GetShmemSection() { return mShmemSection; }
1446 :
1447 0 : explicit ShmemTextureReadLock(const mozilla::layers::ShmemSection& aShmemSection)
1448 0 : : mShmemSection(aShmemSection)
1449 0 : , mAllocSuccess(true)
1450 : {
1451 0 : MOZ_COUNT_CTOR(ShmemTextureReadLock);
1452 0 : }
1453 :
1454 0 : ShmReadLockInfo* GetShmReadLockInfoPtr()
1455 : {
1456 : return reinterpret_cast<ShmReadLockInfo*>
1457 0 : (mShmemSection.shmem().get<char>() + mShmemSection.offset());
1458 : }
1459 :
1460 : RefPtr<LayersIPCChannel> mClientAllocator;
1461 : mozilla::layers::ShmemSection mShmemSection;
1462 : bool mAllocSuccess;
1463 : };
1464 :
1465 111 : class CrossProcessSemaphoreReadLock : public TextureReadLock
1466 : {
1467 : public:
1468 9 : CrossProcessSemaphoreReadLock()
1469 9 : : mSemaphore(CrossProcessSemaphore::Create("TextureReadLock", 1))
1470 9 : {}
1471 33 : explicit CrossProcessSemaphoreReadLock(CrossProcessSemaphoreHandle aHandle)
1472 33 : : mSemaphore(CrossProcessSemaphore::Create(aHandle))
1473 33 : {}
1474 :
1475 33 : virtual bool ReadLock() override
1476 : {
1477 33 : if (!IsValid()) {
1478 0 : return false;
1479 : }
1480 33 : return mSemaphore->Wait();
1481 : }
1482 34 : virtual bool TryReadLock(TimeDuration aTimeout) override
1483 : {
1484 34 : if (!IsValid()) {
1485 0 : return false;
1486 : }
1487 34 : return mSemaphore->Wait(Some(aTimeout));
1488 : }
1489 65 : virtual int32_t ReadUnlock() override
1490 : {
1491 65 : if (!IsValid()) {
1492 0 : return 1;
1493 : }
1494 65 : mSemaphore->Signal();
1495 65 : return 1;
1496 : }
1497 165 : virtual bool IsValid() const override { return !!mSemaphore; }
1498 :
1499 : virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
1500 :
1501 0 : virtual LockType GetType() override { return TYPE_CROSS_PROCESS_SEMAPHORE; }
1502 :
1503 : UniquePtr<CrossProcessSemaphore> mSemaphore;
1504 : };
1505 :
1506 : // static
1507 : already_AddRefed<TextureReadLock>
1508 33 : TextureReadLock::Deserialize(const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator)
1509 : {
1510 33 : switch (aDescriptor.type()) {
1511 : case ReadLockDescriptor::TShmemSection: {
1512 0 : const ShmemSection& section = aDescriptor.get_ShmemSection();
1513 0 : MOZ_RELEASE_ASSERT(section.shmem().IsReadable());
1514 0 : return MakeAndAddRef<ShmemTextureReadLock>(section);
1515 : }
1516 : case ReadLockDescriptor::Tuintptr_t: {
1517 0 : if (!aAllocator->IsSameProcess()) {
1518 : // Trying to use a memory based lock instead of a shmem based one in
1519 : // the cross-process case is a bad security violation.
1520 0 : NS_ERROR("A client process may be trying to peek at the host's address space!");
1521 0 : return nullptr;
1522 : }
1523 : RefPtr<TextureReadLock> lock = reinterpret_cast<MemoryTextureReadLock*>(
1524 0 : aDescriptor.get_uintptr_t()
1525 0 : );
1526 :
1527 0 : MOZ_ASSERT(lock);
1528 0 : if (lock) {
1529 : // The corresponding AddRef is in MemoryTextureReadLock::Serialize
1530 0 : lock.get()->Release();
1531 : }
1532 :
1533 0 : return lock.forget();
1534 : }
1535 : case ReadLockDescriptor::TCrossProcessSemaphoreDescriptor: {
1536 33 : return MakeAndAddRef<CrossProcessSemaphoreReadLock>(aDescriptor.get_CrossProcessSemaphoreDescriptor().sem());
1537 : }
1538 : case ReadLockDescriptor::Tnull_t: {
1539 0 : return nullptr;
1540 : }
1541 : default: {
1542 : // Invalid descriptor.
1543 0 : MOZ_DIAGNOSTIC_ASSERT(false);
1544 : }
1545 : }
1546 : return nullptr;
1547 : }
1548 : // static
1549 : already_AddRefed<TextureReadLock>
1550 0 : NonBlockingTextureReadLock::Create(LayersIPCChannel* aAllocator)
1551 : {
1552 0 : if (aAllocator->IsSameProcess()) {
1553 : // If our compositor is in the same process, we can save some cycles by not
1554 : // using shared memory.
1555 0 : return MakeAndAddRef<MemoryTextureReadLock>();
1556 : }
1557 :
1558 0 : return MakeAndAddRef<ShmemTextureReadLock>(aAllocator);
1559 : }
1560 :
1561 0 : MemoryTextureReadLock::MemoryTextureReadLock()
1562 0 : : mReadCount(1)
1563 : {
1564 0 : MOZ_COUNT_CTOR(MemoryTextureReadLock);
1565 0 : }
1566 :
1567 0 : MemoryTextureReadLock::~MemoryTextureReadLock()
1568 : {
1569 : // One read count that is added in constructor.
1570 0 : MOZ_ASSERT(mReadCount == 1);
1571 0 : MOZ_COUNT_DTOR(MemoryTextureReadLock);
1572 0 : }
1573 :
1574 : bool
1575 0 : MemoryTextureReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
1576 : {
1577 : // AddRef here and Release when receiving on the host side to make sure the
1578 : // reference count doesn't go to zero before the host receives the message.
1579 : // see TextureReadLock::Deserialize
1580 0 : this->AddRef();
1581 0 : aOutput = ReadLockDescriptor(uintptr_t(this));
1582 0 : return true;
1583 : }
1584 :
1585 : bool
1586 0 : MemoryTextureReadLock::ReadLock()
1587 : {
1588 0 : NS_ASSERT_OWNINGTHREAD(MemoryTextureReadLock);
1589 :
1590 0 : PR_ATOMIC_INCREMENT(&mReadCount);
1591 0 : return true;
1592 : }
1593 :
1594 : int32_t
1595 0 : MemoryTextureReadLock::ReadUnlock()
1596 : {
1597 0 : int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
1598 0 : MOZ_ASSERT(readCount >= 0);
1599 :
1600 0 : return readCount;
1601 : }
1602 :
1603 : int32_t
1604 0 : MemoryTextureReadLock::GetReadCount()
1605 : {
1606 0 : NS_ASSERT_OWNINGTHREAD(MemoryTextureReadLock);
1607 0 : return mReadCount;
1608 : }
1609 :
1610 0 : ShmemTextureReadLock::ShmemTextureReadLock(LayersIPCChannel* aAllocator)
1611 : : mClientAllocator(aAllocator)
1612 0 : , mAllocSuccess(false)
1613 : {
1614 0 : MOZ_COUNT_CTOR(ShmemTextureReadLock);
1615 0 : MOZ_ASSERT(mClientAllocator);
1616 : #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
1617 0 : if (mClientAllocator->GetTileLockAllocator()->AllocShmemSection(
1618 : MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)), &mShmemSection)) {
1619 0 : ShmReadLockInfo* info = GetShmReadLockInfoPtr();
1620 0 : info->readCount = 1;
1621 0 : mAllocSuccess = true;
1622 : }
1623 0 : }
1624 :
1625 0 : ShmemTextureReadLock::~ShmemTextureReadLock()
1626 : {
1627 0 : if (mClientAllocator) {
1628 : // Release one read count that is added in constructor.
1629 : // The count is kept for calling GetReadCount() by TextureClientPool.
1630 0 : ReadUnlock();
1631 : }
1632 0 : MOZ_COUNT_DTOR(ShmemTextureReadLock);
1633 0 : }
1634 :
1635 : bool
1636 0 : ShmemTextureReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
1637 : {
1638 0 : aOutput = ReadLockDescriptor(GetShmemSection());
1639 0 : return true;
1640 : }
1641 :
1642 : bool
1643 0 : ShmemTextureReadLock::ReadLock() {
1644 0 : NS_ASSERT_OWNINGTHREAD(ShmemTextureReadLock);
1645 0 : if (!mAllocSuccess) {
1646 0 : return false;
1647 : }
1648 0 : ShmReadLockInfo* info = GetShmReadLockInfoPtr();
1649 0 : PR_ATOMIC_INCREMENT(&info->readCount);
1650 0 : return true;
1651 : }
1652 :
1653 : int32_t
1654 0 : ShmemTextureReadLock::ReadUnlock() {
1655 0 : if (!mAllocSuccess) {
1656 0 : return 0;
1657 : }
1658 0 : ShmReadLockInfo* info = GetShmReadLockInfoPtr();
1659 0 : int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
1660 0 : MOZ_ASSERT(readCount >= 0);
1661 0 : if (readCount <= 0) {
1662 0 : if (mClientAllocator && mClientAllocator->GetTileLockAllocator()) {
1663 0 : mClientAllocator->GetTileLockAllocator()->DeallocShmemSection(mShmemSection);
1664 : } else {
1665 : // we are on the compositor process, or IPC is down.
1666 0 : FixedSizeSmallShmemSectionAllocator::FreeShmemSection(mShmemSection);
1667 : }
1668 : }
1669 0 : return readCount;
1670 : }
1671 :
1672 : int32_t
1673 0 : ShmemTextureReadLock::GetReadCount() {
1674 0 : NS_ASSERT_OWNINGTHREAD(ShmemTextureReadLock);
1675 0 : if (!mAllocSuccess) {
1676 0 : return 0;
1677 : }
1678 0 : ShmReadLockInfo* info = GetShmReadLockInfoPtr();
1679 0 : return info->readCount;
1680 : }
1681 :
1682 : bool
1683 33 : CrossProcessSemaphoreReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
1684 : {
1685 33 : if (IsValid()) {
1686 33 : aOutput = ReadLockDescriptor(CrossProcessSemaphoreDescriptor(mSemaphore->ShareToProcess(aOther)));
1687 33 : return true;
1688 : } else {
1689 0 : return false;
1690 : }
1691 : }
1692 :
1693 : void
1694 9 : TextureClient::EnableBlockingReadLock()
1695 : {
1696 9 : if (!mReadLock) {
1697 9 : mReadLock = new CrossProcessSemaphoreReadLock();
1698 : }
1699 9 : }
1700 :
1701 : bool
1702 0 : UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData)
1703 : {
1704 0 : MOZ_ASSERT(aTexture);
1705 0 : MOZ_ASSERT(aTexture->IsLocked());
1706 0 : MOZ_ASSERT(aTexture->GetFormat() == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
1707 0 : MOZ_ASSERT(!aTexture->IsImmutable());
1708 0 : MOZ_ASSERT(aTexture->IsValid());
1709 0 : MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
1710 :
1711 0 : MappedYCbCrTextureData mapped;
1712 0 : if (!aTexture->BorrowMappedYCbCrData(mapped)) {
1713 0 : NS_WARNING("Failed to extract YCbCr info!");
1714 0 : return false;
1715 : }
1716 :
1717 0 : MappedYCbCrTextureData srcData;
1718 0 : srcData.y.data = aData.mYChannel;
1719 0 : srcData.y.size = aData.mYSize;
1720 0 : srcData.y.stride = aData.mYStride;
1721 0 : srcData.y.skip = aData.mYSkip;
1722 0 : srcData.cb.data = aData.mCbChannel;
1723 0 : srcData.cb.size = aData.mCbCrSize;
1724 0 : srcData.cb.stride = aData.mCbCrStride;
1725 0 : srcData.cb.skip = aData.mCbSkip;
1726 0 : srcData.cr.data = aData.mCrChannel;
1727 0 : srcData.cr.size = aData.mCbCrSize;
1728 0 : srcData.cr.stride = aData.mCbCrStride;
1729 0 : srcData.cr.skip = aData.mCrSkip;
1730 0 : srcData.metadata = nullptr;
1731 :
1732 0 : if (!srcData.CopyInto(mapped)) {
1733 0 : NS_WARNING("Failed to copy image data!");
1734 0 : return false;
1735 : }
1736 :
1737 0 : if (TextureRequiresLocking(aTexture->GetFlags())) {
1738 : // We don't have support for proper locking yet, so we'll
1739 : // have to be immutable instead.
1740 0 : aTexture->MarkImmutable();
1741 : }
1742 0 : return true;
1743 : }
1744 :
1745 : already_AddRefed<SyncObject>
1746 6 : SyncObject::CreateSyncObject(SyncHandle aHandle
1747 : #ifdef XP_WIN
1748 : , ID3D11Device* aDevice
1749 : #endif
1750 : )
1751 : {
1752 6 : if (!aHandle) {
1753 6 : return nullptr;
1754 : }
1755 :
1756 : #ifdef XP_WIN
1757 : return MakeAndAddRef<SyncObjectD3D11>(aHandle, aDevice);
1758 : #else
1759 0 : MOZ_ASSERT_UNREACHABLE();
1760 : return nullptr;
1761 : #endif
1762 : }
1763 :
1764 : already_AddRefed<TextureClient>
1765 0 : TextureClient::CreateWithData(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
1766 : {
1767 0 : if (!aData) {
1768 0 : return nullptr;
1769 : }
1770 0 : return MakeAndAddRef<TextureClient>(aData, aFlags, aAllocator);
1771 : }
1772 :
1773 : bool
1774 0 : MappedYCbCrChannelData::CopyInto(MappedYCbCrChannelData& aDst)
1775 : {
1776 0 : if (!data || !aDst.data || size != aDst.size) {
1777 0 : return false;
1778 : }
1779 :
1780 0 : if (stride == aDst.stride) {
1781 : // fast path!
1782 : // We assume that the padding in the destination is there for alignment
1783 : // purposes and doesn't contain useful data.
1784 0 : memcpy(aDst.data, data, stride * size.height);
1785 0 : return true;
1786 : }
1787 :
1788 0 : for (int32_t i = 0; i < size.height; ++i) {
1789 0 : if (aDst.skip == 0 && skip == 0) {
1790 : // fast-ish path
1791 0 : memcpy(aDst.data + i * aDst.stride,
1792 0 : data + i * stride,
1793 0 : size.width);
1794 : } else {
1795 : // slow path
1796 0 : uint8_t* src = data + i * stride;
1797 0 : uint8_t* dst = aDst.data + i * aDst.stride;
1798 0 : for (int32_t j = 0; j < size.width; ++j) {
1799 0 : *dst = *src;
1800 0 : src += 1 + skip;
1801 0 : dst += 1 + aDst.skip;
1802 : }
1803 : }
1804 : }
1805 0 : return true;
1806 : }
1807 :
1808 : } // namespace layers
1809 : } // namespace mozilla
|