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 "mozilla/layers/TextureHost.h" michael@0: #include "CompositableHost.h" // for CompositableHost michael@0: #include "LayersLogging.h" // for AppendToString michael@0: #include "gfx2DGlue.h" // for ToIntSize michael@0: #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory michael@0: #include "mozilla/ipc/Shmem.h" // for Shmem michael@0: #include "mozilla/layers/Compositor.h" // for Compositor michael@0: #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator michael@0: #include "mozilla/layers/ImageDataSerializer.h" michael@0: #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc michael@0: #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL michael@0: #ifdef MOZ_X11 michael@0: #include "mozilla/layers/X11TextureHost.h" michael@0: #endif michael@0: #include "mozilla/layers/YCbCrImageDataSerializer.h" michael@0: #include "nsAString.h" michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsPrintfCString.h" // for nsPrintfCString michael@0: #include "mozilla/layers/PTextureParent.h" michael@0: #include "mozilla/unused.h" michael@0: #include michael@0: michael@0: #if 0 michael@0: #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) michael@0: #else michael@0: #define RECYCLE_LOG(...) do { } while (0) michael@0: #endif michael@0: michael@0: struct nsIntPoint; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: /** michael@0: * TextureParent is the host-side IPDL glue between TextureClient and TextureHost. michael@0: * It is an IPDL actor just like LayerParent, CompositableParent, etc. michael@0: */ michael@0: class TextureParent : public PTextureParent michael@0: { michael@0: public: michael@0: TextureParent(ISurfaceAllocator* aAllocator); michael@0: michael@0: ~TextureParent(); michael@0: michael@0: bool Init(const SurfaceDescriptor& aSharedData, michael@0: const TextureFlags& aFlags); michael@0: michael@0: void CompositorRecycle(); michael@0: virtual bool RecvClientRecycle() MOZ_OVERRIDE; michael@0: michael@0: virtual bool RecvRemoveTexture() MOZ_OVERRIDE; michael@0: michael@0: virtual bool RecvRemoveTextureSync() MOZ_OVERRIDE; michael@0: michael@0: TextureHost* GetTextureHost() { return mTextureHost; } michael@0: michael@0: void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; michael@0: michael@0: ISurfaceAllocator* mAllocator; michael@0: RefPtr mWaitForClientRecycle; michael@0: RefPtr mTextureHost; michael@0: }; michael@0: michael@0: // static michael@0: PTextureParent* michael@0: TextureHost::CreateIPDLActor(ISurfaceAllocator* aAllocator, michael@0: const SurfaceDescriptor& aSharedData, michael@0: TextureFlags aFlags) michael@0: { michael@0: if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory && michael@0: !aAllocator->IsSameProcess()) michael@0: { michael@0: NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!"); michael@0: return nullptr; michael@0: } michael@0: TextureParent* actor = new TextureParent(aAllocator); michael@0: if (!actor->Init(aSharedData, aFlags)) { michael@0: delete actor; michael@0: return nullptr; michael@0: } michael@0: return actor; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: TextureHost::DestroyIPDLActor(PTextureParent* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: TextureHost::SendDeleteIPDLActor(PTextureParent* actor) michael@0: { michael@0: return PTextureParent::Send__delete__(actor); michael@0: } michael@0: michael@0: // static michael@0: TextureHost* michael@0: TextureHost::AsTextureHost(PTextureParent* actor) michael@0: { michael@0: return actor? static_cast(actor)->mTextureHost : nullptr; michael@0: } michael@0: michael@0: PTextureParent* michael@0: TextureHost::GetIPDLActor() michael@0: { michael@0: return mActor; michael@0: } michael@0: michael@0: // implemented in TextureHostOGL.cpp michael@0: TemporaryRef CreateTextureHostOGL(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags); michael@0: michael@0: // implemented in TextureHostBasic.cpp michael@0: TemporaryRef CreateTextureHostBasic(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags); michael@0: michael@0: // implemented in TextureD3D11.cpp michael@0: TemporaryRef CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags); michael@0: michael@0: // implemented in TextureD3D9.cpp michael@0: TemporaryRef CreateTextureHostD3D9(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags); michael@0: michael@0: // static michael@0: TemporaryRef michael@0: TextureHost::Create(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags) michael@0: { michael@0: switch (aDesc.type()) { michael@0: case SurfaceDescriptor::TSurfaceDescriptorShmem: michael@0: case SurfaceDescriptor::TSurfaceDescriptorMemory: michael@0: return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags); michael@0: case SurfaceDescriptor::TSharedTextureDescriptor: michael@0: case SurfaceDescriptor::TNewSurfaceDescriptorGralloc: michael@0: case SurfaceDescriptor::TSurfaceStreamDescriptor: michael@0: return CreateTextureHostOGL(aDesc, aDeallocator, aFlags); michael@0: case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: michael@0: if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) { michael@0: return CreateTextureHostOGL(aDesc, aDeallocator, aFlags); michael@0: } else { michael@0: return CreateTextureHostBasic(aDesc, aDeallocator, aFlags); michael@0: } michael@0: #ifdef MOZ_X11 michael@0: case SurfaceDescriptor::TSurfaceDescriptorX11: { michael@0: const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11(); michael@0: RefPtr result = new X11TextureHost(aFlags, desc); michael@0: return result; michael@0: } michael@0: #endif michael@0: #ifdef XP_WIN michael@0: case SurfaceDescriptor::TSurfaceDescriptorD3D9: michael@0: case SurfaceDescriptor::TSurfaceDescriptorDIB: michael@0: return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags); michael@0: case SurfaceDescriptor::TSurfaceDescriptorD3D10: michael@0: if (Compositor::GetBackend() == LayersBackend::LAYERS_D3D9) { michael@0: return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags); michael@0: } else { michael@0: return CreateTextureHostD3D11(aDesc, aDeallocator, aFlags); michael@0: } michael@0: #endif michael@0: default: michael@0: MOZ_CRASH("Unsupported Surface type"); michael@0: } michael@0: } michael@0: michael@0: TemporaryRef michael@0: CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags) michael@0: { michael@0: RefPtr result; michael@0: switch (aDesc.type()) { michael@0: case SurfaceDescriptor::TSurfaceDescriptorShmem: { michael@0: const SurfaceDescriptorShmem& descriptor = aDesc.get_SurfaceDescriptorShmem(); michael@0: result = new ShmemTextureHost(descriptor.data(), michael@0: descriptor.format(), michael@0: aDeallocator, michael@0: aFlags); michael@0: break; michael@0: } michael@0: case SurfaceDescriptor::TSurfaceDescriptorMemory: { michael@0: const SurfaceDescriptorMemory& descriptor = aDesc.get_SurfaceDescriptorMemory(); michael@0: result = new MemoryTextureHost(reinterpret_cast(descriptor.data()), michael@0: descriptor.format(), michael@0: aFlags); michael@0: break; michael@0: } michael@0: default: { michael@0: NS_WARNING("No backend independent TextureHost for this descriptor type"); michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: TextureHost::CompositorRecycle() michael@0: { michael@0: if (!mActor) { michael@0: return; michael@0: } michael@0: static_cast(mActor)->CompositorRecycle(); michael@0: } michael@0: michael@0: void michael@0: TextureHost::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) michael@0: { michael@0: mCompositableBackendData = aBackendData; michael@0: } michael@0: michael@0: michael@0: TextureHost::TextureHost(TextureFlags aFlags) michael@0: : mActor(nullptr) michael@0: , mFlags(aFlags) michael@0: {} michael@0: michael@0: TextureHost::~TextureHost() michael@0: { michael@0: } michael@0: michael@0: void TextureHost::Finalize() michael@0: { michael@0: if (!(GetFlags() & TEXTURE_DEALLOCATE_CLIENT)) { michael@0: DeallocateSharedData(); michael@0: DeallocateDeviceData(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextureHost::PrintInfo(nsACString& aTo, const char* aPrefix) michael@0: { michael@0: aTo += aPrefix; michael@0: aTo += nsPrintfCString("%s (0x%p)", Name(), this); michael@0: // Note: the TextureHost needs to be locked before it is safe to call michael@0: // GetSize() and GetFormat() on it. michael@0: if (Lock()) { michael@0: AppendToString(aTo, GetSize(), " [size=", "]"); michael@0: AppendToString(aTo, GetFormat(), " [format=", "]"); michael@0: Unlock(); michael@0: } michael@0: AppendToString(aTo, mFlags, " [flags=", "]"); michael@0: } michael@0: michael@0: void michael@0: TextureSource::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) michael@0: { michael@0: mCompositableBackendData = aBackendData; michael@0: } michael@0: michael@0: TextureSource::TextureSource() michael@0: { michael@0: MOZ_COUNT_CTOR(TextureSource); michael@0: } michael@0: TextureSource::~TextureSource() michael@0: { michael@0: MOZ_COUNT_DTOR(TextureSource); michael@0: } michael@0: michael@0: BufferTextureHost::BufferTextureHost(gfx::SurfaceFormat aFormat, michael@0: TextureFlags aFlags) michael@0: : TextureHost(aFlags) michael@0: , mCompositor(nullptr) michael@0: , mFormat(aFormat) michael@0: , mUpdateSerial(1) michael@0: , mLocked(false) michael@0: , mPartialUpdate(false) michael@0: {} michael@0: michael@0: BufferTextureHost::~BufferTextureHost() michael@0: {} michael@0: michael@0: void michael@0: BufferTextureHost::Updated(const nsIntRegion* aRegion) michael@0: { michael@0: ++mUpdateSerial; michael@0: if (aRegion) { michael@0: mPartialUpdate = true; michael@0: mMaybeUpdatedRegion = *aRegion; michael@0: } else { michael@0: mPartialUpdate = false; michael@0: } michael@0: if (GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) { michael@0: DebugOnly result = MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr); michael@0: NS_WARN_IF_FALSE(result, "Failed to upload a texture"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: BufferTextureHost::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: if (mCompositor == aCompositor) { michael@0: return; michael@0: } michael@0: RefPtr it = mFirstSource; michael@0: while (it) { michael@0: it->SetCompositor(aCompositor); michael@0: it = it->GetNextSibling(); michael@0: } michael@0: mCompositor = aCompositor; michael@0: } michael@0: michael@0: void michael@0: BufferTextureHost::DeallocateDeviceData() michael@0: { michael@0: RefPtr it = mFirstSource; michael@0: while (it) { michael@0: it->DeallocateDeviceData(); michael@0: it = it->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: BufferTextureHost::Lock() michael@0: { michael@0: mLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: BufferTextureHost::Unlock() michael@0: { michael@0: mLocked = false; michael@0: } michael@0: michael@0: NewTextureSource* michael@0: BufferTextureHost::GetTextureSources() michael@0: { michael@0: MOZ_ASSERT(mLocked, "should never be called while not locked"); michael@0: if (!MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) { michael@0: return nullptr; michael@0: } michael@0: return mFirstSource; michael@0: } michael@0: michael@0: gfx::SurfaceFormat michael@0: BufferTextureHost::GetFormat() const michael@0: { michael@0: // mFormat is the format of the data that we share with the content process. michael@0: // GetFormat, on the other hand, expects the format that we present to the michael@0: // Compositor (it is used to choose the effect type). michael@0: // if the compositor does not support YCbCr effects, we give it a RGBX texture michael@0: // instead (see BufferTextureHost::Upload) michael@0: if (mFormat == gfx::SurfaceFormat::YUV && michael@0: mCompositor && michael@0: !mCompositor->SupportsEffect(EFFECT_YCBCR)) { michael@0: return gfx::SurfaceFormat::R8G8B8X8; michael@0: } michael@0: return mFormat; michael@0: } michael@0: michael@0: bool michael@0: BufferTextureHost::MaybeUpload(nsIntRegion *aRegion) michael@0: { michael@0: if (mFirstSource && mFirstSource->GetUpdateSerial() == mUpdateSerial) { michael@0: return true; michael@0: } michael@0: if (!Upload(aRegion)) { michael@0: return false; michael@0: } michael@0: mFirstSource->SetUpdateSerial(mUpdateSerial); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: BufferTextureHost::Upload(nsIntRegion *aRegion) michael@0: { michael@0: if (!GetBuffer()) { michael@0: // We don't have a buffer; a possible cause is that the IPDL actor michael@0: // is already dead. This inevitably happens as IPDL actors can die michael@0: // at any time, so we want to silently return in this case. michael@0: return false; michael@0: } michael@0: if (!mCompositor) { michael@0: NS_WARNING("Tried to upload without a compositor. Skipping texture upload..."); michael@0: // If we are in this situation it means we should have called SetCompositor michael@0: // earlier. It is conceivable that on certain rare conditions with async-video michael@0: // we may end up here for the first frame, but this should not happen repeatedly. michael@0: return false; michael@0: } michael@0: if (mFormat == gfx::SurfaceFormat::UNKNOWN) { michael@0: NS_WARNING("BufferTextureHost: unsupported format!"); michael@0: return false; michael@0: } else if (mFormat == gfx::SurfaceFormat::YUV) { michael@0: YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize()); michael@0: MOZ_ASSERT(yuvDeserializer.IsValid()); michael@0: michael@0: if (!mCompositor->SupportsEffect(EFFECT_YCBCR)) { michael@0: RefPtr surf = yuvDeserializer.ToDataSourceSurface(); michael@0: if (!mFirstSource) { michael@0: mFirstSource = mCompositor->CreateDataTextureSource(mFlags); michael@0: } michael@0: mFirstSource->Update(surf, aRegion); michael@0: return true; michael@0: } michael@0: michael@0: RefPtr srcY; michael@0: RefPtr srcU; michael@0: RefPtr srcV; michael@0: if (!mFirstSource) { michael@0: // We don't support BigImages for YCbCr compositing. michael@0: srcY = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); michael@0: srcU = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); michael@0: srcV = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE); michael@0: mFirstSource = srcY; michael@0: srcY->SetNextSibling(srcU); michael@0: srcU->SetNextSibling(srcV); michael@0: } else { michael@0: // mFormat never changes so if this was created as a YCbCr host and already michael@0: // contains a source it should already have 3 sources. michael@0: // BufferTextureHost only uses DataTextureSources so it is safe to assume michael@0: // all 3 sources are DataTextureSource. michael@0: MOZ_ASSERT(mFirstSource->GetNextSibling()); michael@0: MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling()); michael@0: srcY = mFirstSource; michael@0: srcU = mFirstSource->GetNextSibling()->AsDataTextureSource(); michael@0: srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource(); michael@0: } michael@0: michael@0: michael@0: RefPtr tempY = michael@0: gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetYData(), michael@0: yuvDeserializer.GetYStride(), michael@0: yuvDeserializer.GetYSize(), michael@0: gfx::SurfaceFormat::A8); michael@0: RefPtr tempCb = michael@0: gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCbData(), michael@0: yuvDeserializer.GetCbCrStride(), michael@0: yuvDeserializer.GetCbCrSize(), michael@0: gfx::SurfaceFormat::A8); michael@0: RefPtr tempCr = michael@0: gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCrData(), michael@0: yuvDeserializer.GetCbCrStride(), michael@0: yuvDeserializer.GetCbCrSize(), michael@0: gfx::SurfaceFormat::A8); michael@0: // We don't support partial updates for Y U V textures michael@0: NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures"); michael@0: if (!srcY->Update(tempY) || michael@0: !srcU->Update(tempCb) || michael@0: !srcV->Update(tempCr)) { michael@0: NS_WARNING("failed to update the DataTextureSource"); michael@0: return false; michael@0: } michael@0: } else { michael@0: // non-YCbCr case michael@0: if (!mFirstSource) { michael@0: mFirstSource = mCompositor->CreateDataTextureSource(); michael@0: } michael@0: ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize()); michael@0: if (!deserializer.IsValid()) { michael@0: NS_ERROR("Failed to deserialize image!"); michael@0: return false; michael@0: } michael@0: michael@0: RefPtr surf = deserializer.GetAsSurface(); michael@0: if (!surf) { michael@0: return false; michael@0: } michael@0: michael@0: if (!mFirstSource->Update(surf.get(), aRegion)) { michael@0: NS_WARNING("failed to update the DataTextureSource"); michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: TemporaryRef michael@0: BufferTextureHost::GetAsSurface() michael@0: { michael@0: RefPtr result; michael@0: if (mFormat == gfx::SurfaceFormat::UNKNOWN) { michael@0: NS_WARNING("BufferTextureHost: unsupported format!"); michael@0: return nullptr; michael@0: } else if (mFormat == gfx::SurfaceFormat::YUV) { michael@0: YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize()); michael@0: if (!yuvDeserializer.IsValid()) { michael@0: return nullptr; michael@0: } michael@0: result = yuvDeserializer.ToDataSourceSurface(); michael@0: } else { michael@0: ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize()); michael@0: if (!deserializer.IsValid()) { michael@0: NS_ERROR("Failed to deserialize image!"); michael@0: return nullptr; michael@0: } michael@0: result = deserializer.GetAsSurface(); michael@0: } michael@0: return result.forget(); michael@0: } michael@0: michael@0: ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem, michael@0: gfx::SurfaceFormat aFormat, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags) michael@0: : BufferTextureHost(aFormat, aFlags) michael@0: , mShmem(new ipc::Shmem(aShmem)) michael@0: , mDeallocator(aDeallocator) michael@0: { michael@0: MOZ_COUNT_CTOR(ShmemTextureHost); michael@0: } michael@0: michael@0: ShmemTextureHost::~ShmemTextureHost() michael@0: { michael@0: DeallocateDeviceData(); michael@0: delete mShmem; michael@0: MOZ_COUNT_DTOR(ShmemTextureHost); michael@0: } michael@0: michael@0: void michael@0: ShmemTextureHost::DeallocateSharedData() michael@0: { michael@0: if (mShmem) { michael@0: MOZ_ASSERT(mDeallocator, michael@0: "Shared memory would leak without a ISurfaceAllocator"); michael@0: mDeallocator->DeallocShmem(*mShmem); michael@0: delete mShmem; michael@0: mShmem = nullptr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShmemTextureHost::ForgetSharedData() michael@0: { michael@0: if (mShmem) { michael@0: delete mShmem; michael@0: mShmem = nullptr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShmemTextureHost::OnShutdown() michael@0: { michael@0: delete mShmem; michael@0: mShmem = nullptr; michael@0: } michael@0: michael@0: uint8_t* ShmemTextureHost::GetBuffer() michael@0: { michael@0: return mShmem ? mShmem->get() : nullptr; michael@0: } michael@0: michael@0: size_t ShmemTextureHost::GetBufferSize() michael@0: { michael@0: return mShmem ? mShmem->Size() : 0; michael@0: } michael@0: michael@0: MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer, michael@0: gfx::SurfaceFormat aFormat, michael@0: TextureFlags aFlags) michael@0: : BufferTextureHost(aFormat, aFlags) michael@0: , mBuffer(aBuffer) michael@0: { michael@0: MOZ_COUNT_CTOR(MemoryTextureHost); michael@0: } michael@0: michael@0: MemoryTextureHost::~MemoryTextureHost() michael@0: { michael@0: DeallocateDeviceData(); michael@0: NS_ASSERTION(!mBuffer || (mFlags & TEXTURE_DEALLOCATE_CLIENT), michael@0: "Leaking our buffer"); michael@0: MOZ_COUNT_DTOR(MemoryTextureHost); michael@0: } michael@0: michael@0: void michael@0: MemoryTextureHost::DeallocateSharedData() michael@0: { michael@0: if (mBuffer) { michael@0: GfxMemoryImageReporter::WillFree(mBuffer); michael@0: } michael@0: delete[] mBuffer; michael@0: mBuffer = nullptr; michael@0: } michael@0: michael@0: void michael@0: MemoryTextureHost::ForgetSharedData() michael@0: { michael@0: mBuffer = nullptr; michael@0: } michael@0: michael@0: uint8_t* MemoryTextureHost::GetBuffer() michael@0: { michael@0: return mBuffer; michael@0: } michael@0: michael@0: size_t MemoryTextureHost::GetBufferSize() michael@0: { michael@0: // MemoryTextureHost just trusts that the buffer size is large enough to read michael@0: // anything we need to. That's because MemoryTextureHost has to trust the buffer michael@0: // pointer anyway, so the security model here is just that MemoryTexture's michael@0: // are restricted to same-process clients. michael@0: return std::numeric_limits::max(); michael@0: } michael@0: michael@0: TextureParent::TextureParent(ISurfaceAllocator* aAllocator) michael@0: : mAllocator(aAllocator) michael@0: { michael@0: MOZ_COUNT_CTOR(TextureParent); michael@0: } michael@0: michael@0: TextureParent::~TextureParent() michael@0: { michael@0: MOZ_COUNT_DTOR(TextureParent); michael@0: if (mTextureHost) { michael@0: mTextureHost->ClearRecycleCallback(); michael@0: } michael@0: } michael@0: michael@0: static void RecycleCallback(TextureHost* textureHost, void* aClosure) { michael@0: TextureParent* tp = reinterpret_cast(aClosure); michael@0: tp->CompositorRecycle(); michael@0: } michael@0: michael@0: void michael@0: TextureParent::CompositorRecycle() michael@0: { michael@0: mTextureHost->ClearRecycleCallback(); michael@0: michael@0: MaybeFenceHandle handle = null_t(); michael@0: #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 michael@0: if (mTextureHost) { michael@0: TextureHostOGL* hostOGL = mTextureHost->AsHostOGL(); michael@0: android::sp fence = hostOGL->GetAndResetReleaseFence(); michael@0: if (fence.get() && fence->isValid()) { michael@0: handle = FenceHandle(fence); michael@0: // HWC might not provide Fence. michael@0: // In this case, HWC implicitly handles buffer's fence. michael@0: } michael@0: } michael@0: #endif michael@0: mozilla::unused << SendCompositorRecycle(handle); michael@0: michael@0: // Don't forget to prepare for the next reycle michael@0: // if TextureClient request it. michael@0: if (mTextureHost->GetFlags() & TEXTURE_RECYCLE) { michael@0: mWaitForClientRecycle = mTextureHost; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: TextureParent::RecvClientRecycle() michael@0: { michael@0: // This will allow the RecycleCallback to be called once the compositor michael@0: // releases any external references to TextureHost. michael@0: mTextureHost->SetRecycleCallback(RecycleCallback, this); michael@0: if (!mWaitForClientRecycle) { michael@0: RECYCLE_LOG("Not a recycable tile"); michael@0: } michael@0: mWaitForClientRecycle = nullptr; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TextureParent::Init(const SurfaceDescriptor& aSharedData, michael@0: const TextureFlags& aFlags) michael@0: { michael@0: mTextureHost = TextureHost::Create(aSharedData, michael@0: mAllocator, michael@0: aFlags); michael@0: if (mTextureHost) { michael@0: mTextureHost->mActor = this; michael@0: if (aFlags & TEXTURE_RECYCLE) { michael@0: mWaitForClientRecycle = mTextureHost; michael@0: RECYCLE_LOG("Setup recycling for tile %p\n", this); michael@0: } michael@0: } michael@0: michael@0: return !!mTextureHost; michael@0: } michael@0: michael@0: bool michael@0: TextureParent::RecvRemoveTexture() michael@0: { michael@0: return PTextureParent::Send__delete__(this); michael@0: } michael@0: michael@0: bool michael@0: TextureParent::RecvRemoveTextureSync() michael@0: { michael@0: // we don't need to send a reply in the synchronous case since the child side michael@0: // has the guarantee that this message has been handled synchronously. michael@0: return PTextureParent::Send__delete__(this); michael@0: } michael@0: michael@0: void michael@0: TextureParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (!mTextureHost) { michael@0: return; michael@0: } michael@0: michael@0: switch (why) { michael@0: case AncestorDeletion: michael@0: case Deletion: michael@0: case NormalShutdown: michael@0: case AbnormalShutdown: michael@0: break; michael@0: case FailedConstructor: michael@0: NS_RUNTIMEABORT("FailedConstructor isn't possible in PTexture"); michael@0: } michael@0: michael@0: if (mTextureHost->GetFlags() & TEXTURE_RECYCLE) { michael@0: RECYCLE_LOG("clear recycling for tile %p\n", this); michael@0: mTextureHost->ClearRecycleCallback(); michael@0: } michael@0: if (mTextureHost->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { michael@0: mTextureHost->ForgetSharedData(); michael@0: } michael@0: michael@0: // Clear recycle callback. michael@0: mTextureHost->ClearRecycleCallback(); michael@0: mWaitForClientRecycle = nullptr; michael@0: michael@0: mTextureHost->mActor = nullptr; michael@0: mTextureHost = nullptr; michael@0: } michael@0: michael@0: } // namespace michael@0: } // namespace