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