blob: 0e74f68577f25cdecc90fd81441ddd09b3fdcb02 [file] [log] [blame]
reed@google.com5d4ba882012-07-31 15:45:27 +00001/*
2 * Copyright 2012 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
cblume33e0cb52016-08-30 12:09:23 -07008#include <cstddef>
9#include <cstring>
10#include <type_traits>
11
robertphillipsc5035e72016-03-17 06:58:39 -070012#include "SkAutoPixmapStorage.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050013#include "GrBitmapTextureMaker.h"
reed856e9d92015-09-30 12:21:45 -070014#include "GrCaps.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000015#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050016#include "GrContextPriv.h"
Brian Osman2c2bc112017-02-28 10:02:49 -050017#include "GrGpu.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050018#include "GrImageTextureMaker.h"
Brian Osman11052242016-10-27 14:47:55 -040019#include "GrRenderTargetContext.h"
Brian Osman32342f02017-03-04 08:12:46 -050020#include "GrResourceProvider.h"
Brian Osmanfe3b5162017-03-02 15:09:20 -050021#include "GrSemaphore.h"
Brian Osmane8e54582016-11-28 10:06:27 -050022#include "GrTextureAdjuster.h"
cblume33e0cb52016-08-30 12:09:23 -070023#include "GrTexturePriv.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050024#include "GrTextureProxy.h"
Robert Phillips538f1a32017-03-08 14:32:55 -050025#include "GrTextureToYUVPlanes.h"
Brian Osman63954c92017-03-14 12:07:12 -040026#include "effects/GrNonlinearColorSpaceXformEffect.h"
bsalomonf267c1e2016-02-01 13:16:14 -080027#include "effects/GrYUVEffect.h"
bsalomon993a4212015-05-29 11:37:25 -070028#include "SkCanvas.h"
Brian Osman2c2bc112017-02-28 10:02:49 -050029#include "SkCrossContextImageData.h"
reed262a71b2015-12-05 13:07:27 -080030#include "SkBitmapCache.h"
Brian Osman3b655982017-03-07 16:58:08 -050031#include "SkGr.h"
reed262a71b2015-12-05 13:07:27 -080032#include "SkImage_Gpu.h"
Brian Osman7992da32016-11-18 11:28:24 -050033#include "SkImageCacherator.h"
Matt Sarettcb6266b2017-01-17 10:48:53 -050034#include "SkImageInfoPriv.h"
ericrkb4da01d2016-06-13 11:18:14 -070035#include "SkMipMap.h"
reed6f1216a2015-08-04 08:10:13 -070036#include "SkPixelRef.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050037#include "SkReadPixelsRec.h"
bsalomon993a4212015-05-29 11:37:25 -070038
Robert Phillipsb726d582017-03-09 16:36:32 -050039SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
40 sk_sp<GrTextureProxy> proxy,
41 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
42 : INHERITED(proxy->width(), proxy->height(), uniqueID)
43 , fContext(context)
44 , fProxy(std::move(proxy))
45 , fAlphaType(at)
46 , fBudgeted(budgeted)
47 , fColorSpace(std::move(colorSpace))
48 , fAddedRasterVersionToCache(false) {
reedc9b5f8b2015-10-22 13:20:20 -070049}
piotaixrcef04f82014-07-14 07:48:04 -070050
reed6f1216a2015-08-04 08:10:13 -070051SkImage_Gpu::~SkImage_Gpu() {
52 if (fAddedRasterVersionToCache.load()) {
53 SkNotifyBitmapGenIDIsStale(this->uniqueID());
54 }
55}
56
brianosman396fcdb2016-07-22 06:26:11 -070057SkImageInfo SkImage_Gpu::onImageInfo() const {
58 SkColorType ct;
Robert Phillipsb726d582017-03-09 16:36:32 -050059 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
brianosman396fcdb2016-07-22 06:26:11 -070060 ct = kUnknown_SkColorType;
61 }
Robert Phillipsb726d582017-03-09 16:36:32 -050062 return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
brianosman396fcdb2016-07-22 06:26:11 -070063}
64
Brian Salomon2084ffa2017-03-27 17:32:18 -040065static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp<SkColorSpace> colorSpace) {
66 return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace));
67}
68
Brian Osmanf4d443f2017-03-24 11:22:31 -040069bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint chint) const {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040070 const auto desc = SkBitmapCacheDesc::Make(this);
71 if (SkBitmapCache::Find(desc, dst)) {
reed6f1216a2015-08-04 08:10:13 -070072 SkASSERT(dst->getGenerationID() == this->uniqueID());
73 SkASSERT(dst->isImmutable());
74 SkASSERT(dst->getPixels());
75 return true;
76 }
77
Brian Salomon2084ffa2017-03-27 17:32:18 -040078 SkImageInfo ii = make_info(this->width(), this->height(), this->alphaType(),
79 sk_ref_sp(dstColorSpace));
Mike Reed7a542c52017-04-11 12:03:44 -040080 SkBitmapCache::RecPtr rec = nullptr;
81 SkPixmap pmap;
82 if (kAllow_CachingHint == chint) {
83 rec = SkBitmapCache::Alloc(desc, ii, &pmap);
84 if (!rec) {
85 return false;
86 }
87 } else {
88 if (!dst->tryAllocPixels(ii)) {
89 return false;
90 }
reed8b26b992015-05-07 15:36:17 -070091 }
Robert Phillipsb726d582017-03-09 16:36:32 -050092
Brian Salomon2084ffa2017-03-27 17:32:18 -040093 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
94 fProxy,
95 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -050096 if (!sContext) {
97 return false;
98 }
99
Mike Reed7a542c52017-04-11 12:03:44 -0400100 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
reed8b26b992015-05-07 15:36:17 -0700101 return false;
102 }
reed6f1216a2015-08-04 08:10:13 -0700103
Mike Reed7a542c52017-04-11 12:03:44 -0400104 if (rec) {
105 SkBitmapCache::Add(std::move(rec), dst);
reed09553032015-11-23 12:32:16 -0800106 fAddedRasterVersionToCache.store(true);
107 }
reed8b26b992015-05-07 15:36:17 -0700108 return true;
109}
110
Robert Phillipsb726d582017-03-09 16:36:32 -0500111sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
112 const GrSamplerParams& params,
113 SkColorSpace* dstColorSpace,
114 sk_sp<SkColorSpace>* texColorSpace,
115 SkScalar scaleAdjust[2]) const {
Robert Phillips30a38ff2017-03-22 10:31:11 -0400116 if (context != fContext) {
Robert Phillipsb726d582017-03-09 16:36:32 -0500117 SkASSERT(0);
118 return nullptr;
119 }
120
Brian Osman7992da32016-11-18 11:28:24 -0500121 if (texColorSpace) {
122 *texColorSpace = this->fColorSpace;
123 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500124
Robert Phillips3798c862017-03-27 11:08:16 -0400125 GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(),
Brian Osman7992da32016-11-18 11:28:24 -0500126 this->uniqueID(), this->fColorSpace.get());
Robert Phillips3798c862017-03-27 11:08:16 -0400127 return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
reed85d91782015-09-10 14:33:38 -0700128}
129
reed8b26b992015-05-07 15:36:17 -0700130static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
131 switch (info.colorType()) {
132 case kRGBA_8888_SkColorType:
133 case kBGRA_8888_SkColorType:
134 break;
135 default:
136 return; // nothing to do
137 }
138
139 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
140 // and in either case, the alpha-byte is always in the same place, so we can safely call
141 // SkPreMultiplyColor()
142 //
143 SkColor* row = (SkColor*)pixels;
144 for (int y = 0; y < info.height(); ++y) {
145 for (int x = 0; x < info.width(); ++x) {
146 row[x] = SkPreMultiplyColor(row[x]);
147 }
148 }
149}
150
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400151GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
152 GrSurfaceOrigin* origin) const {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400153 SkASSERT(fProxy);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400154
Robert Phillips7ee385e2017-03-30 08:02:11 -0400155 GrSurface* surface = fProxy->instantiate(fContext->resourceProvider());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400156 if (surface && surface->asTexture()) {
157 if (flushPendingGrContextIO) {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400158 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400159 }
160 if (origin) {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400161 *origin = fProxy->origin();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400162 }
163 return surface->asTexture()->getTextureHandle();
164 }
165 return 0;
166}
167
168GrTexture* SkImage_Gpu::onGetTexture() const {
169 GrTextureProxy* proxy = this->peekProxy();
170 if (!proxy) {
171 return nullptr;
172 }
173
174 return proxy->instantiate(fContext->resourceProvider());
175}
176
Robert Phillips538f1a32017-03-08 14:32:55 -0500177bool SkImage_Gpu::onReadYUV8Planes(const SkISize sizes[3], void* const planes[3],
178 const size_t rowBytes[3], SkYUVColorSpace colorSpace) const {
Robert Phillipsb726d582017-03-09 16:36:32 -0500179 if (GrTextureToYUVPlanes(fContext, fProxy, sizes, planes, rowBytes, colorSpace)) {
180 return true;
Robert Phillips538f1a32017-03-08 14:32:55 -0500181 }
182
183 return INHERITED::onReadYUV8Planes(sizes, planes, rowBytes, colorSpace);
184}
185
Matt Sarett03dd6d52017-01-23 12:15:09 -0500186bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
reed09553032015-11-23 12:32:16 -0800187 int srcX, int srcY, CachingHint) const {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500188 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500189 return false;
190 }
191
Matt Sarett03dd6d52017-01-23 12:15:09 -0500192 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
193 if (!rec.trim(this->width(), this->height())) {
194 return false;
195 }
196
Robert Phillipsb726d582017-03-09 16:36:32 -0500197 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
198 // GrRenderTargetContext::onReadPixels
reed8b26b992015-05-07 15:36:17 -0700199 uint32_t flags = 0;
Matt Sarett03dd6d52017-01-23 12:15:09 -0500200 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
reed8b26b992015-05-07 15:36:17 -0700201 // let the GPU perform this transformation for us
Robert Phillipse78b7252017-04-06 07:59:41 -0400202 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
reed8b26b992015-05-07 15:36:17 -0700203 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500204
Brian Salomon2084ffa2017-03-27 17:32:18 -0400205 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
206 fProxy,
207 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500208 if (!sContext) {
reed8b26b992015-05-07 15:36:17 -0700209 return false;
210 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500211
212 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
213 return false;
214 }
215
reed8b26b992015-05-07 15:36:17 -0700216 // do we have to manually fix-up the alpha channel?
217 // src dst
218 // unpremul premul fix manually
219 // premul unpremul done by kUnpremul_PixelOpsFlag
220 // all other combos need to change.
221 //
222 // Should this be handled by Ganesh? todo:?
223 //
Matt Sarett03dd6d52017-01-23 12:15:09 -0500224 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
225 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
reed8b26b992015-05-07 15:36:17 -0700226 }
227 return true;
228}
229
reed7fb4f8b2016-03-11 04:33:52 -0800230sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
Robert Phillipsb726d582017-03-09 16:36:32 -0500231 GrSurfaceDesc desc = fProxy->desc();
reed7b6945b2015-09-24 00:50:58 -0700232 desc.fWidth = subset.width();
233 desc.fHeight = subset.height();
234
Robert Phillipsb726d582017-03-09 16:36:32 -0500235 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
Robert Phillipse2f7d182016-12-15 09:23:05 -0500236 desc,
237 SkBackingFit::kExact,
238 fBudgeted));
239 if (!sContext) {
240 return nullptr;
241 }
242
Robert Phillipsb726d582017-03-09 16:36:32 -0500243 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500244 return nullptr;
245 }
246
Robert Phillipsb726d582017-03-09 16:36:32 -0500247 // MDB: this call is okay bc we know 'sContext' was kExact
248 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
249 fAlphaType, sContext->asTextureProxyRef(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500250 fColorSpace, fBudgeted);
reed7b6945b2015-09-24 00:50:58 -0700251}
252
reed8b26b992015-05-07 15:36:17 -0700253///////////////////////////////////////////////////////////////////////////////////////////////////
254
reed7fb4f8b2016-03-11 04:33:52 -0800255static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc,
brianosmandddbe382016-07-20 13:55:39 -0700256 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
257 GrWrapOwnership ownership,
reed7fb4f8b2016-03-11 04:33:52 -0800258 SkImage::TextureReleaseProc releaseProc,
259 SkImage::ReleaseContext releaseCtx) {
reed8b26b992015-05-07 15:36:17 -0700260 if (desc.fWidth <= 0 || desc.fHeight <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700261 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700262 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400263
Brian Osman32342f02017-03-04 08:12:46 -0500264 sk_sp<GrTexture> tex = ctx->resourceProvider()->wrapBackendTexture(desc, ownership);
reed8b26b992015-05-07 15:36:17 -0700265 if (!tex) {
halcanary96fcdcc2015-08-27 07:41:13 -0700266 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700267 }
reedde499882015-06-18 13:41:40 -0700268 if (releaseProc) {
269 tex->setRelease(releaseProc, releaseCtx);
270 }
271
Brian Osman766fcbb2017-03-13 09:33:09 -0400272 const SkBudgeted budgeted = (kAdoptAndCache_GrWrapOwnership == ownership)
273 ? SkBudgeted::kYes : SkBudgeted::kNo;
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400274 sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
275 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
276 at, std::move(proxy), std::move(colorSpace), budgeted);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700277}
278
reed7fb4f8b2016-03-11 04:33:52 -0800279sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
brianosmandddbe382016-07-20 13:55:39 -0700280 SkAlphaType at, sk_sp<SkColorSpace> cs,
281 TextureReleaseProc releaseP, ReleaseContext releaseC) {
282 return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kBorrow_GrWrapOwnership,
283 releaseP, releaseC);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700284}
285
reed7fb4f8b2016-03-11 04:33:52 -0800286sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
brianosmandddbe382016-07-20 13:55:39 -0700287 SkAlphaType at, sk_sp<SkColorSpace> cs) {
288 return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kAdopt_GrWrapOwnership,
289 nullptr, nullptr);
reed8b26b992015-05-07 15:36:17 -0700290}
291
Greg Daniel94403452017-04-18 15:52:36 -0400292sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
293 const GrBackendTexture& tex, GrSurfaceOrigin origin,
294 SkAlphaType at, sk_sp<SkColorSpace> cs,
295 TextureReleaseProc releaseP, ReleaseContext releaseC) {
296 // This function is not implemented yet
297 sk_throw();
298 return nullptr;
299}
300
301sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
302 const GrBackendTexture& tex, GrSurfaceOrigin origin,
303 SkAlphaType at, sk_sp<SkColorSpace> cs) {
304 // This function is not implemented yet
305 sk_throw();
306 return nullptr;
307}
308
jbaumanb445a572016-06-09 13:24:48 -0700309static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
310 bool nv12,
311 const GrBackendObject yuvTextureHandles[],
312 const SkISize yuvSizes[],
brianosmandddbe382016-07-20 13:55:39 -0700313 GrSurfaceOrigin origin,
314 sk_sp<SkColorSpace> imageColorSpace) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800315 const SkBudgeted budgeted = SkBudgeted::kYes;
bsalomon993a4212015-05-29 11:37:25 -0700316
jbaumanb445a572016-06-09 13:24:48 -0700317 if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 ||
318 yuvSizes[1].fHeight <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700320 }
jbaumanb445a572016-06-09 13:24:48 -0700321 if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
322 return nullptr;
323 }
324
325 const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
326
bsalomon993a4212015-05-29 11:37:25 -0700327 GrBackendTextureDesc yDesc;
328 yDesc.fConfig = kConfig;
329 yDesc.fOrigin = origin;
330 yDesc.fSampleCnt = 0;
331 yDesc.fTextureHandle = yuvTextureHandles[0];
332 yDesc.fWidth = yuvSizes[0].fWidth;
333 yDesc.fHeight = yuvSizes[0].fHeight;
334
335 GrBackendTextureDesc uDesc;
336 uDesc.fConfig = kConfig;
337 uDesc.fOrigin = origin;
338 uDesc.fSampleCnt = 0;
339 uDesc.fTextureHandle = yuvTextureHandles[1];
340 uDesc.fWidth = yuvSizes[1].fWidth;
341 uDesc.fHeight = yuvSizes[1].fHeight;
342
Robert Phillips26caf892017-01-27 10:58:31 -0500343 sk_sp<GrSurfaceProxy> yProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, yDesc);
344 sk_sp<GrSurfaceProxy> uProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, uDesc);
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500345 sk_sp<GrSurfaceProxy> vProxy;
346
jbaumanb445a572016-06-09 13:24:48 -0700347 if (nv12) {
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500348 vProxy = uProxy;
jbaumanb445a572016-06-09 13:24:48 -0700349 } else {
350 GrBackendTextureDesc vDesc;
351 vDesc.fConfig = kConfig;
352 vDesc.fOrigin = origin;
353 vDesc.fSampleCnt = 0;
354 vDesc.fTextureHandle = yuvTextureHandles[2];
355 vDesc.fWidth = yuvSizes[2].fWidth;
356 vDesc.fHeight = yuvSizes[2].fHeight;
bsalomon993a4212015-05-29 11:37:25 -0700357
Robert Phillips26caf892017-01-27 10:58:31 -0500358 vProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, vDesc);
jbaumanb445a572016-06-09 13:24:48 -0700359 }
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500360 if (!yProxy || !uProxy || !vProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700361 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700362 }
363
robertphillipsd4c741e2016-04-28 09:55:15 -0700364 const int width = yuvSizes[0].fWidth;
365 const int height = yuvSizes[0].fHeight;
robertphillipsaa19a5f2016-04-28 06:21:55 -0700366
robertphillipsd4c741e2016-04-28 09:55:15 -0700367 // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
Robert Phillips93429212017-04-11 12:23:17 +0000368 sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeRenderTargetContext(
Brian Osman11052242016-10-27 14:47:55 -0400369 SkBackingFit::kExact,
370 width, height,
371 kRGBA_8888_GrPixelConfig,
372 std::move(imageColorSpace),
373 0,
374 origin));
375 if (!renderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700376 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700377 }
378
379 GrPaint paint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400380 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
jbaumanb445a572016-06-09 13:24:48 -0700381 paint.addColorFragmentProcessor(
Robert Phillips296b1cc2017-03-15 10:42:12 -0400382 GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(),
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500383 sk_ref_sp(yProxy->asTextureProxy()),
384 sk_ref_sp(uProxy->asTextureProxy()),
385 sk_ref_sp(vProxy->asTextureProxy()), yuvSizes, colorSpace, nv12));
bsalomon993a4212015-05-29 11:37:25 -0700386
Robert Phillipsb726d582017-03-09 16:36:32 -0500387 const SkRect rect = SkRect::MakeIWH(width, height);
robertphillipsc9a37062015-09-01 08:34:28 -0700388
Brian Salomon82f44312017-01-11 13:42:54 -0500389 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
Robert Phillipse60ad622016-11-17 10:22:48 -0500390
Robert Phillips7ee385e2017-03-30 08:02:11 -0400391 if (!renderTargetContext->asSurfaceProxy()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500392 return nullptr;
393 }
Robert Phillips7ee385e2017-03-30 08:02:11 -0400394 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
Robert Phillipsb726d582017-03-09 16:36:32 -0500395
396 // MDB: this call is okay bc we know 'renderTargetContext' was exact
397 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
398 kOpaque_SkAlphaType, renderTargetContext->asTextureProxyRef(),
Robert Phillips75a475c2017-01-13 09:18:59 -0500399 renderTargetContext->refColorSpace(), budgeted);
bsalomon993a4212015-05-29 11:37:25 -0700400}
reed56179002015-07-07 06:11:19 -0700401
jbaumanb445a572016-06-09 13:24:48 -0700402sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
403 const GrBackendObject yuvTextureHandles[3],
brianosmandddbe382016-07-20 13:55:39 -0700404 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
405 sk_sp<SkColorSpace> imageColorSpace) {
406 return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
407 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700408}
409
410sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
411 const GrBackendObject yuvTextureHandles[2],
412 const SkISize yuvSizes[2],
brianosmandddbe382016-07-20 13:55:39 -0700413 GrSurfaceOrigin origin,
414 sk_sp<SkColorSpace> imageColorSpace) {
415 return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
416 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700417}
418
Robert Phillips3798c862017-03-27 11:08:16 -0400419static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
420 SkAlphaType at, uint32_t id,
Brian Osman041f7df2017-02-07 11:23:28 -0500421 SkColorSpace* dstColorSpace) {
422 sk_sp<SkColorSpace> texColorSpace;
Robert Phillips3798c862017-03-27 11:08:16 -0400423 sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
424 dstColorSpace,
425 &texColorSpace, nullptr));
426 if (!proxy) {
Brian Osman041f7df2017-02-07 11:23:28 -0500427 return nullptr;
428 }
Robert Phillips3798c862017-03-27 11:08:16 -0400429 return sk_make_sp<SkImage_Gpu>(context, id, at,
430 std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
Brian Osman041f7df2017-02-07 11:23:28 -0500431}
432
Brian Osman2c2bc112017-02-28 10:02:49 -0500433sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
Brian Osman041f7df2017-02-07 11:23:28 -0500434 if (!context) {
435 return nullptr;
436 }
437 if (GrTexture* peek = as_IB(this)->peekTexture()) {
438 return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
439 }
440
441 if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
442 GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400443 return create_image_from_maker(context, &maker, this->alphaType(),
444 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500445 }
446
447 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
448 GrBitmapTextureMaker maker(context, *bmp);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400449 return create_image_from_maker(context, &maker, this->alphaType(),
450 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500451 }
452 return nullptr;
453}
454
Brian Osman2c2bc112017-02-28 10:02:49 -0500455std::unique_ptr<SkCrossContextImageData> SkCrossContextImageData::MakeFromEncoded(
456 GrContext* context, sk_sp<SkData> encoded, SkColorSpace* dstColorSpace) {
457 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
458 if (!codecImage) {
459 return nullptr;
460 }
461
462 // Some backends or drivers don't support (safely) moving resources between contexts
463 if (!context->caps()->crossContextTextureSupport()) {
464 return std::unique_ptr<SkCrossContextImageData>(
Greg Daniel0cf45f62017-04-17 10:46:51 -0400465 new SkCCIDImage(std::move(codecImage)));
Brian Osman2c2bc112017-02-28 10:02:49 -0500466 }
467
468 sk_sp<SkImage> textureImage = codecImage->makeTextureImage(context, dstColorSpace);
469 if (!textureImage) {
470 // TODO: Force decode to raster here? Do mip-mapping, like getDeferredTextureImageData?
471 return std::unique_ptr<SkCrossContextImageData>(
Greg Daniel0cf45f62017-04-17 10:46:51 -0400472 new SkCCIDImage(std::move(codecImage)));
Brian Osman2c2bc112017-02-28 10:02:49 -0500473 }
474
475 // Crack open the gpu image, extract the backend data, stick it in the SkCCID
476 GrTexture* texture = as_IB(textureImage)->peekTexture();
477 SkASSERT(texture);
478
479 GrBackendTextureDesc desc;
480 desc.fFlags = kNone_GrBackendTextureFlag;
481 desc.fOrigin = texture->origin();
482 desc.fWidth = texture->width();
483 desc.fHeight = texture->height();
484 desc.fConfig = texture->config();
485 desc.fSampleCnt = 0;
486
Robert Phillips7ee385e2017-03-30 08:02:11 -0400487 context->contextPriv().prepareSurfaceForExternalIO(as_IB(textureImage)->peekProxy());
Brian Osman2c2bc112017-02-28 10:02:49 -0500488 auto textureData = texture->texturePriv().detachBackendTexture();
489 SkASSERT(textureData);
490
491 SkImageInfo info = as_IB(textureImage)->onImageInfo();
Greg Daniel0cf45f62017-04-17 10:46:51 -0400492 return std::unique_ptr<SkCrossContextImageData>(new SkCCIDBackendTexture(
Brian Osman2c2bc112017-02-28 10:02:49 -0500493 desc, std::move(textureData), info.alphaType(), info.refColorSpace()));
494}
495
Greg Daniel0cf45f62017-04-17 10:46:51 -0400496sk_sp<SkImage> SkCCIDBackendTexture::makeImage(GrContext* context) {
497 if (fTextureData) {
498 fTextureData->attachToContext(context);
Brian Osman2c2bc112017-02-28 10:02:49 -0500499 }
500
Brian Osman766fcbb2017-03-13 09:33:09 -0400501 // This texture was created by Ganesh on another thread (see MakeFromEncoded, above).
502 // Thus, we can import it back into our cache and treat it as our own (again).
503 GrWrapOwnership ownership = kAdoptAndCache_GrWrapOwnership;
Greg Daniel0cf45f62017-04-17 10:46:51 -0400504 return new_wrapped_texture_common(context, fDesc, fAlphaType,
505 std::move(fColorSpace), ownership, nullptr, nullptr);
506}
507
508sk_sp<SkImage> SkImage::MakeFromCrossContextImageData(
509 GrContext* context, std::unique_ptr<SkCrossContextImageData> ccid) {
510 return ccid->makeImage(context);
Brian Osman2c2bc112017-02-28 10:02:49 -0500511}
512
bsalomon634b4302016-07-12 18:11:17 -0700513sk_sp<SkImage> SkImage::makeNonTextureImage() const {
brianosman396fcdb2016-07-22 06:26:11 -0700514 if (!this->isTextureBacked()) {
bsalomon634b4302016-07-12 18:11:17 -0700515 return sk_ref_sp(const_cast<SkImage*>(this));
516 }
brianosman396fcdb2016-07-22 06:26:11 -0700517 SkImageInfo info = as_IB(this)->onImageInfo();
bsalomon634b4302016-07-12 18:11:17 -0700518 size_t rowBytes = info.minRowBytes();
519 size_t size = info.getSafeSize(rowBytes);
520 auto data = SkData::MakeUninitialized(size);
521 if (!data) {
522 return nullptr;
523 }
524 SkPixmap pm(info, data->writable_data(), rowBytes);
525 if (!this->readPixels(pm, 0, 0, kDisallow_CachingHint)) {
526 return nullptr;
527 }
528 return MakeRasterData(info, data, rowBytes);
529}
530
reed56179002015-07-07 06:11:19 -0700531///////////////////////////////////////////////////////////////////////////////////////////////////
532
bsalomon4d516a62016-07-28 13:37:31 -0700533namespace {
534struct MipMapLevelData {
535 void* fPixelData;
536 size_t fRowBytes;
bsalomon41b952c2016-03-11 06:46:33 -0800537};
538
bsalomon4d516a62016-07-28 13:37:31 -0700539struct DeferredTextureImage {
Brian Osman7b8400d2016-11-08 17:08:54 -0500540 uint32_t fContextUniqueID;
541 // Right now, the destination color mode is only considered when generating mipmaps
542 SkDestinationSurfaceColorMode fColorMode;
bsalomon4d516a62016-07-28 13:37:31 -0700543 // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
Brian Osman7b8400d2016-11-08 17:08:54 -0500544 int fWidth;
545 int fHeight;
546 SkColorType fColorType;
547 SkAlphaType fAlphaType;
548 void* fColorSpace;
549 size_t fColorSpaceSize;
Brian Osman7b8400d2016-11-08 17:08:54 -0500550 int fMipMapLevelCount;
bsalomon4d516a62016-07-28 13:37:31 -0700551 // The fMipMapLevelData array may contain more than 1 element.
552 // It contains fMipMapLevelCount elements.
553 // That means this struct's size is not known at compile-time.
Brian Osman7b8400d2016-11-08 17:08:54 -0500554 MipMapLevelData fMipMapLevelData[1];
bsalomon4d516a62016-07-28 13:37:31 -0700555};
556} // anonymous namespace
557
cblume33e0cb52016-08-30 12:09:23 -0700558static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
Eric Karla422d702016-11-30 11:09:29 -0800559 // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
560 // This can cause runaway memory leaks, so we are disabling this path until we can
561 // investigate further. crbug.com/669775
562 return false;
cblume33e0cb52016-08-30 12:09:23 -0700563}
564
565namespace {
566
567class DTIBufferFiller
568{
569public:
cblume921bc672016-09-22 05:25:26 -0700570 explicit DTIBufferFiller(char* bufferAsCharPtr)
571 : bufferAsCharPtr_(bufferAsCharPtr) {}
cblume33e0cb52016-08-30 12:09:23 -0700572
573 void fillMember(const void* source, size_t memberOffset, size_t size) {
cblume921bc672016-09-22 05:25:26 -0700574 memcpy(bufferAsCharPtr_ + memberOffset, source, size);
cblume33e0cb52016-08-30 12:09:23 -0700575 }
576
577private:
578
cblume921bc672016-09-22 05:25:26 -0700579 char* bufferAsCharPtr_;
cblume33e0cb52016-08-30 12:09:23 -0700580};
581}
582
583#define FILL_MEMBER(bufferFiller, member, source) \
584 bufferFiller.fillMember(source, \
585 offsetof(DeferredTextureImage, member), \
586 sizeof(DeferredTextureImage::member));
587
bsalomon41b952c2016-03-11 06:46:33 -0800588size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
ericrkb4da01d2016-06-13 11:18:14 -0700589 const DeferredTextureImageUsageParams params[],
cblume33e0cb52016-08-30 12:09:23 -0700590 int paramCnt, void* buffer,
Brian Osman6c15cc72016-10-17 09:51:37 -0400591 SkColorSpace* dstColorSpace) const {
ericrkb4da01d2016-06-13 11:18:14 -0700592 // Extract relevant min/max values from the params array.
593 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
594 SkFilterQuality highestFilterQuality = params[0].fQuality;
cblume33e0cb52016-08-30 12:09:23 -0700595 bool useMipMaps = should_use_mip_maps(params[0]);
ericrkb4da01d2016-06-13 11:18:14 -0700596 for (int i = 1; i < paramCnt; ++i) {
597 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
598 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
599 if (highestFilterQuality < params[i].fQuality)
600 highestFilterQuality = params[i].fQuality;
cblume33e0cb52016-08-30 12:09:23 -0700601 useMipMaps |= should_use_mip_maps(params[i]);
ericrkb4da01d2016-06-13 11:18:14 -0700602 }
603
bsalomon41b952c2016-03-11 06:46:33 -0800604 const bool fillMode = SkToBool(buffer);
605 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
606 return 0;
607 }
608
ericrkb4da01d2016-06-13 11:18:14 -0700609 // Calculate scaling parameters.
610 bool isScaled = lowestPreScaleMipLevel != 0;
611
612 SkISize scaledSize;
613 if (isScaled) {
614 // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
615 // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
616 scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
617 lowestPreScaleMipLevel - 1);
618 } else {
619 scaledSize = SkISize::Make(this->width(), this->height());
620 }
621
622 // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
623 SkFilterQuality scaleFilterQuality = highestFilterQuality;
624 if (scaleFilterQuality > kMedium_SkFilterQuality) {
625 scaleFilterQuality = kMedium_SkFilterQuality;
626 }
627
ericrkc429baf2016-03-24 15:35:45 -0700628 const int maxTextureSize = proxy.fCaps->maxTextureSize();
ericrkb4da01d2016-06-13 11:18:14 -0700629 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
ericrkc429baf2016-03-24 15:35:45 -0700630 return 0;
631 }
632
bsalomon41b952c2016-03-11 06:46:33 -0800633 SkAutoPixmapStorage pixmap;
634 SkImageInfo info;
635 size_t pixelSize = 0;
Brian Osmanaaedae72017-01-20 13:21:56 -0500636 if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable()) {
bsalomon41b952c2016-03-11 06:46:33 -0800637 info = pixmap.info();
638 pixelSize = SkAlign8(pixmap.getSafeSize());
Matt Sarettade76e92017-04-14 12:41:55 -0400639 if (!dstColorSpace) {
640 pixmap.setColorSpace(nullptr);
641 info = info.makeColorSpace(nullptr);
642 }
bsalomon41b952c2016-03-11 06:46:33 -0800643 } else {
644 // Here we're just using presence of data to know whether there is a codec behind the image.
645 // In the future we will access the cacherator and get the exact data that we want to (e.g.
646 // yuv planes) upload.
bungemanffae30d2016-08-03 13:32:32 -0700647 sk_sp<SkData> data(this->refEncoded());
ericrkb4da01d2016-06-13 11:18:14 -0700648 if (!data && !this->peekPixels(nullptr)) {
bsalomon41b952c2016-03-11 06:46:33 -0800649 return 0;
650 }
Brian Osman7992da32016-11-18 11:28:24 -0500651 if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
652 // Generator backed image. Tweak info to trigger correct kind of decode.
Brian Osman7992da32016-11-18 11:28:24 -0500653 SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
Brian Osman61624f02016-12-09 14:51:59 -0500654 dstColorSpace, proxy.fCaps.get());
Brian Osman7992da32016-11-18 11:28:24 -0500655 info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
656 scaledSize.height());
Brian Osman7992da32016-11-18 11:28:24 -0500657 } else {
658 info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
Matt Sarettade76e92017-04-14 12:41:55 -0400659 if (!dstColorSpace) {
660 info = info.makeColorSpace(nullptr);
661 }
Brian Osman7992da32016-11-18 11:28:24 -0500662 }
Brian Osmanaaedae72017-01-20 13:21:56 -0500663 if (kIndex_8_SkColorType == info.colorType()) {
664 // Force Index8 to be N32 instead. Index8 is unsupported in Ganesh.
665 info = info.makeColorType(kN32_SkColorType);
666 }
bsalomon41b952c2016-03-11 06:46:33 -0800667 pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
668 if (fillMode) {
669 pixmap.alloc(info);
ericrkb4da01d2016-06-13 11:18:14 -0700670 if (isScaled) {
671 if (!this->scalePixels(pixmap, scaleFilterQuality,
672 SkImage::kDisallow_CachingHint)) {
673 return 0;
674 }
675 } else {
676 if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
677 return 0;
678 }
bsalomon41b952c2016-03-11 06:46:33 -0800679 }
680 SkASSERT(!pixmap.ctable());
681 }
682 }
cblume2c052802016-05-31 09:55:08 -0700683 int mipMapLevelCount = 1;
cblume33e0cb52016-08-30 12:09:23 -0700684 if (useMipMaps) {
685 // SkMipMap only deals with the mipmap levels it generates, which does
686 // not include the base level.
687 // That means it generates and holds levels 1-x instead of 0-x.
688 // So the total mipmap level count is 1 more than what
689 // SkMipMap::ComputeLevelCount returns.
690 mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
691
692 // We already initialized pixelSize to the size of the base level.
693 // SkMipMap will generate the extra mipmap levels. Their sizes need to
694 // be added to the total.
695 // Index 0 here does not refer to the base mipmap level -- it is
696 // SkMipMap's first generated mipmap level (level 1).
697 for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
698 currentMipMapLevelIndex--) {
699 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
700 currentMipMapLevelIndex);
brianosman32b5e702016-10-13 06:44:23 -0700701 SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
cblume33e0cb52016-08-30 12:09:23 -0700702 pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
703 }
704 }
bsalomon41b952c2016-03-11 06:46:33 -0800705 size_t size = 0;
706 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
707 size += dtiSize;
cblume33e0cb52016-08-30 12:09:23 -0700708 size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
709 // We subtract 1 because DeferredTextureImage already includes the base
710 // level in its size
bsalomon41b952c2016-03-11 06:46:33 -0800711 size_t pixelOffset = size;
712 size += pixelSize;
bsalomon4d516a62016-07-28 13:37:31 -0700713 size_t colorSpaceOffset = 0;
714 size_t colorSpaceSize = 0;
Matt Sarett84c9cb72017-04-10 11:03:27 -0400715 SkColorSpaceTransferFn fn;
bsalomon4d516a62016-07-28 13:37:31 -0700716 if (info.colorSpace()) {
Matt Sarettade76e92017-04-14 12:41:55 -0400717 SkASSERT(dstColorSpace);
bsalomon4d516a62016-07-28 13:37:31 -0700718 colorSpaceOffset = size;
719 colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
720 size += colorSpaceSize;
Matt Sarett84c9cb72017-04-10 11:03:27 -0400721 } else if (this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
722 // In legacy mode, preserve the color space tag on the SkImage. This is only
723 // supported if the color space has a parametric transfer function.
724 SkASSERT(!dstColorSpace);
725 colorSpaceOffset = size;
726 colorSpaceSize = this->colorSpace()->writeToMemory(nullptr);
727 size += colorSpaceSize;
bsalomon4d516a62016-07-28 13:37:31 -0700728 }
bsalomon41b952c2016-03-11 06:46:33 -0800729 if (!fillMode) {
730 return size;
731 }
cblume921bc672016-09-22 05:25:26 -0700732 char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
733 char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
734 void* pixels = pixelsAsCharPtr;
bsalomon41b952c2016-03-11 06:46:33 -0800735
cblume921bc672016-09-22 05:25:26 -0700736 memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
737 pixmap.addr(), pixmap.getSafeSize());
bsalomon41b952c2016-03-11 06:46:33 -0800738
Brian Osman6c15cc72016-10-17 09:51:37 -0400739 // If the context has sRGB support, and we're intending to render to a surface with an attached
740 // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
741 // aware mip-mapping.
Brian Osman7b8400d2016-11-08 17:08:54 -0500742 SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
Brian Osman6c15cc72016-10-17 09:51:37 -0400743 if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
744 info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500745 colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
Brian Osman6c15cc72016-10-17 09:51:37 -0400746 }
747
bsalomon41b952c2016-03-11 06:46:33 -0800748 SkASSERT(info == pixmap.info());
749 size_t rowBytes = pixmap.rowBytes();
cblume33e0cb52016-08-30 12:09:23 -0700750 static_assert(std::is_standard_layout<DeferredTextureImage>::value,
751 "offsetof, which we use below, requires the type have standard layout");
cblume921bc672016-09-22 05:25:26 -0700752 auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
Brian Osman7b8400d2016-11-08 17:08:54 -0500753 FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
cblume33e0cb52016-08-30 12:09:23 -0700754 FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
755 int width = info.width();
756 FILL_MEMBER(dtiBufferFiller, fWidth, &width);
757 int height = info.height();
758 FILL_MEMBER(dtiBufferFiller, fHeight, &height);
759 SkColorType colorType = info.colorType();
760 FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
761 SkAlphaType alphaType = info.alphaType();
762 FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
cblume33e0cb52016-08-30 12:09:23 -0700763 FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
cblume921bc672016-09-22 05:25:26 -0700764 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
cblume33e0cb52016-08-30 12:09:23 -0700765 &pixels, sizeof(pixels));
cblume921bc672016-09-22 05:25:26 -0700766 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
cblume33e0cb52016-08-30 12:09:23 -0700767 &rowBytes, sizeof(rowBytes));
bsalomon4d516a62016-07-28 13:37:31 -0700768 if (colorSpaceSize) {
cblume921bc672016-09-22 05:25:26 -0700769 void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
cblume33e0cb52016-08-30 12:09:23 -0700770 FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
771 FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
Matt Sarett84c9cb72017-04-10 11:03:27 -0400772 if (info.colorSpace()) {
773 info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
774 } else {
775 SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn));
776 SkASSERT(!dstColorSpace);
777 this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
778 }
bsalomon4d516a62016-07-28 13:37:31 -0700779 } else {
cblume921bc672016-09-22 05:25:26 -0700780 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
cblume33e0cb52016-08-30 12:09:23 -0700781 0, sizeof(DeferredTextureImage::fColorSpace));
cblume921bc672016-09-22 05:25:26 -0700782 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
cblume33e0cb52016-08-30 12:09:23 -0700783 0, sizeof(DeferredTextureImage::fColorSpaceSize));
784 }
785
786 // Fill in the mipmap levels if they exist
cblume921bc672016-09-22 05:25:26 -0700787 char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.getSafeSize());
cblume33e0cb52016-08-30 12:09:23 -0700788
789 if (useMipMaps) {
cblume94ddf542016-09-16 10:07:32 -0700790 static_assert(std::is_standard_layout<MipMapLevelData>::value,
791 "offsetof, which we use below, requires the type have a standard layout");
cblume33e0cb52016-08-30 12:09:23 -0700792
Brian Osman7b8400d2016-11-08 17:08:54 -0500793 std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
cblume33e0cb52016-08-30 12:09:23 -0700794 // SkMipMap holds only the mipmap levels it generates.
795 // A programmer can use the data they provided to SkMipMap::Build as level 0.
796 // So the SkMipMap provides levels 1-x but it stores them in its own
797 // range 0-(x-1).
798 for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
799 generatedMipLevelIndex++) {
cblume33e0cb52016-08-30 12:09:23 -0700800 SkMipMap::Level mipLevel;
801 mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
802
803 // Make sure the mipmap data is after the start of the buffer
cblume921bc672016-09-22 05:25:26 -0700804 SkASSERT(mipLevelPtr > bufferAsCharPtr);
cblume33e0cb52016-08-30 12:09:23 -0700805 // Make sure the mipmap data starts before the end of the buffer
cblume921bc672016-09-22 05:25:26 -0700806 SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
cblume33e0cb52016-08-30 12:09:23 -0700807 // Make sure the mipmap data ends before the end of the buffer
cblume12f75272016-09-19 06:18:03 -0700808 SkASSERT(mipLevelPtr + mipLevel.fPixmap.getSafeSize() <=
cblume921bc672016-09-22 05:25:26 -0700809 bufferAsCharPtr + pixelOffset + pixelSize);
cblume33e0cb52016-08-30 12:09:23 -0700810
811 // getSafeSize includes rowbyte padding except for the last row,
812 // right?
813
cblume921bc672016-09-22 05:25:26 -0700814 memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.getSafeSize());
cblume33e0cb52016-08-30 12:09:23 -0700815
cblume921bc672016-09-22 05:25:26 -0700816 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
817 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
818 offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
cblume33e0cb52016-08-30 12:09:23 -0700819 size_t rowBytes = mipLevel.fPixmap.rowBytes();
cblume921bc672016-09-22 05:25:26 -0700820 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
821 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
822 offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
cblume33e0cb52016-08-30 12:09:23 -0700823
824 mipLevelPtr += SkAlign8(mipLevel.fPixmap.getSafeSize());
825 }
bsalomon4d516a62016-07-28 13:37:31 -0700826 }
bsalomon41b952c2016-03-11 06:46:33 -0800827 return size;
828}
829
830sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
831 SkBudgeted budgeted) {
832 if (!data) {
833 return nullptr;
834 }
835 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
836
837 if (!context || context->uniqueID() != dti->fContextUniqueID) {
838 return nullptr;
839 }
cblume33e0cb52016-08-30 12:09:23 -0700840 int mipLevelCount = dti->fMipMapLevelCount;
841 SkASSERT(mipLevelCount >= 1);
bsalomon4d516a62016-07-28 13:37:31 -0700842 sk_sp<SkColorSpace> colorSpace;
843 if (dti->fColorSpaceSize) {
844 colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
845 }
846 SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
847 dti->fColorType, dti->fAlphaType, colorSpace);
Brian Osmanb92234a2017-01-25 14:13:00 +0000848 if (mipLevelCount == 1) {
849 SkPixmap pixmap;
850 pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
Matt Sarett84c9cb72017-04-10 11:03:27 -0400851
852 // Use the NoCheck version because we have already validated the SkImage. The |data|
853 // used to be an SkImage before calling getDeferredTextureImageData(). In legacy mode,
854 // getDeferredTextureImageData() will allow parametric transfer functions for images
855 // generated from codecs - which is slightly more lenient than typical SkImage
856 // constructors.
857 sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxyNoCheck(
858 context->resourceProvider(), pixmap, budgeted));
Brian Osmaned182d72017-03-20 11:03:55 -0400859 if (!proxy) {
860 return nullptr;
861 }
862 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
863 std::move(proxy), std::move(colorSpace), budgeted);
Brian Osmanb92234a2017-01-25 14:13:00 +0000864 } else {
865 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
866 for (int i = 0; i < mipLevelCount; i++) {
867 texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
868 texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
869 }
Brian Osman8ccbbb42017-01-20 14:08:04 -0500870
Brian Osmanb92234a2017-01-25 14:13:00 +0000871 return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
872 mipLevelCount, SkBudgeted::kYes,
873 dti->fColorMode);
874 }
bsalomon41b952c2016-03-11 06:46:33 -0800875}
876
877///////////////////////////////////////////////////////////////////////////////////////////////////
878
cblume186d2d42016-06-03 11:17:42 -0700879sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
880 const GrMipLevel* texels, int mipLevelCount,
cblume33e0cb52016-08-30 12:09:23 -0700881 SkBudgeted budgeted,
Brian Osman7b8400d2016-11-08 17:08:54 -0500882 SkDestinationSurfaceColorMode colorMode) {
Robert Phillips1119dc32017-04-11 12:54:57 -0400883 SkASSERT(mipLevelCount >= 1);
cblume186d2d42016-06-03 11:17:42 -0700884 if (!ctx) {
885 return nullptr;
886 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400887 sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount,
888 colorMode));
889 if (!proxy) {
cblume186d2d42016-06-03 11:17:42 -0700890 return nullptr;
891 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400892
893 SkASSERT(proxy->priv().isExact());
894 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
895 info.alphaType(), std::move(proxy),
896 info.refColorSpace(), budgeted);
cblume186d2d42016-06-03 11:17:42 -0700897}
Brian Osman63954c92017-03-14 12:07:12 -0400898
899sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> colorSpace) const {
Mike Klein919cc452017-03-18 15:36:52 +0000900 sk_sp<SkColorSpace> srcSpace = fColorSpace ? fColorSpace : SkColorSpace::MakeSRGB();
901 auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), colorSpace.get());
Brian Osman63954c92017-03-14 12:07:12 -0400902 if (!xform) {
903 return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
904 }
905
Robert Phillips93429212017-04-11 12:23:17 +0000906 sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeRenderTargetContext(
Brian Osman63954c92017-03-14 12:07:12 -0400907 SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
908 if (!renderTargetContext) {
909 return nullptr;
910 }
911
912 GrPaint paint;
913 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400914 paint.addColorTextureProcessor(fContext->resourceProvider(), fProxy, nullptr, SkMatrix::I());
Brian Osman63954c92017-03-14 12:07:12 -0400915 paint.addColorFragmentProcessor(std::move(xform));
916
917 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
918
919 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
920
Robert Phillips7ee385e2017-03-30 08:02:11 -0400921 if (!renderTargetContext->asTextureProxy()) {
Brian Osman63954c92017-03-14 12:07:12 -0400922 return nullptr;
923 }
924
925 // MDB: this call is okay bc we know 'renderTargetContext' was exact
926 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
927 fAlphaType, renderTargetContext->asTextureProxyRef(),
928 std::move(colorSpace), fBudgeted);
929
930}