1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/client/TextureClient.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,825 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/layers/TextureClient.h" 1.10 +#include <stdint.h> // for uint8_t, uint32_t, etc 1.11 +#include "Layers.h" // for Layer, etc 1.12 +#include "gfx2DGlue.h" 1.13 +#include "gfxContext.h" // for gfxContext, etc 1.14 +#include "gfxPlatform.h" // for gfxPlatform 1.15 +#include "gfxPoint.h" // for gfxIntSize, gfxSize 1.16 +#include "gfxReusableSurfaceWrapper.h" // for gfxReusableSurfaceWrapper 1.17 +#include "mozilla/gfx/BaseSize.h" // for BaseSize 1.18 +#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc 1.19 +#include "mozilla/layers/CompositableClient.h" // for CompositableClient 1.20 +#include "mozilla/layers/CompositableForwarder.h" 1.21 +#include "mozilla/layers/ISurfaceAllocator.h" 1.22 +#include "mozilla/layers/ImageDataSerializer.h" 1.23 +#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder 1.24 +#include "mozilla/layers/SharedPlanarYCbCrImage.h" 1.25 +#include "mozilla/layers/YCbCrImageDataSerializer.h" 1.26 +#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc 1.27 +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc 1.28 +#include "ImageContainer.h" // for PlanarYCbCrImage, etc 1.29 +#include "mozilla/gfx/2D.h" 1.30 +#include "mozilla/layers/TextureClientOGL.h" 1.31 + 1.32 +#ifdef XP_WIN 1.33 +#include "mozilla/layers/TextureD3D9.h" 1.34 +#include "mozilla/layers/TextureD3D11.h" 1.35 +#include "gfxWindowsPlatform.h" 1.36 +#include "gfx2DGlue.h" 1.37 +#endif 1.38 +#ifdef MOZ_X11 1.39 +#include "mozilla/layers/TextureClientX11.h" 1.40 +#ifdef GL_PROVIDER_GLX 1.41 +#include "GLXLibrary.h" 1.42 +#endif 1.43 +#endif 1.44 + 1.45 +#ifdef MOZ_WIDGET_GONK 1.46 +#include <cutils/properties.h> 1.47 +#include "mozilla/layers/GrallocTextureClient.h" 1.48 +#endif 1.49 + 1.50 +#ifdef MOZ_ANDROID_OMTC 1.51 +# include "gfxReusableImageSurfaceWrapper.h" 1.52 +#else 1.53 +# include "gfxReusableSharedImageSurfaceWrapper.h" 1.54 +# include "gfxSharedImageSurface.h" 1.55 +#endif 1.56 + 1.57 +#if 0 1.58 +#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) 1.59 +#else 1.60 +#define RECYCLE_LOG(...) do { } while (0) 1.61 +#endif 1.62 + 1.63 +using namespace mozilla::gl; 1.64 +using namespace mozilla::gfx; 1.65 + 1.66 +namespace mozilla { 1.67 +namespace layers { 1.68 + 1.69 +/** 1.70 + * TextureChild is the content-side incarnation of the PTexture IPDL actor. 1.71 + * 1.72 + * TextureChild is used to synchronize a texture client and its corresponding 1.73 + * TextureHost if needed (a TextureClient that is not shared with the compositor 1.74 + * does not have a TextureChild) 1.75 + * 1.76 + * During the deallocation phase, a TextureChild may hold its recently destroyed 1.77 + * TextureClient's data until the compositor side confirmed that it is safe to 1.78 + * deallocte or recycle the it. 1.79 + */ 1.80 +class TextureChild MOZ_FINAL : public PTextureChild 1.81 +{ 1.82 +public: 1.83 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild) 1.84 + 1.85 + TextureChild() 1.86 + : mForwarder(nullptr) 1.87 + , mTextureData(nullptr) 1.88 + , mTextureClient(nullptr) 1.89 + , mIPCOpen(false) 1.90 + { 1.91 + } 1.92 + 1.93 + bool Recv__delete__() MOZ_OVERRIDE; 1.94 + 1.95 + bool RecvCompositorRecycle(const MaybeFenceHandle& aFence) 1.96 + { 1.97 + RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get()); 1.98 + if (aFence.type() != aFence.Tnull_t) { 1.99 + FenceHandle fence = aFence.get_FenceHandle(); 1.100 + if (fence.IsValid() && mTextureClient) { 1.101 + mTextureClient->SetReleaseFenceHandle(aFence); 1.102 + // HWC might not provide Fence. 1.103 + // In this case, HWC implicitly handles buffer's fence. 1.104 + } 1.105 + } 1.106 + mWaitForRecycle = nullptr; 1.107 + return true; 1.108 + } 1.109 + 1.110 + void WaitForCompositorRecycle() 1.111 + { 1.112 + mWaitForRecycle = mTextureClient; 1.113 + RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get()); 1.114 + SendClientRecycle(); 1.115 + } 1.116 + 1.117 + /** 1.118 + * Only used during the deallocation phase iff we need synchronization between 1.119 + * the client and host side for deallocation (that is, when the data is going 1.120 + * to be deallocated or recycled on the client side). 1.121 + */ 1.122 + void SetTextureData(TextureClientData* aData) 1.123 + { 1.124 + mTextureData = aData; 1.125 + } 1.126 + 1.127 + void DeleteTextureData(); 1.128 + 1.129 + CompositableForwarder* GetForwarder() { return mForwarder; } 1.130 + 1.131 + ISurfaceAllocator* GetAllocator() { return mForwarder; } 1.132 + 1.133 + void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; 1.134 + 1.135 + bool IPCOpen() const { return mIPCOpen; } 1.136 + 1.137 +private: 1.138 + 1.139 + // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor 1.140 + // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse. 1.141 + // The purpose of these methods is to be aware of when the IPC system around this 1.142 + // actor goes down: mIPCOpen is then set to false. 1.143 + void AddIPDLReference() { 1.144 + MOZ_ASSERT(mIPCOpen == false); 1.145 + mIPCOpen = true; 1.146 + AddRef(); 1.147 + } 1.148 + void ReleaseIPDLReference() { 1.149 + MOZ_ASSERT(mIPCOpen == true); 1.150 + mIPCOpen = false; 1.151 + Release(); 1.152 + } 1.153 + 1.154 + RefPtr<CompositableForwarder> mForwarder; 1.155 + RefPtr<TextureClient> mWaitForRecycle; 1.156 + TextureClientData* mTextureData; 1.157 + TextureClient* mTextureClient; 1.158 + bool mIPCOpen; 1.159 + 1.160 + friend class TextureClient; 1.161 +}; 1.162 + 1.163 +void 1.164 +TextureChild::DeleteTextureData() 1.165 +{ 1.166 + mWaitForRecycle = nullptr; 1.167 + if (mTextureData) { 1.168 + mTextureData->DeallocateSharedData(GetAllocator()); 1.169 + delete mTextureData; 1.170 + mTextureData = nullptr; 1.171 + } 1.172 +} 1.173 + 1.174 +bool 1.175 +TextureChild::Recv__delete__() 1.176 +{ 1.177 + DeleteTextureData(); 1.178 + return true; 1.179 +} 1.180 + 1.181 +void 1.182 +TextureChild::ActorDestroy(ActorDestroyReason why) 1.183 +{ 1.184 + if (mTextureClient) { 1.185 + mTextureClient->mActor = nullptr; 1.186 + } 1.187 + mWaitForRecycle = nullptr; 1.188 +} 1.189 + 1.190 +// static 1.191 +PTextureChild* 1.192 +TextureClient::CreateIPDLActor() 1.193 +{ 1.194 + TextureChild* c = new TextureChild(); 1.195 + c->AddIPDLReference(); 1.196 + return c; 1.197 +} 1.198 + 1.199 +// static 1.200 +bool 1.201 +TextureClient::DestroyIPDLActor(PTextureChild* actor) 1.202 +{ 1.203 + static_cast<TextureChild*>(actor)->ReleaseIPDLReference(); 1.204 + return true; 1.205 +} 1.206 + 1.207 +// static 1.208 +TextureClient* 1.209 +TextureClient::AsTextureClient(PTextureChild* actor) 1.210 +{ 1.211 + return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr; 1.212 +} 1.213 + 1.214 +void 1.215 +TextureClient::WaitForCompositorRecycle() 1.216 +{ 1.217 + mActor->WaitForCompositorRecycle(); 1.218 +} 1.219 + 1.220 +bool 1.221 +TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) 1.222 +{ 1.223 + MOZ_ASSERT(aForwarder); 1.224 + if (mActor && mActor->GetForwarder() == aForwarder) { 1.225 + return true; 1.226 + } 1.227 + MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels."); 1.228 + 1.229 + SurfaceDescriptor desc; 1.230 + if (!ToSurfaceDescriptor(desc)) { 1.231 + return false; 1.232 + } 1.233 + 1.234 + mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, GetFlags())); 1.235 + MOZ_ASSERT(mActor); 1.236 + mActor->mForwarder = aForwarder; 1.237 + mActor->mTextureClient = this; 1.238 + mShared = true; 1.239 + return mActor->IPCOpen(); 1.240 +} 1.241 + 1.242 +PTextureChild* 1.243 +TextureClient::GetIPDLActor() 1.244 +{ 1.245 + return mActor; 1.246 +} 1.247 + 1.248 +#ifdef MOZ_WIDGET_GONK 1.249 +static bool 1.250 +DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint) 1.251 +{ 1.252 + if (aFormat == gfx::SurfaceFormat::A8) { 1.253 + return true; 1.254 + } 1.255 + 1.256 +#if ANDROID_VERSION <= 15 1.257 + // Adreno 200 has a problem of drawing gralloc buffer width less than 64 and 1.258 + // drawing gralloc buffer with a height 9px-16px. 1.259 + // See Bug 983971. 1.260 + if (aSizeHint.width < 64 || aSizeHint.height < 32) { 1.261 + return true; 1.262 + } 1.263 +#endif 1.264 + 1.265 + return false; 1.266 +} 1.267 +#endif 1.268 + 1.269 +// static 1.270 +TemporaryRef<TextureClient> 1.271 +TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator, 1.272 + SurfaceFormat aFormat, 1.273 + TextureFlags aTextureFlags, 1.274 + gfx::BackendType aMoz2DBackend, 1.275 + const gfx::IntSize& aSizeHint) 1.276 +{ 1.277 + if (aMoz2DBackend == gfx::BackendType::NONE) { 1.278 + aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend(); 1.279 + } 1.280 + 1.281 + RefPtr<TextureClient> result; 1.282 + 1.283 +#if defined(MOZ_WIDGET_GONK) || defined(XP_WIN) 1.284 + int32_t maxTextureSize = aAllocator->GetMaxTextureSize(); 1.285 +#endif 1.286 + 1.287 +#ifdef XP_WIN 1.288 + LayersBackend parentBackend = aAllocator->GetCompositorBackendType(); 1.289 + if (parentBackend == LayersBackend::LAYERS_D3D11 && 1.290 + (aMoz2DBackend == gfx::BackendType::DIRECT2D || 1.291 + aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) && 1.292 + gfxWindowsPlatform::GetPlatform()->GetD2DDevice() && 1.293 + aSizeHint.width <= maxTextureSize && 1.294 + aSizeHint.height <= maxTextureSize && 1.295 + !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) { 1.296 + result = new TextureClientD3D11(aFormat, aTextureFlags); 1.297 + } 1.298 + if (parentBackend == LayersBackend::LAYERS_D3D9 && 1.299 + aMoz2DBackend == gfx::BackendType::CAIRO && 1.300 + aAllocator->IsSameProcess() && 1.301 + aSizeHint.width <= maxTextureSize && 1.302 + aSizeHint.height <= maxTextureSize && 1.303 + !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) { 1.304 + if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) { 1.305 + result = new DIBTextureClientD3D9(aFormat, aTextureFlags); 1.306 + } else { 1.307 + result = new CairoTextureClientD3D9(aFormat, aTextureFlags); 1.308 + } 1.309 + } 1.310 +#endif 1.311 + 1.312 +#ifdef MOZ_X11 1.313 + LayersBackend parentBackend = aAllocator->GetCompositorBackendType(); 1.314 + gfxSurfaceType type = 1.315 + gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(); 1.316 + 1.317 + if (parentBackend == LayersBackend::LAYERS_BASIC && 1.318 + aMoz2DBackend == gfx::BackendType::CAIRO && 1.319 + type == gfxSurfaceType::Xlib && 1.320 + !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) 1.321 + { 1.322 + result = new TextureClientX11(aFormat, aTextureFlags); 1.323 + } 1.324 +#ifdef GL_PROVIDER_GLX 1.325 + if (parentBackend == LayersBackend::LAYERS_OPENGL && 1.326 + type == gfxSurfaceType::Xlib && 1.327 + !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) && 1.328 + aFormat != SurfaceFormat::A8 && 1.329 + gl::sGLXLibrary.UseTextureFromPixmap()) 1.330 + { 1.331 + result = new TextureClientX11(aFormat, aTextureFlags); 1.332 + } 1.333 +#endif 1.334 +#endif 1.335 + 1.336 +#ifdef MOZ_WIDGET_GONK 1.337 + if (!DisableGralloc(aFormat, aSizeHint)) { 1.338 + // Don't allow Gralloc texture clients to exceed the maximum texture size. 1.339 + // BufferTextureClients have code to handle tiling the surface client-side. 1.340 + if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) { 1.341 + result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend, 1.342 + aTextureFlags); 1.343 + } 1.344 + } 1.345 +#endif 1.346 + 1.347 + // Can't do any better than a buffer texture client. 1.348 + if (!result) { 1.349 + result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend); 1.350 + } 1.351 + 1.352 + MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?"); 1.353 + return result; 1.354 +} 1.355 + 1.356 +// static 1.357 +TemporaryRef<BufferTextureClient> 1.358 +TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator, 1.359 + SurfaceFormat aFormat, 1.360 + TextureFlags aTextureFlags, 1.361 + gfx::BackendType aMoz2DBackend) 1.362 +{ 1.363 + if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) { 1.364 + RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat, 1.365 + aMoz2DBackend, 1.366 + aTextureFlags); 1.367 + return result.forget(); 1.368 + } 1.369 + RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat, 1.370 + aMoz2DBackend, 1.371 + aTextureFlags); 1.372 + return result.forget(); 1.373 +} 1.374 + 1.375 + 1.376 +class ShmemTextureClientData : public TextureClientData 1.377 +{ 1.378 +public: 1.379 + ShmemTextureClientData(ipc::Shmem& aShmem) 1.380 + : mShmem(aShmem) 1.381 + { 1.382 + MOZ_COUNT_CTOR(ShmemTextureClientData); 1.383 + } 1.384 + 1.385 + ~ShmemTextureClientData() 1.386 + { 1.387 + MOZ_COUNT_CTOR(ShmemTextureClientData); 1.388 + } 1.389 + 1.390 + virtual void DeallocateSharedData(ISurfaceAllocator* allocator) 1.391 + { 1.392 + allocator->DeallocShmem(mShmem); 1.393 + mShmem = ipc::Shmem(); 1.394 + } 1.395 + 1.396 +private: 1.397 + ipc::Shmem mShmem; 1.398 +}; 1.399 + 1.400 +class MemoryTextureClientData : public TextureClientData 1.401 +{ 1.402 +public: 1.403 + MemoryTextureClientData(uint8_t* aBuffer) 1.404 + : mBuffer(aBuffer) 1.405 + { 1.406 + MOZ_COUNT_CTOR(MemoryTextureClientData); 1.407 + } 1.408 + 1.409 + ~MemoryTextureClientData() 1.410 + { 1.411 + MOZ_ASSERT(!mBuffer, "Forgot to deallocate the shared texture data?"); 1.412 + MOZ_COUNT_DTOR(MemoryTextureClientData); 1.413 + } 1.414 + 1.415 + virtual void DeallocateSharedData(ISurfaceAllocator*) 1.416 + { 1.417 + delete[] mBuffer; 1.418 + mBuffer = nullptr; 1.419 + } 1.420 + 1.421 +private: 1.422 + uint8_t* mBuffer; 1.423 +}; 1.424 + 1.425 +TextureClientData* 1.426 +MemoryTextureClient::DropTextureData() 1.427 +{ 1.428 + if (!mBuffer) { 1.429 + return nullptr; 1.430 + } 1.431 + TextureClientData* result = new MemoryTextureClientData(mBuffer); 1.432 + MarkInvalid(); 1.433 + mBuffer = nullptr; 1.434 + return result; 1.435 +} 1.436 + 1.437 +TextureClientData* 1.438 +ShmemTextureClient::DropTextureData() 1.439 +{ 1.440 + if (!mShmem.IsReadable()) { 1.441 + return nullptr; 1.442 + } 1.443 + TextureClientData* result = new ShmemTextureClientData(mShmem); 1.444 + MarkInvalid(); 1.445 + mShmem = ipc::Shmem(); 1.446 + return result; 1.447 +} 1.448 + 1.449 +TextureClient::TextureClient(TextureFlags aFlags) 1.450 + : mFlags(aFlags) 1.451 + , mShared(false) 1.452 + , mValid(true) 1.453 +{} 1.454 + 1.455 +TextureClient::~TextureClient() 1.456 +{ 1.457 + // All the destruction code that may lead to virtual method calls must 1.458 + // be in Finalize() which is called just before the destructor. 1.459 +} 1.460 + 1.461 +void TextureClient::ForceRemove() 1.462 +{ 1.463 + if (mValid && mActor) { 1.464 + if (GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { 1.465 + mActor->SetTextureData(DropTextureData()); 1.466 + if (mActor->IPCOpen()) { 1.467 + mActor->SendRemoveTextureSync(); 1.468 + } 1.469 + mActor->DeleteTextureData(); 1.470 + } else { 1.471 + if (mActor->IPCOpen()) { 1.472 + mActor->SendRemoveTexture(); 1.473 + } 1.474 + } 1.475 + } 1.476 + MarkInvalid(); 1.477 +} 1.478 + 1.479 +bool TextureClient::CopyToTextureClient(TextureClient* aTarget, 1.480 + const gfx::IntRect* aRect, 1.481 + const gfx::IntPoint* aPoint) 1.482 +{ 1.483 + MOZ_ASSERT(IsLocked()); 1.484 + MOZ_ASSERT(aTarget->IsLocked()); 1.485 + 1.486 + if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) { 1.487 + return false; 1.488 + } 1.489 + 1.490 + RefPtr<DrawTarget> destinationTarget = aTarget->GetAsDrawTarget(); 1.491 + RefPtr<DrawTarget> sourceTarget = GetAsDrawTarget(); 1.492 + RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot(); 1.493 + destinationTarget->CopySurface(source, 1.494 + aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()), 1.495 + aPoint ? *aPoint : gfx::IntPoint(0, 0)); 1.496 + destinationTarget = nullptr; 1.497 + source = nullptr; 1.498 + sourceTarget = nullptr; 1.499 + 1.500 + return true; 1.501 +} 1.502 + 1.503 +void 1.504 +TextureClient::Finalize() 1.505 +{ 1.506 + MOZ_ASSERT(!IsLocked()); 1.507 + // Always make a temporary strong reference to the actor before we use it, 1.508 + // in case TextureChild::ActorDestroy might null mActor concurrently. 1.509 + RefPtr<TextureChild> actor = mActor; 1.510 + 1.511 + if (actor) { 1.512 + // The actor has a raw pointer to us, actor->mTextureClient. 1.513 + // Null it before RemoveTexture calls to avoid invalid actor->mTextureClient 1.514 + // when calling TextureChild::ActorDestroy() 1.515 + actor->mTextureClient = nullptr; 1.516 + // this will call ForceRemove in the right thread, using a sync proxy if needed 1.517 + if (actor->GetForwarder()) { 1.518 + actor->GetForwarder()->RemoveTexture(this); 1.519 + } 1.520 + } 1.521 +} 1.522 + 1.523 +bool 1.524 +TextureClient::ShouldDeallocateInDestructor() const 1.525 +{ 1.526 + if (!IsAllocated()) { 1.527 + return false; 1.528 + } 1.529 + 1.530 + // If we're meant to be deallocated by the host, 1.531 + // but we haven't been shared yet, then we should 1.532 + // deallocate on the client instead. 1.533 + return !IsSharedWithCompositor(); 1.534 +} 1.535 + 1.536 +bool 1.537 +ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) 1.538 +{ 1.539 + MOZ_ASSERT(IsValid()); 1.540 + if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) { 1.541 + return false; 1.542 + } 1.543 + 1.544 + aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat()); 1.545 + 1.546 + return true; 1.547 +} 1.548 + 1.549 +bool 1.550 +ShmemTextureClient::Allocate(uint32_t aSize) 1.551 +{ 1.552 + MOZ_ASSERT(mValid); 1.553 + ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType(); 1.554 + mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem); 1.555 + return mAllocated; 1.556 +} 1.557 + 1.558 +uint8_t* 1.559 +ShmemTextureClient::GetBuffer() const 1.560 +{ 1.561 + MOZ_ASSERT(IsValid()); 1.562 + if (mAllocated) { 1.563 + return mShmem.get<uint8_t>(); 1.564 + } 1.565 + return nullptr; 1.566 +} 1.567 + 1.568 +size_t 1.569 +ShmemTextureClient::GetBufferSize() const 1.570 +{ 1.571 + MOZ_ASSERT(IsValid()); 1.572 + return mShmem.Size<uint8_t>(); 1.573 +} 1.574 + 1.575 +ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator, 1.576 + gfx::SurfaceFormat aFormat, 1.577 + gfx::BackendType aMoz2DBackend, 1.578 + TextureFlags aFlags) 1.579 + : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags) 1.580 + , mAllocated(false) 1.581 +{ 1.582 + MOZ_COUNT_CTOR(ShmemTextureClient); 1.583 +} 1.584 + 1.585 +ShmemTextureClient::~ShmemTextureClient() 1.586 +{ 1.587 + MOZ_COUNT_DTOR(ShmemTextureClient); 1.588 + if (ShouldDeallocateInDestructor()) { 1.589 + // if the buffer has never been shared we must deallocate it or ir would 1.590 + // leak. 1.591 + GetAllocator()->DeallocShmem(mShmem); 1.592 + } 1.593 +} 1.594 + 1.595 +bool 1.596 +MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) 1.597 +{ 1.598 + MOZ_ASSERT(IsValid()); 1.599 + if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) { 1.600 + return false; 1.601 + } 1.602 + aDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer), 1.603 + GetFormat()); 1.604 + return true; 1.605 +} 1.606 + 1.607 +bool 1.608 +MemoryTextureClient::Allocate(uint32_t aSize) 1.609 +{ 1.610 + MOZ_ASSERT(!mBuffer); 1.611 + static const fallible_t fallible = fallible_t(); 1.612 + mBuffer = new(fallible) uint8_t[aSize]; 1.613 + if (!mBuffer) { 1.614 + NS_WARNING("Failed to allocate buffer"); 1.615 + return false; 1.616 + } 1.617 + GfxMemoryImageReporter::DidAlloc(mBuffer); 1.618 + mBufSize = aSize; 1.619 + return true; 1.620 +} 1.621 + 1.622 +MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator, 1.623 + gfx::SurfaceFormat aFormat, 1.624 + gfx::BackendType aMoz2DBackend, 1.625 + TextureFlags aFlags) 1.626 + : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags) 1.627 + , mBuffer(nullptr) 1.628 + , mBufSize(0) 1.629 +{ 1.630 + MOZ_COUNT_CTOR(MemoryTextureClient); 1.631 +} 1.632 + 1.633 +MemoryTextureClient::~MemoryTextureClient() 1.634 +{ 1.635 + MOZ_COUNT_DTOR(MemoryTextureClient); 1.636 + if (mBuffer && ShouldDeallocateInDestructor()) { 1.637 + // if the buffer has never been shared we must deallocate it or it would 1.638 + // leak. 1.639 + GfxMemoryImageReporter::WillFree(mBuffer); 1.640 + delete [] mBuffer; 1.641 + } 1.642 +} 1.643 + 1.644 +BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator, 1.645 + gfx::SurfaceFormat aFormat, 1.646 + gfx::BackendType aMoz2DBackend, 1.647 + TextureFlags aFlags) 1.648 + : TextureClient(aFlags) 1.649 + , mAllocator(aAllocator) 1.650 + , mFormat(aFormat) 1.651 + , mBackend(aMoz2DBackend) 1.652 + , mOpenMode(0) 1.653 + , mUsingFallbackDrawTarget(false) 1.654 + , mLocked(false) 1.655 +{} 1.656 + 1.657 +BufferTextureClient::~BufferTextureClient() 1.658 +{} 1.659 + 1.660 +ISurfaceAllocator* 1.661 +BufferTextureClient::GetAllocator() const 1.662 +{ 1.663 + return mAllocator; 1.664 +} 1.665 + 1.666 +bool 1.667 +BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) 1.668 +{ 1.669 + MOZ_ASSERT(IsValid()); 1.670 + MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data"); 1.671 + MOZ_ASSERT(aSize.width * aSize.height); 1.672 + 1.673 + int bufSize 1.674 + = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat); 1.675 + if (!Allocate(bufSize)) { 1.676 + return false; 1.677 + } 1.678 + 1.679 + if (aFlags & ALLOC_CLEAR_BUFFER) { 1.680 + memset(GetBuffer(), 0, bufSize); 1.681 + } 1.682 + 1.683 + ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); 1.684 + serializer.InitializeBufferInfo(aSize, mFormat); 1.685 + mSize = aSize; 1.686 + return true; 1.687 +} 1.688 + 1.689 +TemporaryRef<gfx::DrawTarget> 1.690 +BufferTextureClient::GetAsDrawTarget() 1.691 +{ 1.692 + MOZ_ASSERT(IsValid()); 1.693 + MOZ_ASSERT(mLocked, "GetAsDrawTarget should be called on locked textures only"); 1.694 + 1.695 + if (mDrawTarget) { 1.696 + return mDrawTarget; 1.697 + } 1.698 + 1.699 + ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); 1.700 + if (!serializer.IsValid()) { 1.701 + return nullptr; 1.702 + } 1.703 + 1.704 + MOZ_ASSERT(mUsingFallbackDrawTarget == false); 1.705 + mDrawTarget = serializer.GetAsDrawTarget(mBackend); 1.706 + if (mDrawTarget) { 1.707 + return mDrawTarget; 1.708 + } 1.709 + 1.710 + // fallback path, probably because the Moz2D backend can't create a 1.711 + // DrawTarget around raw memory. This is going to be slow :( 1.712 + mDrawTarget = gfx::Factory::CreateDrawTarget(mBackend, serializer.GetSize(), 1.713 + serializer.GetFormat()); 1.714 + if (!mDrawTarget) { 1.715 + return nullptr; 1.716 + } 1.717 + 1.718 + mUsingFallbackDrawTarget = true; 1.719 + if (mOpenMode & OPEN_READ) { 1.720 + RefPtr<DataSourceSurface> surface = serializer.GetAsSurface(); 1.721 + IntRect rect(0, 0, surface->GetSize().width, surface->GetSize().height); 1.722 + mDrawTarget->CopySurface(surface, rect, IntPoint(0,0)); 1.723 + } 1.724 + return mDrawTarget; 1.725 +} 1.726 + 1.727 +bool 1.728 +BufferTextureClient::Lock(OpenMode aMode) 1.729 +{ 1.730 + MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!"); 1.731 + mOpenMode = aMode; 1.732 + mLocked = IsValid() && IsAllocated();; 1.733 + return mLocked; 1.734 +} 1.735 + 1.736 +void 1.737 +BufferTextureClient::Unlock() 1.738 +{ 1.739 + MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!"); 1.740 + mLocked = false; 1.741 + if (!mDrawTarget) { 1.742 + mUsingFallbackDrawTarget = false; 1.743 + return; 1.744 + } 1.745 + 1.746 + // see the comment on TextureClient::GetAsDrawTarget. 1.747 + // This DrawTarget is internal to the TextureClient and is only exposed to the 1.748 + // outside world between Lock() and Unlock(). This assertion checks that no outside 1.749 + // reference remains by the time Unlock() is called. 1.750 + MOZ_ASSERT(mDrawTarget->refCount() == 1); 1.751 + 1.752 + mDrawTarget->Flush(); 1.753 + if (mUsingFallbackDrawTarget && (mOpenMode & OPEN_WRITE)) { 1.754 + // When we are using a fallback DrawTarget, it means we could not create 1.755 + // a DrawTarget wrapping the TextureClient's shared memory. In this scenario 1.756 + // we need to put the content of the fallback draw target back into our shared 1.757 + // memory. 1.758 + RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot(); 1.759 + RefPtr<DataSourceSurface> surface = snapshot->GetDataSurface(); 1.760 + ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); 1.761 + if (!serializer.IsValid() || serializer.GetSize() != surface->GetSize()) { 1.762 + NS_WARNING("Could not write the data back into the texture."); 1.763 + mDrawTarget = nullptr; 1.764 + mUsingFallbackDrawTarget = false; 1.765 + return; 1.766 + } 1.767 + MOZ_ASSERT(surface->GetSize() == serializer.GetSize()); 1.768 + MOZ_ASSERT(surface->GetFormat() == serializer.GetFormat()); 1.769 + int bpp = BytesPerPixel(surface->GetFormat()); 1.770 + for (int i = 0; i < surface->GetSize().height; ++i) { 1.771 + memcpy(serializer.GetData() + i*serializer.GetStride(), 1.772 + surface->GetData() + i*surface->Stride(), 1.773 + surface->GetSize().width * bpp); 1.774 + } 1.775 + } 1.776 + mDrawTarget = nullptr; 1.777 + mUsingFallbackDrawTarget = false; 1.778 +} 1.779 + 1.780 +bool 1.781 +BufferTextureClient::UpdateYCbCr(const PlanarYCbCrData& aData) 1.782 +{ 1.783 + MOZ_ASSERT(mLocked); 1.784 + MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data"); 1.785 + MOZ_ASSERT(!IsImmutable()); 1.786 + MOZ_ASSERT(IsValid()); 1.787 + MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip); 1.788 + 1.789 + YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize()); 1.790 + MOZ_ASSERT(serializer.IsValid()); 1.791 + if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel, 1.792 + aData.mYSize, aData.mYStride, 1.793 + aData.mCbCrSize, aData.mCbCrStride, 1.794 + aData.mYSkip, aData.mCbSkip)) { 1.795 + NS_WARNING("Failed to copy image data!"); 1.796 + return false; 1.797 + } 1.798 + 1.799 + if (TextureRequiresLocking(mFlags)) { 1.800 + // We don't have support for proper locking yet, so we'll 1.801 + // have to be immutable instead. 1.802 + MarkImmutable(); 1.803 + } 1.804 + return true; 1.805 +} 1.806 + 1.807 +bool 1.808 +BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, 1.809 + gfx::IntSize aCbCrSize, 1.810 + StereoMode aStereoMode) 1.811 +{ 1.812 + MOZ_ASSERT(IsValid()); 1.813 + 1.814 + size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, 1.815 + aCbCrSize); 1.816 + if (!Allocate(bufSize)) { 1.817 + return false; 1.818 + } 1.819 + YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize()); 1.820 + serializer.InitializeBufferInfo(aYSize, 1.821 + aCbCrSize, 1.822 + aStereoMode); 1.823 + mSize = aYSize; 1.824 + return true; 1.825 +} 1.826 + 1.827 +} 1.828 +}