Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "ShareableCanvasLayer.h"
7 :
8 : #include "GLContext.h" // for GLContext
9 : #include "GLScreenBuffer.h" // for GLScreenBuffer
10 : #include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc
11 : #include "mozilla/layers/AsyncCanvasRenderer.h"
12 : #include "mozilla/layers/TextureClientSharedSurface.h"
13 :
14 : namespace mozilla {
15 : namespace layers {
16 :
17 0 : ShareableCanvasLayer::ShareableCanvasLayer(LayerManager* aLayerManager, void *aImplData)
18 : : CopyableCanvasLayer(aLayerManager, aImplData)
19 0 : , mFlags(TextureFlags::NO_FLAGS)
20 : {
21 0 : MOZ_COUNT_CTOR(ShareableCanvasLayer);
22 0 : }
23 :
24 0 : ShareableCanvasLayer::~ShareableCanvasLayer()
25 : {
26 0 : MOZ_COUNT_DTOR(ShareableCanvasLayer);
27 0 : if (mBufferProvider) {
28 0 : mBufferProvider->ClearCachedResources();
29 : }
30 0 : if (mCanvasClient) {
31 0 : mCanvasClient->OnDetach();
32 0 : mCanvasClient = nullptr;
33 : }
34 0 : }
35 :
36 : void
37 0 : ShareableCanvasLayer::Initialize(const Data& aData)
38 : {
39 0 : CopyableCanvasLayer::Initialize(aData);
40 :
41 0 : mCanvasClient = nullptr;
42 :
43 0 : if (!mGLContext)
44 0 : return;
45 :
46 0 : gl::GLScreenBuffer* screen = mGLContext->Screen();
47 :
48 0 : gl::SurfaceCaps caps;
49 0 : if (mGLFrontbuffer) {
50 : // The screen caps are irrelevant if we're using a separate frontbuffer.
51 0 : caps = mGLFrontbuffer->mHasAlpha ? gl::SurfaceCaps::ForRGBA()
52 0 : : gl::SurfaceCaps::ForRGB();
53 : } else {
54 0 : MOZ_ASSERT(screen);
55 0 : caps = screen->mCaps;
56 : }
57 0 : MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
58 :
59 0 : auto forwarder = GetForwarder();
60 :
61 0 : mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
62 0 : if (!aData.mIsGLAlphaPremult) {
63 0 : mFlags |= TextureFlags::NON_PREMULTIPLIED;
64 : }
65 :
66 : UniquePtr<gl::SurfaceFactory> factory =
67 0 : gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
68 :
69 0 : if (mGLFrontbuffer || aData.mIsMirror) {
70 : // We're using a source other than the one in the default screen.
71 : // (SkiaGL)
72 0 : mFactory = Move(factory);
73 0 : if (!mFactory) {
74 : // Absolutely must have a factory here, so create a basic one
75 0 : mFactory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, caps, mFlags);
76 : }
77 : } else {
78 0 : if (factory)
79 0 : screen->Morph(Move(factory));
80 : }
81 : }
82 :
83 : bool
84 0 : ShareableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
85 : {
86 0 : MOZ_ASSERT(aDestTarget);
87 0 : if (!aDestTarget) {
88 0 : return false;
89 : }
90 :
91 0 : RefPtr<SourceSurface> surface;
92 :
93 0 : if (!mGLContext) {
94 0 : AutoReturnSnapshot autoReturn;
95 :
96 0 : if (mAsyncRenderer) {
97 0 : surface = mAsyncRenderer->GetSurface();
98 0 : } else if (mBufferProvider) {
99 0 : surface = mBufferProvider->BorrowSnapshot();
100 0 : autoReturn.mSnapshot = &surface;
101 0 : autoReturn.mBufferProvider = mBufferProvider;
102 : }
103 :
104 0 : MOZ_ASSERT(surface);
105 0 : if (!surface) {
106 0 : return false;
107 : }
108 :
109 0 : aDestTarget->CopySurface(surface,
110 0 : IntRect(0, 0, mBounds.width, mBounds.height),
111 0 : IntPoint(0, 0));
112 0 : return true;
113 : }
114 :
115 0 : gl::SharedSurface* frontbuffer = nullptr;
116 0 : if (mGLFrontbuffer) {
117 0 : frontbuffer = mGLFrontbuffer.get();
118 : } else {
119 0 : gl::GLScreenBuffer* screen = mGLContext->Screen();
120 0 : const auto& front = screen->Front();
121 0 : if (front) {
122 0 : frontbuffer = front->Surf();
123 : }
124 : }
125 :
126 0 : if (!frontbuffer) {
127 0 : NS_WARNING("Null frame received.");
128 0 : return false;
129 : }
130 :
131 0 : IntSize readSize(frontbuffer->mSize);
132 0 : SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
133 0 : ? SurfaceFormat::B8G8R8X8
134 0 : : SurfaceFormat::B8G8R8A8;
135 0 : bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
136 :
137 : // Try to read back directly into aDestTarget's output buffer
138 : uint8_t* destData;
139 0 : IntSize destSize;
140 : int32_t destStride;
141 : SurfaceFormat destFormat;
142 0 : if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
143 0 : if (destSize == readSize && destFormat == format) {
144 : RefPtr<DataSourceSurface> data =
145 0 : Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
146 0 : mGLContext->Readback(frontbuffer, data);
147 0 : if (needsPremult) {
148 0 : gfxUtils::PremultiplyDataSurface(data, data);
149 : }
150 0 : aDestTarget->ReleaseBits(destData);
151 0 : return true;
152 : }
153 0 : aDestTarget->ReleaseBits(destData);
154 : }
155 :
156 0 : RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
157 : // There will already be a warning from inside of GetTempSurface, but
158 : // it doesn't hurt to complain:
159 0 : if (NS_WARN_IF(!resultSurf)) {
160 0 : return false;
161 : }
162 :
163 : // Readback handles Flush/MarkDirty.
164 0 : mGLContext->Readback(frontbuffer, resultSurf);
165 0 : if (needsPremult) {
166 0 : gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
167 : }
168 :
169 : aDestTarget->CopySurface(resultSurf,
170 0 : IntRect(0, 0, readSize.width, readSize.height),
171 0 : IntPoint(0, 0));
172 :
173 0 : return true;
174 : }
175 :
176 : CanvasClient::CanvasClientType
177 0 : ShareableCanvasLayer::GetCanvasClientType()
178 : {
179 0 : if (mAsyncRenderer) {
180 0 : return CanvasClient::CanvasClientAsync;
181 : }
182 :
183 0 : if (mGLContext) {
184 0 : return CanvasClient::CanvasClientTypeShSurf;
185 : }
186 0 : return CanvasClient::CanvasClientSurface;
187 : }
188 :
189 : void
190 0 : ShareableCanvasLayer::UpdateCompositableClient()
191 : {
192 0 : if (!mCanvasClient) {
193 0 : TextureFlags flags = TextureFlags::DEFAULT;
194 0 : if (mOriginPos == gl::OriginPos::BottomLeft) {
195 0 : flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
196 : }
197 :
198 0 : if (!mIsAlphaPremultiplied) {
199 0 : flags |= TextureFlags::NON_PREMULTIPLIED;
200 : }
201 :
202 0 : mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
203 0 : GetForwarder(),
204 0 : flags);
205 0 : if (!mCanvasClient) {
206 0 : return;
207 : }
208 :
209 0 : AttachCompositable();
210 : }
211 :
212 0 : if (mCanvasClient && mAsyncRenderer) {
213 0 : mCanvasClient->UpdateAsync(mAsyncRenderer);
214 : }
215 :
216 0 : if (!IsDirty()) {
217 0 : return;
218 : }
219 0 : Painted();
220 :
221 0 : FirePreTransactionCallback();
222 0 : if (mBufferProvider && mBufferProvider->GetTextureClient()) {
223 0 : if (!mBufferProvider->SetForwarder(mManager->AsShadowForwarder())) {
224 0 : gfxCriticalNote << "BufferProvider::SetForwarder failed";
225 0 : return;
226 : }
227 0 : mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
228 : } else {
229 0 : mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
230 : }
231 :
232 0 : FireDidTransactionCallback();
233 :
234 0 : mCanvasClient->Updated();
235 : }
236 :
237 : } // namespace layers
238 : } // namespace mozilla
|