1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "SharedRGBImage.h"
8 #include "ImageTypes.h"         // for ImageFormat::SHARED_RGB, etc
9 #include "Shmem.h"              // for Shmem
10 #include "gfx2DGlue.h"          // for ImageFormatToSurfaceFormat, etc
11 #include "gfxPlatform.h"        // for gfxPlatform, gfxImageFormat
12 #include "mozilla/gfx/Point.h"  // for IntSIze
13 #include "mozilla/layers/BufferTexture.h"
14 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator, etc
15 #include "mozilla/layers/ImageClient.h"        // for ImageClient
16 #include "mozilla/layers/LayersSurfaces.h"     // for SurfaceDescriptor, etc
17 #include "mozilla/layers/TextureClient.h"      // for BufferTextureClient, etc
18 #include "mozilla/layers/ImageBridgeChild.h"   // for ImageBridgeChild
19 #include "mozilla/mozalloc.h"                  // for operator delete, etc
20 #include "nsDebug.h"                           // for NS_WARNING, NS_ASSERTION
21 #include "nsISupportsImpl.h"                   // for Image::AddRef, etc
22 #include "nsRect.h"                            // for mozilla::gfx::IntRect
23 
24 // Just big enough for a 1080p RGBA32 frame
25 #define MAX_FRAME_SIZE (16 * 1024 * 1024)
26 
27 namespace mozilla {
28 namespace layers {
29 
CreateSharedRGBImage(ImageContainer * aImageContainer,gfx::IntSize aSize,gfxImageFormat aImageFormat)30 already_AddRefed<Image> CreateSharedRGBImage(ImageContainer* aImageContainer,
31                                              gfx::IntSize aSize,
32                                              gfxImageFormat aImageFormat) {
33   NS_ASSERTION(aImageFormat == gfx::SurfaceFormat::A8R8G8B8_UINT32 ||
34                    aImageFormat == gfx::SurfaceFormat::X8R8G8B8_UINT32 ||
35                    aImageFormat == gfx::SurfaceFormat::R5G6B5_UINT16,
36                "RGB formats supported only");
37 
38   if (!aImageContainer) {
39     NS_WARNING("No ImageContainer to allocate SharedRGBImage");
40     return nullptr;
41   }
42 
43   RefPtr<SharedRGBImage> rgbImage = aImageContainer->CreateSharedRGBImage();
44   if (!rgbImage) {
45     NS_WARNING("Failed to create SharedRGBImage");
46     return nullptr;
47   }
48   if (!rgbImage->Allocate(aSize,
49                           gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
50     NS_WARNING("Failed to allocate a shared image");
51     return nullptr;
52   }
53   return rgbImage.forget();
54 }
55 
SharedRGBImage(ImageClient * aCompositable)56 SharedRGBImage::SharedRGBImage(ImageClient* aCompositable)
57     : Image(nullptr, ImageFormat::SHARED_RGB), mCompositable(aCompositable) {
58   MOZ_COUNT_CTOR(SharedRGBImage);
59 }
60 
~SharedRGBImage()61 SharedRGBImage::~SharedRGBImage() { MOZ_COUNT_DTOR(SharedRGBImage); }
62 
Allocate(gfx::IntSize aSize,gfx::SurfaceFormat aFormat)63 bool SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
64   mSize = aSize;
65   mTextureClient = mCompositable->CreateBufferTextureClient(
66       aFormat, aSize, gfx::BackendType::NONE, TextureFlags::DEFAULT);
67   return !!mTextureClient;
68 }
69 
GetBuffer() const70 uint8_t* SharedRGBImage::GetBuffer() const {
71   MappedTextureData mapped;
72   if (mTextureClient && mTextureClient->BorrowMappedData(mapped)) {
73     return mapped.data;
74   }
75   return 0;
76 }
77 
GetSize() const78 gfx::IntSize SharedRGBImage::GetSize() const { return mSize; }
79 
GetTextureClient(KnowsCompositor * aForwarder)80 TextureClient* SharedRGBImage::GetTextureClient(KnowsCompositor* aForwarder) {
81   return mTextureClient.get();
82 }
83 
ReleaseTextureClient(void * aData)84 static void ReleaseTextureClient(void* aData) {
85   RELEASE_MANUALLY(static_cast<TextureClient*>(aData));
86 }
87 
88 static gfx::UserDataKey sTextureClientKey;
89 
GetAsSourceSurface()90 already_AddRefed<gfx::SourceSurface> SharedRGBImage::GetAsSourceSurface() {
91   NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
92 
93   if (mSourceSurface) {
94     RefPtr<gfx::SourceSurface> surface(mSourceSurface);
95     return surface.forget();
96   }
97 
98   RefPtr<gfx::SourceSurface> surface;
99   {
100     // We are 'borrowing' the DrawTarget and retaining a permanent reference to
101     // the underlying data (via the surface). It is in this instance since we
102     // know that the TextureClient is always wrapping a BufferTextureData and
103     // therefore it won't go away underneath us.
104     BufferTextureData* decoded_buffer =
105         mTextureClient->GetInternalData()->AsBufferTextureData();
106     RefPtr<gfx::DrawTarget> drawTarget = decoded_buffer->BorrowDrawTarget();
107 
108     if (!drawTarget) {
109       return nullptr;
110     }
111 
112     surface = drawTarget->Snapshot();
113     if (!surface) {
114       return nullptr;
115     }
116 
117     // The surface may outlive the owning TextureClient. So, we need to ensure
118     // that the surface keeps the TextureClient alive via a reference held in
119     // user data. The TextureClient's DrawTarget only has a weak reference to
120     // the surface, so we won't create any cycles by just referencing the
121     // TextureClient.
122     if (!surface->GetUserData(&sTextureClientKey)) {
123       surface->AddUserData(&sTextureClientKey, mTextureClient,
124                            ReleaseTextureClient);
125       ADDREF_MANUALLY(mTextureClient);
126     }
127   }
128 
129   mSourceSurface = surface;
130   return surface.forget();
131 }
132 
133 }  // namespace layers
134 }  // namespace mozilla
135