|
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/TextureHost.h" |
|
7 #include "CompositableHost.h" // for CompositableHost |
|
8 #include "LayersLogging.h" // for AppendToString |
|
9 #include "gfx2DGlue.h" // for ToIntSize |
|
10 #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory |
|
11 #include "mozilla/ipc/Shmem.h" // for Shmem |
|
12 #include "mozilla/layers/Compositor.h" // for Compositor |
|
13 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator |
|
14 #include "mozilla/layers/ImageDataSerializer.h" |
|
15 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc |
|
16 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
|
17 #ifdef MOZ_X11 |
|
18 #include "mozilla/layers/X11TextureHost.h" |
|
19 #endif |
|
20 #include "mozilla/layers/YCbCrImageDataSerializer.h" |
|
21 #include "nsAString.h" |
|
22 #include "nsAutoPtr.h" // for nsRefPtr |
|
23 #include "nsPrintfCString.h" // for nsPrintfCString |
|
24 #include "mozilla/layers/PTextureParent.h" |
|
25 #include "mozilla/unused.h" |
|
26 #include <limits> |
|
27 |
|
28 #if 0 |
|
29 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) |
|
30 #else |
|
31 #define RECYCLE_LOG(...) do { } while (0) |
|
32 #endif |
|
33 |
|
34 struct nsIntPoint; |
|
35 |
|
36 namespace mozilla { |
|
37 namespace layers { |
|
38 |
|
39 /** |
|
40 * TextureParent is the host-side IPDL glue between TextureClient and TextureHost. |
|
41 * It is an IPDL actor just like LayerParent, CompositableParent, etc. |
|
42 */ |
|
43 class TextureParent : public PTextureParent |
|
44 { |
|
45 public: |
|
46 TextureParent(ISurfaceAllocator* aAllocator); |
|
47 |
|
48 ~TextureParent(); |
|
49 |
|
50 bool Init(const SurfaceDescriptor& aSharedData, |
|
51 const TextureFlags& aFlags); |
|
52 |
|
53 void CompositorRecycle(); |
|
54 virtual bool RecvClientRecycle() MOZ_OVERRIDE; |
|
55 |
|
56 virtual bool RecvRemoveTexture() MOZ_OVERRIDE; |
|
57 |
|
58 virtual bool RecvRemoveTextureSync() MOZ_OVERRIDE; |
|
59 |
|
60 TextureHost* GetTextureHost() { return mTextureHost; } |
|
61 |
|
62 void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; |
|
63 |
|
64 ISurfaceAllocator* mAllocator; |
|
65 RefPtr<TextureHost> mWaitForClientRecycle; |
|
66 RefPtr<TextureHost> mTextureHost; |
|
67 }; |
|
68 |
|
69 // static |
|
70 PTextureParent* |
|
71 TextureHost::CreateIPDLActor(ISurfaceAllocator* aAllocator, |
|
72 const SurfaceDescriptor& aSharedData, |
|
73 TextureFlags aFlags) |
|
74 { |
|
75 if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory && |
|
76 !aAllocator->IsSameProcess()) |
|
77 { |
|
78 NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!"); |
|
79 return nullptr; |
|
80 } |
|
81 TextureParent* actor = new TextureParent(aAllocator); |
|
82 if (!actor->Init(aSharedData, aFlags)) { |
|
83 delete actor; |
|
84 return nullptr; |
|
85 } |
|
86 return actor; |
|
87 } |
|
88 |
|
89 // static |
|
90 bool |
|
91 TextureHost::DestroyIPDLActor(PTextureParent* actor) |
|
92 { |
|
93 delete actor; |
|
94 return true; |
|
95 } |
|
96 |
|
97 // static |
|
98 bool |
|
99 TextureHost::SendDeleteIPDLActor(PTextureParent* actor) |
|
100 { |
|
101 return PTextureParent::Send__delete__(actor); |
|
102 } |
|
103 |
|
104 // static |
|
105 TextureHost* |
|
106 TextureHost::AsTextureHost(PTextureParent* actor) |
|
107 { |
|
108 return actor? static_cast<TextureParent*>(actor)->mTextureHost : nullptr; |
|
109 } |
|
110 |
|
111 PTextureParent* |
|
112 TextureHost::GetIPDLActor() |
|
113 { |
|
114 return mActor; |
|
115 } |
|
116 |
|
117 // implemented in TextureHostOGL.cpp |
|
118 TemporaryRef<TextureHost> CreateTextureHostOGL(const SurfaceDescriptor& aDesc, |
|
119 ISurfaceAllocator* aDeallocator, |
|
120 TextureFlags aFlags); |
|
121 |
|
122 // implemented in TextureHostBasic.cpp |
|
123 TemporaryRef<TextureHost> CreateTextureHostBasic(const SurfaceDescriptor& aDesc, |
|
124 ISurfaceAllocator* aDeallocator, |
|
125 TextureFlags aFlags); |
|
126 |
|
127 // implemented in TextureD3D11.cpp |
|
128 TemporaryRef<TextureHost> CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, |
|
129 ISurfaceAllocator* aDeallocator, |
|
130 TextureFlags aFlags); |
|
131 |
|
132 // implemented in TextureD3D9.cpp |
|
133 TemporaryRef<TextureHost> CreateTextureHostD3D9(const SurfaceDescriptor& aDesc, |
|
134 ISurfaceAllocator* aDeallocator, |
|
135 TextureFlags aFlags); |
|
136 |
|
137 // static |
|
138 TemporaryRef<TextureHost> |
|
139 TextureHost::Create(const SurfaceDescriptor& aDesc, |
|
140 ISurfaceAllocator* aDeallocator, |
|
141 TextureFlags aFlags) |
|
142 { |
|
143 switch (aDesc.type()) { |
|
144 case SurfaceDescriptor::TSurfaceDescriptorShmem: |
|
145 case SurfaceDescriptor::TSurfaceDescriptorMemory: |
|
146 return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags); |
|
147 case SurfaceDescriptor::TSharedTextureDescriptor: |
|
148 case SurfaceDescriptor::TNewSurfaceDescriptorGralloc: |
|
149 case SurfaceDescriptor::TSurfaceStreamDescriptor: |
|
150 return CreateTextureHostOGL(aDesc, aDeallocator, aFlags); |
|
151 case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: |
|
152 if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) { |
|
153 return CreateTextureHostOGL(aDesc, aDeallocator, aFlags); |
|
154 } else { |
|
155 return CreateTextureHostBasic(aDesc, aDeallocator, aFlags); |
|
156 } |
|
157 #ifdef MOZ_X11 |
|
158 case SurfaceDescriptor::TSurfaceDescriptorX11: { |
|
159 const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11(); |
|
160 RefPtr<TextureHost> result = new X11TextureHost(aFlags, desc); |
|
161 return result; |
|
162 } |
|
163 #endif |
|
164 #ifdef XP_WIN |
|
165 case SurfaceDescriptor::TSurfaceDescriptorD3D9: |
|
166 case SurfaceDescriptor::TSurfaceDescriptorDIB: |
|
167 return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags); |
|
168 case SurfaceDescriptor::TSurfaceDescriptorD3D10: |
|
169 if (Compositor::GetBackend() == LayersBackend::LAYERS_D3D9) { |
|
170 return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags); |
|
171 } else { |
|
172 return CreateTextureHostD3D11(aDesc, aDeallocator, aFlags); |
|
173 } |
|
174 #endif |
|
175 default: |
|
176 MOZ_CRASH("Unsupported Surface type"); |
|
177 } |
|
178 } |
|
179 |
|
180 TemporaryRef<TextureHost> |
|
181 CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc, |
|
182 ISurfaceAllocator* aDeallocator, |
|
183 TextureFlags aFlags) |
|
184 { |
|
185 RefPtr<TextureHost> result; |
|
186 switch (aDesc.type()) { |
|
187 case SurfaceDescriptor::TSurfaceDescriptorShmem: { |
|
188 const SurfaceDescriptorShmem& descriptor = aDesc.get_SurfaceDescriptorShmem(); |
|
189 result = new ShmemTextureHost(descriptor.data(), |
|
190 descriptor.format(), |
|
191 aDeallocator, |
|
192 aFlags); |
|
193 break; |
|
194 } |
|
195 case SurfaceDescriptor::TSurfaceDescriptorMemory: { |
|
196 const SurfaceDescriptorMemory& descriptor = aDesc.get_SurfaceDescriptorMemory(); |
|
197 result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(descriptor.data()), |
|
198 descriptor.format(), |
|
199 aFlags); |
|
200 break; |
|
201 } |
|
202 default: { |
|
203 NS_WARNING("No backend independent TextureHost for this descriptor type"); |
|
204 } |
|
205 } |
|
206 return result; |
|
207 } |
|
208 |
|
209 void |
|
210 TextureHost::CompositorRecycle() |
|
211 { |
|
212 if (!mActor) { |
|
213 return; |
|
214 } |
|
215 static_cast<TextureParent*>(mActor)->CompositorRecycle(); |
|
216 } |
|
217 |
|
218 void |
|
219 TextureHost::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) |
|
220 { |
|
221 mCompositableBackendData = aBackendData; |
|
222 } |
|
223 |
|
224 |
|
225 TextureHost::TextureHost(TextureFlags aFlags) |
|
226 : mActor(nullptr) |
|
227 , mFlags(aFlags) |
|
228 {} |
|
229 |
|
230 TextureHost::~TextureHost() |
|
231 { |
|
232 } |
|
233 |
|
234 void TextureHost::Finalize() |
|
235 { |
|
236 if (!(GetFlags() & TEXTURE_DEALLOCATE_CLIENT)) { |
|
237 DeallocateSharedData(); |
|
238 DeallocateDeviceData(); |
|
239 } |
|
240 } |
|
241 |
|
242 void |
|
243 TextureHost::PrintInfo(nsACString& aTo, const char* aPrefix) |
|
244 { |
|
245 aTo += aPrefix; |
|
246 aTo += nsPrintfCString("%s (0x%p)", Name(), this); |
|
247 // Note: the TextureHost needs to be locked before it is safe to call |
|
248 // GetSize() and GetFormat() on it. |
|
249 if (Lock()) { |
|
250 AppendToString(aTo, GetSize(), " [size=", "]"); |
|
251 AppendToString(aTo, GetFormat(), " [format=", "]"); |
|
252 Unlock(); |
|
253 } |
|
254 AppendToString(aTo, mFlags, " [flags=", "]"); |
|
255 } |
|
256 |
|
257 void |
|
258 TextureSource::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) |
|
259 { |
|
260 mCompositableBackendData = aBackendData; |
|
261 } |
|
262 |
|
263 TextureSource::TextureSource() |
|
264 { |
|
265 MOZ_COUNT_CTOR(TextureSource); |
|
266 } |
|
267 TextureSource::~TextureSource() |
|
268 { |
|
269 MOZ_COUNT_DTOR(TextureSource); |
|
270 } |
|
271 |
|
272 BufferTextureHost::BufferTextureHost(gfx::SurfaceFormat aFormat, |
|
273 TextureFlags aFlags) |
|
274 : TextureHost(aFlags) |
|
275 , mCompositor(nullptr) |
|
276 , mFormat(aFormat) |
|
277 , mUpdateSerial(1) |
|
278 , mLocked(false) |
|
279 , mPartialUpdate(false) |
|
280 {} |
|
281 |
|
282 BufferTextureHost::~BufferTextureHost() |
|
283 {} |
|
284 |
|
285 void |
|
286 BufferTextureHost::Updated(const nsIntRegion* aRegion) |
|
287 { |
|
288 ++mUpdateSerial; |
|
289 if (aRegion) { |
|
290 mPartialUpdate = true; |
|
291 mMaybeUpdatedRegion = *aRegion; |
|
292 } else { |
|
293 mPartialUpdate = false; |
|
294 } |
|
295 if (GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) { |
|
296 DebugOnly<bool> result = MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr); |
|
297 NS_WARN_IF_FALSE(result, "Failed to upload a texture"); |
|
298 } |
|
299 } |
|
300 |
|
301 void |
|
302 BufferTextureHost::SetCompositor(Compositor* aCompositor) |
|
303 { |
|
304 if (mCompositor == aCompositor) { |
|
305 return; |
|
306 } |
|
307 RefPtr<NewTextureSource> it = mFirstSource; |
|
308 while (it) { |
|
309 it->SetCompositor(aCompositor); |
|
310 it = it->GetNextSibling(); |
|
311 } |
|
312 mCompositor = aCompositor; |
|
313 } |
|
314 |
|
315 void |
|
316 BufferTextureHost::DeallocateDeviceData() |
|
317 { |
|
318 RefPtr<NewTextureSource> it = mFirstSource; |
|
319 while (it) { |
|
320 it->DeallocateDeviceData(); |
|
321 it = it->GetNextSibling(); |
|
322 } |
|
323 } |
|
324 |
|
325 bool |
|
326 BufferTextureHost::Lock() |
|
327 { |
|
328 mLocked = true; |
|
329 return true; |
|
330 } |
|
331 |
|
332 void |
|
333 BufferTextureHost::Unlock() |
|
334 { |
|
335 mLocked = false; |
|
336 } |
|
337 |
|
338 NewTextureSource* |
|
339 BufferTextureHost::GetTextureSources() |
|
340 { |
|
341 MOZ_ASSERT(mLocked, "should never be called while not locked"); |
|
342 if (!MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) { |
|
343 return nullptr; |
|
344 } |
|
345 return mFirstSource; |
|
346 } |
|
347 |
|
348 gfx::SurfaceFormat |
|
349 BufferTextureHost::GetFormat() const |
|
350 { |
|
351 // mFormat is the format of the data that we share with the content process. |
|
352 // GetFormat, on the other hand, expects the format that we present to the |
|
353 // Compositor (it is used to choose the effect type). |
|
354 // if the compositor does not support YCbCr effects, we give it a RGBX texture |
|
355 // instead (see BufferTextureHost::Upload) |
|
356 if (mFormat == gfx::SurfaceFormat::YUV && |
|
357 mCompositor && |
|
358 !mCompositor->SupportsEffect(EFFECT_YCBCR)) { |
|
359 return gfx::SurfaceFormat::R8G8B8X8; |
|
360 } |
|
361 return mFormat; |
|
362 } |
|
363 |
|
364 bool |
|
365 BufferTextureHost::MaybeUpload(nsIntRegion *aRegion) |
|
366 { |
|
367 if (mFirstSource && mFirstSource->GetUpdateSerial() == mUpdateSerial) { |
|
368 return true; |
|
369 } |
|
370 if (!Upload(aRegion)) { |
|
371 return false; |
|
372 } |
|
373 mFirstSource->SetUpdateSerial(mUpdateSerial); |
|
374 return true; |
|
375 } |
|
376 |
|
377 bool |
|
378 BufferTextureHost::Upload(nsIntRegion *aRegion) |
|
379 { |
|
380 if (!GetBuffer()) { |
|
381 // We don't have a buffer; a possible cause is that the IPDL actor |
|
382 // is already dead. This inevitably happens as IPDL actors can die |
|
383 // at any time, so we want to silently return in this case. |
|
384 return false; |
|
385 } |
|
386 if (!mCompositor) { |
|
387 NS_WARNING("Tried to upload without a compositor. Skipping texture upload..."); |
|
388 // If we are in this situation it means we should have called SetCompositor |
|
389 // earlier. It is conceivable that on certain rare conditions with async-video |
|
390 // we may end up here for the first frame, but this should not happen repeatedly. |
|
391 return false; |
|
392 } |
|
393 if (mFormat == gfx::SurfaceFormat::UNKNOWN) { |
|
394 NS_WARNING("BufferTextureHost: unsupported format!"); |
|
395 return false; |
|
396 } else if (mFormat == gfx::SurfaceFormat::YUV) { |
|
397 YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize()); |
|
398 MOZ_ASSERT(yuvDeserializer.IsValid()); |
|
399 |
|
400 if (!mCompositor->SupportsEffect(EFFECT_YCBCR)) { |
|
401 RefPtr<gfx::DataSourceSurface> surf = yuvDeserializer.ToDataSourceSurface(); |
|
402 if (!mFirstSource) { |
|
403 mFirstSource = mCompositor->CreateDataTextureSource(mFlags); |
|
404 } |
|
405 mFirstSource->Update(surf, aRegion); |
|
406 return true; |
|
407 } |
|
408 |
|
409 RefPtr<DataTextureSource> srcY; |
|
410 RefPtr<DataTextureSource> srcU; |
|
411 RefPtr<DataTextureSource> srcV; |
|
412 if (!mFirstSource) { |
|
413 // We don't support BigImages for YCbCr compositing. |
|
414 srcY = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); |
|
415 srcU = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); |
|
416 srcV = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); |
|
417 mFirstSource = srcY; |
|
418 srcY->SetNextSibling(srcU); |
|
419 srcU->SetNextSibling(srcV); |
|
420 } else { |
|
421 // mFormat never changes so if this was created as a YCbCr host and already |
|
422 // contains a source it should already have 3 sources. |
|
423 // BufferTextureHost only uses DataTextureSources so it is safe to assume |
|
424 // all 3 sources are DataTextureSource. |
|
425 MOZ_ASSERT(mFirstSource->GetNextSibling()); |
|
426 MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling()); |
|
427 srcY = mFirstSource; |
|
428 srcU = mFirstSource->GetNextSibling()->AsDataTextureSource(); |
|
429 srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource(); |
|
430 } |
|
431 |
|
432 |
|
433 RefPtr<gfx::DataSourceSurface> tempY = |
|
434 gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetYData(), |
|
435 yuvDeserializer.GetYStride(), |
|
436 yuvDeserializer.GetYSize(), |
|
437 gfx::SurfaceFormat::A8); |
|
438 RefPtr<gfx::DataSourceSurface> tempCb = |
|
439 gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCbData(), |
|
440 yuvDeserializer.GetCbCrStride(), |
|
441 yuvDeserializer.GetCbCrSize(), |
|
442 gfx::SurfaceFormat::A8); |
|
443 RefPtr<gfx::DataSourceSurface> tempCr = |
|
444 gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCrData(), |
|
445 yuvDeserializer.GetCbCrStride(), |
|
446 yuvDeserializer.GetCbCrSize(), |
|
447 gfx::SurfaceFormat::A8); |
|
448 // We don't support partial updates for Y U V textures |
|
449 NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures"); |
|
450 if (!srcY->Update(tempY) || |
|
451 !srcU->Update(tempCb) || |
|
452 !srcV->Update(tempCr)) { |
|
453 NS_WARNING("failed to update the DataTextureSource"); |
|
454 return false; |
|
455 } |
|
456 } else { |
|
457 // non-YCbCr case |
|
458 if (!mFirstSource) { |
|
459 mFirstSource = mCompositor->CreateDataTextureSource(); |
|
460 } |
|
461 ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize()); |
|
462 if (!deserializer.IsValid()) { |
|
463 NS_ERROR("Failed to deserialize image!"); |
|
464 return false; |
|
465 } |
|
466 |
|
467 RefPtr<gfx::DataSourceSurface> surf = deserializer.GetAsSurface(); |
|
468 if (!surf) { |
|
469 return false; |
|
470 } |
|
471 |
|
472 if (!mFirstSource->Update(surf.get(), aRegion)) { |
|
473 NS_WARNING("failed to update the DataTextureSource"); |
|
474 return false; |
|
475 } |
|
476 } |
|
477 return true; |
|
478 } |
|
479 |
|
480 TemporaryRef<gfx::DataSourceSurface> |
|
481 BufferTextureHost::GetAsSurface() |
|
482 { |
|
483 RefPtr<gfx::DataSourceSurface> result; |
|
484 if (mFormat == gfx::SurfaceFormat::UNKNOWN) { |
|
485 NS_WARNING("BufferTextureHost: unsupported format!"); |
|
486 return nullptr; |
|
487 } else if (mFormat == gfx::SurfaceFormat::YUV) { |
|
488 YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize()); |
|
489 if (!yuvDeserializer.IsValid()) { |
|
490 return nullptr; |
|
491 } |
|
492 result = yuvDeserializer.ToDataSourceSurface(); |
|
493 } else { |
|
494 ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize()); |
|
495 if (!deserializer.IsValid()) { |
|
496 NS_ERROR("Failed to deserialize image!"); |
|
497 return nullptr; |
|
498 } |
|
499 result = deserializer.GetAsSurface(); |
|
500 } |
|
501 return result.forget(); |
|
502 } |
|
503 |
|
504 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem, |
|
505 gfx::SurfaceFormat aFormat, |
|
506 ISurfaceAllocator* aDeallocator, |
|
507 TextureFlags aFlags) |
|
508 : BufferTextureHost(aFormat, aFlags) |
|
509 , mShmem(new ipc::Shmem(aShmem)) |
|
510 , mDeallocator(aDeallocator) |
|
511 { |
|
512 MOZ_COUNT_CTOR(ShmemTextureHost); |
|
513 } |
|
514 |
|
515 ShmemTextureHost::~ShmemTextureHost() |
|
516 { |
|
517 DeallocateDeviceData(); |
|
518 delete mShmem; |
|
519 MOZ_COUNT_DTOR(ShmemTextureHost); |
|
520 } |
|
521 |
|
522 void |
|
523 ShmemTextureHost::DeallocateSharedData() |
|
524 { |
|
525 if (mShmem) { |
|
526 MOZ_ASSERT(mDeallocator, |
|
527 "Shared memory would leak without a ISurfaceAllocator"); |
|
528 mDeallocator->DeallocShmem(*mShmem); |
|
529 delete mShmem; |
|
530 mShmem = nullptr; |
|
531 } |
|
532 } |
|
533 |
|
534 void |
|
535 ShmemTextureHost::ForgetSharedData() |
|
536 { |
|
537 if (mShmem) { |
|
538 delete mShmem; |
|
539 mShmem = nullptr; |
|
540 } |
|
541 } |
|
542 |
|
543 void |
|
544 ShmemTextureHost::OnShutdown() |
|
545 { |
|
546 delete mShmem; |
|
547 mShmem = nullptr; |
|
548 } |
|
549 |
|
550 uint8_t* ShmemTextureHost::GetBuffer() |
|
551 { |
|
552 return mShmem ? mShmem->get<uint8_t>() : nullptr; |
|
553 } |
|
554 |
|
555 size_t ShmemTextureHost::GetBufferSize() |
|
556 { |
|
557 return mShmem ? mShmem->Size<uint8_t>() : 0; |
|
558 } |
|
559 |
|
560 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer, |
|
561 gfx::SurfaceFormat aFormat, |
|
562 TextureFlags aFlags) |
|
563 : BufferTextureHost(aFormat, aFlags) |
|
564 , mBuffer(aBuffer) |
|
565 { |
|
566 MOZ_COUNT_CTOR(MemoryTextureHost); |
|
567 } |
|
568 |
|
569 MemoryTextureHost::~MemoryTextureHost() |
|
570 { |
|
571 DeallocateDeviceData(); |
|
572 NS_ASSERTION(!mBuffer || (mFlags & TEXTURE_DEALLOCATE_CLIENT), |
|
573 "Leaking our buffer"); |
|
574 MOZ_COUNT_DTOR(MemoryTextureHost); |
|
575 } |
|
576 |
|
577 void |
|
578 MemoryTextureHost::DeallocateSharedData() |
|
579 { |
|
580 if (mBuffer) { |
|
581 GfxMemoryImageReporter::WillFree(mBuffer); |
|
582 } |
|
583 delete[] mBuffer; |
|
584 mBuffer = nullptr; |
|
585 } |
|
586 |
|
587 void |
|
588 MemoryTextureHost::ForgetSharedData() |
|
589 { |
|
590 mBuffer = nullptr; |
|
591 } |
|
592 |
|
593 uint8_t* MemoryTextureHost::GetBuffer() |
|
594 { |
|
595 return mBuffer; |
|
596 } |
|
597 |
|
598 size_t MemoryTextureHost::GetBufferSize() |
|
599 { |
|
600 // MemoryTextureHost just trusts that the buffer size is large enough to read |
|
601 // anything we need to. That's because MemoryTextureHost has to trust the buffer |
|
602 // pointer anyway, so the security model here is just that MemoryTexture's |
|
603 // are restricted to same-process clients. |
|
604 return std::numeric_limits<size_t>::max(); |
|
605 } |
|
606 |
|
607 TextureParent::TextureParent(ISurfaceAllocator* aAllocator) |
|
608 : mAllocator(aAllocator) |
|
609 { |
|
610 MOZ_COUNT_CTOR(TextureParent); |
|
611 } |
|
612 |
|
613 TextureParent::~TextureParent() |
|
614 { |
|
615 MOZ_COUNT_DTOR(TextureParent); |
|
616 if (mTextureHost) { |
|
617 mTextureHost->ClearRecycleCallback(); |
|
618 } |
|
619 } |
|
620 |
|
621 static void RecycleCallback(TextureHost* textureHost, void* aClosure) { |
|
622 TextureParent* tp = reinterpret_cast<TextureParent*>(aClosure); |
|
623 tp->CompositorRecycle(); |
|
624 } |
|
625 |
|
626 void |
|
627 TextureParent::CompositorRecycle() |
|
628 { |
|
629 mTextureHost->ClearRecycleCallback(); |
|
630 |
|
631 MaybeFenceHandle handle = null_t(); |
|
632 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
|
633 if (mTextureHost) { |
|
634 TextureHostOGL* hostOGL = mTextureHost->AsHostOGL(); |
|
635 android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence(); |
|
636 if (fence.get() && fence->isValid()) { |
|
637 handle = FenceHandle(fence); |
|
638 // HWC might not provide Fence. |
|
639 // In this case, HWC implicitly handles buffer's fence. |
|
640 } |
|
641 } |
|
642 #endif |
|
643 mozilla::unused << SendCompositorRecycle(handle); |
|
644 |
|
645 // Don't forget to prepare for the next reycle |
|
646 // if TextureClient request it. |
|
647 if (mTextureHost->GetFlags() & TEXTURE_RECYCLE) { |
|
648 mWaitForClientRecycle = mTextureHost; |
|
649 } |
|
650 } |
|
651 |
|
652 bool |
|
653 TextureParent::RecvClientRecycle() |
|
654 { |
|
655 // This will allow the RecycleCallback to be called once the compositor |
|
656 // releases any external references to TextureHost. |
|
657 mTextureHost->SetRecycleCallback(RecycleCallback, this); |
|
658 if (!mWaitForClientRecycle) { |
|
659 RECYCLE_LOG("Not a recycable tile"); |
|
660 } |
|
661 mWaitForClientRecycle = nullptr; |
|
662 return true; |
|
663 } |
|
664 |
|
665 bool |
|
666 TextureParent::Init(const SurfaceDescriptor& aSharedData, |
|
667 const TextureFlags& aFlags) |
|
668 { |
|
669 mTextureHost = TextureHost::Create(aSharedData, |
|
670 mAllocator, |
|
671 aFlags); |
|
672 if (mTextureHost) { |
|
673 mTextureHost->mActor = this; |
|
674 if (aFlags & TEXTURE_RECYCLE) { |
|
675 mWaitForClientRecycle = mTextureHost; |
|
676 RECYCLE_LOG("Setup recycling for tile %p\n", this); |
|
677 } |
|
678 } |
|
679 |
|
680 return !!mTextureHost; |
|
681 } |
|
682 |
|
683 bool |
|
684 TextureParent::RecvRemoveTexture() |
|
685 { |
|
686 return PTextureParent::Send__delete__(this); |
|
687 } |
|
688 |
|
689 bool |
|
690 TextureParent::RecvRemoveTextureSync() |
|
691 { |
|
692 // we don't need to send a reply in the synchronous case since the child side |
|
693 // has the guarantee that this message has been handled synchronously. |
|
694 return PTextureParent::Send__delete__(this); |
|
695 } |
|
696 |
|
697 void |
|
698 TextureParent::ActorDestroy(ActorDestroyReason why) |
|
699 { |
|
700 if (!mTextureHost) { |
|
701 return; |
|
702 } |
|
703 |
|
704 switch (why) { |
|
705 case AncestorDeletion: |
|
706 case Deletion: |
|
707 case NormalShutdown: |
|
708 case AbnormalShutdown: |
|
709 break; |
|
710 case FailedConstructor: |
|
711 NS_RUNTIMEABORT("FailedConstructor isn't possible in PTexture"); |
|
712 } |
|
713 |
|
714 if (mTextureHost->GetFlags() & TEXTURE_RECYCLE) { |
|
715 RECYCLE_LOG("clear recycling for tile %p\n", this); |
|
716 mTextureHost->ClearRecycleCallback(); |
|
717 } |
|
718 if (mTextureHost->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { |
|
719 mTextureHost->ForgetSharedData(); |
|
720 } |
|
721 |
|
722 // Clear recycle callback. |
|
723 mTextureHost->ClearRecycleCallback(); |
|
724 mWaitForClientRecycle = nullptr; |
|
725 |
|
726 mTextureHost->mActor = nullptr; |
|
727 mTextureHost = nullptr; |
|
728 } |
|
729 |
|
730 } // namespace |
|
731 } // namespace |