Coverage Report

Created: 2018-09-25 14:53

/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