|
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 "gfxContext.h" // for gfxContext, etc |
|
11 #include "gfxPlatform.h" // for gfxPlatform |
|
12 #include "gfxPoint.h" // for gfxIntSize, gfxSize |
|
13 #include "gfxReusableSurfaceWrapper.h" // for gfxReusableSurfaceWrapper |
|
14 #include "mozilla/gfx/BaseSize.h" // for BaseSize |
|
15 #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc |
|
16 #include "mozilla/layers/CompositableClient.h" // for CompositableClient |
|
17 #include "mozilla/layers/CompositableForwarder.h" |
|
18 #include "mozilla/layers/ISurfaceAllocator.h" |
|
19 #include "mozilla/layers/ImageDataSerializer.h" |
|
20 #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder |
|
21 #include "mozilla/layers/SharedPlanarYCbCrImage.h" |
|
22 #include "mozilla/layers/YCbCrImageDataSerializer.h" |
|
23 #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc |
|
24 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc |
|
25 #include "ImageContainer.h" // for PlanarYCbCrImage, etc |
|
26 #include "mozilla/gfx/2D.h" |
|
27 #include "mozilla/layers/TextureClientOGL.h" |
|
28 |
|
29 #ifdef XP_WIN |
|
30 #include "mozilla/layers/TextureD3D9.h" |
|
31 #include "mozilla/layers/TextureD3D11.h" |
|
32 #include "gfxWindowsPlatform.h" |
|
33 #include "gfx2DGlue.h" |
|
34 #endif |
|
35 #ifdef MOZ_X11 |
|
36 #include "mozilla/layers/TextureClientX11.h" |
|
37 #ifdef GL_PROVIDER_GLX |
|
38 #include "GLXLibrary.h" |
|
39 #endif |
|
40 #endif |
|
41 |
|
42 #ifdef MOZ_WIDGET_GONK |
|
43 #include <cutils/properties.h> |
|
44 #include "mozilla/layers/GrallocTextureClient.h" |
|
45 #endif |
|
46 |
|
47 #ifdef MOZ_ANDROID_OMTC |
|
48 # include "gfxReusableImageSurfaceWrapper.h" |
|
49 #else |
|
50 # include "gfxReusableSharedImageSurfaceWrapper.h" |
|
51 # include "gfxSharedImageSurface.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 using namespace mozilla::gl; |
|
61 using namespace mozilla::gfx; |
|
62 |
|
63 namespace mozilla { |
|
64 namespace layers { |
|
65 |
|
66 /** |
|
67 * TextureChild is the content-side incarnation of the PTexture IPDL actor. |
|
68 * |
|
69 * TextureChild is used to synchronize a texture client and its corresponding |
|
70 * TextureHost if needed (a TextureClient that is not shared with the compositor |
|
71 * does not have a TextureChild) |
|
72 * |
|
73 * During the deallocation phase, a TextureChild may hold its recently destroyed |
|
74 * TextureClient's data until the compositor side confirmed that it is safe to |
|
75 * deallocte or recycle the it. |
|
76 */ |
|
77 class TextureChild MOZ_FINAL : public PTextureChild |
|
78 { |
|
79 public: |
|
80 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild) |
|
81 |
|
82 TextureChild() |
|
83 : mForwarder(nullptr) |
|
84 , mTextureData(nullptr) |
|
85 , mTextureClient(nullptr) |
|
86 , mIPCOpen(false) |
|
87 { |
|
88 } |
|
89 |
|
90 bool Recv__delete__() MOZ_OVERRIDE; |
|
91 |
|
92 bool RecvCompositorRecycle(const MaybeFenceHandle& aFence) |
|
93 { |
|
94 RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get()); |
|
95 if (aFence.type() != aFence.Tnull_t) { |
|
96 FenceHandle fence = aFence.get_FenceHandle(); |
|
97 if (fence.IsValid() && mTextureClient) { |
|
98 mTextureClient->SetReleaseFenceHandle(aFence); |
|
99 // HWC might not provide Fence. |
|
100 // In this case, HWC implicitly handles buffer's fence. |
|
101 } |
|
102 } |
|
103 mWaitForRecycle = nullptr; |
|
104 return true; |
|
105 } |
|
106 |
|
107 void WaitForCompositorRecycle() |
|
108 { |
|
109 mWaitForRecycle = mTextureClient; |
|
110 RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get()); |
|
111 SendClientRecycle(); |
|
112 } |
|
113 |
|
114 /** |
|
115 * Only used during the deallocation phase iff we need synchronization between |
|
116 * the client and host side for deallocation (that is, when the data is going |
|
117 * to be deallocated or recycled on the client side). |
|
118 */ |
|
119 void SetTextureData(TextureClientData* aData) |
|
120 { |
|
121 mTextureData = aData; |
|
122 } |
|
123 |
|
124 void DeleteTextureData(); |
|
125 |
|
126 CompositableForwarder* GetForwarder() { return mForwarder; } |
|
127 |
|
128 ISurfaceAllocator* GetAllocator() { return mForwarder; } |
|
129 |
|
130 void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; |
|
131 |
|
132 bool IPCOpen() const { return mIPCOpen; } |
|
133 |
|
134 private: |
|
135 |
|
136 // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor |
|
137 // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse. |
|
138 // The purpose of these methods is to be aware of when the IPC system around this |
|
139 // actor goes down: mIPCOpen is then set to false. |
|
140 void AddIPDLReference() { |
|
141 MOZ_ASSERT(mIPCOpen == false); |
|
142 mIPCOpen = true; |
|
143 AddRef(); |
|
144 } |
|
145 void ReleaseIPDLReference() { |
|
146 MOZ_ASSERT(mIPCOpen == true); |
|
147 mIPCOpen = false; |
|
148 Release(); |
|
149 } |
|
150 |
|
151 RefPtr<CompositableForwarder> mForwarder; |
|
152 RefPtr<TextureClient> mWaitForRecycle; |
|
153 TextureClientData* mTextureData; |
|
154 TextureClient* mTextureClient; |
|
155 bool mIPCOpen; |
|
156 |
|
157 friend class TextureClient; |
|
158 }; |
|
159 |
|
160 void |
|
161 TextureChild::DeleteTextureData() |
|
162 { |
|
163 mWaitForRecycle = nullptr; |
|
164 if (mTextureData) { |
|
165 mTextureData->DeallocateSharedData(GetAllocator()); |
|
166 delete mTextureData; |
|
167 mTextureData = nullptr; |
|
168 } |
|
169 } |
|
170 |
|
171 bool |
|
172 TextureChild::Recv__delete__() |
|
173 { |
|
174 DeleteTextureData(); |
|
175 return true; |
|
176 } |
|
177 |
|
178 void |
|
179 TextureChild::ActorDestroy(ActorDestroyReason why) |
|
180 { |
|
181 if (mTextureClient) { |
|
182 mTextureClient->mActor = nullptr; |
|
183 } |
|
184 mWaitForRecycle = nullptr; |
|
185 } |
|
186 |
|
187 // static |
|
188 PTextureChild* |
|
189 TextureClient::CreateIPDLActor() |
|
190 { |
|
191 TextureChild* c = new TextureChild(); |
|
192 c->AddIPDLReference(); |
|
193 return c; |
|
194 } |
|
195 |
|
196 // static |
|
197 bool |
|
198 TextureClient::DestroyIPDLActor(PTextureChild* actor) |
|
199 { |
|
200 static_cast<TextureChild*>(actor)->ReleaseIPDLReference(); |
|
201 return true; |
|
202 } |
|
203 |
|
204 // static |
|
205 TextureClient* |
|
206 TextureClient::AsTextureClient(PTextureChild* actor) |
|
207 { |
|
208 return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr; |
|
209 } |
|
210 |
|
211 void |
|
212 TextureClient::WaitForCompositorRecycle() |
|
213 { |
|
214 mActor->WaitForCompositorRecycle(); |
|
215 } |
|
216 |
|
217 bool |
|
218 TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) |
|
219 { |
|
220 MOZ_ASSERT(aForwarder); |
|
221 if (mActor && mActor->GetForwarder() == aForwarder) { |
|
222 return true; |
|
223 } |
|
224 MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels."); |
|
225 |
|
226 SurfaceDescriptor desc; |
|
227 if (!ToSurfaceDescriptor(desc)) { |
|
228 return false; |
|
229 } |
|
230 |
|
231 mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, GetFlags())); |
|
232 MOZ_ASSERT(mActor); |
|
233 mActor->mForwarder = aForwarder; |
|
234 mActor->mTextureClient = this; |
|
235 mShared = true; |
|
236 return mActor->IPCOpen(); |
|
237 } |
|
238 |
|
239 PTextureChild* |
|
240 TextureClient::GetIPDLActor() |
|
241 { |
|
242 return mActor; |
|
243 } |
|
244 |
|
245 #ifdef MOZ_WIDGET_GONK |
|
246 static bool |
|
247 DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint) |
|
248 { |
|
249 if (aFormat == gfx::SurfaceFormat::A8) { |
|
250 return true; |
|
251 } |
|
252 |
|
253 #if ANDROID_VERSION <= 15 |
|
254 // Adreno 200 has a problem of drawing gralloc buffer width less than 64 and |
|
255 // drawing gralloc buffer with a height 9px-16px. |
|
256 // See Bug 983971. |
|
257 if (aSizeHint.width < 64 || aSizeHint.height < 32) { |
|
258 return true; |
|
259 } |
|
260 #endif |
|
261 |
|
262 return false; |
|
263 } |
|
264 #endif |
|
265 |
|
266 // static |
|
267 TemporaryRef<TextureClient> |
|
268 TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator, |
|
269 SurfaceFormat aFormat, |
|
270 TextureFlags aTextureFlags, |
|
271 gfx::BackendType aMoz2DBackend, |
|
272 const gfx::IntSize& aSizeHint) |
|
273 { |
|
274 if (aMoz2DBackend == gfx::BackendType::NONE) { |
|
275 aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend(); |
|
276 } |
|
277 |
|
278 RefPtr<TextureClient> result; |
|
279 |
|
280 #if defined(MOZ_WIDGET_GONK) || defined(XP_WIN) |
|
281 int32_t maxTextureSize = aAllocator->GetMaxTextureSize(); |
|
282 #endif |
|
283 |
|
284 #ifdef XP_WIN |
|
285 LayersBackend parentBackend = aAllocator->GetCompositorBackendType(); |
|
286 if (parentBackend == LayersBackend::LAYERS_D3D11 && |
|
287 (aMoz2DBackend == gfx::BackendType::DIRECT2D || |
|
288 aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) && |
|
289 gfxWindowsPlatform::GetPlatform()->GetD2DDevice() && |
|
290 aSizeHint.width <= maxTextureSize && |
|
291 aSizeHint.height <= maxTextureSize && |
|
292 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) { |
|
293 result = new TextureClientD3D11(aFormat, aTextureFlags); |
|
294 } |
|
295 if (parentBackend == LayersBackend::LAYERS_D3D9 && |
|
296 aMoz2DBackend == gfx::BackendType::CAIRO && |
|
297 aAllocator->IsSameProcess() && |
|
298 aSizeHint.width <= maxTextureSize && |
|
299 aSizeHint.height <= maxTextureSize && |
|
300 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) { |
|
301 if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) { |
|
302 result = new DIBTextureClientD3D9(aFormat, aTextureFlags); |
|
303 } else { |
|
304 result = new CairoTextureClientD3D9(aFormat, aTextureFlags); |
|
305 } |
|
306 } |
|
307 #endif |
|
308 |
|
309 #ifdef MOZ_X11 |
|
310 LayersBackend parentBackend = aAllocator->GetCompositorBackendType(); |
|
311 gfxSurfaceType type = |
|
312 gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(); |
|
313 |
|
314 if (parentBackend == LayersBackend::LAYERS_BASIC && |
|
315 aMoz2DBackend == gfx::BackendType::CAIRO && |
|
316 type == gfxSurfaceType::Xlib && |
|
317 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) |
|
318 { |
|
319 result = new TextureClientX11(aFormat, aTextureFlags); |
|
320 } |
|
321 #ifdef GL_PROVIDER_GLX |
|
322 if (parentBackend == LayersBackend::LAYERS_OPENGL && |
|
323 type == gfxSurfaceType::Xlib && |
|
324 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) && |
|
325 aFormat != SurfaceFormat::A8 && |
|
326 gl::sGLXLibrary.UseTextureFromPixmap()) |
|
327 { |
|
328 result = new TextureClientX11(aFormat, aTextureFlags); |
|
329 } |
|
330 #endif |
|
331 #endif |
|
332 |
|
333 #ifdef MOZ_WIDGET_GONK |
|
334 if (!DisableGralloc(aFormat, aSizeHint)) { |
|
335 // Don't allow Gralloc texture clients to exceed the maximum texture size. |
|
336 // BufferTextureClients have code to handle tiling the surface client-side. |
|
337 if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) { |
|
338 result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend, |
|
339 aTextureFlags); |
|
340 } |
|
341 } |
|
342 #endif |
|
343 |
|
344 // Can't do any better than a buffer texture client. |
|
345 if (!result) { |
|
346 result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend); |
|
347 } |
|
348 |
|
349 MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?"); |
|
350 return result; |
|
351 } |
|
352 |
|
353 // static |
|
354 TemporaryRef<BufferTextureClient> |
|
355 TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator, |
|
356 SurfaceFormat aFormat, |
|
357 TextureFlags aTextureFlags, |
|
358 gfx::BackendType aMoz2DBackend) |
|
359 { |
|
360 if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) { |
|
361 RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat, |
|
362 aMoz2DBackend, |
|
363 aTextureFlags); |
|
364 return result.forget(); |
|
365 } |
|
366 RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat, |
|
367 aMoz2DBackend, |
|
368 aTextureFlags); |
|
369 return result.forget(); |
|
370 } |
|
371 |
|
372 |
|
373 class ShmemTextureClientData : public TextureClientData |
|
374 { |
|
375 public: |
|
376 ShmemTextureClientData(ipc::Shmem& aShmem) |
|
377 : mShmem(aShmem) |
|
378 { |
|
379 MOZ_COUNT_CTOR(ShmemTextureClientData); |
|
380 } |
|
381 |
|
382 ~ShmemTextureClientData() |
|
383 { |
|
384 MOZ_COUNT_CTOR(ShmemTextureClientData); |
|
385 } |
|
386 |
|
387 virtual void DeallocateSharedData(ISurfaceAllocator* allocator) |
|
388 { |
|
389 allocator->DeallocShmem(mShmem); |
|
390 mShmem = ipc::Shmem(); |
|
391 } |
|
392 |
|
393 private: |
|
394 ipc::Shmem mShmem; |
|
395 }; |
|
396 |
|
397 class MemoryTextureClientData : public TextureClientData |
|
398 { |
|
399 public: |
|
400 MemoryTextureClientData(uint8_t* aBuffer) |
|
401 : mBuffer(aBuffer) |
|
402 { |
|
403 MOZ_COUNT_CTOR(MemoryTextureClientData); |
|
404 } |
|
405 |
|
406 ~MemoryTextureClientData() |
|
407 { |
|
408 MOZ_ASSERT(!mBuffer, "Forgot to deallocate the shared texture data?"); |
|
409 MOZ_COUNT_DTOR(MemoryTextureClientData); |
|
410 } |
|
411 |
|
412 virtual void DeallocateSharedData(ISurfaceAllocator*) |
|
413 { |
|
414 delete[] mBuffer; |
|
415 mBuffer = nullptr; |
|
416 } |
|
417 |
|
418 private: |
|
419 uint8_t* mBuffer; |
|
420 }; |
|
421 |
|
422 TextureClientData* |
|
423 MemoryTextureClient::DropTextureData() |
|
424 { |
|
425 if (!mBuffer) { |
|
426 return nullptr; |
|
427 } |
|
428 TextureClientData* result = new MemoryTextureClientData(mBuffer); |
|
429 MarkInvalid(); |
|
430 mBuffer = nullptr; |
|
431 return result; |
|
432 } |
|
433 |
|
434 TextureClientData* |
|
435 ShmemTextureClient::DropTextureData() |
|
436 { |
|
437 if (!mShmem.IsReadable()) { |
|
438 return nullptr; |
|
439 } |
|
440 TextureClientData* result = new ShmemTextureClientData(mShmem); |
|
441 MarkInvalid(); |
|
442 mShmem = ipc::Shmem(); |
|
443 return result; |
|
444 } |
|
445 |
|
446 TextureClient::TextureClient(TextureFlags aFlags) |
|
447 : mFlags(aFlags) |
|
448 , mShared(false) |
|
449 , mValid(true) |
|
450 {} |
|
451 |
|
452 TextureClient::~TextureClient() |
|
453 { |
|
454 // All the destruction code that may lead to virtual method calls must |
|
455 // be in Finalize() which is called just before the destructor. |
|
456 } |
|
457 |
|
458 void TextureClient::ForceRemove() |
|
459 { |
|
460 if (mValid && mActor) { |
|
461 if (GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { |
|
462 mActor->SetTextureData(DropTextureData()); |
|
463 if (mActor->IPCOpen()) { |
|
464 mActor->SendRemoveTextureSync(); |
|
465 } |
|
466 mActor->DeleteTextureData(); |
|
467 } else { |
|
468 if (mActor->IPCOpen()) { |
|
469 mActor->SendRemoveTexture(); |
|
470 } |
|
471 } |
|
472 } |
|
473 MarkInvalid(); |
|
474 } |
|
475 |
|
476 bool TextureClient::CopyToTextureClient(TextureClient* aTarget, |
|
477 const gfx::IntRect* aRect, |
|
478 const gfx::IntPoint* aPoint) |
|
479 { |
|
480 MOZ_ASSERT(IsLocked()); |
|
481 MOZ_ASSERT(aTarget->IsLocked()); |
|
482 |
|
483 if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) { |
|
484 return false; |
|
485 } |
|
486 |
|
487 RefPtr<DrawTarget> destinationTarget = aTarget->GetAsDrawTarget(); |
|
488 RefPtr<DrawTarget> sourceTarget = GetAsDrawTarget(); |
|
489 RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot(); |
|
490 destinationTarget->CopySurface(source, |
|
491 aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()), |
|
492 aPoint ? *aPoint : gfx::IntPoint(0, 0)); |
|
493 destinationTarget = nullptr; |
|
494 source = nullptr; |
|
495 sourceTarget = nullptr; |
|
496 |
|
497 return true; |
|
498 } |
|
499 |
|
500 void |
|
501 TextureClient::Finalize() |
|
502 { |
|
503 MOZ_ASSERT(!IsLocked()); |
|
504 // Always make a temporary strong reference to the actor before we use it, |
|
505 // in case TextureChild::ActorDestroy might null mActor concurrently. |
|
506 RefPtr<TextureChild> actor = mActor; |
|
507 |
|
508 if (actor) { |
|
509 // The actor has a raw pointer to us, actor->mTextureClient. |
|
510 // Null it before RemoveTexture calls to avoid invalid actor->mTextureClient |
|
511 // when calling TextureChild::ActorDestroy() |
|
512 actor->mTextureClient = nullptr; |
|
513 // this will call ForceRemove in the right thread, using a sync proxy if needed |
|
514 if (actor->GetForwarder()) { |
|
515 actor->GetForwarder()->RemoveTexture(this); |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 bool |
|
521 TextureClient::ShouldDeallocateInDestructor() const |
|
522 { |
|
523 if (!IsAllocated()) { |
|
524 return false; |
|
525 } |
|
526 |
|
527 // If we're meant to be deallocated by the host, |
|
528 // but we haven't been shared yet, then we should |
|
529 // deallocate on the client instead. |
|
530 return !IsSharedWithCompositor(); |
|
531 } |
|
532 |
|
533 bool |
|
534 ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) |
|
535 { |
|
536 MOZ_ASSERT(IsValid()); |
|
537 if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) { |
|
538 return false; |
|
539 } |
|
540 |
|
541 aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat()); |
|
542 |
|
543 return true; |
|
544 } |
|
545 |
|
546 bool |
|
547 ShmemTextureClient::Allocate(uint32_t aSize) |
|
548 { |
|
549 MOZ_ASSERT(mValid); |
|
550 ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType(); |
|
551 mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem); |
|
552 return mAllocated; |
|
553 } |
|
554 |
|
555 uint8_t* |
|
556 ShmemTextureClient::GetBuffer() const |
|
557 { |
|
558 MOZ_ASSERT(IsValid()); |
|
559 if (mAllocated) { |
|
560 return mShmem.get<uint8_t>(); |
|
561 } |
|
562 return nullptr; |
|
563 } |
|
564 |
|
565 size_t |
|
566 ShmemTextureClient::GetBufferSize() const |
|
567 { |
|
568 MOZ_ASSERT(IsValid()); |
|
569 return mShmem.Size<uint8_t>(); |
|
570 } |
|
571 |
|
572 ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator, |
|
573 gfx::SurfaceFormat aFormat, |
|
574 gfx::BackendType aMoz2DBackend, |
|
575 TextureFlags aFlags) |
|
576 : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags) |
|
577 , mAllocated(false) |
|
578 { |
|
579 MOZ_COUNT_CTOR(ShmemTextureClient); |
|
580 } |
|
581 |
|
582 ShmemTextureClient::~ShmemTextureClient() |
|
583 { |
|
584 MOZ_COUNT_DTOR(ShmemTextureClient); |
|
585 if (ShouldDeallocateInDestructor()) { |
|
586 // if the buffer has never been shared we must deallocate it or ir would |
|
587 // leak. |
|
588 GetAllocator()->DeallocShmem(mShmem); |
|
589 } |
|
590 } |
|
591 |
|
592 bool |
|
593 MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) |
|
594 { |
|
595 MOZ_ASSERT(IsValid()); |
|
596 if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) { |
|
597 return false; |
|
598 } |
|
599 aDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer), |
|
600 GetFormat()); |
|
601 return true; |
|
602 } |
|
603 |
|
604 bool |
|
605 MemoryTextureClient::Allocate(uint32_t aSize) |
|
606 { |
|
607 MOZ_ASSERT(!mBuffer); |
|
608 static const fallible_t fallible = fallible_t(); |
|
609 mBuffer = new(fallible) uint8_t[aSize]; |
|
610 if (!mBuffer) { |
|
611 NS_WARNING("Failed to allocate buffer"); |
|
612 return false; |
|
613 } |
|
614 GfxMemoryImageReporter::DidAlloc(mBuffer); |
|
615 mBufSize = aSize; |
|
616 return true; |
|
617 } |
|
618 |
|
619 MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator, |
|
620 gfx::SurfaceFormat aFormat, |
|
621 gfx::BackendType aMoz2DBackend, |
|
622 TextureFlags aFlags) |
|
623 : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags) |
|
624 , mBuffer(nullptr) |
|
625 , mBufSize(0) |
|
626 { |
|
627 MOZ_COUNT_CTOR(MemoryTextureClient); |
|
628 } |
|
629 |
|
630 MemoryTextureClient::~MemoryTextureClient() |
|
631 { |
|
632 MOZ_COUNT_DTOR(MemoryTextureClient); |
|
633 if (mBuffer && ShouldDeallocateInDestructor()) { |
|
634 // if the buffer has never been shared we must deallocate it or it would |
|
635 // leak. |
|
636 GfxMemoryImageReporter::WillFree(mBuffer); |
|
637 delete [] mBuffer; |
|
638 } |
|
639 } |
|
640 |
|
641 BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator, |
|
642 gfx::SurfaceFormat aFormat, |
|
643 gfx::BackendType aMoz2DBackend, |
|
644 TextureFlags aFlags) |
|
645 : TextureClient(aFlags) |
|
646 , mAllocator(aAllocator) |
|
647 , mFormat(aFormat) |
|
648 , mBackend(aMoz2DBackend) |
|
649 , mOpenMode(0) |
|
650 , mUsingFallbackDrawTarget(false) |
|
651 , mLocked(false) |
|
652 {} |
|
653 |
|
654 BufferTextureClient::~BufferTextureClient() |
|
655 {} |
|
656 |
|
657 ISurfaceAllocator* |
|
658 BufferTextureClient::GetAllocator() const |
|
659 { |
|
660 return mAllocator; |
|
661 } |
|
662 |
|
663 bool |
|
664 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) |
|
665 { |
|
666 MOZ_ASSERT(IsValid()); |
|
667 MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data"); |
|
668 MOZ_ASSERT(aSize.width * aSize.height); |
|
669 |
|
670 int bufSize |
|
671 = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat); |
|
672 if (!Allocate(bufSize)) { |
|
673 return false; |
|
674 } |
|
675 |
|
676 if (aFlags & ALLOC_CLEAR_BUFFER) { |
|
677 memset(GetBuffer(), 0, bufSize); |
|
678 } |
|
679 |
|
680 ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); |
|
681 serializer.InitializeBufferInfo(aSize, mFormat); |
|
682 mSize = aSize; |
|
683 return true; |
|
684 } |
|
685 |
|
686 TemporaryRef<gfx::DrawTarget> |
|
687 BufferTextureClient::GetAsDrawTarget() |
|
688 { |
|
689 MOZ_ASSERT(IsValid()); |
|
690 MOZ_ASSERT(mLocked, "GetAsDrawTarget should be called on locked textures only"); |
|
691 |
|
692 if (mDrawTarget) { |
|
693 return mDrawTarget; |
|
694 } |
|
695 |
|
696 ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); |
|
697 if (!serializer.IsValid()) { |
|
698 return nullptr; |
|
699 } |
|
700 |
|
701 MOZ_ASSERT(mUsingFallbackDrawTarget == false); |
|
702 mDrawTarget = serializer.GetAsDrawTarget(mBackend); |
|
703 if (mDrawTarget) { |
|
704 return mDrawTarget; |
|
705 } |
|
706 |
|
707 // fallback path, probably because the Moz2D backend can't create a |
|
708 // DrawTarget around raw memory. This is going to be slow :( |
|
709 mDrawTarget = gfx::Factory::CreateDrawTarget(mBackend, serializer.GetSize(), |
|
710 serializer.GetFormat()); |
|
711 if (!mDrawTarget) { |
|
712 return nullptr; |
|
713 } |
|
714 |
|
715 mUsingFallbackDrawTarget = true; |
|
716 if (mOpenMode & OPEN_READ) { |
|
717 RefPtr<DataSourceSurface> surface = serializer.GetAsSurface(); |
|
718 IntRect rect(0, 0, surface->GetSize().width, surface->GetSize().height); |
|
719 mDrawTarget->CopySurface(surface, rect, IntPoint(0,0)); |
|
720 } |
|
721 return mDrawTarget; |
|
722 } |
|
723 |
|
724 bool |
|
725 BufferTextureClient::Lock(OpenMode aMode) |
|
726 { |
|
727 MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!"); |
|
728 mOpenMode = aMode; |
|
729 mLocked = IsValid() && IsAllocated();; |
|
730 return mLocked; |
|
731 } |
|
732 |
|
733 void |
|
734 BufferTextureClient::Unlock() |
|
735 { |
|
736 MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!"); |
|
737 mLocked = false; |
|
738 if (!mDrawTarget) { |
|
739 mUsingFallbackDrawTarget = false; |
|
740 return; |
|
741 } |
|
742 |
|
743 // see the comment on TextureClient::GetAsDrawTarget. |
|
744 // This DrawTarget is internal to the TextureClient and is only exposed to the |
|
745 // outside world between Lock() and Unlock(). This assertion checks that no outside |
|
746 // reference remains by the time Unlock() is called. |
|
747 MOZ_ASSERT(mDrawTarget->refCount() == 1); |
|
748 |
|
749 mDrawTarget->Flush(); |
|
750 if (mUsingFallbackDrawTarget && (mOpenMode & OPEN_WRITE)) { |
|
751 // When we are using a fallback DrawTarget, it means we could not create |
|
752 // a DrawTarget wrapping the TextureClient's shared memory. In this scenario |
|
753 // we need to put the content of the fallback draw target back into our shared |
|
754 // memory. |
|
755 RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot(); |
|
756 RefPtr<DataSourceSurface> surface = snapshot->GetDataSurface(); |
|
757 ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); |
|
758 if (!serializer.IsValid() || serializer.GetSize() != surface->GetSize()) { |
|
759 NS_WARNING("Could not write the data back into the texture."); |
|
760 mDrawTarget = nullptr; |
|
761 mUsingFallbackDrawTarget = false; |
|
762 return; |
|
763 } |
|
764 MOZ_ASSERT(surface->GetSize() == serializer.GetSize()); |
|
765 MOZ_ASSERT(surface->GetFormat() == serializer.GetFormat()); |
|
766 int bpp = BytesPerPixel(surface->GetFormat()); |
|
767 for (int i = 0; i < surface->GetSize().height; ++i) { |
|
768 memcpy(serializer.GetData() + i*serializer.GetStride(), |
|
769 surface->GetData() + i*surface->Stride(), |
|
770 surface->GetSize().width * bpp); |
|
771 } |
|
772 } |
|
773 mDrawTarget = nullptr; |
|
774 mUsingFallbackDrawTarget = false; |
|
775 } |
|
776 |
|
777 bool |
|
778 BufferTextureClient::UpdateYCbCr(const PlanarYCbCrData& aData) |
|
779 { |
|
780 MOZ_ASSERT(mLocked); |
|
781 MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data"); |
|
782 MOZ_ASSERT(!IsImmutable()); |
|
783 MOZ_ASSERT(IsValid()); |
|
784 MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip); |
|
785 |
|
786 YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize()); |
|
787 MOZ_ASSERT(serializer.IsValid()); |
|
788 if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel, |
|
789 aData.mYSize, aData.mYStride, |
|
790 aData.mCbCrSize, aData.mCbCrStride, |
|
791 aData.mYSkip, aData.mCbSkip)) { |
|
792 NS_WARNING("Failed to copy image data!"); |
|
793 return false; |
|
794 } |
|
795 |
|
796 if (TextureRequiresLocking(mFlags)) { |
|
797 // We don't have support for proper locking yet, so we'll |
|
798 // have to be immutable instead. |
|
799 MarkImmutable(); |
|
800 } |
|
801 return true; |
|
802 } |
|
803 |
|
804 bool |
|
805 BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, |
|
806 gfx::IntSize aCbCrSize, |
|
807 StereoMode aStereoMode) |
|
808 { |
|
809 MOZ_ASSERT(IsValid()); |
|
810 |
|
811 size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, |
|
812 aCbCrSize); |
|
813 if (!Allocate(bufSize)) { |
|
814 return false; |
|
815 } |
|
816 YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize()); |
|
817 serializer.InitializeBufferInfo(aYSize, |
|
818 aCbCrSize, |
|
819 aStereoMode); |
|
820 mSize = aYSize; |
|
821 return true; |
|
822 } |
|
823 |
|
824 } |
|
825 } |