gfx/layers/client/TextureClient.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/layers/TextureClient.h"
michael@0 7 #include <stdint.h> // for uint8_t, uint32_t, etc
michael@0 8 #include "Layers.h" // for Layer, etc
michael@0 9 #include "gfx2DGlue.h"
michael@0 10 #include "gfxContext.h" // for gfxContext, etc
michael@0 11 #include "gfxPlatform.h" // for gfxPlatform
michael@0 12 #include "gfxPoint.h" // for gfxIntSize, gfxSize
michael@0 13 #include "gfxReusableSurfaceWrapper.h" // for gfxReusableSurfaceWrapper
michael@0 14 #include "mozilla/gfx/BaseSize.h" // for BaseSize
michael@0 15 #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
michael@0 16 #include "mozilla/layers/CompositableClient.h" // for CompositableClient
michael@0 17 #include "mozilla/layers/CompositableForwarder.h"
michael@0 18 #include "mozilla/layers/ISurfaceAllocator.h"
michael@0 19 #include "mozilla/layers/ImageDataSerializer.h"
michael@0 20 #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
michael@0 21 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
michael@0 22 #include "mozilla/layers/YCbCrImageDataSerializer.h"
michael@0 23 #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
michael@0 24 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
michael@0 25 #include "ImageContainer.h" // for PlanarYCbCrImage, etc
michael@0 26 #include "mozilla/gfx/2D.h"
michael@0 27 #include "mozilla/layers/TextureClientOGL.h"
michael@0 28
michael@0 29 #ifdef XP_WIN
michael@0 30 #include "mozilla/layers/TextureD3D9.h"
michael@0 31 #include "mozilla/layers/TextureD3D11.h"
michael@0 32 #include "gfxWindowsPlatform.h"
michael@0 33 #include "gfx2DGlue.h"
michael@0 34 #endif
michael@0 35 #ifdef MOZ_X11
michael@0 36 #include "mozilla/layers/TextureClientX11.h"
michael@0 37 #ifdef GL_PROVIDER_GLX
michael@0 38 #include "GLXLibrary.h"
michael@0 39 #endif
michael@0 40 #endif
michael@0 41
michael@0 42 #ifdef MOZ_WIDGET_GONK
michael@0 43 #include <cutils/properties.h>
michael@0 44 #include "mozilla/layers/GrallocTextureClient.h"
michael@0 45 #endif
michael@0 46
michael@0 47 #ifdef MOZ_ANDROID_OMTC
michael@0 48 # include "gfxReusableImageSurfaceWrapper.h"
michael@0 49 #else
michael@0 50 # include "gfxReusableSharedImageSurfaceWrapper.h"
michael@0 51 # include "gfxSharedImageSurface.h"
michael@0 52 #endif
michael@0 53
michael@0 54 #if 0
michael@0 55 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
michael@0 56 #else
michael@0 57 #define RECYCLE_LOG(...) do { } while (0)
michael@0 58 #endif
michael@0 59
michael@0 60 using namespace mozilla::gl;
michael@0 61 using namespace mozilla::gfx;
michael@0 62
michael@0 63 namespace mozilla {
michael@0 64 namespace layers {
michael@0 65
michael@0 66 /**
michael@0 67 * TextureChild is the content-side incarnation of the PTexture IPDL actor.
michael@0 68 *
michael@0 69 * TextureChild is used to synchronize a texture client and its corresponding
michael@0 70 * TextureHost if needed (a TextureClient that is not shared with the compositor
michael@0 71 * does not have a TextureChild)
michael@0 72 *
michael@0 73 * During the deallocation phase, a TextureChild may hold its recently destroyed
michael@0 74 * TextureClient's data until the compositor side confirmed that it is safe to
michael@0 75 * deallocte or recycle the it.
michael@0 76 */
michael@0 77 class TextureChild MOZ_FINAL : public PTextureChild
michael@0 78 {
michael@0 79 public:
michael@0 80 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
michael@0 81
michael@0 82 TextureChild()
michael@0 83 : mForwarder(nullptr)
michael@0 84 , mTextureData(nullptr)
michael@0 85 , mTextureClient(nullptr)
michael@0 86 , mIPCOpen(false)
michael@0 87 {
michael@0 88 }
michael@0 89
michael@0 90 bool Recv__delete__() MOZ_OVERRIDE;
michael@0 91
michael@0 92 bool RecvCompositorRecycle(const MaybeFenceHandle& aFence)
michael@0 93 {
michael@0 94 RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
michael@0 95 if (aFence.type() != aFence.Tnull_t) {
michael@0 96 FenceHandle fence = aFence.get_FenceHandle();
michael@0 97 if (fence.IsValid() && mTextureClient) {
michael@0 98 mTextureClient->SetReleaseFenceHandle(aFence);
michael@0 99 // HWC might not provide Fence.
michael@0 100 // In this case, HWC implicitly handles buffer's fence.
michael@0 101 }
michael@0 102 }
michael@0 103 mWaitForRecycle = nullptr;
michael@0 104 return true;
michael@0 105 }
michael@0 106
michael@0 107 void WaitForCompositorRecycle()
michael@0 108 {
michael@0 109 mWaitForRecycle = mTextureClient;
michael@0 110 RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
michael@0 111 SendClientRecycle();
michael@0 112 }
michael@0 113
michael@0 114 /**
michael@0 115 * Only used during the deallocation phase iff we need synchronization between
michael@0 116 * the client and host side for deallocation (that is, when the data is going
michael@0 117 * to be deallocated or recycled on the client side).
michael@0 118 */
michael@0 119 void SetTextureData(TextureClientData* aData)
michael@0 120 {
michael@0 121 mTextureData = aData;
michael@0 122 }
michael@0 123
michael@0 124 void DeleteTextureData();
michael@0 125
michael@0 126 CompositableForwarder* GetForwarder() { return mForwarder; }
michael@0 127
michael@0 128 ISurfaceAllocator* GetAllocator() { return mForwarder; }
michael@0 129
michael@0 130 void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
michael@0 131
michael@0 132 bool IPCOpen() const { return mIPCOpen; }
michael@0 133
michael@0 134 private:
michael@0 135
michael@0 136 // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
michael@0 137 // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
michael@0 138 // The purpose of these methods is to be aware of when the IPC system around this
michael@0 139 // actor goes down: mIPCOpen is then set to false.
michael@0 140 void AddIPDLReference() {
michael@0 141 MOZ_ASSERT(mIPCOpen == false);
michael@0 142 mIPCOpen = true;
michael@0 143 AddRef();
michael@0 144 }
michael@0 145 void ReleaseIPDLReference() {
michael@0 146 MOZ_ASSERT(mIPCOpen == true);
michael@0 147 mIPCOpen = false;
michael@0 148 Release();
michael@0 149 }
michael@0 150
michael@0 151 RefPtr<CompositableForwarder> mForwarder;
michael@0 152 RefPtr<TextureClient> mWaitForRecycle;
michael@0 153 TextureClientData* mTextureData;
michael@0 154 TextureClient* mTextureClient;
michael@0 155 bool mIPCOpen;
michael@0 156
michael@0 157 friend class TextureClient;
michael@0 158 };
michael@0 159
michael@0 160 void
michael@0 161 TextureChild::DeleteTextureData()
michael@0 162 {
michael@0 163 mWaitForRecycle = nullptr;
michael@0 164 if (mTextureData) {
michael@0 165 mTextureData->DeallocateSharedData(GetAllocator());
michael@0 166 delete mTextureData;
michael@0 167 mTextureData = nullptr;
michael@0 168 }
michael@0 169 }
michael@0 170
michael@0 171 bool
michael@0 172 TextureChild::Recv__delete__()
michael@0 173 {
michael@0 174 DeleteTextureData();
michael@0 175 return true;
michael@0 176 }
michael@0 177
michael@0 178 void
michael@0 179 TextureChild::ActorDestroy(ActorDestroyReason why)
michael@0 180 {
michael@0 181 if (mTextureClient) {
michael@0 182 mTextureClient->mActor = nullptr;
michael@0 183 }
michael@0 184 mWaitForRecycle = nullptr;
michael@0 185 }
michael@0 186
michael@0 187 // static
michael@0 188 PTextureChild*
michael@0 189 TextureClient::CreateIPDLActor()
michael@0 190 {
michael@0 191 TextureChild* c = new TextureChild();
michael@0 192 c->AddIPDLReference();
michael@0 193 return c;
michael@0 194 }
michael@0 195
michael@0 196 // static
michael@0 197 bool
michael@0 198 TextureClient::DestroyIPDLActor(PTextureChild* actor)
michael@0 199 {
michael@0 200 static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
michael@0 201 return true;
michael@0 202 }
michael@0 203
michael@0 204 // static
michael@0 205 TextureClient*
michael@0 206 TextureClient::AsTextureClient(PTextureChild* actor)
michael@0 207 {
michael@0 208 return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr;
michael@0 209 }
michael@0 210
michael@0 211 void
michael@0 212 TextureClient::WaitForCompositorRecycle()
michael@0 213 {
michael@0 214 mActor->WaitForCompositorRecycle();
michael@0 215 }
michael@0 216
michael@0 217 bool
michael@0 218 TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
michael@0 219 {
michael@0 220 MOZ_ASSERT(aForwarder);
michael@0 221 if (mActor && mActor->GetForwarder() == aForwarder) {
michael@0 222 return true;
michael@0 223 }
michael@0 224 MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels.");
michael@0 225
michael@0 226 SurfaceDescriptor desc;
michael@0 227 if (!ToSurfaceDescriptor(desc)) {
michael@0 228 return false;
michael@0 229 }
michael@0 230
michael@0 231 mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, GetFlags()));
michael@0 232 MOZ_ASSERT(mActor);
michael@0 233 mActor->mForwarder = aForwarder;
michael@0 234 mActor->mTextureClient = this;
michael@0 235 mShared = true;
michael@0 236 return mActor->IPCOpen();
michael@0 237 }
michael@0 238
michael@0 239 PTextureChild*
michael@0 240 TextureClient::GetIPDLActor()
michael@0 241 {
michael@0 242 return mActor;
michael@0 243 }
michael@0 244
michael@0 245 #ifdef MOZ_WIDGET_GONK
michael@0 246 static bool
michael@0 247 DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
michael@0 248 {
michael@0 249 if (aFormat == gfx::SurfaceFormat::A8) {
michael@0 250 return true;
michael@0 251 }
michael@0 252
michael@0 253 #if ANDROID_VERSION <= 15
michael@0 254 // Adreno 200 has a problem of drawing gralloc buffer width less than 64 and
michael@0 255 // drawing gralloc buffer with a height 9px-16px.
michael@0 256 // See Bug 983971.
michael@0 257 if (aSizeHint.width < 64 || aSizeHint.height < 32) {
michael@0 258 return true;
michael@0 259 }
michael@0 260 #endif
michael@0 261
michael@0 262 return false;
michael@0 263 }
michael@0 264 #endif
michael@0 265
michael@0 266 // static
michael@0 267 TemporaryRef<TextureClient>
michael@0 268 TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
michael@0 269 SurfaceFormat aFormat,
michael@0 270 TextureFlags aTextureFlags,
michael@0 271 gfx::BackendType aMoz2DBackend,
michael@0 272 const gfx::IntSize& aSizeHint)
michael@0 273 {
michael@0 274 if (aMoz2DBackend == gfx::BackendType::NONE) {
michael@0 275 aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
michael@0 276 }
michael@0 277
michael@0 278 RefPtr<TextureClient> result;
michael@0 279
michael@0 280 #if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
michael@0 281 int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
michael@0 282 #endif
michael@0 283
michael@0 284 #ifdef XP_WIN
michael@0 285 LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
michael@0 286 if (parentBackend == LayersBackend::LAYERS_D3D11 &&
michael@0 287 (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
michael@0 288 aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
michael@0 289 gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
michael@0 290 aSizeHint.width <= maxTextureSize &&
michael@0 291 aSizeHint.height <= maxTextureSize &&
michael@0 292 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
michael@0 293 result = new TextureClientD3D11(aFormat, aTextureFlags);
michael@0 294 }
michael@0 295 if (parentBackend == LayersBackend::LAYERS_D3D9 &&
michael@0 296 aMoz2DBackend == gfx::BackendType::CAIRO &&
michael@0 297 aAllocator->IsSameProcess() &&
michael@0 298 aSizeHint.width <= maxTextureSize &&
michael@0 299 aSizeHint.height <= maxTextureSize &&
michael@0 300 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
michael@0 301 if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
michael@0 302 result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
michael@0 303 } else {
michael@0 304 result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
michael@0 305 }
michael@0 306 }
michael@0 307 #endif
michael@0 308
michael@0 309 #ifdef MOZ_X11
michael@0 310 LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
michael@0 311 gfxSurfaceType type =
michael@0 312 gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
michael@0 313
michael@0 314 if (parentBackend == LayersBackend::LAYERS_BASIC &&
michael@0 315 aMoz2DBackend == gfx::BackendType::CAIRO &&
michael@0 316 type == gfxSurfaceType::Xlib &&
michael@0 317 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
michael@0 318 {
michael@0 319 result = new TextureClientX11(aFormat, aTextureFlags);
michael@0 320 }
michael@0 321 #ifdef GL_PROVIDER_GLX
michael@0 322 if (parentBackend == LayersBackend::LAYERS_OPENGL &&
michael@0 323 type == gfxSurfaceType::Xlib &&
michael@0 324 !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
michael@0 325 aFormat != SurfaceFormat::A8 &&
michael@0 326 gl::sGLXLibrary.UseTextureFromPixmap())
michael@0 327 {
michael@0 328 result = new TextureClientX11(aFormat, aTextureFlags);
michael@0 329 }
michael@0 330 #endif
michael@0 331 #endif
michael@0 332
michael@0 333 #ifdef MOZ_WIDGET_GONK
michael@0 334 if (!DisableGralloc(aFormat, aSizeHint)) {
michael@0 335 // Don't allow Gralloc texture clients to exceed the maximum texture size.
michael@0 336 // BufferTextureClients have code to handle tiling the surface client-side.
michael@0 337 if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
michael@0 338 result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
michael@0 339 aTextureFlags);
michael@0 340 }
michael@0 341 }
michael@0 342 #endif
michael@0 343
michael@0 344 // Can't do any better than a buffer texture client.
michael@0 345 if (!result) {
michael@0 346 result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
michael@0 347 }
michael@0 348
michael@0 349 MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?");
michael@0 350 return result;
michael@0 351 }
michael@0 352
michael@0 353 // static
michael@0 354 TemporaryRef<BufferTextureClient>
michael@0 355 TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
michael@0 356 SurfaceFormat aFormat,
michael@0 357 TextureFlags aTextureFlags,
michael@0 358 gfx::BackendType aMoz2DBackend)
michael@0 359 {
michael@0 360 if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
michael@0 361 RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
michael@0 362 aMoz2DBackend,
michael@0 363 aTextureFlags);
michael@0 364 return result.forget();
michael@0 365 }
michael@0 366 RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat,
michael@0 367 aMoz2DBackend,
michael@0 368 aTextureFlags);
michael@0 369 return result.forget();
michael@0 370 }
michael@0 371
michael@0 372
michael@0 373 class ShmemTextureClientData : public TextureClientData
michael@0 374 {
michael@0 375 public:
michael@0 376 ShmemTextureClientData(ipc::Shmem& aShmem)
michael@0 377 : mShmem(aShmem)
michael@0 378 {
michael@0 379 MOZ_COUNT_CTOR(ShmemTextureClientData);
michael@0 380 }
michael@0 381
michael@0 382 ~ShmemTextureClientData()
michael@0 383 {
michael@0 384 MOZ_COUNT_CTOR(ShmemTextureClientData);
michael@0 385 }
michael@0 386
michael@0 387 virtual void DeallocateSharedData(ISurfaceAllocator* allocator)
michael@0 388 {
michael@0 389 allocator->DeallocShmem(mShmem);
michael@0 390 mShmem = ipc::Shmem();
michael@0 391 }
michael@0 392
michael@0 393 private:
michael@0 394 ipc::Shmem mShmem;
michael@0 395 };
michael@0 396
michael@0 397 class MemoryTextureClientData : public TextureClientData
michael@0 398 {
michael@0 399 public:
michael@0 400 MemoryTextureClientData(uint8_t* aBuffer)
michael@0 401 : mBuffer(aBuffer)
michael@0 402 {
michael@0 403 MOZ_COUNT_CTOR(MemoryTextureClientData);
michael@0 404 }
michael@0 405
michael@0 406 ~MemoryTextureClientData()
michael@0 407 {
michael@0 408 MOZ_ASSERT(!mBuffer, "Forgot to deallocate the shared texture data?");
michael@0 409 MOZ_COUNT_DTOR(MemoryTextureClientData);
michael@0 410 }
michael@0 411
michael@0 412 virtual void DeallocateSharedData(ISurfaceAllocator*)
michael@0 413 {
michael@0 414 delete[] mBuffer;
michael@0 415 mBuffer = nullptr;
michael@0 416 }
michael@0 417
michael@0 418 private:
michael@0 419 uint8_t* mBuffer;
michael@0 420 };
michael@0 421
michael@0 422 TextureClientData*
michael@0 423 MemoryTextureClient::DropTextureData()
michael@0 424 {
michael@0 425 if (!mBuffer) {
michael@0 426 return nullptr;
michael@0 427 }
michael@0 428 TextureClientData* result = new MemoryTextureClientData(mBuffer);
michael@0 429 MarkInvalid();
michael@0 430 mBuffer = nullptr;
michael@0 431 return result;
michael@0 432 }
michael@0 433
michael@0 434 TextureClientData*
michael@0 435 ShmemTextureClient::DropTextureData()
michael@0 436 {
michael@0 437 if (!mShmem.IsReadable()) {
michael@0 438 return nullptr;
michael@0 439 }
michael@0 440 TextureClientData* result = new ShmemTextureClientData(mShmem);
michael@0 441 MarkInvalid();
michael@0 442 mShmem = ipc::Shmem();
michael@0 443 return result;
michael@0 444 }
michael@0 445
michael@0 446 TextureClient::TextureClient(TextureFlags aFlags)
michael@0 447 : mFlags(aFlags)
michael@0 448 , mShared(false)
michael@0 449 , mValid(true)
michael@0 450 {}
michael@0 451
michael@0 452 TextureClient::~TextureClient()
michael@0 453 {
michael@0 454 // All the destruction code that may lead to virtual method calls must
michael@0 455 // be in Finalize() which is called just before the destructor.
michael@0 456 }
michael@0 457
michael@0 458 void TextureClient::ForceRemove()
michael@0 459 {
michael@0 460 if (mValid && mActor) {
michael@0 461 if (GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
michael@0 462 mActor->SetTextureData(DropTextureData());
michael@0 463 if (mActor->IPCOpen()) {
michael@0 464 mActor->SendRemoveTextureSync();
michael@0 465 }
michael@0 466 mActor->DeleteTextureData();
michael@0 467 } else {
michael@0 468 if (mActor->IPCOpen()) {
michael@0 469 mActor->SendRemoveTexture();
michael@0 470 }
michael@0 471 }
michael@0 472 }
michael@0 473 MarkInvalid();
michael@0 474 }
michael@0 475
michael@0 476 bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
michael@0 477 const gfx::IntRect* aRect,
michael@0 478 const gfx::IntPoint* aPoint)
michael@0 479 {
michael@0 480 MOZ_ASSERT(IsLocked());
michael@0 481 MOZ_ASSERT(aTarget->IsLocked());
michael@0 482
michael@0 483 if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) {
michael@0 484 return false;
michael@0 485 }
michael@0 486
michael@0 487 RefPtr<DrawTarget> destinationTarget = aTarget->GetAsDrawTarget();
michael@0 488 RefPtr<DrawTarget> sourceTarget = GetAsDrawTarget();
michael@0 489 RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
michael@0 490 destinationTarget->CopySurface(source,
michael@0 491 aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
michael@0 492 aPoint ? *aPoint : gfx::IntPoint(0, 0));
michael@0 493 destinationTarget = nullptr;
michael@0 494 source = nullptr;
michael@0 495 sourceTarget = nullptr;
michael@0 496
michael@0 497 return true;
michael@0 498 }
michael@0 499
michael@0 500 void
michael@0 501 TextureClient::Finalize()
michael@0 502 {
michael@0 503 MOZ_ASSERT(!IsLocked());
michael@0 504 // Always make a temporary strong reference to the actor before we use it,
michael@0 505 // in case TextureChild::ActorDestroy might null mActor concurrently.
michael@0 506 RefPtr<TextureChild> actor = mActor;
michael@0 507
michael@0 508 if (actor) {
michael@0 509 // The actor has a raw pointer to us, actor->mTextureClient.
michael@0 510 // Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
michael@0 511 // when calling TextureChild::ActorDestroy()
michael@0 512 actor->mTextureClient = nullptr;
michael@0 513 // this will call ForceRemove in the right thread, using a sync proxy if needed
michael@0 514 if (actor->GetForwarder()) {
michael@0 515 actor->GetForwarder()->RemoveTexture(this);
michael@0 516 }
michael@0 517 }
michael@0 518 }
michael@0 519
michael@0 520 bool
michael@0 521 TextureClient::ShouldDeallocateInDestructor() const
michael@0 522 {
michael@0 523 if (!IsAllocated()) {
michael@0 524 return false;
michael@0 525 }
michael@0 526
michael@0 527 // If we're meant to be deallocated by the host,
michael@0 528 // but we haven't been shared yet, then we should
michael@0 529 // deallocate on the client instead.
michael@0 530 return !IsSharedWithCompositor();
michael@0 531 }
michael@0 532
michael@0 533 bool
michael@0 534 ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
michael@0 535 {
michael@0 536 MOZ_ASSERT(IsValid());
michael@0 537 if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
michael@0 538 return false;
michael@0 539 }
michael@0 540
michael@0 541 aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
michael@0 542
michael@0 543 return true;
michael@0 544 }
michael@0 545
michael@0 546 bool
michael@0 547 ShmemTextureClient::Allocate(uint32_t aSize)
michael@0 548 {
michael@0 549 MOZ_ASSERT(mValid);
michael@0 550 ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType();
michael@0 551 mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
michael@0 552 return mAllocated;
michael@0 553 }
michael@0 554
michael@0 555 uint8_t*
michael@0 556 ShmemTextureClient::GetBuffer() const
michael@0 557 {
michael@0 558 MOZ_ASSERT(IsValid());
michael@0 559 if (mAllocated) {
michael@0 560 return mShmem.get<uint8_t>();
michael@0 561 }
michael@0 562 return nullptr;
michael@0 563 }
michael@0 564
michael@0 565 size_t
michael@0 566 ShmemTextureClient::GetBufferSize() const
michael@0 567 {
michael@0 568 MOZ_ASSERT(IsValid());
michael@0 569 return mShmem.Size<uint8_t>();
michael@0 570 }
michael@0 571
michael@0 572 ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
michael@0 573 gfx::SurfaceFormat aFormat,
michael@0 574 gfx::BackendType aMoz2DBackend,
michael@0 575 TextureFlags aFlags)
michael@0 576 : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
michael@0 577 , mAllocated(false)
michael@0 578 {
michael@0 579 MOZ_COUNT_CTOR(ShmemTextureClient);
michael@0 580 }
michael@0 581
michael@0 582 ShmemTextureClient::~ShmemTextureClient()
michael@0 583 {
michael@0 584 MOZ_COUNT_DTOR(ShmemTextureClient);
michael@0 585 if (ShouldDeallocateInDestructor()) {
michael@0 586 // if the buffer has never been shared we must deallocate it or ir would
michael@0 587 // leak.
michael@0 588 GetAllocator()->DeallocShmem(mShmem);
michael@0 589 }
michael@0 590 }
michael@0 591
michael@0 592 bool
michael@0 593 MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
michael@0 594 {
michael@0 595 MOZ_ASSERT(IsValid());
michael@0 596 if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
michael@0 597 return false;
michael@0 598 }
michael@0 599 aDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
michael@0 600 GetFormat());
michael@0 601 return true;
michael@0 602 }
michael@0 603
michael@0 604 bool
michael@0 605 MemoryTextureClient::Allocate(uint32_t aSize)
michael@0 606 {
michael@0 607 MOZ_ASSERT(!mBuffer);
michael@0 608 static const fallible_t fallible = fallible_t();
michael@0 609 mBuffer = new(fallible) uint8_t[aSize];
michael@0 610 if (!mBuffer) {
michael@0 611 NS_WARNING("Failed to allocate buffer");
michael@0 612 return false;
michael@0 613 }
michael@0 614 GfxMemoryImageReporter::DidAlloc(mBuffer);
michael@0 615 mBufSize = aSize;
michael@0 616 return true;
michael@0 617 }
michael@0 618
michael@0 619 MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
michael@0 620 gfx::SurfaceFormat aFormat,
michael@0 621 gfx::BackendType aMoz2DBackend,
michael@0 622 TextureFlags aFlags)
michael@0 623 : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
michael@0 624 , mBuffer(nullptr)
michael@0 625 , mBufSize(0)
michael@0 626 {
michael@0 627 MOZ_COUNT_CTOR(MemoryTextureClient);
michael@0 628 }
michael@0 629
michael@0 630 MemoryTextureClient::~MemoryTextureClient()
michael@0 631 {
michael@0 632 MOZ_COUNT_DTOR(MemoryTextureClient);
michael@0 633 if (mBuffer && ShouldDeallocateInDestructor()) {
michael@0 634 // if the buffer has never been shared we must deallocate it or it would
michael@0 635 // leak.
michael@0 636 GfxMemoryImageReporter::WillFree(mBuffer);
michael@0 637 delete [] mBuffer;
michael@0 638 }
michael@0 639 }
michael@0 640
michael@0 641 BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
michael@0 642 gfx::SurfaceFormat aFormat,
michael@0 643 gfx::BackendType aMoz2DBackend,
michael@0 644 TextureFlags aFlags)
michael@0 645 : TextureClient(aFlags)
michael@0 646 , mAllocator(aAllocator)
michael@0 647 , mFormat(aFormat)
michael@0 648 , mBackend(aMoz2DBackend)
michael@0 649 , mOpenMode(0)
michael@0 650 , mUsingFallbackDrawTarget(false)
michael@0 651 , mLocked(false)
michael@0 652 {}
michael@0 653
michael@0 654 BufferTextureClient::~BufferTextureClient()
michael@0 655 {}
michael@0 656
michael@0 657 ISurfaceAllocator*
michael@0 658 BufferTextureClient::GetAllocator() const
michael@0 659 {
michael@0 660 return mAllocator;
michael@0 661 }
michael@0 662
michael@0 663 bool
michael@0 664 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
michael@0 665 {
michael@0 666 MOZ_ASSERT(IsValid());
michael@0 667 MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data");
michael@0 668 MOZ_ASSERT(aSize.width * aSize.height);
michael@0 669
michael@0 670 int bufSize
michael@0 671 = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
michael@0 672 if (!Allocate(bufSize)) {
michael@0 673 return false;
michael@0 674 }
michael@0 675
michael@0 676 if (aFlags & ALLOC_CLEAR_BUFFER) {
michael@0 677 memset(GetBuffer(), 0, bufSize);
michael@0 678 }
michael@0 679
michael@0 680 ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
michael@0 681 serializer.InitializeBufferInfo(aSize, mFormat);
michael@0 682 mSize = aSize;
michael@0 683 return true;
michael@0 684 }
michael@0 685
michael@0 686 TemporaryRef<gfx::DrawTarget>
michael@0 687 BufferTextureClient::GetAsDrawTarget()
michael@0 688 {
michael@0 689 MOZ_ASSERT(IsValid());
michael@0 690 MOZ_ASSERT(mLocked, "GetAsDrawTarget should be called on locked textures only");
michael@0 691
michael@0 692 if (mDrawTarget) {
michael@0 693 return mDrawTarget;
michael@0 694 }
michael@0 695
michael@0 696 ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
michael@0 697 if (!serializer.IsValid()) {
michael@0 698 return nullptr;
michael@0 699 }
michael@0 700
michael@0 701 MOZ_ASSERT(mUsingFallbackDrawTarget == false);
michael@0 702 mDrawTarget = serializer.GetAsDrawTarget(mBackend);
michael@0 703 if (mDrawTarget) {
michael@0 704 return mDrawTarget;
michael@0 705 }
michael@0 706
michael@0 707 // fallback path, probably because the Moz2D backend can't create a
michael@0 708 // DrawTarget around raw memory. This is going to be slow :(
michael@0 709 mDrawTarget = gfx::Factory::CreateDrawTarget(mBackend, serializer.GetSize(),
michael@0 710 serializer.GetFormat());
michael@0 711 if (!mDrawTarget) {
michael@0 712 return nullptr;
michael@0 713 }
michael@0 714
michael@0 715 mUsingFallbackDrawTarget = true;
michael@0 716 if (mOpenMode & OPEN_READ) {
michael@0 717 RefPtr<DataSourceSurface> surface = serializer.GetAsSurface();
michael@0 718 IntRect rect(0, 0, surface->GetSize().width, surface->GetSize().height);
michael@0 719 mDrawTarget->CopySurface(surface, rect, IntPoint(0,0));
michael@0 720 }
michael@0 721 return mDrawTarget;
michael@0 722 }
michael@0 723
michael@0 724 bool
michael@0 725 BufferTextureClient::Lock(OpenMode aMode)
michael@0 726 {
michael@0 727 MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!");
michael@0 728 mOpenMode = aMode;
michael@0 729 mLocked = IsValid() && IsAllocated();;
michael@0 730 return mLocked;
michael@0 731 }
michael@0 732
michael@0 733 void
michael@0 734 BufferTextureClient::Unlock()
michael@0 735 {
michael@0 736 MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!");
michael@0 737 mLocked = false;
michael@0 738 if (!mDrawTarget) {
michael@0 739 mUsingFallbackDrawTarget = false;
michael@0 740 return;
michael@0 741 }
michael@0 742
michael@0 743 // see the comment on TextureClient::GetAsDrawTarget.
michael@0 744 // This DrawTarget is internal to the TextureClient and is only exposed to the
michael@0 745 // outside world between Lock() and Unlock(). This assertion checks that no outside
michael@0 746 // reference remains by the time Unlock() is called.
michael@0 747 MOZ_ASSERT(mDrawTarget->refCount() == 1);
michael@0 748
michael@0 749 mDrawTarget->Flush();
michael@0 750 if (mUsingFallbackDrawTarget && (mOpenMode & OPEN_WRITE)) {
michael@0 751 // When we are using a fallback DrawTarget, it means we could not create
michael@0 752 // a DrawTarget wrapping the TextureClient's shared memory. In this scenario
michael@0 753 // we need to put the content of the fallback draw target back into our shared
michael@0 754 // memory.
michael@0 755 RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
michael@0 756 RefPtr<DataSourceSurface> surface = snapshot->GetDataSurface();
michael@0 757 ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
michael@0 758 if (!serializer.IsValid() || serializer.GetSize() != surface->GetSize()) {
michael@0 759 NS_WARNING("Could not write the data back into the texture.");
michael@0 760 mDrawTarget = nullptr;
michael@0 761 mUsingFallbackDrawTarget = false;
michael@0 762 return;
michael@0 763 }
michael@0 764 MOZ_ASSERT(surface->GetSize() == serializer.GetSize());
michael@0 765 MOZ_ASSERT(surface->GetFormat() == serializer.GetFormat());
michael@0 766 int bpp = BytesPerPixel(surface->GetFormat());
michael@0 767 for (int i = 0; i < surface->GetSize().height; ++i) {
michael@0 768 memcpy(serializer.GetData() + i*serializer.GetStride(),
michael@0 769 surface->GetData() + i*surface->Stride(),
michael@0 770 surface->GetSize().width * bpp);
michael@0 771 }
michael@0 772 }
michael@0 773 mDrawTarget = nullptr;
michael@0 774 mUsingFallbackDrawTarget = false;
michael@0 775 }
michael@0 776
michael@0 777 bool
michael@0 778 BufferTextureClient::UpdateYCbCr(const PlanarYCbCrData& aData)
michael@0 779 {
michael@0 780 MOZ_ASSERT(mLocked);
michael@0 781 MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
michael@0 782 MOZ_ASSERT(!IsImmutable());
michael@0 783 MOZ_ASSERT(IsValid());
michael@0 784 MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
michael@0 785
michael@0 786 YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
michael@0 787 MOZ_ASSERT(serializer.IsValid());
michael@0 788 if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
michael@0 789 aData.mYSize, aData.mYStride,
michael@0 790 aData.mCbCrSize, aData.mCbCrStride,
michael@0 791 aData.mYSkip, aData.mCbSkip)) {
michael@0 792 NS_WARNING("Failed to copy image data!");
michael@0 793 return false;
michael@0 794 }
michael@0 795
michael@0 796 if (TextureRequiresLocking(mFlags)) {
michael@0 797 // We don't have support for proper locking yet, so we'll
michael@0 798 // have to be immutable instead.
michael@0 799 MarkImmutable();
michael@0 800 }
michael@0 801 return true;
michael@0 802 }
michael@0 803
michael@0 804 bool
michael@0 805 BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize,
michael@0 806 gfx::IntSize aCbCrSize,
michael@0 807 StereoMode aStereoMode)
michael@0 808 {
michael@0 809 MOZ_ASSERT(IsValid());
michael@0 810
michael@0 811 size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize,
michael@0 812 aCbCrSize);
michael@0 813 if (!Allocate(bufSize)) {
michael@0 814 return false;
michael@0 815 }
michael@0 816 YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
michael@0 817 serializer.InitializeBufferInfo(aYSize,
michael@0 818 aCbCrSize,
michael@0 819 aStereoMode);
michael@0 820 mSize = aYSize;
michael@0 821 return true;
michael@0 822 }
michael@0 823
michael@0 824 }
michael@0 825 }

mercurial