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/. */
6 #include "BasicLayersImpl.h" // for FillWithMask, etc
7 #include "CopyableCanvasLayer.h"
8 #include "GLContext.h" // for GLContext
9 #include "GLScreenBuffer.h" // for GLScreenBuffer
10 #include "SharedSurface.h" // for SharedSurface
11 #include "SharedSurfaceGL.h" // for SharedSurface
12 #include "gfxPattern.h" // for gfxPattern, etc
13 #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
14 #include "gfxRect.h" // for gfxRect
15 #include "gfxUtils.h" // for gfxUtils
16 #include "gfx2DGlue.h" // for thebes --> moz2d transition
17 #include "mozilla/gfx/BaseSize.h" // for BaseSize
18 #include "mozilla/gfx/Tools.h"
19 #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
20 #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
21 #include "nsRect.h" // for nsIntRect
22 #include "nsSize.h" // for nsIntSize
28 using namespace mozilla::gfx
;
29 using namespace mozilla::gl
;
31 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager
* aLayerManager
, void *aImplData
) :
32 CanvasLayer(aLayerManager
, aImplData
)
33 , mGLFrontbuffer(nullptr)
34 , mIsAlphaPremultiplied(true)
35 , mOriginPos(gl::OriginPos::TopLeft
)
37 MOZ_COUNT_CTOR(CopyableCanvasLayer
);
40 CopyableCanvasLayer::~CopyableCanvasLayer()
42 MOZ_COUNT_DTOR(CopyableCanvasLayer
);
46 CopyableCanvasLayer::Initialize(const Data
& aData
)
48 NS_ASSERTION(mSurface
== nullptr, "BasicCanvasLayer::Initialize called twice!");
50 if (aData
.mGLContext
) {
51 mGLContext
= aData
.mGLContext
;
52 mIsAlphaPremultiplied
= aData
.mIsGLAlphaPremult
;
53 mOriginPos
= gl::OriginPos::BottomLeft
;
55 MOZ_ASSERT(mGLContext
->IsOffscreen(), "canvas gl context isn't offscreen");
57 if (aData
.mFrontbufferGLTex
) {
58 gfx::IntSize
size(aData
.mSize
.width
, aData
.mSize
.height
);
59 mGLFrontbuffer
= SharedSurface_GLTexture::Create(aData
.mGLContext
,
61 aData
.mGLContext
->GetGLFormats(),
62 size
, aData
.mHasAlpha
,
63 aData
.mFrontbufferGLTex
);
65 } else if (aData
.mDrawTarget
) {
66 mDrawTarget
= aData
.mDrawTarget
;
67 mSurface
= mDrawTarget
->Snapshot();
69 MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
72 mBounds
.SetRect(0, 0, aData
.mSize
.width
, aData
.mSize
.height
);
76 CopyableCanvasLayer::IsDataValid(const Data
& aData
)
78 return mGLContext
== aData
.mGLContext
;
82 CopyableCanvasLayer::UpdateTarget(DrawTarget
* aDestTarget
)
86 mSurface
= mDrawTarget
->Snapshot();
89 if (!mGLContext
&& aDestTarget
) {
90 NS_ASSERTION(mSurface
, "Must have surface to draw!");
92 aDestTarget
->CopySurface(mSurface
,
93 IntRect(0, 0, mBounds
.width
, mBounds
.height
),
104 MOZ_ASSERT(mGLContext
);
106 SharedSurface
* frontbuffer
= nullptr;
107 if (mGLFrontbuffer
) {
108 frontbuffer
= mGLFrontbuffer
.get();
110 GLScreenBuffer
* screen
= mGLContext
->Screen();
111 ShSurfHandle
* front
= screen
->Front();
113 frontbuffer
= front
->Surf();
118 NS_WARNING("Null frame received.");
122 IntSize
readSize(frontbuffer
->mSize
);
123 SurfaceFormat format
= (GetContentFlags() & CONTENT_OPAQUE
)
124 ? SurfaceFormat::B8G8R8X8
125 : SurfaceFormat::B8G8R8A8
;
126 bool needsPremult
= frontbuffer
->mHasAlpha
&& !mIsAlphaPremultiplied
;
128 // Try to read back directly into aDestTarget's output buffer
133 SurfaceFormat destFormat
;
134 if (aDestTarget
->LockBits(&destData
, &destSize
, &destStride
, &destFormat
)) {
135 if (destSize
== readSize
&& destFormat
== format
) {
136 RefPtr
<DataSourceSurface
> data
=
137 Factory::CreateWrappingDataSourceSurface(destData
, destStride
, destSize
, destFormat
);
138 mGLContext
->Screen()->Readback(frontbuffer
, data
);
140 gfxUtils::PremultiplyDataSurface(data
, data
);
142 aDestTarget
->ReleaseBits(destData
);
145 aDestTarget
->ReleaseBits(destData
);
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
)) {
156 // Readback handles Flush/MarkDirty.
157 mGLContext
->Screen()->Readback(frontbuffer
, resultSurf
);
159 gfxUtils::PremultiplyDataSurface(resultSurf
, resultSurf
);
161 MOZ_ASSERT(resultSurf
);
164 aDestTarget
->CopySurface(resultSurf
,
165 IntRect(0, 0, readSize
.width
, readSize
.height
),
168 // If !aDestSurface then we will end up painting using mSurface, so
169 // stick our surface into mSurface, so that the Paint() path is the same.
170 mSurface
= resultSurf
;
175 CopyableCanvasLayer::GetTempSurface(const IntSize
& aSize
,
176 const SurfaceFormat aFormat
)
178 if (!mCachedTempSurface
||
179 aSize
!= mCachedTempSurface
->GetSize() ||
180 aFormat
!= mCachedTempSurface
->GetFormat())
182 // Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle.
183 uint32_t stride
= GetAlignedStride
<8>(aSize
.width
* BytesPerPixel(aFormat
));
184 mCachedTempSurface
= Factory::CreateDataSourceSurfaceWithStride(aSize
, aFormat
, stride
);
187 return mCachedTempSurface
;
191 CopyableCanvasLayer::DiscardTempSurface()
193 mCachedTempSurface
= nullptr;