Source code

Revision control

Other Tools

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
MOZ_COUNT_CTOR(ShareableCanvasRenderer);
28
}
29
30
ShareableCanvasRenderer::~ShareableCanvasRenderer() {
31
MOZ_COUNT_DTOR(ShareableCanvasRenderer);
32
33
Destroy();
34
}
35
36
void ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
37
CopyableCanvasRenderer::Initialize(aData);
38
39
mCanvasClient = nullptr;
40
41
if (!mGLContext) return;
42
43
gl::GLScreenBuffer* screen = mGLContext->Screen();
44
MOZ_ASSERT(screen);
45
gl::SurfaceCaps caps = screen->mCaps;
46
47
auto forwarder = GetForwarder();
48
49
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
50
if (!aData.mIsGLAlphaPremult) {
51
mFlags |= TextureFlags::NON_PREMULTIPLIED;
52
}
53
54
UniquePtr<gl::SurfaceFactory> factory =
55
gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
56
if (factory) {
57
screen->Morph(std::move(factory));
58
}
59
}
60
61
void ShareableCanvasRenderer::ClearCachedResources() {
62
CopyableCanvasRenderer::ClearCachedResources();
63
64
if (mCanvasClient) {
65
mCanvasClient->Clear();
66
}
67
}
68
69
void ShareableCanvasRenderer::Destroy() {
70
CopyableCanvasRenderer::Destroy();
71
72
if (mCanvasClient) {
73
mCanvasClient->OnDetach();
74
mCanvasClient = nullptr;
75
}
76
}
77
78
bool ShareableCanvasRenderer::UpdateTarget(DrawTarget* aDestTarget) {
79
MOZ_ASSERT(!mOOPRenderer);
80
81
MOZ_ASSERT(aDestTarget);
82
if (!aDestTarget) {
83
return false;
84
}
85
86
RefPtr<SourceSurface> surface;
87
88
if (!mGLContext) {
89
AutoReturnSnapshot autoReturn;
90
91
if (mAsyncRenderer) {
92
surface = mAsyncRenderer->GetSurface();
93
} else if (mBufferProvider) {
94
surface = mBufferProvider->BorrowSnapshot();
95
autoReturn.mSnapshot = &surface;
96
autoReturn.mBufferProvider = mBufferProvider;
97
}
98
99
MOZ_ASSERT(surface);
100
if (!surface) {
101
return false;
102
}
103
104
aDestTarget->CopySurface(surface, IntRect(0, 0, mSize.width, mSize.height),
105
IntPoint(0, 0));
106
return true;
107
}
108
109
gl::SharedSurface* frontbuffer = nullptr;
110
111
gl::GLScreenBuffer* screen = mGLContext->Screen();
112
const auto& front = screen->Front();
113
if (front) {
114
frontbuffer = front->Surf();
115
}
116
117
if (!frontbuffer) {
118
NS_WARNING("Null frame received.");
119
return false;
120
}
121
122
IntSize readSize(frontbuffer->mSize);
123
SurfaceFormat format =
124
mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
125
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
126
127
// Try to read back directly into aDestTarget's output buffer
128
uint8_t* destData;
129
IntSize destSize;
130
int32_t destStride;
131
SurfaceFormat destFormat;
132
if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
133
if (destSize == readSize && destFormat == format) {
134
RefPtr<DataSourceSurface> data = Factory::CreateWrappingDataSourceSurface(
135
destData, destStride, destSize, destFormat);
136
if (!mGLContext->Readback(frontbuffer, data)) {
137
aDestTarget->ReleaseBits(destData);
138
return false;
139
}
140
if (needsPremult) {
141
gfxUtils::PremultiplyDataSurface(data, data);
142
}
143
aDestTarget->ReleaseBits(destData);
144
return true;
145
}
146
aDestTarget->ReleaseBits(destData);
147
}
148
149
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
150
// There will already be a warning from inside of GetTempSurface, but
151
// it doesn't hurt to complain:
152
if (NS_WARN_IF(!resultSurf)) {
153
return false;
154
}
155
156
// Readback handles Flush/MarkDirty.
157
if (!mGLContext->Readback(frontbuffer, resultSurf)) {
158
return false;
159
}
160
if (needsPremult) {
161
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
162
}
163
164
aDestTarget->CopySurface(resultSurf,
165
IntRect(0, 0, readSize.width, readSize.height),
166
IntPoint(0, 0));
167
168
return true;
169
}
170
171
CanvasClient::CanvasClientType ShareableCanvasRenderer::GetCanvasClientType() {
172
if (mAsyncRenderer) {
173
return CanvasClient::CanvasClientAsync;
174
}
175
176
if (mGLContext) {
177
return CanvasClient::CanvasClientTypeShSurf;
178
}
179
180
if (mOOPRenderer) {
181
return CanvasClient::CanvasClientTypeOOP;
182
}
183
184
return CanvasClient::CanvasClientSurface;
185
}
186
187
void ShareableCanvasRenderer::UpdateCompositableClient(
188
wr::RenderRoot aRenderRoot) {
189
if (!CreateCompositable()) {
190
return;
191
}
192
193
if (mCanvasClient && mAsyncRenderer) {
194
mCanvasClient->UpdateAsync(mAsyncRenderer);
195
}
196
197
if (!IsDirty()) {
198
return;
199
}
200
ResetDirty();
201
202
FirePreTransactionCallback();
203
if (mBufferProvider && mBufferProvider->GetTextureClient()) {
204
if (!mBufferProvider->SetKnowsCompositor(GetForwarder())) {
205
gfxCriticalNote << "BufferProvider::SetForwarder failed";
206
return;
207
}
208
mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient(),
209
aRenderRoot);
210
} else {
211
mCanvasClient->Update(gfx::IntSize(mSize.width, mSize.height), this,
212
aRenderRoot);
213
}
214
215
FireDidTransactionCallback();
216
217
mCanvasClient->Updated(aRenderRoot);
218
}
219
220
} // namespace layers
221
} // namespace mozilla