1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file
6 */
7
8#include "include/core/SkCanvas.h"
9#include "src/core/SkSpecialImage.h"
10#include "src/core/SkSpecialSurface.h"
11#include "src/core/SkSurfacePriv.h"
12
13 ///////////////////////////////////////////////////////////////////////////////
14class SkSpecialSurface_Base : public SkSpecialSurface {
15public:
16 SkSpecialSurface_Base(const SkIRect& subset, const SkSurfaceProps* props)
17 : INHERITED(subset, props)
18 , fCanvas(nullptr) {
19 }
20
21 virtual ~SkSpecialSurface_Base() { }
22
23 // reset is called after an SkSpecialImage has been snapped
24 void reset() { fCanvas.reset(); }
25
26 // This can return nullptr if reset has already been called or something when wrong in the ctor
27 SkCanvas* onGetCanvas() { return fCanvas.get(); }
28
29 virtual sk_sp<SkSpecialImage> onMakeImageSnapshot() = 0;
30
31protected:
32 std::unique_ptr<SkCanvas> fCanvas; // initialized by derived classes in ctors
33
34private:
35 typedef SkSpecialSurface INHERITED;
36};
37
38///////////////////////////////////////////////////////////////////////////////
39static SkSpecialSurface_Base* as_SB(SkSpecialSurface* surface) {
40 return static_cast<SkSpecialSurface_Base*>(surface);
41}
42
43SkSpecialSurface::SkSpecialSurface(const SkIRect& subset,
44 const SkSurfaceProps* props)
45 : fProps(SkSurfacePropsCopyOrDefault(props).flags(), kUnknown_SkPixelGeometry)
46 , fSubset(subset) {
47 SkASSERT(fSubset.width() > 0);
48 SkASSERT(fSubset.height() > 0);
49}
50
51SkCanvas* SkSpecialSurface::getCanvas() {
52 return as_SB(this)->onGetCanvas();
53}
54
55sk_sp<SkSpecialImage> SkSpecialSurface::makeImageSnapshot() {
56 sk_sp<SkSpecialImage> image(as_SB(this)->onMakeImageSnapshot());
57 as_SB(this)->reset();
58 return image; // the caller gets the creation ref
59}
60
61///////////////////////////////////////////////////////////////////////////////
62#include "include/core/SkMallocPixelRef.h"
63
64class SkSpecialSurface_Raster : public SkSpecialSurface_Base {
65public:
66 SkSpecialSurface_Raster(const SkImageInfo& info,
67 sk_sp<SkPixelRef> pr,
68 const SkIRect& subset,
69 const SkSurfaceProps* props)
70 : INHERITED(subset, props) {
71 SkASSERT(info.width() == pr->width() && info.height() == pr->height());
72 fBitmap.setInfo(info, info.minRowBytes());
73 fBitmap.setPixelRef(std::move(pr), 0, 0);
74
75 fCanvas.reset(new SkCanvas(fBitmap, this->props()));
76 fCanvas->clipRect(SkRect::Make(subset));
77#ifdef SK_IS_BOT
78 fCanvas->clear(SK_ColorRED); // catch any imageFilter sloppiness
79#endif
80 }
81
82 ~SkSpecialSurface_Raster() override { }
83
84 sk_sp<SkSpecialImage> onMakeImageSnapshot() override {
85 return SkSpecialImage::MakeFromRaster(this->subset(), fBitmap, &this->props());
86 }
87
88private:
89 SkBitmap fBitmap;
90
91 typedef SkSpecialSurface_Base INHERITED;
92};
93
94sk_sp<SkSpecialSurface> SkSpecialSurface::MakeFromBitmap(const SkIRect& subset, SkBitmap& bm,
95 const SkSurfaceProps* props) {
96 if (subset.isEmpty() || !SkSurfaceValidateRasterInfo(bm.info(), bm.rowBytes())) {
97 return nullptr;
98 }
99 return sk_make_sp<SkSpecialSurface_Raster>(bm.info(), sk_ref_sp(bm.pixelRef()), subset, props);
100}
101
102sk_sp<SkSpecialSurface> SkSpecialSurface::MakeRaster(const SkImageInfo& info,
103 const SkSurfaceProps* props) {
104 if (!SkSurfaceValidateRasterInfo(info)) {
105 return nullptr;
106 }
107
108 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, 0);
109 if (!pr) {
110 return nullptr;
111 }
112
113 const SkIRect subset = SkIRect::MakeWH(info.width(), info.height());
114
115 return sk_make_sp<SkSpecialSurface_Raster>(info, std::move(pr), subset, props);
116}
117
118#if SK_SUPPORT_GPU
119///////////////////////////////////////////////////////////////////////////////
120#include "include/private/GrRecordingContext.h"
121#include "src/gpu/GrRecordingContextPriv.h"
122#include "src/gpu/SkGpuDevice.h"
123
124class SkSpecialSurface_Gpu : public SkSpecialSurface_Base {
125public:
126 SkSpecialSurface_Gpu(GrRecordingContext* context,
127 std::unique_ptr<GrRenderTargetContext> renderTargetContext,
128 int width, int height, const SkIRect& subset)
129 : INHERITED(subset, &renderTargetContext->surfaceProps())
130 , fReadView(renderTargetContext->readSurfaceView()) {
131 // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice
132 auto device = SkGpuDevice::Make(context->priv().backdoor(), std::move(renderTargetContext),
133 SkGpuDevice::kUninit_InitContents);
134 if (!device) {
135 return;
136 }
137
138 fCanvas.reset(new SkCanvas(std::move(device)));
139 fCanvas->clipRect(SkRect::Make(subset));
140#ifdef SK_IS_BOT
141 fCanvas->clear(SK_ColorRED); // catch any imageFilter sloppiness
142#endif
143 }
144
145 sk_sp<SkSpecialImage> onMakeImageSnapshot() override {
146 if (!fReadView.asTextureProxy()) {
147 return nullptr;
148 }
149 GrColorType ct = SkColorTypeToGrColorType(fCanvas->imageInfo().colorType());
150
151 // Note: SkSpecialImages can only be snapShotted once, so this call is destructive and we
152 // move fReadMove.
153 return SkSpecialImage::MakeDeferredFromGpu(fCanvas->getGrContext(),
154 this->subset(),
155 kNeedNewImageUniqueID_SpecialImage,
156 std::move(fReadView), ct,
157 fCanvas->imageInfo().refColorSpace(),
158 &this->props());
159 }
160
161private:
162 GrSurfaceProxyView fReadView;
163 typedef SkSpecialSurface_Base INHERITED;
164};
165
166sk_sp<SkSpecialSurface> SkSpecialSurface::MakeRenderTarget(GrRecordingContext* context,
167 int width, int height,
168 GrColorType colorType,
169 sk_sp<SkColorSpace> colorSpace,
170 const SkSurfaceProps* props) {
171 if (!context) {
172 return nullptr;
173 }
174 auto renderTargetContext = GrRenderTargetContext::Make(
175 context, colorType, std::move(colorSpace), SkBackingFit::kApprox, {width, height}, 1,
176 GrMipMapped::kNo, GrProtected::kNo, kBottomLeft_GrSurfaceOrigin, SkBudgeted::kYes,
177 props);
178 if (!renderTargetContext) {
179 return nullptr;
180 }
181
182 const SkIRect subset = SkIRect::MakeWH(width, height);
183
184 return sk_make_sp<SkSpecialSurface_Gpu>(context, std::move(renderTargetContext),
185 width, height, subset);
186}
187
188#endif
189