blob: 63d65a49a1450e15936db70509418754964ed467 [file] [log] [blame]
Jim Van Verth8026ccc2018-10-04 13:10:39 -04001/*
2 * Copyright 2018 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 "GrBackendSurface.h"
9#include "GrClip.h"
10#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrRenderTargetContext.h"
13#include "GrTexture.h"
14#include "GrTextureAdjuster.h"
15#include "SkBitmapCache.h"
16#include "SkImage_Gpu.h"
17#include "SkImage_GpuBase.h"
18
19SkImage_GpuBase::SkImage_GpuBase(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
20 SkAlphaType at, SkBudgeted budgeted, sk_sp<SkColorSpace> cs)
21 : INHERITED(width, height, uniqueID)
22 , fContext(std::move(context))
23 , fAlphaType(at)
24 , fBudgeted(budgeted)
25 , fColorSpace(std::move(cs)) {}
26
27SkImage_GpuBase::~SkImage_GpuBase() {}
28
29//////////////////////////////////////////////////////////////////////////////////////////////////
30
31bool SkImage_GpuBase::ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
32 GrPixelConfig* config, SkColorType ct, SkAlphaType at,
33 sk_sp<SkColorSpace> cs) {
34 if (!tex.isValid()) {
35 return false;
36 }
37 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
38 // create a fake image info here.
39 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
40 if (!SkImageInfoIsValid(info)) {
41 return false;
42 }
43
44 return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
45}
46
47//////////////////////////////////////////////////////////////////////////////////////////////////
48
49bool SkImage_GpuBase::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
50 if (!fContext->contextPriv().resourceProvider()) {
51 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
52 return false;
53 }
54
55 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
56 // will be used. The client doesn't expect that we convert to that color space, it's intended
57 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
58 // into that color space (to save the client some effort in whatever they're about to do), but
59 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
60 // rolled the dstColorSpace into the key).
61 const auto desc = SkBitmapCacheDesc::Make(this);
62 if (SkBitmapCache::Find(desc, dst)) {
63 SkASSERT(dst->getGenerationID() == this->uniqueID());
64 SkASSERT(dst->isImmutable());
65 SkASSERT(dst->getPixels());
66 return true;
67 }
68
69 SkBitmapCache::RecPtr rec = nullptr;
70 SkPixmap pmap;
71 if (kAllow_CachingHint == chint) {
72 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
73 if (!rec) {
74 return false;
75 }
76 } else {
77 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
78 return false;
79 }
80 }
81
82 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
83 this->asTextureProxyRef(),
84 fColorSpace);
85 if (!sContext) {
86 return false;
87 }
88
89 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
90 return false;
91 }
92
93 if (rec) {
94 SkBitmapCache::Add(std::move(rec), dst);
95 this->notifyAddedToRasterCache();
96 }
97 return true;
98}
99
100sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(const SkIRect& subset) const {
101 sk_sp<GrSurfaceProxy> proxy = this->asTextureProxyRef();
102
103 GrSurfaceDesc desc;
104 desc.fWidth = subset.width();
105 desc.fHeight = subset.height();
106 desc.fConfig = proxy->config();
107
108 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
109 desc, proxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, fBudgeted));
110 if (!sContext) {
111 return nullptr;
112 }
113
114 if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
115 return nullptr;
116 }
117
118 // MDB: this call is okay bc we know 'sContext' was kExact
119 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
120 fAlphaType, sContext->asTextureProxyRef(),
121 fColorSpace, fBudgeted);
122}
123
124sk_sp<GrTextureProxy> SkImage_GpuBase::asTextureProxyRef(GrContext* context,
125 const GrSamplerState& params,
126 SkColorSpace* dstColorSpace,
127 sk_sp<SkColorSpace>* texColorSpace,
128 SkScalar scaleAdjust[2]) const {
129 if (context->uniqueID() != fContext->uniqueID()) {
130 SkASSERT(0);
131 return nullptr;
132 }
133
134 GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(), fAlphaType,
135 this->uniqueID(), fColorSpace.get());
136 return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
137}
138
139GrBackendTexture SkImage_GpuBase::onGetBackendTexture(bool flushPendingGrContextIO,
140 GrSurfaceOrigin* origin) const {
141 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
142 SkASSERT(proxy);
143
144 if (!fContext->contextPriv().resourceProvider() && !proxy->isInstantiated()) {
145 // This image was created with a DDL context and cannot be instantiated.
146 return GrBackendTexture();
147}
148
149 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
150 return GrBackendTexture(); // invalid
151 }
152
153 GrTexture* texture = proxy->peekTexture();
154
155 if (texture) {
156 if (flushPendingGrContextIO) {
157 fContext->contextPriv().prepareSurfaceForExternalIO(proxy.get());
158 }
159 if (origin) {
160 *origin = proxy->origin();
161 }
162 return texture->getBackendTexture();
163 }
164 return GrBackendTexture(); // invalid
165}
166
167GrTexture* SkImage_GpuBase::onGetTexture() const {
168 GrTextureProxy* proxy = this->peekProxy();
169 if (!proxy) {
170 return nullptr;
171 }
172
173 sk_sp<GrTextureProxy> proxyRef = this->asTextureProxyRef();
174 if (!fContext->contextPriv().resourceProvider() && !proxyRef->isInstantiated()) {
175 // This image was created with a DDL context and cannot be instantiated.
176 return nullptr;
177 }
178
179 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
180 return nullptr;
181 }
182
183 return proxy->peekTexture();
184}
185
186sk_sp<SkImage> SkImage_GpuBase::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
187 SkAlphaType newAlphaType = fAlphaType;
188#if defined(SK_LEGACY_MAKE_COLOR_SPACE_IMPL)
189 if (kUnpremul_SkAlphaType == fAlphaType) {
190 newAlphaType = kPremul_SkAlphaType;
191 }
192#endif
193 auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), this->alphaType(),
194 target.get(), newAlphaType);
195 if (!xform) {
196 return sk_ref_sp(const_cast<SkImage_GpuBase*>(this));
197 }
198
199 sk_sp<GrRenderTargetContext> renderTargetContext(
200 fContext->contextPriv().makeDeferredRenderTargetContext(
201 SkBackingFit::kExact, this->width(), this->height(),
202 kRGBA_8888_GrPixelConfig, nullptr));
203 if (!renderTargetContext) {
204 return nullptr;
205 }
206
207 GrPaint paint;
208 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
209 paint.addColorTextureProcessor(this->asTextureProxyRef(), SkMatrix::I());
210 paint.addColorFragmentProcessor(std::move(xform));
211
212 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
213
214 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
215
216 if (!renderTargetContext->asTextureProxy()) {
217 return nullptr;
218 }
219
220 // MDB: this call is okay bc we know 'renderTargetContext' was exact
221 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
222 newAlphaType, renderTargetContext->asTextureProxyRef(),
223 std::move(target), fBudgeted);
224}
225
226bool SkImage_GpuBase::onIsValid(GrContext* context) const {
227 // The base class has already checked that context isn't abandoned (if it's not nullptr)
228 if (fContext->abandoned()) {
229 return false;
230 }
231
232 if (context && context != fContext.get()) {
233 return false;
234 }
235
236 return true;
237}