|
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 |
|
7 #include "ImageContainer.h" |
|
8 #include <string.h> // for memcpy, memset |
|
9 #include "SharedTextureImage.h" // for SharedTextureImage |
|
10 #include "gfx2DGlue.h" |
|
11 #include "gfxPlatform.h" // for gfxPlatform |
|
12 #include "gfxUtils.h" // for gfxUtils |
|
13 #include "mozilla/RefPtr.h" // for TemporaryRef |
|
14 #include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc |
|
15 #include "mozilla/layers/CompositorTypes.h" |
|
16 #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild |
|
17 #include "mozilla/layers/ImageClient.h" // for ImageClient |
|
18 #include "nsISupportsUtils.h" // for NS_IF_ADDREF |
|
19 #include "YCbCrUtils.h" // for YCbCr conversions |
|
20 #ifdef MOZ_WIDGET_GONK |
|
21 #include "GrallocImages.h" |
|
22 #endif |
|
23 #include "gfx2DGlue.h" |
|
24 #include "mozilla/gfx/2D.h" |
|
25 |
|
26 #ifdef XP_MACOSX |
|
27 #include "mozilla/gfx/QuartzSupport.h" |
|
28 #include "MacIOSurfaceImage.h" |
|
29 #endif |
|
30 |
|
31 #ifdef XP_WIN |
|
32 #include "gfxD2DSurface.h" |
|
33 #include "gfxWindowsPlatform.h" |
|
34 #include <d3d10_1.h> |
|
35 #include "d3d10/ImageLayerD3D10.h" |
|
36 #include "D3D9SurfaceImage.h" |
|
37 #endif |
|
38 |
|
39 using namespace mozilla::ipc; |
|
40 using namespace android; |
|
41 using namespace mozilla::gfx; |
|
42 |
|
43 |
|
44 namespace mozilla { |
|
45 namespace layers { |
|
46 |
|
47 |
|
48 Atomic<int32_t> Image::sSerialCounter(0); |
|
49 |
|
50 already_AddRefed<Image> |
|
51 ImageFactory::CreateImage(ImageFormat aFormat, |
|
52 const gfx::IntSize &, |
|
53 BufferRecycleBin *aRecycleBin) |
|
54 { |
|
55 nsRefPtr<Image> img; |
|
56 #ifdef MOZ_WIDGET_GONK |
|
57 if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) { |
|
58 img = new GrallocImage(); |
|
59 return img.forget(); |
|
60 } |
|
61 #endif |
|
62 if (aFormat == ImageFormat::PLANAR_YCBCR) { |
|
63 img = new PlanarYCbCrImage(aRecycleBin); |
|
64 return img.forget(); |
|
65 } |
|
66 if (aFormat == ImageFormat::CAIRO_SURFACE) { |
|
67 img = new CairoImage(); |
|
68 return img.forget(); |
|
69 } |
|
70 if (aFormat == ImageFormat::SHARED_TEXTURE) { |
|
71 img = new SharedTextureImage(); |
|
72 return img.forget(); |
|
73 } |
|
74 #ifdef XP_MACOSX |
|
75 if (aFormat == ImageFormat::MAC_IOSURFACE) { |
|
76 img = new MacIOSurfaceImage(); |
|
77 return img.forget(); |
|
78 } |
|
79 #endif |
|
80 #ifdef XP_WIN |
|
81 if (aFormat == ImageFormat::D3D9_RGB32_TEXTURE) { |
|
82 img = new D3D9SurfaceImage(); |
|
83 return img.forget(); |
|
84 } |
|
85 #endif |
|
86 return nullptr; |
|
87 } |
|
88 |
|
89 BufferRecycleBin::BufferRecycleBin() |
|
90 : mLock("mozilla.layers.BufferRecycleBin.mLock") |
|
91 { |
|
92 } |
|
93 |
|
94 void |
|
95 BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize) |
|
96 { |
|
97 MutexAutoLock lock(mLock); |
|
98 |
|
99 if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) { |
|
100 mRecycledBuffers.Clear(); |
|
101 } |
|
102 mRecycledBufferSize = aSize; |
|
103 mRecycledBuffers.AppendElement(aBuffer); |
|
104 } |
|
105 |
|
106 uint8_t* |
|
107 BufferRecycleBin::GetBuffer(uint32_t aSize) |
|
108 { |
|
109 MutexAutoLock lock(mLock); |
|
110 |
|
111 if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize) |
|
112 return new uint8_t[aSize]; |
|
113 |
|
114 uint32_t last = mRecycledBuffers.Length() - 1; |
|
115 uint8_t* result = mRecycledBuffers[last].forget(); |
|
116 mRecycledBuffers.RemoveElementAt(last); |
|
117 return result; |
|
118 } |
|
119 |
|
120 ImageContainer::ImageContainer(int flag) |
|
121 : mReentrantMonitor("ImageContainer.mReentrantMonitor"), |
|
122 mPaintCount(0), |
|
123 mPreviousImagePainted(false), |
|
124 mImageFactory(new ImageFactory()), |
|
125 mRecycleBin(new BufferRecycleBin()), |
|
126 mRemoteData(nullptr), |
|
127 mRemoteDataMutex(nullptr), |
|
128 mCompositionNotifySink(nullptr), |
|
129 mImageClient(nullptr) |
|
130 { |
|
131 if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) { |
|
132 // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount |
|
133 // of this class must be done on the ImageBridge thread. |
|
134 mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(BUFFER_IMAGE_SINGLE).drop(); |
|
135 MOZ_ASSERT(mImageClient); |
|
136 } |
|
137 } |
|
138 |
|
139 ImageContainer::~ImageContainer() |
|
140 { |
|
141 if (IsAsync()) { |
|
142 ImageBridgeChild::DispatchReleaseImageClient(mImageClient); |
|
143 } |
|
144 } |
|
145 |
|
146 already_AddRefed<Image> |
|
147 ImageContainer::CreateImage(ImageFormat aFormat) |
|
148 { |
|
149 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
150 |
|
151 if (mImageClient) { |
|
152 nsRefPtr<Image> img = mImageClient->CreateImage(aFormat); |
|
153 if (img) { |
|
154 return img.forget(); |
|
155 } |
|
156 } |
|
157 return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin); |
|
158 } |
|
159 |
|
160 void |
|
161 ImageContainer::SetCurrentImageInternal(Image *aImage) |
|
162 { |
|
163 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
164 |
|
165 if (mRemoteData) { |
|
166 NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); |
|
167 mRemoteDataMutex->Lock(); |
|
168 // This is important since it ensures we won't change the active image |
|
169 // when we currently have a locked image that depends on mRemoteData. |
|
170 } |
|
171 |
|
172 mActiveImage = aImage; |
|
173 CurrentImageChanged(); |
|
174 |
|
175 if (mRemoteData) { |
|
176 mRemoteDataMutex->Unlock(); |
|
177 } |
|
178 } |
|
179 |
|
180 void |
|
181 ImageContainer::ClearCurrentImage() |
|
182 { |
|
183 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
184 SetCurrentImageInternal(nullptr); |
|
185 } |
|
186 |
|
187 void |
|
188 ImageContainer::SetCurrentImage(Image *aImage) |
|
189 { |
|
190 if (!aImage) { |
|
191 ClearAllImages(); |
|
192 return; |
|
193 } |
|
194 |
|
195 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
196 if (IsAsync()) { |
|
197 ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this); |
|
198 } |
|
199 SetCurrentImageInternal(aImage); |
|
200 } |
|
201 |
|
202 void |
|
203 ImageContainer::ClearAllImages() |
|
204 { |
|
205 if (IsAsync()) { |
|
206 // Let ImageClient release all TextureClients. |
|
207 ImageBridgeChild::FlushAllImages(mImageClient, this, false); |
|
208 return; |
|
209 } |
|
210 |
|
211 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
212 SetCurrentImageInternal(nullptr); |
|
213 } |
|
214 |
|
215 void |
|
216 ImageContainer::ClearAllImagesExceptFront() |
|
217 { |
|
218 if (IsAsync()) { |
|
219 // Let ImageClient release all TextureClients except front one. |
|
220 ImageBridgeChild::FlushAllImages(mImageClient, this, true); |
|
221 } |
|
222 } |
|
223 |
|
224 void |
|
225 ImageContainer::SetCurrentImageInTransaction(Image *aImage) |
|
226 { |
|
227 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
|
228 NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge."); |
|
229 |
|
230 SetCurrentImageInternal(aImage); |
|
231 } |
|
232 |
|
233 bool ImageContainer::IsAsync() const { |
|
234 return mImageClient != nullptr; |
|
235 } |
|
236 |
|
237 uint64_t ImageContainer::GetAsyncContainerID() const |
|
238 { |
|
239 NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers"); |
|
240 if (IsAsync()) { |
|
241 return mImageClient->GetAsyncID(); |
|
242 } else { |
|
243 return 0; // zero is always an invalid AsyncID |
|
244 } |
|
245 } |
|
246 |
|
247 bool |
|
248 ImageContainer::HasCurrentImage() |
|
249 { |
|
250 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
251 |
|
252 if (mRemoteData) { |
|
253 CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); |
|
254 |
|
255 EnsureActiveImage(); |
|
256 |
|
257 return !!mActiveImage.get(); |
|
258 } |
|
259 |
|
260 return !!mActiveImage.get(); |
|
261 } |
|
262 |
|
263 already_AddRefed<Image> |
|
264 ImageContainer::LockCurrentImage() |
|
265 { |
|
266 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
267 |
|
268 if (mRemoteData) { |
|
269 NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); |
|
270 mRemoteDataMutex->Lock(); |
|
271 } |
|
272 |
|
273 EnsureActiveImage(); |
|
274 |
|
275 nsRefPtr<Image> retval = mActiveImage; |
|
276 return retval.forget(); |
|
277 } |
|
278 |
|
279 TemporaryRef<gfx::SourceSurface> |
|
280 ImageContainer::LockCurrentAsSourceSurface(gfx::IntSize *aSize, Image** aCurrentImage) |
|
281 { |
|
282 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
283 |
|
284 if (mRemoteData) { |
|
285 NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); |
|
286 mRemoteDataMutex->Lock(); |
|
287 |
|
288 EnsureActiveImage(); |
|
289 |
|
290 if (aCurrentImage) { |
|
291 NS_IF_ADDREF(mActiveImage); |
|
292 *aCurrentImage = mActiveImage.get(); |
|
293 } |
|
294 |
|
295 if (!mActiveImage) { |
|
296 return nullptr; |
|
297 } |
|
298 |
|
299 if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) { |
|
300 gfxImageFormat fmt = mRemoteData->mFormat == RemoteImageData::BGRX32 |
|
301 ? gfxImageFormat::ARGB32 |
|
302 : gfxImageFormat::RGB24; |
|
303 |
|
304 RefPtr<gfx::DataSourceSurface> newSurf |
|
305 = gfx::Factory::CreateWrappingDataSourceSurface(mRemoteData->mBitmap.mData, |
|
306 mRemoteData->mBitmap.mStride, |
|
307 mRemoteData->mSize, |
|
308 gfx::ImageFormatToSurfaceFormat(fmt)); |
|
309 *aSize = newSurf->GetSize(); |
|
310 |
|
311 return newSurf; |
|
312 } |
|
313 |
|
314 *aSize = mActiveImage->GetSize(); |
|
315 return mActiveImage->GetAsSourceSurface(); |
|
316 } |
|
317 |
|
318 if (aCurrentImage) { |
|
319 NS_IF_ADDREF(mActiveImage); |
|
320 *aCurrentImage = mActiveImage.get(); |
|
321 } |
|
322 |
|
323 if (!mActiveImage) { |
|
324 return nullptr; |
|
325 } |
|
326 |
|
327 *aSize = mActiveImage->GetSize(); |
|
328 return mActiveImage->GetAsSourceSurface(); |
|
329 } |
|
330 |
|
331 void |
|
332 ImageContainer::UnlockCurrentImage() |
|
333 { |
|
334 if (mRemoteData) { |
|
335 NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); |
|
336 mRemoteDataMutex->Unlock(); |
|
337 } |
|
338 } |
|
339 |
|
340 TemporaryRef<gfx::SourceSurface> |
|
341 ImageContainer::GetCurrentAsSourceSurface(gfx::IntSize *aSize) |
|
342 { |
|
343 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
344 |
|
345 if (mRemoteData) { |
|
346 CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); |
|
347 EnsureActiveImage(); |
|
348 |
|
349 if (!mActiveImage) |
|
350 return nullptr; |
|
351 *aSize = mRemoteData->mSize; |
|
352 } else { |
|
353 if (!mActiveImage) |
|
354 return nullptr; |
|
355 *aSize = mActiveImage->GetSize(); |
|
356 } |
|
357 return mActiveImage->GetAsSourceSurface(); |
|
358 } |
|
359 |
|
360 gfx::IntSize |
|
361 ImageContainer::GetCurrentSize() |
|
362 { |
|
363 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
364 |
|
365 if (mRemoteData) { |
|
366 CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); |
|
367 |
|
368 // We don't need to ensure we have an active image here, as we need to |
|
369 // be in the mutex anyway, and this is easiest to return from there. |
|
370 return mRemoteData->mSize; |
|
371 } |
|
372 |
|
373 if (!mActiveImage) { |
|
374 return gfx::IntSize(0, 0); |
|
375 } |
|
376 |
|
377 return mActiveImage->GetSize(); |
|
378 } |
|
379 |
|
380 void |
|
381 ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex) |
|
382 { |
|
383 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
384 |
|
385 NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData."); |
|
386 NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData."); |
|
387 |
|
388 mRemoteData = aData; |
|
389 |
|
390 if (aData) { |
|
391 memset(aData, 0, sizeof(RemoteImageData)); |
|
392 } else { |
|
393 mActiveImage = nullptr; |
|
394 } |
|
395 |
|
396 mRemoteDataMutex = aMutex; |
|
397 } |
|
398 |
|
399 void |
|
400 ImageContainer::EnsureActiveImage() |
|
401 { |
|
402 if (mRemoteData) { |
|
403 if (mRemoteData->mWasUpdated) { |
|
404 mActiveImage = nullptr; |
|
405 } |
|
406 |
|
407 if (mRemoteData->mType == RemoteImageData::RAW_BITMAP && |
|
408 mRemoteData->mBitmap.mData && !mActiveImage) { |
|
409 nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage(); |
|
410 |
|
411 newImg->mFormat = mRemoteData->mFormat; |
|
412 newImg->mData = mRemoteData->mBitmap.mData; |
|
413 newImg->mSize = mRemoteData->mSize; |
|
414 newImg->mStride = mRemoteData->mBitmap.mStride; |
|
415 mRemoteData->mWasUpdated = false; |
|
416 |
|
417 mActiveImage = newImg; |
|
418 } |
|
419 #ifdef XP_WIN |
|
420 else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE && |
|
421 mRemoteData->mTextureHandle && !mActiveImage) { |
|
422 nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage(); |
|
423 newImg->mSize = mRemoteData->mSize; |
|
424 newImg->mHandle = mRemoteData->mTextureHandle; |
|
425 newImg->mFormat = mRemoteData->mFormat; |
|
426 mRemoteData->mWasUpdated = false; |
|
427 |
|
428 mActiveImage = newImg; |
|
429 } |
|
430 #endif |
|
431 } |
|
432 } |
|
433 |
|
434 |
|
435 PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin) |
|
436 : Image(nullptr, ImageFormat::PLANAR_YCBCR) |
|
437 , mBufferSize(0) |
|
438 , mOffscreenFormat(gfxImageFormat::Unknown) |
|
439 , mRecycleBin(aRecycleBin) |
|
440 { |
|
441 } |
|
442 |
|
443 PlanarYCbCrImage::~PlanarYCbCrImage() |
|
444 { |
|
445 if (mBuffer) { |
|
446 mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize); |
|
447 } |
|
448 } |
|
449 |
|
450 size_t |
|
451 PlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
|
452 { |
|
453 // Ignoring: |
|
454 // - mData - just wraps mBuffer |
|
455 // - Surfaces should be reported under gfx-surfaces-*: |
|
456 // - mSourceSurface |
|
457 // - Base class: |
|
458 // - mImplData is not used |
|
459 // Not owned: |
|
460 // - mRecycleBin |
|
461 size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf); |
|
462 |
|
463 // Could add in the future: |
|
464 // - mBackendData (from base class) |
|
465 |
|
466 return size; |
|
467 } |
|
468 |
|
469 uint8_t* |
|
470 PlanarYCbCrImage::AllocateBuffer(uint32_t aSize) |
|
471 { |
|
472 return mRecycleBin->GetBuffer(aSize); |
|
473 } |
|
474 |
|
475 static void |
|
476 CopyPlane(uint8_t *aDst, const uint8_t *aSrc, |
|
477 const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip) |
|
478 { |
|
479 if (!aSkip) { |
|
480 // Fast path: planar input. |
|
481 memcpy(aDst, aSrc, aSize.height * aStride); |
|
482 } else { |
|
483 int32_t height = aSize.height; |
|
484 int32_t width = aSize.width; |
|
485 for (int y = 0; y < height; ++y) { |
|
486 const uint8_t *src = aSrc; |
|
487 uint8_t *dst = aDst; |
|
488 // Slow path |
|
489 for (int x = 0; x < width; ++x) { |
|
490 *dst++ = *src++; |
|
491 src += aSkip; |
|
492 } |
|
493 aSrc += aStride; |
|
494 aDst += aStride; |
|
495 } |
|
496 } |
|
497 } |
|
498 |
|
499 void |
|
500 PlanarYCbCrImage::CopyData(const Data& aData) |
|
501 { |
|
502 mData = aData; |
|
503 |
|
504 // update buffer size |
|
505 size_t size = mData.mCbCrStride * mData.mCbCrSize.height * 2 + |
|
506 mData.mYStride * mData.mYSize.height; |
|
507 |
|
508 // get new buffer |
|
509 mBuffer = AllocateBuffer(size); |
|
510 if (!mBuffer) |
|
511 return; |
|
512 |
|
513 // update buffer size |
|
514 mBufferSize = size; |
|
515 |
|
516 mData.mYChannel = mBuffer; |
|
517 mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; |
|
518 mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; |
|
519 |
|
520 CopyPlane(mData.mYChannel, aData.mYChannel, |
|
521 mData.mYSize, mData.mYStride, mData.mYSkip); |
|
522 CopyPlane(mData.mCbChannel, aData.mCbChannel, |
|
523 mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip); |
|
524 CopyPlane(mData.mCrChannel, aData.mCrChannel, |
|
525 mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip); |
|
526 |
|
527 mSize = aData.mPicSize; |
|
528 } |
|
529 |
|
530 void |
|
531 PlanarYCbCrImage::SetData(const Data &aData) |
|
532 { |
|
533 CopyData(aData); |
|
534 } |
|
535 |
|
536 gfxImageFormat |
|
537 PlanarYCbCrImage::GetOffscreenFormat() |
|
538 { |
|
539 return mOffscreenFormat == gfxImageFormat::Unknown ? |
|
540 gfxPlatform::GetPlatform()->GetOffscreenFormat() : |
|
541 mOffscreenFormat; |
|
542 } |
|
543 |
|
544 void |
|
545 PlanarYCbCrImage::SetDataNoCopy(const Data &aData) |
|
546 { |
|
547 mData = aData; |
|
548 mSize = aData.mPicSize; |
|
549 } |
|
550 |
|
551 uint8_t* |
|
552 PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize) |
|
553 { |
|
554 // get new buffer |
|
555 mBuffer = AllocateBuffer(aSize); |
|
556 if (mBuffer) { |
|
557 // update buffer size |
|
558 mBufferSize = aSize; |
|
559 } |
|
560 return mBuffer; |
|
561 } |
|
562 |
|
563 TemporaryRef<gfx::SourceSurface> |
|
564 PlanarYCbCrImage::GetAsSourceSurface() |
|
565 { |
|
566 if (mSourceSurface) { |
|
567 return mSourceSurface.get(); |
|
568 } |
|
569 |
|
570 gfx::IntSize size(mSize); |
|
571 gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat()); |
|
572 gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size); |
|
573 if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION || |
|
574 mSize.height > PlanarYCbCrImage::MAX_DIMENSION) { |
|
575 NS_ERROR("Illegal image dest width or height"); |
|
576 return nullptr; |
|
577 } |
|
578 |
|
579 RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format); |
|
580 |
|
581 gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride()); |
|
582 |
|
583 mSourceSurface = surface; |
|
584 |
|
585 return surface.forget(); |
|
586 } |
|
587 |
|
588 TemporaryRef<gfx::SourceSurface> |
|
589 RemoteBitmapImage::GetAsSourceSurface() |
|
590 { |
|
591 gfx::SurfaceFormat fmt = mFormat == RemoteImageData::BGRX32 |
|
592 ? gfx::SurfaceFormat::B8G8R8X8 |
|
593 : gfx::SurfaceFormat::B8G8R8A8; |
|
594 RefPtr<gfx::DataSourceSurface> newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt); |
|
595 |
|
596 for (int y = 0; y < mSize.height; y++) { |
|
597 memcpy(newSurf->GetData() + newSurf->Stride() * y, |
|
598 mData + mStride * y, |
|
599 mSize.width * 4); |
|
600 } |
|
601 |
|
602 return newSurf; |
|
603 } |
|
604 |
|
605 CairoImage::CairoImage() |
|
606 : Image(nullptr, ImageFormat::CAIRO_SURFACE) |
|
607 {} |
|
608 |
|
609 CairoImage::~CairoImage() |
|
610 { |
|
611 } |
|
612 |
|
613 TextureClient* |
|
614 CairoImage::GetTextureClient(CompositableClient *aClient) |
|
615 { |
|
616 CompositableForwarder* forwarder = aClient->GetForwarder(); |
|
617 RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); |
|
618 if (textureClient) { |
|
619 return textureClient; |
|
620 } |
|
621 |
|
622 RefPtr<SourceSurface> surface = GetAsSourceSurface(); |
|
623 MOZ_ASSERT(surface); |
|
624 |
|
625 // gfx::BackendType::NONE means default to content backend |
|
626 textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), |
|
627 TEXTURE_FLAGS_DEFAULT, |
|
628 gfx::BackendType::NONE, |
|
629 surface->GetSize()); |
|
630 MOZ_ASSERT(textureClient->CanExposeDrawTarget()); |
|
631 if (!textureClient->AllocateForSurface(surface->GetSize()) || |
|
632 !textureClient->Lock(OPEN_WRITE_ONLY)) { |
|
633 return nullptr; |
|
634 } |
|
635 |
|
636 { |
|
637 // We must not keep a reference to the DrawTarget after it has been unlocked. |
|
638 RefPtr<DrawTarget> dt = textureClient->GetAsDrawTarget(); |
|
639 dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); |
|
640 } |
|
641 |
|
642 textureClient->Unlock(); |
|
643 |
|
644 mTextureClients.Put(forwarder->GetSerial(), textureClient); |
|
645 return textureClient; |
|
646 } |
|
647 |
|
648 } // namespace |
|
649 } // namespace |