Line data Source code
1 : /*
2 : * Copyright 2011 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 "GrContext.h"
9 : #include "GrClip.h"
10 : #include "GrContextOptions.h"
11 : #include "GrContextPriv.h"
12 : #include "GrDrawingManager.h"
13 : #include "GrRenderTargetContext.h"
14 : #include "GrRenderTargetProxy.h"
15 : #include "GrResourceCache.h"
16 : #include "GrResourceProvider.h"
17 : #include "GrSemaphore.h"
18 : #include "GrSoftwarePathRenderer.h"
19 : #include "GrSurfaceContext.h"
20 : #include "GrSurfacePriv.h"
21 : #include "GrSurfaceProxyPriv.h"
22 : #include "GrTextureContext.h"
23 : #include "SkConvertPixels.h"
24 : #include "SkGr.h"
25 : #include "SkUnPreMultiplyPriv.h"
26 : #include "effects/GrConfigConversionEffect.h"
27 : #include "text/GrTextBlobCache.h"
28 :
29 : #define ASSERT_OWNED_PROXY(P) \
30 : SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
31 : #define ASSERT_OWNED_PROXY_PRIV(P) \
32 : SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
33 :
34 : #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
35 : #define ASSERT_SINGLE_OWNER \
36 : SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
37 : #define ASSERT_SINGLE_OWNER_PRIV \
38 : SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
39 : #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
40 : #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
41 : #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
42 : #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
43 : #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
44 :
45 : ////////////////////////////////////////////////////////////////////////////////
46 :
47 0 : GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
48 0 : GrContextOptions defaultOptions;
49 0 : return Create(backend, backendContext, defaultOptions);
50 : }
51 :
52 0 : GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
53 : const GrContextOptions& options) {
54 0 : GrContext* context = new GrContext;
55 :
56 0 : if (context->init(backend, backendContext, options)) {
57 0 : return context;
58 : } else {
59 0 : context->unref();
60 0 : return nullptr;
61 : }
62 : }
63 :
64 : static int32_t gNextID = 1;
65 0 : static int32_t next_id() {
66 : int32_t id;
67 0 : do {
68 0 : id = sk_atomic_inc(&gNextID);
69 0 : } while (id == SK_InvalidGenID);
70 0 : return id;
71 : }
72 :
73 0 : GrContext::GrContext() : fUniqueID(next_id()) {
74 0 : fGpu = nullptr;
75 0 : fCaps = nullptr;
76 0 : fResourceCache = nullptr;
77 0 : fResourceProvider = nullptr;
78 0 : fAtlasGlyphCache = nullptr;
79 0 : }
80 :
81 0 : bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
82 : const GrContextOptions& options) {
83 0 : ASSERT_SINGLE_OWNER
84 0 : SkASSERT(!fGpu);
85 :
86 0 : fGpu = GrGpu::Create(backend, backendContext, options, this);
87 0 : if (!fGpu) {
88 0 : return false;
89 : }
90 0 : this->initCommon(options);
91 0 : return true;
92 : }
93 :
94 0 : void GrContext::initCommon(const GrContextOptions& options) {
95 0 : ASSERT_SINGLE_OWNER
96 :
97 0 : fCaps = SkRef(fGpu->caps());
98 0 : fResourceCache = new GrResourceCache(fCaps);
99 0 : fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
100 :
101 0 : fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
102 0 : fDidTestPMConversions = false;
103 :
104 0 : GrRenderTargetOpList::Options rtOpListOptions;
105 0 : rtOpListOptions.fMaxOpCombineLookback = options.fMaxOpCombineLookback;
106 0 : rtOpListOptions.fMaxOpCombineLookahead = options.fMaxOpCombineLookahead;
107 0 : GrPathRendererChain::Options prcOptions;
108 0 : prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
109 0 : prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
110 0 : fDrawingManager.reset(new GrDrawingManager(this, rtOpListOptions, prcOptions,
111 0 : options.fImmediateMode, &fSingleOwner));
112 :
113 0 : fAtlasGlyphCache = new GrAtlasGlyphCache(this);
114 :
115 0 : fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
116 0 : }
117 :
118 0 : GrContext::~GrContext() {
119 0 : ASSERT_SINGLE_OWNER
120 :
121 0 : if (!fGpu) {
122 0 : SkASSERT(!fCaps);
123 0 : return;
124 : }
125 :
126 0 : this->flush();
127 :
128 0 : fDrawingManager->cleanup();
129 :
130 0 : for (int i = 0; i < fCleanUpData.count(); ++i) {
131 0 : (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
132 : }
133 :
134 0 : delete fResourceProvider;
135 0 : delete fResourceCache;
136 0 : delete fAtlasGlyphCache;
137 :
138 0 : fGpu->unref();
139 0 : fCaps->unref();
140 0 : }
141 :
142 0 : sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
143 0 : if (!fThreadSafeProxy) {
144 0 : fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID()));
145 : }
146 0 : return fThreadSafeProxy;
147 : }
148 :
149 0 : void GrContext::abandonContext() {
150 0 : ASSERT_SINGLE_OWNER
151 :
152 0 : fResourceProvider->abandon();
153 :
154 : // Need to abandon the drawing manager first so all the render targets
155 : // will be released/forgotten before they too are abandoned.
156 0 : fDrawingManager->abandon();
157 :
158 : // abandon first to so destructors
159 : // don't try to free the resources in the API.
160 0 : fResourceCache->abandonAll();
161 :
162 0 : fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
163 :
164 0 : fAtlasGlyphCache->freeAll();
165 0 : fTextBlobCache->freeAll();
166 0 : }
167 :
168 0 : void GrContext::releaseResourcesAndAbandonContext() {
169 0 : ASSERT_SINGLE_OWNER
170 :
171 0 : fResourceProvider->abandon();
172 :
173 : // Need to abandon the drawing manager first so all the render targets
174 : // will be released/forgotten before they too are abandoned.
175 0 : fDrawingManager->abandon();
176 :
177 : // Release all resources in the backend 3D API.
178 0 : fResourceCache->releaseAll();
179 :
180 0 : fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
181 :
182 0 : fAtlasGlyphCache->freeAll();
183 0 : fTextBlobCache->freeAll();
184 0 : }
185 :
186 0 : void GrContext::resetContext(uint32_t state) {
187 0 : ASSERT_SINGLE_OWNER
188 0 : fGpu->markContextDirty(state);
189 0 : }
190 :
191 0 : void GrContext::freeGpuResources() {
192 0 : ASSERT_SINGLE_OWNER
193 :
194 0 : this->flush();
195 :
196 0 : fAtlasGlyphCache->freeAll();
197 :
198 0 : fDrawingManager->freeGpuResources();
199 :
200 0 : fResourceCache->purgeAllUnlocked();
201 0 : }
202 :
203 0 : void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) {
204 0 : ASSERT_SINGLE_OWNER
205 0 : fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms);
206 0 : }
207 :
208 0 : void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
209 0 : ASSERT_SINGLE_OWNER
210 :
211 0 : if (resourceCount) {
212 0 : *resourceCount = fResourceCache->getBudgetedResourceCount();
213 : }
214 0 : if (resourceBytes) {
215 0 : *resourceBytes = fResourceCache->getBudgetedResourceBytes();
216 : }
217 0 : }
218 :
219 : ////////////////////////////////////////////////////////////////////////////////
220 :
221 0 : void GrContext::TextBlobCacheOverBudgetCB(void* data) {
222 0 : SkASSERT(data);
223 : // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
224 : // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls
225 : // to below the GrContext level, but this is not trivial because they call drawPath on
226 : // SkGpuDevice.
227 0 : GrContext* context = reinterpret_cast<GrContext*>(data);
228 0 : context->flush();
229 0 : }
230 :
231 : ////////////////////////////////////////////////////////////////////////////////
232 :
233 0 : void GrContext::flush() {
234 0 : ASSERT_SINGLE_OWNER
235 0 : RETURN_IF_ABANDONED
236 :
237 0 : fDrawingManager->flush(nullptr);
238 : }
239 :
240 0 : void GrContextPriv::flush(GrSurfaceProxy* proxy) {
241 0 : ASSERT_SINGLE_OWNER_PRIV
242 0 : RETURN_IF_ABANDONED_PRIV
243 0 : ASSERT_OWNED_PROXY_PRIV(proxy);
244 :
245 0 : fContext->fDrawingManager->flush(proxy);
246 : }
247 :
248 0 : bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
249 : const void* inPixels, size_t outRowBytes, void* outPixels) {
250 : SkColorType colorType;
251 0 : if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
252 0 : 4 != SkColorTypeBytesPerPixel(colorType))
253 : {
254 0 : return false;
255 : }
256 :
257 0 : for (int y = 0; y < height; y++) {
258 0 : SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
259 0 : outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
260 0 : inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
261 : }
262 :
263 0 : return true;
264 : }
265 :
266 0 : static bool valid_unpremul_config(GrPixelConfig config) {
267 0 : return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
268 : }
269 :
270 0 : bool GrContextPriv::writeSurfacePixels(GrSurfaceProxy* dstProxy, SkColorSpace* dstColorSpace,
271 : int left, int top, int width, int height,
272 : GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
273 : const void* buffer, size_t rowBytes,
274 : uint32_t pixelOpsFlags) {
275 : // TODO: Color space conversion
276 :
277 0 : ASSERT_SINGLE_OWNER_PRIV
278 0 : RETURN_FALSE_IF_ABANDONED_PRIV
279 0 : ASSERT_OWNED_PROXY_PRIV(dstProxy);
280 0 : SkASSERT(dstProxy);
281 0 : GR_AUDIT_TRAIL_AUTO_FRAME(&fContext->fAuditTrail, "GrContextPriv::writeSurfacePixels");
282 :
283 0 : GrSurface* surface = dstProxy->instantiate(fContext->resourceProvider());
284 0 : if (!surface) {
285 0 : return false;
286 : }
287 :
288 0 : fContext->testPMConversionsIfNecessary(pixelOpsFlags);
289 :
290 : // Trim the params here so that if we wind up making a temporary surface it can be as small as
291 : // necessary and because GrGpu::getWritePixelsInfo requires it.
292 0 : if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(),
293 : GrBytesPerPixel(srcConfig), &left, &top, &width,
294 : &height, &buffer, &rowBytes)) {
295 0 : return false;
296 : }
297 :
298 0 : bool applyPremulToSrc = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
299 0 : if (applyPremulToSrc && !valid_unpremul_config(srcConfig)) {
300 0 : return false;
301 : }
302 : // We don't allow conversion between integer configs and float/fixed configs.
303 0 : if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(srcConfig)) {
304 0 : return false;
305 : }
306 :
307 0 : GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
308 : // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
309 : // we've already determined that there isn't a roundtrip preserving conversion processor pair.
310 0 : if (applyPremulToSrc && fContext->validPMUPMConversionExists(srcConfig)) {
311 0 : drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
312 : }
313 :
314 0 : GrGpu::WritePixelTempDrawInfo tempDrawInfo;
315 0 : if (!fContext->fGpu->getWritePixelsInfo(surface, width, height, srcConfig,
316 : &drawPreference, &tempDrawInfo)) {
317 0 : return false;
318 : }
319 :
320 0 : if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) {
321 0 : this->flush(nullptr); // MDB TODO: tighten this
322 : }
323 :
324 0 : sk_sp<GrTextureProxy> tempProxy;
325 0 : if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
326 0 : tempProxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
327 : tempDrawInfo.fTempSurfaceDesc,
328 : SkBackingFit::kApprox,
329 0 : SkBudgeted::kYes);
330 0 : if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
331 0 : return false;
332 : }
333 : }
334 :
335 : // temp buffer for doing sw premul conversion, if needed.
336 0 : SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
337 0 : if (tempProxy) {
338 : sk_sp<GrFragmentProcessor> texFP = GrSimpleTextureEffect::Make(
339 0 : fContext->resourceProvider(), tempProxy, nullptr, SkMatrix::I());
340 0 : sk_sp<GrFragmentProcessor> fp;
341 0 : if (applyPremulToSrc) {
342 0 : fp = fContext->createUPMToPMEffect(texFP, tempProxy->config());
343 0 : if (fp) {
344 : // We no longer need to do this on CPU before the upload.
345 0 : applyPremulToSrc = false;
346 0 : } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
347 : // We only wanted to do the draw to perform the premul so don't bother.
348 0 : tempProxy.reset(nullptr);
349 : }
350 : }
351 0 : if (tempProxy) {
352 0 : if (!fp) {
353 0 : fp = std::move(texFP);
354 : }
355 0 : fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
356 0 : SkASSERT(fp);
357 :
358 0 : if (tempProxy->priv().hasPendingIO()) {
359 0 : this->flush(tempProxy.get());
360 : }
361 0 : GrTexture* texture = tempProxy->instantiate(fContext->resourceProvider());
362 0 : if (!texture) {
363 0 : return false;
364 : }
365 0 : if (applyPremulToSrc) {
366 0 : size_t tmpRowBytes = 4 * width;
367 0 : tmpPixels.reset(width * height);
368 0 : if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
369 0 : tmpPixels.get())) {
370 0 : return false;
371 : }
372 0 : rowBytes = tmpRowBytes;
373 0 : buffer = tmpPixels.get();
374 0 : applyPremulToSrc = false;
375 : }
376 0 : if (!fContext->fGpu->writePixels(texture, 0, 0, width, height,
377 : tempDrawInfo.fWriteConfig, buffer,
378 : rowBytes)) {
379 0 : return false;
380 : }
381 : SkMatrix matrix;
382 0 : matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
383 : // TODO: Need to decide the semantics of this function for color spaces. Do we support
384 : // conversion from a passed-in color space? For now, specifying nullptr means that this
385 : // path will do no conversion, so it will match the behavior of the non-draw path.
386 0 : GrRenderTarget* renderTarget = surface->asRenderTarget();
387 0 : SkASSERT(renderTarget);
388 : sk_sp<GrRenderTargetContext> renderTargetContext(
389 0 : this->makeWrappedRenderTargetContext(sk_ref_sp(renderTarget), nullptr));
390 0 : if (!renderTargetContext) {
391 0 : return false;
392 : }
393 0 : GrPaint paint;
394 0 : paint.addColorFragmentProcessor(std::move(fp));
395 0 : paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
396 0 : paint.setAllowSRGBInputs(true);
397 0 : SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
398 0 : renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
399 0 : nullptr);
400 :
401 0 : if (kFlushWrites_PixelOp & pixelOpsFlags) {
402 0 : this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
403 : }
404 : }
405 : }
406 0 : if (!tempProxy) {
407 0 : if (applyPremulToSrc) {
408 0 : size_t tmpRowBytes = 4 * width;
409 0 : tmpPixels.reset(width * height);
410 0 : if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
411 0 : tmpPixels.get())) {
412 0 : return false;
413 : }
414 0 : rowBytes = tmpRowBytes;
415 0 : buffer = tmpPixels.get();
416 0 : applyPremulToSrc = false;
417 : }
418 0 : return fContext->fGpu->writePixels(surface, left, top, width, height, srcConfig,
419 0 : buffer, rowBytes);
420 : }
421 0 : return true;
422 : }
423 :
424 0 : bool GrContextPriv::readSurfacePixels(GrSurfaceProxy* srcProxy, SkColorSpace* srcColorSpace,
425 : int left, int top, int width, int height,
426 : GrPixelConfig dstConfig, SkColorSpace* dstColorSpace,
427 : void* buffer, size_t rowBytes, uint32_t flags) {
428 : // TODO: Color space conversion
429 :
430 0 : ASSERT_SINGLE_OWNER_PRIV
431 0 : RETURN_FALSE_IF_ABANDONED_PRIV
432 0 : ASSERT_OWNED_PROXY_PRIV(srcProxy);
433 0 : SkASSERT(srcProxy);
434 0 : GR_AUDIT_TRAIL_AUTO_FRAME(&fContext->fAuditTrail, "GrContextPriv::readSurfacePixels");
435 :
436 : // MDB TODO: delay this instantiation until later in the method
437 0 : GrSurface* src = srcProxy->instantiate(fContext->resourceProvider());
438 0 : if (!src) {
439 0 : return false;
440 : }
441 :
442 0 : fContext->testPMConversionsIfNecessary(flags);
443 :
444 : // Adjust the params so that if we wind up using an intermediate surface we've already done
445 : // all the trimming and the temporary can be the min size required.
446 0 : if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(),
447 : GrBytesPerPixel(dstConfig), &left,
448 : &top, &width, &height, &buffer, &rowBytes)) {
449 0 : return false;
450 : }
451 :
452 0 : if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) {
453 0 : this->flush(nullptr); // MDB TODO: tighten this
454 : }
455 :
456 0 : bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
457 0 : if (unpremul && !valid_unpremul_config(dstConfig)) {
458 : // The unpremul flag is only allowed for 8888 and F16 configs.
459 0 : return false;
460 : }
461 : // We don't allow conversion between integer configs and float/fixed configs.
462 0 : if (GrPixelConfigIsSint(src->config()) != GrPixelConfigIsSint(dstConfig)) {
463 0 : return false;
464 : }
465 :
466 0 : GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
467 : // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
468 : // we've already determined that there isn't a roundtrip preserving conversion processor pair.
469 0 : if (unpremul && fContext->validPMUPMConversionExists(src->config())) {
470 0 : drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
471 : }
472 :
473 0 : GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
474 0 : if (!fContext->fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig,
475 : &drawPreference, &tempDrawInfo)) {
476 0 : return false;
477 : }
478 :
479 0 : sk_sp<GrSurfaceProxy> proxyToRead = sk_ref_sp(srcProxy);
480 0 : bool didTempDraw = false;
481 0 : if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
482 0 : if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
483 : // We only respect this when the entire src is being read. Otherwise we can trigger too
484 : // many odd ball texture sizes and trash the cache.
485 0 : if (width != src->width() || height != src->height()) {
486 0 : tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
487 : }
488 : }
489 : // TODO: Need to decide the semantics of this function for color spaces. Do we support
490 : // conversion to a passed-in color space? For now, specifying nullptr means that this
491 : // path will do no conversion, so it will match the behavior of the non-draw path.
492 0 : sk_sp<GrRenderTargetContext> tempRTC = fContext->makeRenderTargetContext(
493 : tempDrawInfo.fTempSurfaceFit,
494 : tempDrawInfo.fTempSurfaceDesc.fWidth,
495 : tempDrawInfo.fTempSurfaceDesc.fHeight,
496 : tempDrawInfo.fTempSurfaceDesc.fConfig,
497 : nullptr,
498 : tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
499 0 : tempDrawInfo.fTempSurfaceDesc.fOrigin);
500 0 : if (tempRTC) {
501 0 : SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
502 0 : sk_sp<GrTextureProxy> proxy = sk_ref_sp(srcProxy->asTextureProxy());
503 : sk_sp<GrFragmentProcessor> texFP = GrSimpleTextureEffect::Make(
504 0 : fContext->resourceProvider(), proxy, nullptr, textureMatrix);
505 0 : sk_sp<GrFragmentProcessor> fp;
506 0 : if (unpremul) {
507 0 : fp = fContext->createPMToUPMEffect(texFP, proxy->config());
508 0 : if (fp) {
509 : // We no longer need to do this on CPU after the read back.
510 0 : unpremul = false;
511 0 : } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
512 : // We only wanted to do the draw to perform the unpremul so don't bother.
513 0 : tempRTC.reset(nullptr);
514 : }
515 : }
516 0 : if (tempRTC) {
517 0 : if (!fp) {
518 0 : fp = std::move(texFP);
519 : }
520 0 : fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
521 0 : SkASSERT(fp);
522 :
523 0 : GrPaint paint;
524 0 : paint.addColorFragmentProcessor(std::move(fp));
525 0 : paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
526 0 : paint.setAllowSRGBInputs(true);
527 0 : SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
528 0 : tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
529 0 : nullptr);
530 0 : proxyToRead = tempRTC->asTextureProxyRef();
531 0 : left = 0;
532 0 : top = 0;
533 0 : didTempDraw = true;
534 : }
535 : }
536 : }
537 :
538 0 : if (!proxyToRead) {
539 0 : return false;
540 : }
541 :
542 0 : GrSurface* surfaceToRead = proxyToRead->instantiate(fContext->resourceProvider());
543 0 : if (!surfaceToRead) {
544 0 : return false;
545 : }
546 :
547 0 : if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
548 0 : return false;
549 : }
550 0 : GrPixelConfig configToRead = dstConfig;
551 0 : if (didTempDraw) {
552 0 : this->flushSurfaceWrites(proxyToRead.get());
553 0 : configToRead = tempDrawInfo.fReadConfig;
554 : }
555 0 : if (!fContext->fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead,
556 : buffer, rowBytes)) {
557 0 : return false;
558 : }
559 :
560 : // Perform umpremul conversion if we weren't able to perform it as a draw.
561 0 : if (unpremul) {
562 : SkColorType colorType;
563 0 : if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
564 0 : 4 != SkColorTypeBytesPerPixel(colorType))
565 : {
566 0 : return false;
567 : }
568 :
569 0 : for (int y = 0; y < height; y++) {
570 0 : SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
571 0 : buffer = SkTAddOffset<void>(buffer, rowBytes);
572 : }
573 : }
574 0 : return true;
575 : }
576 :
577 0 : void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
578 0 : ASSERT_SINGLE_OWNER_PRIV
579 0 : RETURN_IF_ABANDONED_PRIV
580 0 : SkASSERT(proxy);
581 0 : ASSERT_OWNED_PROXY_PRIV(proxy);
582 0 : fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy);
583 : }
584 :
585 0 : void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
586 0 : ASSERT_SINGLE_OWNER_PRIV
587 0 : RETURN_IF_ABANDONED_PRIV
588 0 : SkASSERT(proxy);
589 0 : ASSERT_OWNED_PROXY_PRIV(proxy);
590 0 : if (proxy->priv().hasPendingWrite()) {
591 0 : this->flush(proxy);
592 : }
593 : }
594 :
595 0 : void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
596 0 : ASSERT_SINGLE_OWNER_PRIV
597 0 : RETURN_IF_ABANDONED_PRIV
598 0 : SkASSERT(proxy);
599 0 : ASSERT_OWNED_PROXY_PRIV(proxy);
600 0 : if (proxy->priv().hasPendingIO()) {
601 0 : this->flush(proxy);
602 : }
603 : }
604 :
605 : ////////////////////////////////////////////////////////////////////////////////
606 0 : int GrContext::getRecommendedSampleCount(GrPixelConfig config,
607 : SkScalar dpi) const {
608 0 : ASSERT_SINGLE_OWNER
609 :
610 0 : if (!this->caps()->isConfigRenderable(config, true)) {
611 0 : return 0;
612 : }
613 0 : int chosenSampleCount = 0;
614 0 : if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
615 0 : if (dpi >= 250.0f) {
616 0 : chosenSampleCount = 4;
617 : } else {
618 0 : chosenSampleCount = 16;
619 : }
620 : }
621 0 : return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0;
622 : }
623 :
624 0 : sk_sp<GrRenderTargetContext> GrContextPriv::makeWrappedRenderTargetContext(
625 : sk_sp<GrRenderTarget> rt,
626 : sk_sp<SkColorSpace> colorSpace,
627 : const SkSurfaceProps* surfaceProps) {
628 0 : ASSERT_SINGLE_OWNER_PRIV
629 :
630 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt)));
631 0 : if (!proxy) {
632 0 : return nullptr;
633 : }
634 :
635 0 : return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
636 0 : std::move(colorSpace),
637 0 : surfaceProps);
638 : }
639 :
640 0 : sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
641 : sk_sp<SkColorSpace> colorSpace) {
642 0 : ASSERT_SINGLE_OWNER_PRIV
643 :
644 0 : if (proxy->asRenderTargetProxy()) {
645 0 : return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
646 0 : std::move(colorSpace), nullptr);
647 : } else {
648 0 : SkASSERT(proxy->asTextureProxy());
649 0 : return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
650 : }
651 : }
652 :
653 0 : sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurface> surface) {
654 0 : ASSERT_SINGLE_OWNER_PRIV
655 :
656 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
657 0 : if (!proxy) {
658 0 : return nullptr;
659 : }
660 :
661 0 : return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
662 : }
663 :
664 0 : sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
665 : SkBackingFit fit,
666 : SkBudgeted isDstBudgeted) {
667 :
668 0 : sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
669 0 : dstDesc, fit, isDstBudgeted);
670 0 : if (!proxy) {
671 0 : return nullptr;
672 : }
673 :
674 0 : return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
675 : }
676 :
677 0 : sk_sp<GrSurfaceContext> GrContextPriv::makeBackendSurfaceContext(const GrBackendTextureDesc& desc,
678 : sk_sp<SkColorSpace> colorSpace) {
679 0 : ASSERT_SINGLE_OWNER_PRIV
680 :
681 0 : sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(desc));
682 0 : if (!surface) {
683 0 : return nullptr;
684 : }
685 :
686 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
687 0 : if (!proxy) {
688 0 : return nullptr;
689 : }
690 :
691 0 : return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace));
692 : }
693 :
694 0 : sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
695 : const GrBackendTextureDesc& desc,
696 : sk_sp<SkColorSpace> colorSpace,
697 : const SkSurfaceProps* props) {
698 0 : ASSERT_SINGLE_OWNER_PRIV
699 0 : SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
700 :
701 0 : sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(desc));
702 0 : if (!surface) {
703 0 : return nullptr;
704 : }
705 :
706 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
707 0 : if (!proxy) {
708 0 : return nullptr;
709 : }
710 :
711 0 : return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
712 0 : std::move(colorSpace), props);
713 : }
714 :
715 0 : sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
716 : const GrBackendRenderTargetDesc& desc,
717 : sk_sp<SkColorSpace> colorSpace,
718 : const SkSurfaceProps* surfaceProps) {
719 0 : ASSERT_SINGLE_OWNER_PRIV
720 :
721 0 : sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(desc));
722 0 : if (!rt) {
723 0 : return nullptr;
724 : }
725 :
726 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt)));
727 0 : if (!proxy) {
728 0 : return nullptr;
729 : }
730 :
731 0 : return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
732 0 : std::move(colorSpace),
733 0 : surfaceProps);
734 : }
735 :
736 0 : sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
737 : const GrBackendTextureDesc& desc,
738 : sk_sp<SkColorSpace> colorSpace,
739 : const SkSurfaceProps* surfaceProps) {
740 0 : ASSERT_SINGLE_OWNER_PRIV
741 0 : SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
742 :
743 0 : sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(desc));
744 0 : if (!surface) {
745 0 : return nullptr;
746 : }
747 :
748 0 : sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
749 0 : if (!proxy) {
750 0 : return nullptr;
751 : }
752 :
753 0 : return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
754 0 : std::move(colorSpace),
755 0 : surfaceProps);
756 : }
757 :
758 0 : void GrContextPriv::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) {
759 0 : fContext->fDrawingManager->addPreFlushCallbackObject(std::move(preFlushCBObject));
760 0 : }
761 :
762 :
763 0 : static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
764 0 : switch (config) {
765 : case kAlpha_8_GrPixelConfig:
766 : case kRGB_565_GrPixelConfig:
767 : case kRGBA_4444_GrPixelConfig:
768 : case kBGRA_8888_GrPixelConfig:
769 0 : return kRGBA_8888_GrPixelConfig;
770 : case kSBGRA_8888_GrPixelConfig:
771 0 : return kSRGBA_8888_GrPixelConfig;
772 : case kAlpha_half_GrPixelConfig:
773 0 : return kRGBA_half_GrPixelConfig;
774 : default:
775 0 : return kUnknown_GrPixelConfig;
776 : }
777 : }
778 :
779 0 : sk_sp<GrRenderTargetContext> GrContext::makeRenderTargetContextWithFallback(
780 : SkBackingFit fit,
781 : int width, int height,
782 : GrPixelConfig config,
783 : sk_sp<SkColorSpace> colorSpace,
784 : int sampleCnt,
785 : GrSurfaceOrigin origin,
786 : const SkSurfaceProps* surfaceProps,
787 : SkBudgeted budgeted) {
788 0 : if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
789 0 : config = GrPixelConfigFallback(config);
790 : }
791 :
792 0 : return this->makeRenderTargetContext(fit, width, height, config, std::move(colorSpace),
793 0 : sampleCnt, origin, surfaceProps, budgeted);
794 : }
795 :
796 0 : sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
797 : SkBackingFit fit,
798 : int width, int height,
799 : GrPixelConfig config,
800 : sk_sp<SkColorSpace> colorSpace,
801 : int sampleCnt,
802 : GrSurfaceOrigin origin,
803 : const SkSurfaceProps* surfaceProps,
804 : SkBudgeted budgeted) {
805 0 : if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
806 0 : config = GrPixelConfigFallback(config);
807 : }
808 :
809 0 : return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
810 0 : sampleCnt, origin, surfaceProps, budgeted);
811 : }
812 :
813 0 : sk_sp<GrRenderTargetContext> GrContext::makeRenderTargetContext(SkBackingFit fit,
814 : int width, int height,
815 : GrPixelConfig config,
816 : sk_sp<SkColorSpace> colorSpace,
817 : int sampleCnt,
818 : GrSurfaceOrigin origin,
819 : const SkSurfaceProps* surfaceProps,
820 : SkBudgeted budgeted) {
821 0 : if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
822 0 : return nullptr;
823 : }
824 :
825 0 : GrSurfaceDesc desc;
826 0 : desc.fFlags = kRenderTarget_GrSurfaceFlag;
827 0 : desc.fOrigin = origin;
828 0 : desc.fWidth = width;
829 0 : desc.fHeight = height;
830 0 : desc.fConfig = config;
831 0 : desc.fSampleCnt = sampleCnt;
832 :
833 0 : sk_sp<GrTexture> tex;
834 0 : if (SkBackingFit::kExact == fit) {
835 0 : tex = this->resourceProvider()->createTexture(desc, budgeted);
836 : } else {
837 0 : tex.reset(this->resourceProvider()->createApproxTexture(desc, 0));
838 : }
839 0 : if (!tex) {
840 0 : return nullptr;
841 : }
842 :
843 : sk_sp<GrRenderTargetContext> renderTargetContext(
844 0 : this->contextPriv().makeWrappedRenderTargetContext(sk_ref_sp(tex->asRenderTarget()),
845 0 : std::move(colorSpace), surfaceProps));
846 0 : if (!renderTargetContext) {
847 0 : return nullptr;
848 : }
849 :
850 0 : renderTargetContext->discard();
851 :
852 0 : return renderTargetContext;
853 : }
854 :
855 0 : sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
856 : SkBackingFit fit,
857 : int width, int height,
858 : GrPixelConfig config,
859 : sk_sp<SkColorSpace> colorSpace,
860 : int sampleCnt,
861 : GrSurfaceOrigin origin,
862 : const SkSurfaceProps* surfaceProps,
863 : SkBudgeted budgeted) {
864 0 : GrSurfaceDesc desc;
865 0 : desc.fFlags = kRenderTarget_GrSurfaceFlag;
866 0 : desc.fOrigin = origin;
867 0 : desc.fWidth = width;
868 0 : desc.fHeight = height;
869 0 : desc.fConfig = config;
870 0 : desc.fSampleCnt = sampleCnt;
871 :
872 : sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(),
873 0 : desc, fit, budgeted);
874 0 : if (!rtp) {
875 0 : return nullptr;
876 : }
877 :
878 : sk_sp<GrRenderTargetContext> renderTargetContext(
879 0 : fDrawingManager->makeRenderTargetContext(std::move(rtp),
880 0 : std::move(colorSpace),
881 0 : surfaceProps));
882 :
883 0 : if (!renderTargetContext) {
884 0 : return nullptr;
885 : }
886 :
887 0 : renderTargetContext->discard();
888 :
889 0 : return renderTargetContext;
890 : }
891 :
892 0 : bool GrContext::abandoned() const {
893 0 : ASSERT_SINGLE_OWNER
894 0 : return fDrawingManager->wasAbandoned();
895 : }
896 :
897 : namespace {
898 0 : void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
899 : GrConfigConversionEffect::PMConversion pmToUPM;
900 : GrConfigConversionEffect::PMConversion upmToPM;
901 0 : GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
902 0 : *pmToUPMValue = pmToUPM;
903 0 : *upmToPMValue = upmToPM;
904 0 : }
905 : }
906 :
907 0 : void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
908 0 : ASSERT_SINGLE_OWNER
909 0 : if (SkToBool(GrContextPriv::kUnpremul_PixelOpsFlag & flags)) {
910 0 : if (!fDidTestPMConversions) {
911 0 : test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
912 0 : fDidTestPMConversions = true;
913 : }
914 : }
915 0 : }
916 :
917 0 : sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(sk_sp<GrFragmentProcessor> fp,
918 : GrPixelConfig config) {
919 0 : ASSERT_SINGLE_OWNER
920 : // We should have already called this->testPMConversionsIfNecessary().
921 0 : SkASSERT(fDidTestPMConversions);
922 0 : if (kRGBA_half_GrPixelConfig == config) {
923 0 : return GrFragmentProcessor::UnpremulOutput(std::move(fp));
924 0 : } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) {
925 : GrConfigConversionEffect::PMConversion pmToUPM =
926 0 : static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
927 0 : if (GrConfigConversionEffect::kPMConversionCnt != pmToUPM) {
928 0 : return GrConfigConversionEffect::Make(std::move(fp), pmToUPM);
929 : }
930 : }
931 0 : return nullptr;
932 : }
933 :
934 0 : sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrFragmentProcessor> fp,
935 : GrPixelConfig config) {
936 0 : ASSERT_SINGLE_OWNER
937 : // We should have already called this->testPMConversionsIfNecessary().
938 0 : SkASSERT(fDidTestPMConversions);
939 0 : if (kRGBA_half_GrPixelConfig == config) {
940 0 : return GrFragmentProcessor::PremulOutput(std::move(fp));
941 0 : } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) {
942 : GrConfigConversionEffect::PMConversion upmToPM =
943 0 : static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
944 0 : if (GrConfigConversionEffect::kPMConversionCnt != upmToPM) {
945 0 : return GrConfigConversionEffect::Make(std::move(fp), upmToPM);
946 : }
947 : }
948 0 : return nullptr;
949 : }
950 :
951 0 : bool GrContext::validPMUPMConversionExists(GrPixelConfig config) const {
952 0 : ASSERT_SINGLE_OWNER
953 : // We should have already called this->testPMConversionsIfNecessary().
954 0 : SkASSERT(fDidTestPMConversions);
955 : // The PM<->UPM tests fail or succeed together so we only need to check one.
956 : // For F16, we always allow PM/UPM conversion on the GPU, even if it doesn't round-trip.
957 0 : return GrConfigConversionEffect::kPMConversionCnt != fPMToUPMConversion ||
958 0 : kRGBA_half_GrPixelConfig == config;
959 : }
960 :
961 : //////////////////////////////////////////////////////////////////////////////
962 :
963 0 : void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
964 0 : ASSERT_SINGLE_OWNER
965 0 : if (maxTextures) {
966 0 : *maxTextures = fResourceCache->getMaxResourceCount();
967 : }
968 0 : if (maxTextureBytes) {
969 0 : *maxTextureBytes = fResourceCache->getMaxResourceBytes();
970 : }
971 0 : }
972 :
973 0 : void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
974 0 : ASSERT_SINGLE_OWNER
975 0 : fResourceCache->setLimits(maxTextures, maxTextureBytes);
976 0 : }
977 :
978 : //////////////////////////////////////////////////////////////////////////////
979 :
980 0 : void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
981 0 : ASSERT_SINGLE_OWNER
982 0 : fResourceCache->dumpMemoryStatistics(traceMemoryDump);
983 0 : }
|