michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SharedPlanarYCbCrImage.h" michael@0: #include // for size_t michael@0: #include // for printf michael@0: #include "gfx2DGlue.h" // for Moz2D transition helpers michael@0: #include "ISurfaceAllocator.h" // for ISurfaceAllocator, etc michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/gfx/Types.h" // for SurfaceFormat::SurfaceFormat::YUV michael@0: #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc michael@0: #include "mozilla/layers/ImageClient.h" // for ImageClient michael@0: #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc michael@0: #include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc michael@0: #include "mozilla/layers/YCbCrImageDataSerializer.h" michael@0: #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild michael@0: #include "mozilla/mozalloc.h" // for operator delete michael@0: #include "nsISupportsImpl.h" // for Image::AddRef michael@0: #include "mozilla/ipc/Shmem.h" michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(ImageClient* aCompositable) michael@0: : PlanarYCbCrImage(nullptr) michael@0: , mCompositable(aCompositable) michael@0: { michael@0: mTextureClient = aCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV); michael@0: MOZ_COUNT_CTOR(SharedPlanarYCbCrImage); michael@0: } michael@0: michael@0: SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() { michael@0: MOZ_COUNT_DTOR(SharedPlanarYCbCrImage); michael@0: michael@0: if (mCompositable->GetAsyncID() != 0 && michael@0: !InImageBridgeChildThread()) { michael@0: ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().drop()); michael@0: ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().drop()); michael@0: } michael@0: } michael@0: michael@0: size_t michael@0: SharedPlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: // NB: Explicitly skipping mTextureClient, the memory is already reported michael@0: // at time of allocation in GfxMemoryImageReporter. michael@0: // Not owned: michael@0: // - mCompositable michael@0: size_t size = PlanarYCbCrImage::SizeOfExcludingThis(aMallocSizeOf); michael@0: return size; michael@0: } michael@0: michael@0: TextureClient* michael@0: SharedPlanarYCbCrImage::GetTextureClient(CompositableClient* aClient) michael@0: { michael@0: return mTextureClient.get(); michael@0: } michael@0: michael@0: uint8_t* michael@0: SharedPlanarYCbCrImage::GetBuffer() michael@0: { michael@0: return mTextureClient->GetBuffer(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: SharedPlanarYCbCrImage::GetAsSourceSurface() michael@0: { michael@0: if (!mTextureClient->IsAllocated()) { michael@0: NS_WARNING("Can't get as surface"); michael@0: return nullptr; michael@0: } michael@0: return PlanarYCbCrImage::GetAsSourceSurface(); michael@0: } michael@0: michael@0: void michael@0: SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData) michael@0: { michael@0: // If mShmem has not been allocated (through Allocate(aData)), allocate it. michael@0: // This code path is slower than the one used when Allocate has been called michael@0: // since it will trigger a full copy. michael@0: if (!mTextureClient->IsAllocated()) { michael@0: Data data = aData; michael@0: if (!Allocate(data)) { michael@0: NS_WARNING("SharedPlanarYCbCrImage::SetData failed to allocate"); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr()); michael@0: if (!mTextureClient->Lock(OPEN_WRITE_ONLY)) { michael@0: MOZ_ASSERT(false, "Failed to lock the texture."); michael@0: return; michael@0: } michael@0: TextureClientAutoUnlock unlock(mTextureClient); michael@0: if (!mTextureClient->AsTextureClientYCbCr()->UpdateYCbCr(aData)) { michael@0: MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient"); michael@0: return; michael@0: } michael@0: // do not set mBuffer like in PlanarYCbCrImage because the later michael@0: // will try to manage this memory without knowing it belongs to a michael@0: // shmem. michael@0: mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize, michael@0: mData.mCbCrSize); michael@0: mSize = mData.mPicSize; michael@0: michael@0: YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize()); michael@0: mData.mYChannel = serializer.GetYData(); michael@0: mData.mCbChannel = serializer.GetCbData(); michael@0: mData.mCrChannel = serializer.GetCrData(); michael@0: mTextureClient->MarkImmutable(); michael@0: } michael@0: michael@0: // needs to be overriden because the parent class sets mBuffer which we michael@0: // do not want to happen. michael@0: uint8_t* michael@0: SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize) michael@0: { michael@0: NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(), "This image already has allocated data"); michael@0: size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize); michael@0: michael@0: // get new buffer _without_ setting mBuffer. michael@0: if (!mTextureClient->Allocate(size)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // update buffer size michael@0: mBufferSize = size; michael@0: michael@0: YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize()); michael@0: return serializer.GetData(); michael@0: } michael@0: michael@0: void michael@0: SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData) michael@0: { michael@0: mData = aData; michael@0: mSize = aData.mPicSize; michael@0: /* SetDataNoCopy is used to update YUV plane offsets without (re)allocating michael@0: * memory previously allocated with AllocateAndGetNewBuffer(). michael@0: * serializer.GetData() returns the address of the memory previously allocated michael@0: * with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr michael@0: * channels to compute 0-based offsets to pass to InitializeBufferInfo. michael@0: */ michael@0: YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize()); michael@0: uint8_t *base = serializer.GetData(); michael@0: uint32_t yOffset = aData.mYChannel - base; michael@0: uint32_t cbOffset = aData.mCbChannel - base; michael@0: uint32_t crOffset = aData.mCrChannel - base; michael@0: serializer.InitializeBufferInfo(yOffset, michael@0: cbOffset, michael@0: crOffset, michael@0: aData.mYStride, michael@0: aData.mCbCrStride, michael@0: aData.mYSize, michael@0: aData.mCbCrSize, michael@0: aData.mStereoMode); michael@0: } michael@0: michael@0: uint8_t* michael@0: SharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize) michael@0: { michael@0: NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(), michael@0: "This image already has allocated data"); michael@0: if (!mTextureClient->Allocate(aSize)) { michael@0: return nullptr; michael@0: } michael@0: return mTextureClient->GetBuffer(); michael@0: } michael@0: michael@0: bool michael@0: SharedPlanarYCbCrImage::IsValid() { michael@0: return mTextureClient->IsAllocated(); michael@0: } michael@0: michael@0: bool michael@0: SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData) michael@0: { michael@0: NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(), michael@0: "This image already has allocated data"); michael@0: michael@0: size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aData.mYSize, michael@0: aData.mCbCrSize); michael@0: michael@0: if (AllocateBuffer(static_cast(size)) == nullptr) { michael@0: return false; michael@0: } michael@0: michael@0: YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize()); michael@0: serializer.InitializeBufferInfo(aData.mYSize, michael@0: aData.mCbCrSize, michael@0: aData.mStereoMode); michael@0: MOZ_ASSERT(serializer.IsValid()); michael@0: michael@0: aData.mYChannel = serializer.GetYData(); michael@0: aData.mCbChannel = serializer.GetCbData(); michael@0: aData.mCrChannel = serializer.GetCrData(); michael@0: michael@0: // copy some of aData's values in mData (most of them) michael@0: mData.mYChannel = aData.mYChannel; michael@0: mData.mCbChannel = aData.mCbChannel; michael@0: mData.mCrChannel = aData.mCrChannel; michael@0: mData.mYSize = aData.mYSize; michael@0: mData.mCbCrSize = aData.mCbCrSize; michael@0: mData.mPicX = aData.mPicX; michael@0: mData.mPicY = aData.mPicY; michael@0: mData.mPicSize = aData.mPicSize; michael@0: mData.mStereoMode = aData.mStereoMode; michael@0: // those members are not always equal to aData's, due to potentially different michael@0: // packing. michael@0: mData.mYSkip = 0; michael@0: mData.mCbSkip = 0; michael@0: mData.mCrSkip = 0; michael@0: mData.mYStride = mData.mYSize.width; michael@0: mData.mCbCrStride = mData.mCbCrSize.width; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: } // namespace michael@0: } // namespace