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