blob: 501d95b19eddf4b368e2d7c243dfb25159b845d3 [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"
Greg Daniel7ef28f32017-04-20 16:41:55 +000013#include "GrBackendSurface.h"
Brian Osman13dddce2017-05-09 13:19:50 -040014#include "GrBackendTextureImageGenerator.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050015#include "GrBitmapTextureMaker.h"
reed856e9d92015-09-30 12:21:45 -070016#include "GrCaps.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000017#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050018#include "GrContextPriv.h"
Brian Osman2c2bc112017-02-28 10:02:49 -050019#include "GrGpu.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050020#include "GrImageTextureMaker.h"
Brian Osman11052242016-10-27 14:47:55 -040021#include "GrRenderTargetContext.h"
Brian Osman32342f02017-03-04 08:12:46 -050022#include "GrResourceProvider.h"
Brian Osmanfe3b5162017-03-02 15:09:20 -050023#include "GrSemaphore.h"
Brian Osmane8e54582016-11-28 10:06:27 -050024#include "GrTextureAdjuster.h"
cblume33e0cb52016-08-30 12:09:23 -070025#include "GrTexturePriv.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050026#include "GrTextureProxy.h"
Brian Osman63954c92017-03-14 12:07:12 -040027#include "effects/GrNonlinearColorSpaceXformEffect.h"
bsalomonf267c1e2016-02-01 13:16:14 -080028#include "effects/GrYUVEffect.h"
bsalomon993a4212015-05-29 11:37:25 -070029#include "SkCanvas.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 Osman62517712017-04-26 16:26:39 -040065bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
66 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
67 // will be used. The client doesn't expect that we convert to that color space, it's intended
68 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
69 // into that color space (to save the client some effort in whatever they're about to do), but
70 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
71 // rolled the dstColorSpace into the key).
Mike Reed5fa3d6d2017-03-25 09:51:00 -040072 const auto desc = SkBitmapCacheDesc::Make(this);
73 if (SkBitmapCache::Find(desc, dst)) {
reed6f1216a2015-08-04 08:10:13 -070074 SkASSERT(dst->getGenerationID() == this->uniqueID());
75 SkASSERT(dst->isImmutable());
76 SkASSERT(dst->getPixels());
77 return true;
78 }
79
Mike Reed7a542c52017-04-11 12:03:44 -040080 SkBitmapCache::RecPtr rec = nullptr;
81 SkPixmap pmap;
82 if (kAllow_CachingHint == chint) {
Brian Osman62517712017-04-26 16:26:39 -040083 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
Mike Reed7a542c52017-04-11 12:03:44 -040084 if (!rec) {
85 return false;
86 }
87 } else {
Brian Osman62517712017-04-26 16:26:39 -040088 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
Mike Reed7a542c52017-04-11 12:03:44 -040089 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
Matt Sarett03dd6d52017-01-23 12:15:09 -0500177bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
reed09553032015-11-23 12:32:16 -0800178 int srcX, int srcY, CachingHint) const {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500179 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500180 return false;
181 }
182
Matt Sarett03dd6d52017-01-23 12:15:09 -0500183 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
184 if (!rec.trim(this->width(), this->height())) {
185 return false;
186 }
187
Robert Phillipsb726d582017-03-09 16:36:32 -0500188 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
189 // GrRenderTargetContext::onReadPixels
reed8b26b992015-05-07 15:36:17 -0700190 uint32_t flags = 0;
Matt Sarett03dd6d52017-01-23 12:15:09 -0500191 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
reed8b26b992015-05-07 15:36:17 -0700192 // let the GPU perform this transformation for us
Robert Phillipse78b7252017-04-06 07:59:41 -0400193 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
reed8b26b992015-05-07 15:36:17 -0700194 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500195
Brian Salomon2084ffa2017-03-27 17:32:18 -0400196 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
197 fProxy,
198 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500199 if (!sContext) {
reed8b26b992015-05-07 15:36:17 -0700200 return false;
201 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500202
203 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
204 return false;
205 }
206
reed8b26b992015-05-07 15:36:17 -0700207 // do we have to manually fix-up the alpha channel?
208 // src dst
209 // unpremul premul fix manually
210 // premul unpremul done by kUnpremul_PixelOpsFlag
211 // all other combos need to change.
212 //
213 // Should this be handled by Ganesh? todo:?
214 //
Matt Sarett03dd6d52017-01-23 12:15:09 -0500215 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
216 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
reed8b26b992015-05-07 15:36:17 -0700217 }
218 return true;
219}
220
reed7fb4f8b2016-03-11 04:33:52 -0800221sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
Robert Phillipsb726d582017-03-09 16:36:32 -0500222 GrSurfaceDesc desc = fProxy->desc();
reed7b6945b2015-09-24 00:50:58 -0700223 desc.fWidth = subset.width();
224 desc.fHeight = subset.height();
225
Robert Phillipsb726d582017-03-09 16:36:32 -0500226 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
Robert Phillipse2f7d182016-12-15 09:23:05 -0500227 desc,
228 SkBackingFit::kExact,
229 fBudgeted));
230 if (!sContext) {
231 return nullptr;
232 }
233
Robert Phillipsb726d582017-03-09 16:36:32 -0500234 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500235 return nullptr;
236 }
237
Robert Phillipsb726d582017-03-09 16:36:32 -0500238 // MDB: this call is okay bc we know 'sContext' was kExact
239 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
240 fAlphaType, sContext->asTextureProxyRef(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500241 fColorSpace, fBudgeted);
reed7b6945b2015-09-24 00:50:58 -0700242}
243
reed8b26b992015-05-07 15:36:17 -0700244///////////////////////////////////////////////////////////////////////////////////////////////////
245
Greg Daniel7ef28f32017-04-20 16:41:55 +0000246static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
247 const GrBackendTexture& backendTex,
248 GrSurfaceOrigin origin,
brianosmandddbe382016-07-20 13:55:39 -0700249 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
250 GrWrapOwnership ownership,
reed7fb4f8b2016-03-11 04:33:52 -0800251 SkImage::TextureReleaseProc releaseProc,
252 SkImage::ReleaseContext releaseCtx) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000253 if (backendTex.width() <= 0 || backendTex.height() <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700254 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700255 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400256
Greg Daniel7ef28f32017-04-20 16:41:55 +0000257 GrBackendTextureFlags flags = kNone_GrBackendTextureFlag;
258 sk_sp<GrTexture> tex = ctx->resourceProvider()->wrapBackendTexture(backendTex,
259 origin,
260 flags,
261 0,
262 ownership);
reed8b26b992015-05-07 15:36:17 -0700263 if (!tex) {
halcanary96fcdcc2015-08-27 07:41:13 -0700264 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700265 }
reedde499882015-06-18 13:41:40 -0700266 if (releaseProc) {
267 tex->setRelease(releaseProc, releaseCtx);
268 }
269
Brian Osman85d34b22017-05-10 12:06:26 -0400270 const SkBudgeted budgeted = SkBudgeted::kNo;
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400271 sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
272 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
273 at, std::move(proxy), std::move(colorSpace), budgeted);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700274}
275
reed7fb4f8b2016-03-11 04:33:52 -0800276sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
brianosmandddbe382016-07-20 13:55:39 -0700277 SkAlphaType at, sk_sp<SkColorSpace> cs,
278 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000279 SkASSERT(!(kRenderTarget_GrBackendTextureFlag & desc.fFlags));
280 GrBackendTexture tex(desc, ctx->contextPriv().getBackend());
281 return new_wrapped_texture_common(ctx, tex, desc.fOrigin, at, std::move(cs),
282 kBorrow_GrWrapOwnership,
brianosmandddbe382016-07-20 13:55:39 -0700283 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) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000288 SkASSERT(!(kRenderTarget_GrBackendTextureFlag & desc.fFlags));
289 GrBackendTexture tex(desc, ctx->contextPriv().getBackend());
290 return new_wrapped_texture_common(ctx, tex, desc.fOrigin, at, std::move(cs),
291 kAdopt_GrWrapOwnership,
brianosmandddbe382016-07-20 13:55:39 -0700292 nullptr, nullptr);
reed8b26b992015-05-07 15:36:17 -0700293}
294
Greg Daniel94403452017-04-18 15:52:36 -0400295sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
296 const GrBackendTexture& tex, GrSurfaceOrigin origin,
297 SkAlphaType at, sk_sp<SkColorSpace> cs,
298 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000299 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership,
300 releaseP, releaseC);
Greg Daniel94403452017-04-18 15:52:36 -0400301}
302
303sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
304 const GrBackendTexture& tex, GrSurfaceOrigin origin,
305 SkAlphaType at, sk_sp<SkColorSpace> cs) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000306 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
307 nullptr, nullptr);
308}
309
310static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
311 int width, int height,
312 GrPixelConfig config,
313 GrBackendObject handle) {
314
315 if (kOpenGL_GrBackend == backend) {
316 GrGLTextureInfo* glInfo = (GrGLTextureInfo*)(handle);
Greg Daniel207282e2017-04-26 13:29:21 -0400317 return GrBackendTexture(width, height, config, *glInfo);
Greg Daniel7ef28f32017-04-20 16:41:55 +0000318 } else {
319 SkASSERT(kVulkan_GrBackend == backend);
320 GrVkImageInfo* vkInfo = (GrVkImageInfo*)(handle);
Greg Daniel207282e2017-04-26 13:29:21 -0400321 return GrBackendTexture(width, height, *vkInfo);
Greg Daniel7ef28f32017-04-20 16:41:55 +0000322 }
Greg Daniel94403452017-04-18 15:52:36 -0400323}
324
jbaumanb445a572016-06-09 13:24:48 -0700325static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
326 bool nv12,
327 const GrBackendObject yuvTextureHandles[],
328 const SkISize yuvSizes[],
brianosmandddbe382016-07-20 13:55:39 -0700329 GrSurfaceOrigin origin,
330 sk_sp<SkColorSpace> imageColorSpace) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800331 const SkBudgeted budgeted = SkBudgeted::kYes;
bsalomon993a4212015-05-29 11:37:25 -0700332
jbaumanb445a572016-06-09 13:24:48 -0700333 if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 ||
334 yuvSizes[1].fHeight <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700335 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700336 }
jbaumanb445a572016-06-09 13:24:48 -0700337 if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
338 return nullptr;
339 }
340
341 const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
342
Greg Daniel7ef28f32017-04-20 16:41:55 +0000343 GrBackend backend = ctx->contextPriv().getBackend();
344 GrBackendTexture yTex = make_backend_texture_from_handle(backend,
345 yuvSizes[0].fWidth,
346 yuvSizes[0].fHeight,
347 kConfig,
348 yuvTextureHandles[0]);
349 GrBackendTexture uTex = make_backend_texture_from_handle(backend,
350 yuvSizes[1].fWidth,
351 yuvSizes[1].fHeight,
352 kConfig,
353 yuvTextureHandles[1]);
bsalomon993a4212015-05-29 11:37:25 -0700354
Greg Daniel7ef28f32017-04-20 16:41:55 +0000355 sk_sp<GrTextureProxy> yProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, yTex, origin);
356 sk_sp<GrTextureProxy> uProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, uTex, origin);
357 sk_sp<GrTextureProxy> vProxy;
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500358
jbaumanb445a572016-06-09 13:24:48 -0700359 if (nv12) {
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500360 vProxy = uProxy;
jbaumanb445a572016-06-09 13:24:48 -0700361 } else {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000362 GrBackendTexture vTex = make_backend_texture_from_handle(backend,
363 yuvSizes[2].fWidth,
364 yuvSizes[2].fHeight,
365 kConfig,
366 yuvTextureHandles[2]);
367 vProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, vTex, origin);
jbaumanb445a572016-06-09 13:24:48 -0700368 }
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500369 if (!yProxy || !uProxy || !vProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700370 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700371 }
372
robertphillipsd4c741e2016-04-28 09:55:15 -0700373 const int width = yuvSizes[0].fWidth;
374 const int height = yuvSizes[0].fHeight;
robertphillipsaa19a5f2016-04-28 06:21:55 -0700375
robertphillipsd4c741e2016-04-28 09:55:15 -0700376 // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400377 sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
Brian Osman11052242016-10-27 14:47:55 -0400378 SkBackingFit::kExact,
379 width, height,
380 kRGBA_8888_GrPixelConfig,
381 std::move(imageColorSpace),
382 0,
383 origin));
384 if (!renderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700386 }
387
388 GrPaint paint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400389 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
jbaumanb445a572016-06-09 13:24:48 -0700390 paint.addColorFragmentProcessor(
Robert Phillips296b1cc2017-03-15 10:42:12 -0400391 GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(),
Greg Daniel7ef28f32017-04-20 16:41:55 +0000392 yProxy, uProxy, vProxy,
393 yuvSizes, colorSpace, nv12));
bsalomon993a4212015-05-29 11:37:25 -0700394
Robert Phillipsb726d582017-03-09 16:36:32 -0500395 const SkRect rect = SkRect::MakeIWH(width, height);
robertphillipsc9a37062015-09-01 08:34:28 -0700396
Brian Salomon82f44312017-01-11 13:42:54 -0500397 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
Robert Phillipse60ad622016-11-17 10:22:48 -0500398
Robert Phillips7ee385e2017-03-30 08:02:11 -0400399 if (!renderTargetContext->asSurfaceProxy()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500400 return nullptr;
401 }
Robert Phillips7ee385e2017-03-30 08:02:11 -0400402 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
Robert Phillipsb726d582017-03-09 16:36:32 -0500403
404 // MDB: this call is okay bc we know 'renderTargetContext' was exact
405 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
406 kOpaque_SkAlphaType, renderTargetContext->asTextureProxyRef(),
Robert Phillips75a475c2017-01-13 09:18:59 -0500407 renderTargetContext->refColorSpace(), budgeted);
bsalomon993a4212015-05-29 11:37:25 -0700408}
reed56179002015-07-07 06:11:19 -0700409
jbaumanb445a572016-06-09 13:24:48 -0700410sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
411 const GrBackendObject yuvTextureHandles[3],
brianosmandddbe382016-07-20 13:55:39 -0700412 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
413 sk_sp<SkColorSpace> imageColorSpace) {
414 return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
415 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700416}
417
418sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
419 const GrBackendObject yuvTextureHandles[2],
420 const SkISize yuvSizes[2],
brianosmandddbe382016-07-20 13:55:39 -0700421 GrSurfaceOrigin origin,
422 sk_sp<SkColorSpace> imageColorSpace) {
423 return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
424 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700425}
426
Robert Phillips3798c862017-03-27 11:08:16 -0400427static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
428 SkAlphaType at, uint32_t id,
Brian Osman041f7df2017-02-07 11:23:28 -0500429 SkColorSpace* dstColorSpace) {
430 sk_sp<SkColorSpace> texColorSpace;
Robert Phillips3798c862017-03-27 11:08:16 -0400431 sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
432 dstColorSpace,
433 &texColorSpace, nullptr));
434 if (!proxy) {
Brian Osman041f7df2017-02-07 11:23:28 -0500435 return nullptr;
436 }
Robert Phillips3798c862017-03-27 11:08:16 -0400437 return sk_make_sp<SkImage_Gpu>(context, id, at,
438 std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
Brian Osman041f7df2017-02-07 11:23:28 -0500439}
440
Brian Osman2c2bc112017-02-28 10:02:49 -0500441sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
Brian Osman041f7df2017-02-07 11:23:28 -0500442 if (!context) {
443 return nullptr;
444 }
445 if (GrTexture* peek = as_IB(this)->peekTexture()) {
446 return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
447 }
448
Brian Osmandf7e0752017-04-26 16:20:28 -0400449 if (this->isLazyGenerated()) {
450 GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400451 return create_image_from_maker(context, &maker, this->alphaType(),
452 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500453 }
454
455 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
456 GrBitmapTextureMaker maker(context, *bmp);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400457 return create_image_from_maker(context, &maker, this->alphaType(),
458 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500459 }
460 return nullptr;
461}
462
Brian Osman13dddce2017-05-09 13:19:50 -0400463sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
464 bool buildMips, SkColorSpace* dstColorSpace) {
465 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
466 if (!codecImage) {
467 return nullptr;
468 }
469
470 // Some backends or drivers don't support (safely) moving resources between contexts
471 if (!context || !context->caps()->crossContextTextureSupport()) {
472 return codecImage;
473 }
474
475 // Turn the codec image into a GrTextureProxy
476 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
477 sk_sp<SkColorSpace> texColorSpace;
478 GrSamplerParams params(SkShader::kClamp_TileMode,
479 buildMips ? GrSamplerParams::kMipMap_FilterMode
480 : GrSamplerParams::kBilerp_FilterMode);
481 sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(params, dstColorSpace,
482 &texColorSpace, nullptr));
483 if (!proxy) {
484 return codecImage;
485 }
486
487 sk_sp<GrTexture> texture(sk_ref_sp(proxy->instantiate(context->resourceProvider())));
488 if (!texture) {
489 return codecImage;
490 }
491
492 // Flush any writes or uploads
493 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
494
495 sk_sp<GrSemaphore> sema = context->getGpu()->prepareTextureForCrossContextUsage(texture.get());
496
497 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), std::move(sema),
498 codecImage->alphaType(),
499 std::move(texColorSpace));
500 return SkImage::MakeFromGenerator(std::move(gen));
501}
502
bsalomon634b4302016-07-12 18:11:17 -0700503sk_sp<SkImage> SkImage::makeNonTextureImage() const {
brianosman396fcdb2016-07-22 06:26:11 -0700504 if (!this->isTextureBacked()) {
bsalomon634b4302016-07-12 18:11:17 -0700505 return sk_ref_sp(const_cast<SkImage*>(this));
506 }
brianosman396fcdb2016-07-22 06:26:11 -0700507 SkImageInfo info = as_IB(this)->onImageInfo();
bsalomon634b4302016-07-12 18:11:17 -0700508 size_t rowBytes = info.minRowBytes();
509 size_t size = info.getSafeSize(rowBytes);
510 auto data = SkData::MakeUninitialized(size);
511 if (!data) {
512 return nullptr;
513 }
514 SkPixmap pm(info, data->writable_data(), rowBytes);
515 if (!this->readPixels(pm, 0, 0, kDisallow_CachingHint)) {
516 return nullptr;
517 }
518 return MakeRasterData(info, data, rowBytes);
519}
520
reed56179002015-07-07 06:11:19 -0700521///////////////////////////////////////////////////////////////////////////////////////////////////
522
bsalomon4d516a62016-07-28 13:37:31 -0700523namespace {
524struct MipMapLevelData {
525 void* fPixelData;
526 size_t fRowBytes;
bsalomon41b952c2016-03-11 06:46:33 -0800527};
528
bsalomon4d516a62016-07-28 13:37:31 -0700529struct DeferredTextureImage {
Brian Osman7b8400d2016-11-08 17:08:54 -0500530 uint32_t fContextUniqueID;
531 // Right now, the destination color mode is only considered when generating mipmaps
532 SkDestinationSurfaceColorMode fColorMode;
bsalomon4d516a62016-07-28 13:37:31 -0700533 // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
Brian Osman7b8400d2016-11-08 17:08:54 -0500534 int fWidth;
535 int fHeight;
536 SkColorType fColorType;
537 SkAlphaType fAlphaType;
538 void* fColorSpace;
539 size_t fColorSpaceSize;
Brian Osman7b8400d2016-11-08 17:08:54 -0500540 int fMipMapLevelCount;
bsalomon4d516a62016-07-28 13:37:31 -0700541 // The fMipMapLevelData array may contain more than 1 element.
542 // It contains fMipMapLevelCount elements.
543 // That means this struct's size is not known at compile-time.
Brian Osman7b8400d2016-11-08 17:08:54 -0500544 MipMapLevelData fMipMapLevelData[1];
bsalomon4d516a62016-07-28 13:37:31 -0700545};
546} // anonymous namespace
547
cblume33e0cb52016-08-30 12:09:23 -0700548static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
Eric Karla422d702016-11-30 11:09:29 -0800549 // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
550 // This can cause runaway memory leaks, so we are disabling this path until we can
551 // investigate further. crbug.com/669775
552 return false;
cblume33e0cb52016-08-30 12:09:23 -0700553}
554
555namespace {
556
557class DTIBufferFiller
558{
559public:
cblume921bc672016-09-22 05:25:26 -0700560 explicit DTIBufferFiller(char* bufferAsCharPtr)
561 : bufferAsCharPtr_(bufferAsCharPtr) {}
cblume33e0cb52016-08-30 12:09:23 -0700562
563 void fillMember(const void* source, size_t memberOffset, size_t size) {
cblume921bc672016-09-22 05:25:26 -0700564 memcpy(bufferAsCharPtr_ + memberOffset, source, size);
cblume33e0cb52016-08-30 12:09:23 -0700565 }
566
567private:
568
cblume921bc672016-09-22 05:25:26 -0700569 char* bufferAsCharPtr_;
cblume33e0cb52016-08-30 12:09:23 -0700570};
571}
572
573#define FILL_MEMBER(bufferFiller, member, source) \
574 bufferFiller.fillMember(source, \
575 offsetof(DeferredTextureImage, member), \
576 sizeof(DeferredTextureImage::member));
577
bsalomon41b952c2016-03-11 06:46:33 -0800578size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
ericrkb4da01d2016-06-13 11:18:14 -0700579 const DeferredTextureImageUsageParams params[],
cblume33e0cb52016-08-30 12:09:23 -0700580 int paramCnt, void* buffer,
Brian Osman6c15cc72016-10-17 09:51:37 -0400581 SkColorSpace* dstColorSpace) const {
Mike Reed7f1d0202017-05-08 16:13:39 -0400582 // Some quick-rejects where is makes no sense to return CPU data
583 // e.g.
584 // - texture backed
585 // - picture backed
586 //
587 if (this->isTextureBacked()) {
588 return 0;
589 }
590 if (as_IB(this)->onCanLazyGenerateOnGPU()) {
591 return 0;
592 }
593
ericrkb4da01d2016-06-13 11:18:14 -0700594 // Extract relevant min/max values from the params array.
595 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
596 SkFilterQuality highestFilterQuality = params[0].fQuality;
cblume33e0cb52016-08-30 12:09:23 -0700597 bool useMipMaps = should_use_mip_maps(params[0]);
ericrkb4da01d2016-06-13 11:18:14 -0700598 for (int i = 1; i < paramCnt; ++i) {
599 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
600 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
601 if (highestFilterQuality < params[i].fQuality)
602 highestFilterQuality = params[i].fQuality;
cblume33e0cb52016-08-30 12:09:23 -0700603 useMipMaps |= should_use_mip_maps(params[i]);
ericrkb4da01d2016-06-13 11:18:14 -0700604 }
605
bsalomon41b952c2016-03-11 06:46:33 -0800606 const bool fillMode = SkToBool(buffer);
607 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
608 return 0;
609 }
610
ericrkb4da01d2016-06-13 11:18:14 -0700611 // Calculate scaling parameters.
612 bool isScaled = lowestPreScaleMipLevel != 0;
613
614 SkISize scaledSize;
615 if (isScaled) {
616 // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
617 // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
618 scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
619 lowestPreScaleMipLevel - 1);
620 } else {
621 scaledSize = SkISize::Make(this->width(), this->height());
622 }
623
624 // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
625 SkFilterQuality scaleFilterQuality = highestFilterQuality;
626 if (scaleFilterQuality > kMedium_SkFilterQuality) {
627 scaleFilterQuality = kMedium_SkFilterQuality;
628 }
629
ericrkc429baf2016-03-24 15:35:45 -0700630 const int maxTextureSize = proxy.fCaps->maxTextureSize();
ericrkb4da01d2016-06-13 11:18:14 -0700631 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
ericrkc429baf2016-03-24 15:35:45 -0700632 return 0;
633 }
634
bsalomon41b952c2016-03-11 06:46:33 -0800635 SkAutoPixmapStorage pixmap;
636 SkImageInfo info;
637 size_t pixelSize = 0;
Brian Osmanaaedae72017-01-20 13:21:56 -0500638 if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable()) {
bsalomon41b952c2016-03-11 06:46:33 -0800639 info = pixmap.info();
640 pixelSize = SkAlign8(pixmap.getSafeSize());
Matt Sarettade76e92017-04-14 12:41:55 -0400641 if (!dstColorSpace) {
642 pixmap.setColorSpace(nullptr);
643 info = info.makeColorSpace(nullptr);
644 }
bsalomon41b952c2016-03-11 06:46:33 -0800645 } else {
Mike Reed7f1d0202017-05-08 16:13:39 -0400646 if (!this->isLazyGenerated() && !this->peekPixels(nullptr)) {
bsalomon41b952c2016-03-11 06:46:33 -0800647 return 0;
648 }
Brian Osman7992da32016-11-18 11:28:24 -0500649 if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
650 // Generator backed image. Tweak info to trigger correct kind of decode.
Brian Osman7992da32016-11-18 11:28:24 -0500651 SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
Brian Osman61624f02016-12-09 14:51:59 -0500652 dstColorSpace, proxy.fCaps.get());
Brian Osman7992da32016-11-18 11:28:24 -0500653 info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
654 scaledSize.height());
Brian Osman7992da32016-11-18 11:28:24 -0500655 } else {
656 info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
Matt Sarettade76e92017-04-14 12:41:55 -0400657 if (!dstColorSpace) {
658 info = info.makeColorSpace(nullptr);
659 }
Brian Osman7992da32016-11-18 11:28:24 -0500660 }
Brian Osmanaaedae72017-01-20 13:21:56 -0500661 if (kIndex_8_SkColorType == info.colorType()) {
662 // Force Index8 to be N32 instead. Index8 is unsupported in Ganesh.
663 info = info.makeColorType(kN32_SkColorType);
664 }
bsalomon41b952c2016-03-11 06:46:33 -0800665 pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
666 if (fillMode) {
667 pixmap.alloc(info);
ericrkb4da01d2016-06-13 11:18:14 -0700668 if (isScaled) {
669 if (!this->scalePixels(pixmap, scaleFilterQuality,
670 SkImage::kDisallow_CachingHint)) {
671 return 0;
672 }
673 } else {
674 if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
675 return 0;
676 }
bsalomon41b952c2016-03-11 06:46:33 -0800677 }
678 SkASSERT(!pixmap.ctable());
679 }
680 }
cblume2c052802016-05-31 09:55:08 -0700681 int mipMapLevelCount = 1;
cblume33e0cb52016-08-30 12:09:23 -0700682 if (useMipMaps) {
683 // SkMipMap only deals with the mipmap levels it generates, which does
684 // not include the base level.
685 // That means it generates and holds levels 1-x instead of 0-x.
686 // So the total mipmap level count is 1 more than what
687 // SkMipMap::ComputeLevelCount returns.
688 mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
689
690 // We already initialized pixelSize to the size of the base level.
691 // SkMipMap will generate the extra mipmap levels. Their sizes need to
692 // be added to the total.
693 // Index 0 here does not refer to the base mipmap level -- it is
694 // SkMipMap's first generated mipmap level (level 1).
695 for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
696 currentMipMapLevelIndex--) {
697 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
698 currentMipMapLevelIndex);
brianosman32b5e702016-10-13 06:44:23 -0700699 SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
cblume33e0cb52016-08-30 12:09:23 -0700700 pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
701 }
702 }
bsalomon41b952c2016-03-11 06:46:33 -0800703 size_t size = 0;
704 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
705 size += dtiSize;
cblume33e0cb52016-08-30 12:09:23 -0700706 size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
707 // We subtract 1 because DeferredTextureImage already includes the base
708 // level in its size
bsalomon41b952c2016-03-11 06:46:33 -0800709 size_t pixelOffset = size;
710 size += pixelSize;
bsalomon4d516a62016-07-28 13:37:31 -0700711 size_t colorSpaceOffset = 0;
712 size_t colorSpaceSize = 0;
Matt Sarett84c9cb72017-04-10 11:03:27 -0400713 SkColorSpaceTransferFn fn;
bsalomon4d516a62016-07-28 13:37:31 -0700714 if (info.colorSpace()) {
Matt Sarettade76e92017-04-14 12:41:55 -0400715 SkASSERT(dstColorSpace);
bsalomon4d516a62016-07-28 13:37:31 -0700716 colorSpaceOffset = size;
717 colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
718 size += colorSpaceSize;
Matt Sarett84c9cb72017-04-10 11:03:27 -0400719 } else if (this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
720 // In legacy mode, preserve the color space tag on the SkImage. This is only
721 // supported if the color space has a parametric transfer function.
722 SkASSERT(!dstColorSpace);
723 colorSpaceOffset = size;
724 colorSpaceSize = this->colorSpace()->writeToMemory(nullptr);
725 size += colorSpaceSize;
bsalomon4d516a62016-07-28 13:37:31 -0700726 }
bsalomon41b952c2016-03-11 06:46:33 -0800727 if (!fillMode) {
728 return size;
729 }
cblume921bc672016-09-22 05:25:26 -0700730 char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
731 char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
732 void* pixels = pixelsAsCharPtr;
bsalomon41b952c2016-03-11 06:46:33 -0800733
cblume921bc672016-09-22 05:25:26 -0700734 memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
735 pixmap.addr(), pixmap.getSafeSize());
bsalomon41b952c2016-03-11 06:46:33 -0800736
Brian Osman6c15cc72016-10-17 09:51:37 -0400737 // If the context has sRGB support, and we're intending to render to a surface with an attached
738 // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
739 // aware mip-mapping.
Brian Osman7b8400d2016-11-08 17:08:54 -0500740 SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
Brian Osman6c15cc72016-10-17 09:51:37 -0400741 if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
742 info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500743 colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
Brian Osman6c15cc72016-10-17 09:51:37 -0400744 }
745
bsalomon41b952c2016-03-11 06:46:33 -0800746 SkASSERT(info == pixmap.info());
747 size_t rowBytes = pixmap.rowBytes();
cblume33e0cb52016-08-30 12:09:23 -0700748 static_assert(std::is_standard_layout<DeferredTextureImage>::value,
749 "offsetof, which we use below, requires the type have standard layout");
cblume921bc672016-09-22 05:25:26 -0700750 auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
Brian Osman7b8400d2016-11-08 17:08:54 -0500751 FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
cblume33e0cb52016-08-30 12:09:23 -0700752 FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
753 int width = info.width();
754 FILL_MEMBER(dtiBufferFiller, fWidth, &width);
755 int height = info.height();
756 FILL_MEMBER(dtiBufferFiller, fHeight, &height);
757 SkColorType colorType = info.colorType();
758 FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
759 SkAlphaType alphaType = info.alphaType();
760 FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
cblume33e0cb52016-08-30 12:09:23 -0700761 FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
cblume921bc672016-09-22 05:25:26 -0700762 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
cblume33e0cb52016-08-30 12:09:23 -0700763 &pixels, sizeof(pixels));
cblume921bc672016-09-22 05:25:26 -0700764 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
cblume33e0cb52016-08-30 12:09:23 -0700765 &rowBytes, sizeof(rowBytes));
bsalomon4d516a62016-07-28 13:37:31 -0700766 if (colorSpaceSize) {
cblume921bc672016-09-22 05:25:26 -0700767 void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
cblume33e0cb52016-08-30 12:09:23 -0700768 FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
769 FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
Matt Sarett84c9cb72017-04-10 11:03:27 -0400770 if (info.colorSpace()) {
771 info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
772 } else {
773 SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn));
774 SkASSERT(!dstColorSpace);
775 this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
776 }
bsalomon4d516a62016-07-28 13:37:31 -0700777 } else {
cblume921bc672016-09-22 05:25:26 -0700778 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
cblume33e0cb52016-08-30 12:09:23 -0700779 0, sizeof(DeferredTextureImage::fColorSpace));
cblume921bc672016-09-22 05:25:26 -0700780 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
cblume33e0cb52016-08-30 12:09:23 -0700781 0, sizeof(DeferredTextureImage::fColorSpaceSize));
782 }
783
784 // Fill in the mipmap levels if they exist
cblume921bc672016-09-22 05:25:26 -0700785 char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.getSafeSize());
cblume33e0cb52016-08-30 12:09:23 -0700786
787 if (useMipMaps) {
cblume94ddf542016-09-16 10:07:32 -0700788 static_assert(std::is_standard_layout<MipMapLevelData>::value,
789 "offsetof, which we use below, requires the type have a standard layout");
cblume33e0cb52016-08-30 12:09:23 -0700790
Brian Osman7b8400d2016-11-08 17:08:54 -0500791 std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
cblume33e0cb52016-08-30 12:09:23 -0700792 // SkMipMap holds only the mipmap levels it generates.
793 // A programmer can use the data they provided to SkMipMap::Build as level 0.
794 // So the SkMipMap provides levels 1-x but it stores them in its own
795 // range 0-(x-1).
796 for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
797 generatedMipLevelIndex++) {
cblume33e0cb52016-08-30 12:09:23 -0700798 SkMipMap::Level mipLevel;
799 mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
800
801 // Make sure the mipmap data is after the start of the buffer
cblume921bc672016-09-22 05:25:26 -0700802 SkASSERT(mipLevelPtr > bufferAsCharPtr);
cblume33e0cb52016-08-30 12:09:23 -0700803 // Make sure the mipmap data starts before the end of the buffer
cblume921bc672016-09-22 05:25:26 -0700804 SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
cblume33e0cb52016-08-30 12:09:23 -0700805 // Make sure the mipmap data ends before the end of the buffer
cblume12f75272016-09-19 06:18:03 -0700806 SkASSERT(mipLevelPtr + mipLevel.fPixmap.getSafeSize() <=
cblume921bc672016-09-22 05:25:26 -0700807 bufferAsCharPtr + pixelOffset + pixelSize);
cblume33e0cb52016-08-30 12:09:23 -0700808
809 // getSafeSize includes rowbyte padding except for the last row,
810 // right?
811
cblume921bc672016-09-22 05:25:26 -0700812 memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.getSafeSize());
cblume33e0cb52016-08-30 12:09:23 -0700813
cblume921bc672016-09-22 05:25:26 -0700814 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
815 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
816 offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
cblume33e0cb52016-08-30 12:09:23 -0700817 size_t rowBytes = mipLevel.fPixmap.rowBytes();
cblume921bc672016-09-22 05:25:26 -0700818 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
819 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
820 offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
cblume33e0cb52016-08-30 12:09:23 -0700821
822 mipLevelPtr += SkAlign8(mipLevel.fPixmap.getSafeSize());
823 }
bsalomon4d516a62016-07-28 13:37:31 -0700824 }
bsalomon41b952c2016-03-11 06:46:33 -0800825 return size;
826}
827
828sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
829 SkBudgeted budgeted) {
830 if (!data) {
831 return nullptr;
832 }
833 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
834
835 if (!context || context->uniqueID() != dti->fContextUniqueID) {
836 return nullptr;
837 }
cblume33e0cb52016-08-30 12:09:23 -0700838 int mipLevelCount = dti->fMipMapLevelCount;
839 SkASSERT(mipLevelCount >= 1);
bsalomon4d516a62016-07-28 13:37:31 -0700840 sk_sp<SkColorSpace> colorSpace;
841 if (dti->fColorSpaceSize) {
842 colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
843 }
844 SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
845 dti->fColorType, dti->fAlphaType, colorSpace);
Brian Osmanb92234a2017-01-25 14:13:00 +0000846 if (mipLevelCount == 1) {
847 SkPixmap pixmap;
848 pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
Matt Sarett84c9cb72017-04-10 11:03:27 -0400849
Matt Sarettdedac852017-05-12 10:56:49 -0400850 // Pass nullptr for the |dstColorSpace|. This opts in to more lenient color space
851 // verification. This is ok because we've already verified the color space in
852 // getDeferredTextureImageData().
853 sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy(
854 context->resourceProvider(), pixmap, budgeted, nullptr));
Brian Osmaned182d72017-03-20 11:03:55 -0400855 if (!proxy) {
856 return nullptr;
857 }
858 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
859 std::move(proxy), std::move(colorSpace), budgeted);
Brian Osmanb92234a2017-01-25 14:13:00 +0000860 } else {
861 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
862 for (int i = 0; i < mipLevelCount; i++) {
863 texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
864 texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
865 }
Brian Osman8ccbbb42017-01-20 14:08:04 -0500866
Brian Osmanb92234a2017-01-25 14:13:00 +0000867 return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
868 mipLevelCount, SkBudgeted::kYes,
869 dti->fColorMode);
870 }
bsalomon41b952c2016-03-11 06:46:33 -0800871}
872
873///////////////////////////////////////////////////////////////////////////////////////////////////
874
cblume186d2d42016-06-03 11:17:42 -0700875sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
876 const GrMipLevel* texels, int mipLevelCount,
cblume33e0cb52016-08-30 12:09:23 -0700877 SkBudgeted budgeted,
Brian Osman7b8400d2016-11-08 17:08:54 -0500878 SkDestinationSurfaceColorMode colorMode) {
Robert Phillips1119dc32017-04-11 12:54:57 -0400879 SkASSERT(mipLevelCount >= 1);
cblume186d2d42016-06-03 11:17:42 -0700880 if (!ctx) {
881 return nullptr;
882 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400883 sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount,
884 colorMode));
885 if (!proxy) {
cblume186d2d42016-06-03 11:17:42 -0700886 return nullptr;
887 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400888
889 SkASSERT(proxy->priv().isExact());
890 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
891 info.alphaType(), std::move(proxy),
892 info.refColorSpace(), budgeted);
cblume186d2d42016-06-03 11:17:42 -0700893}
Brian Osman63954c92017-03-14 12:07:12 -0400894
Matt Sarett9f3dcb32017-05-04 08:53:32 -0400895sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> colorSpace, SkColorType,
896 SkTransferFunctionBehavior premulBehavior) const {
897 if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
898 // TODO: Implement this.
899 return nullptr;
900 }
901
Mike Klein919cc452017-03-18 15:36:52 +0000902 sk_sp<SkColorSpace> srcSpace = fColorSpace ? fColorSpace : SkColorSpace::MakeSRGB();
903 auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), colorSpace.get());
Brian Osman63954c92017-03-14 12:07:12 -0400904 if (!xform) {
905 return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
906 }
907
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400908 sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext(
Brian Osman63954c92017-03-14 12:07:12 -0400909 SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
910 if (!renderTargetContext) {
911 return nullptr;
912 }
913
914 GrPaint paint;
915 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400916 paint.addColorTextureProcessor(fContext->resourceProvider(), fProxy, nullptr, SkMatrix::I());
Brian Osman63954c92017-03-14 12:07:12 -0400917 paint.addColorFragmentProcessor(std::move(xform));
918
919 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
920
921 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
922
Robert Phillips7ee385e2017-03-30 08:02:11 -0400923 if (!renderTargetContext->asTextureProxy()) {
Brian Osman63954c92017-03-14 12:07:12 -0400924 return nullptr;
925 }
926
927 // MDB: this call is okay bc we know 'renderTargetContext' was exact
928 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
929 fAlphaType, renderTargetContext->asTextureProxyRef(),
930 std::move(colorSpace), fBudgeted);
931
932}
Brian Osman5bbd0762017-05-08 11:07:42 -0400933
934bool SkImage_Gpu::onIsValid(GrContext* context) const {
935 // The base class has already checked that context isn't abandoned (if it's not nullptr)
936 if (fContext->abandoned()) {
937 return false;
938 }
939
940 if (context && context != fContext) {
941 return false;
942 }
943
944 return true;
945}