blob: 398c423a17d4b10e8332886c4ff7ab3a728c30e6 [file] [log] [blame]
Jim Van Verthf49262d2018-10-02 12:07:20 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <cstddef>
9#include <cstring>
10#include <type_traits>
11
12#include "GrClip.h"
13#include "GrContext.h"
14#include "GrContextPriv.h"
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040015#include "GrGpu.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040016#include "GrRenderTargetContext.h"
17#include "GrTexture.h"
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040018#include "GrTextureProducer.h"
Jim Van Verthc8429ad2018-11-20 11:12:37 -050019#include "SkAutoPixmapStorage.h"
Jim Van Verth803a5022018-11-05 15:55:53 -050020#include "SkGr.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040021#include "SkImage_Gpu.h"
22#include "SkImage_GpuYUVA.h"
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040023#include "SkMipMap.h"
Brian Salomonbe5a0932018-12-10 10:03:26 -050024#include "SkScopeExit.h"
Jim Van Verthe24b5872018-10-29 16:26:02 -040025#include "SkYUVASizeInfo.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040026#include "effects/GrYUVtoRGBEffect.h"
27
Jim Van Verthcea39022018-10-12 16:15:34 -040028SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
Jim Van Verthf49262d2018-10-02 12:07:20 -040029 SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
Jim Van Verth0e671942018-11-09 12:03:57 -050030 int numProxies, const SkYUVAIndex yuvaIndices[4],
Brian Salomonf05e6d32018-12-20 08:41:41 -050031 GrSurfaceOrigin origin, sk_sp<SkColorSpace> imageColorSpace)
Jim Van Verthcea39022018-10-12 16:15:34 -040032 : INHERITED(std::move(context), width, height, uniqueID,
Jim Van Verth8026ccc2018-10-04 13:10:39 -040033 // If an alpha channel is present we always switch to kPremul. This is because,
34 // although the planar data is always un-premul, the final interleaved RGB image
35 // is/would-be premul.
Brian Salomonf05e6d32018-12-20 08:41:41 -050036 GetAlphaTypeFromYUVAIndices(yuvaIndices), imageColorSpace)
Jim Van Verth0e671942018-11-09 12:03:57 -050037 , fNumProxies(numProxies)
Jim Van Verth8026ccc2018-10-04 13:10:39 -040038 , fYUVColorSpace(colorSpace)
39 , fOrigin(origin) {
Jim Van Verth0e671942018-11-09 12:03:57 -050040 // The caller should have done this work, just verifying
41 SkDEBUGCODE(int textureCount;)
42 SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &textureCount));
43 SkASSERT(textureCount == fNumProxies);
44
45 for (int i = 0; i < numProxies; ++i) {
Jim Van Verthf49262d2018-10-02 12:07:20 -040046 fProxies[i] = std::move(proxies[i]);
47 }
48 memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
Jim Van Verthf49262d2018-10-02 12:07:20 -040049}
50
Jim Van Verth3e4c2f32019-01-11 13:32:45 -050051// For onMakeColorSpace()
52SkImage_GpuYUVA::SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace> targetCS)
53 : INHERITED(image->fContext, image->width(), image->height(), kNeedNewImageUniqueID,
54 // If an alpha channel is present we always switch to kPremul. This is because,
55 // although the planar data is always un-premul, the final interleaved RGB image
56 // is/would-be premul.
57 GetAlphaTypeFromYUVAIndices(image->fYUVAIndices), image->fColorSpace)
58 , fNumProxies(image->fNumProxies)
59 , fYUVColorSpace(image->fYUVColorSpace)
60 , fOrigin(image->fOrigin)
61 , fTargetColorSpace(targetCS) {
62 // The caller should have done this work, just verifying
63 SkDEBUGCODE(int textureCount;)
64 SkASSERT(SkYUVAIndex::AreValidIndices(image->fYUVAIndices, &textureCount));
65 SkASSERT(textureCount == fNumProxies);
66
67 for (int i = 0; i < fNumProxies; ++i) {
68 fProxies[i] = image->fProxies[i]; // we ref in this case, not move
69 }
70 memcpy(fYUVAIndices, image->fYUVAIndices, 4 * sizeof(SkYUVAIndex));
71}
72
Jim Van Verthf49262d2018-10-02 12:07:20 -040073SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
74
75SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
76 // Note: this is the imageInfo for the flattened image, not the YUV planes
77 return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
Brian Osmane9560492019-02-05 17:00:03 -050078 fAlphaType, fTargetColorSpace ? fTargetColorSpace : fColorSpace);
Jim Van Verthf49262d2018-10-02 12:07:20 -040079}
80
Jim Van Verthf542cab2018-11-07 12:08:21 -050081bool SkImage_GpuYUVA::setupMipmapsForPlanes() const {
Jim Van Verth0e671942018-11-09 12:03:57 -050082 for (int i = 0; i < fNumProxies; ++i) {
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040083 GrTextureProducer::CopyParams copyParams;
84 int mipCount = SkMipMap::ComputeLevelCount(fProxies[i]->width(), fProxies[i]->height());
Robert Phillips9da87e02019-02-04 13:26:26 -050085 if (mipCount && GrGpu::IsACopyNeededForMips(fContext->priv().caps(),
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040086 fProxies[i].get(),
87 GrSamplerState::Filter::kMipMap,
88 &copyParams)) {
Jim Van Verthf542cab2018-11-07 12:08:21 -050089 auto mippedProxy = GrCopyBaseMipMapToTextureProxy(fContext.get(), fProxies[i].get());
90 if (!mippedProxy) {
91 return false;
92 }
93 fProxies[i] = mippedProxy;
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040094 }
95 }
96 return true;
97}
98
Jim Van Verthf49262d2018-10-02 12:07:20 -040099//////////////////////////////////////////////////////////////////////////////////////////////////
Jim Van Verthf49262d2018-10-02 12:07:20 -0400100
101sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
102 if (!fRGBProxy) {
Greg Daniel4065d452018-11-16 15:43:41 -0500103 const GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500104 fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
Greg Daniel4065d452018-11-16 15:43:41 -0500105
Jim Van Verthf49262d2018-10-02 12:07:20 -0400106 // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
107 sk_sp<GrRenderTargetContext> renderTargetContext(
Robert Phillips9da87e02019-02-04 13:26:26 -0500108 fContext->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500109 format, SkBackingFit::kExact, this->width(), this->height(),
110 kRGBA_8888_GrPixelConfig, fColorSpace, 1, GrMipMapped::kNo, fOrigin));
Jim Van Verthf49262d2018-10-02 12:07:20 -0400111 if (!renderTargetContext) {
112 return nullptr;
113 }
Jim Van Verthf49262d2018-10-02 12:07:20 -0400114
Brian Osmane9560492019-02-05 17:00:03 -0500115 auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), fAlphaType,
116 fTargetColorSpace.get(), fAlphaType);
Jim Van Verth0e671942018-11-09 12:03:57 -0500117 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
118 if (!RenderYUVAToRGBA(fContext.get(), renderTargetContext.get(), rect, fYUVColorSpace,
Brian Osmane9560492019-02-05 17:00:03 -0500119 std::move(colorSpaceXform), fProxies, fYUVAIndices)) {
Jim Van Verthf49262d2018-10-02 12:07:20 -0400120 return nullptr;
121 }
122
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400123 fRGBProxy = renderTargetContext->asTextureProxyRef();
Jim Van Verthf49262d2018-10-02 12:07:20 -0400124 }
125
126 return fRGBProxy;
127}
128
Jim Van Verth803a5022018-11-05 15:55:53 -0500129sk_sp<GrTextureProxy> SkImage_GpuYUVA::asMippedTextureProxyRef() const {
130 // if invalid or already has miplevels
131 auto proxy = this->asTextureProxyRef();
132 if (!proxy || GrMipMapped::kYes == fRGBProxy->mipMapped()) {
133 return proxy;
134 }
135
136 // need to generate mips for the proxy
137 if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(fContext.get(), proxy.get())) {
138 fRGBProxy = mippedProxy;
139 return mippedProxy;
140 }
141
142 // failed to generate mips
143 return nullptr;
144}
145
Jim Van Verth9bf81202018-10-30 15:53:36 -0400146//////////////////////////////////////////////////////////////////////////////////////////////////
147
Brian Osmanf48c9962019-01-14 11:15:50 -0500148sk_sp<SkImage> SkImage_GpuYUVA::onMakeColorTypeAndColorSpace(SkColorType,
149 sk_sp<SkColorSpace> targetCS) const {
150 // We explicitly ignore color type changes, for now.
151
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500152 // we may need a mutex here but for now we expect usage to be in a single thread
153 if (fOnMakeColorSpaceTarget &&
Brian Osmanf48c9962019-01-14 11:15:50 -0500154 SkColorSpace::Equals(targetCS.get(), fOnMakeColorSpaceTarget.get())) {
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500155 return fOnMakeColorSpaceResult;
156 }
Brian Osmanf48c9962019-01-14 11:15:50 -0500157 sk_sp<SkImage> result = sk_sp<SkImage>(new SkImage_GpuYUVA(this, targetCS));
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500158 if (result) {
Brian Osmanf48c9962019-01-14 11:15:50 -0500159 fOnMakeColorSpaceTarget = targetCS;
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500160 fOnMakeColorSpaceResult = result;
161 }
162 return result;
163}
164
165//////////////////////////////////////////////////////////////////////////////////////////////////
166
Jim Van Verth9bf81202018-10-30 15:53:36 -0400167sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
168 SkYUVColorSpace colorSpace,
169 const GrBackendTexture yuvaTextures[],
170 const SkYUVAIndex yuvaIndices[4],
171 SkISize imageSize,
172 GrSurfaceOrigin imageOrigin,
173 sk_sp<SkColorSpace> imageColorSpace) {
Jim Van Verth0e671942018-11-09 12:03:57 -0500174 int numTextures;
175 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
176 return nullptr;
Jim Van Verth9bf81202018-10-30 15:53:36 -0400177 }
178
Jim Van Verth0e671942018-11-09 12:03:57 -0500179 sk_sp<GrTextureProxy> tempTextureProxies[4];
Jim Van Verth53275362018-11-09 15:42:35 -0500180 if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
181 imageOrigin, tempTextureProxies)) {
Jim Van Verth0e671942018-11-09 12:03:57 -0500182 return nullptr;
Jim Van Verth9bf81202018-10-30 15:53:36 -0400183 }
184
185 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
186 kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500187 numTextures, yuvaIndices, imageOrigin, imageColorSpace);
Jim Van Verth9bf81202018-10-30 15:53:36 -0400188}
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500189
190sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(
191 GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[],
192 const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin,
193 bool buildMips, bool limitToMaxTextureSize, sk_sp<SkColorSpace> imageColorSpace) {
194 int numPixmaps;
195 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numPixmaps)) {
196 return nullptr;
197 }
198
199 // Make proxies
Robert Phillips9da87e02019-02-04 13:26:26 -0500200 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500201 sk_sp<GrTextureProxy> tempTextureProxies[4];
202 for (int i = 0; i < numPixmaps; ++i) {
203 const SkPixmap* pixmap = &yuvaPixmaps[i];
204 SkAutoPixmapStorage resized;
Robert Phillips9da87e02019-02-04 13:26:26 -0500205 int maxTextureSize = context->priv().caps()->maxTextureSize();
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500206 int maxDim = SkTMax(yuvaPixmaps[i].width(), yuvaPixmaps[i].height());
207 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
208 float scale = static_cast<float>(maxTextureSize) / maxDim;
209 int newWidth = SkTMin(static_cast<int>(yuvaPixmaps[i].width() * scale),
210 maxTextureSize);
211 int newHeight = SkTMin(static_cast<int>(yuvaPixmaps[i].height() * scale),
212 maxTextureSize);
213 SkImageInfo info = yuvaPixmaps[i].info().makeWH(newWidth, newHeight);
214 if (!resized.tryAlloc(info) ||
215 !yuvaPixmaps[i].scalePixels(resized, kLow_SkFilterQuality)) {
216 return nullptr;
217 }
218 pixmap = &resized;
219 }
220 // Turn the pixmap into a GrTextureProxy
221 if (buildMips) {
222 SkBitmap bmp;
223 bmp.installPixels(*pixmap);
224 tempTextureProxies[i] = proxyProvider->createMipMapProxyFromBitmap(bmp);
Jim Van Verthbd975d42018-12-06 15:16:14 +0000225 }
226 if (!tempTextureProxies[i]) {
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500227 if (SkImageInfoIsValid(pixmap->info())) {
228 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]",
229 pixmap->width(), pixmap->height());
230 // We don't need a release proc on the data in pixmap since we know we are in a
231 // GrContext that has a resource provider. Thus the createTextureProxy call will
232 // immediately upload the data.
233 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
234 tempTextureProxies[i] =
235 proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
236 SkBudgeted::kYes, SkBackingFit::kExact);
237 }
238 }
239
240 if (!tempTextureProxies[i]) {
241 return nullptr;
242 }
243 }
244
245 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageSize.width(), imageSize.height(),
246 kNeedNewImageUniqueID, yuvColorSpace, tempTextureProxies,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500247 numPixmaps, yuvaIndices, imageOrigin, imageColorSpace);
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500248}
249
250
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400251/////////////////////////////////////////////////////////////////////////////////////////////////
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500252sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
253 GrContext* context,
254 SkYUVColorSpace yuvColorSpace,
255 const GrBackendFormat yuvaFormats[],
256 const SkISize yuvaSizes[],
257 const SkYUVAIndex yuvaIndices[4],
258 int imageWidth,
259 int imageHeight,
260 GrSurfaceOrigin imageOrigin,
261 sk_sp<SkColorSpace> imageColorSpace,
262 PromiseImageTextureFulfillProc textureFulfillProc,
263 PromiseImageTextureReleaseProc textureReleaseProc,
264 PromiseImageTextureDoneProc promiseDoneProc,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500265 PromiseImageTextureContext textureContexts[],
266 DelayReleaseCallback delayReleaseCallback) {
Jim Van Verthf00b1622018-10-10 13:03:23 -0400267 int numTextures;
268 bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);
269
Brian Salomonbe5a0932018-12-10 10:03:26 -0500270 // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
271 // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
272 // responsibility for calling the done proc.
273 if (!promiseDoneProc) {
274 return nullptr;
Jim Van Verthf00b1622018-10-10 13:03:23 -0400275 }
Brian Salomonbe5a0932018-12-10 10:03:26 -0500276 int proxiesCreated = 0;
277 SkScopeExit callDone([promiseDoneProc, textureContexts, numTextures, &proxiesCreated]() {
278 for (int i = proxiesCreated; i < numTextures; ++i) {
279 promiseDoneProc(textureContexts[i]);
280 }
281 });
Jim Van Verthf00b1622018-10-10 13:03:23 -0400282
283 if (!valid) {
284 return nullptr;
285 }
Robert Phillipsef85d192018-10-09 11:24:09 -0400286
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400287 if (!context) {
288 return nullptr;
289 }
290
Greg Kaiser9a2169e2019-02-10 17:29:46 -0800291 if (imageWidth <= 0 || imageHeight <= 0) {
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400292 return nullptr;
293 }
294
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400295 SkAlphaType at = (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) ? kPremul_SkAlphaType
296 : kOpaque_SkAlphaType;
Jim Van Verthcea39022018-10-12 16:15:34 -0400297 SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kRGBA_8888_SkColorType,
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400298 at, imageColorSpace);
299 if (!SkImageInfoIsValid(info)) {
300 return nullptr;
301 }
302
Jim Van Verthf9f07352018-10-24 10:32:20 -0400303 // verify sizes with expected texture count
Jim Van Verth8f11e432018-10-18 14:36:59 -0400304 for (int i = 0; i < numTextures; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400305 if (yuvaSizes[i].isEmpty()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400306 return nullptr;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400307 }
308 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400309 for (int i = numTextures; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400310 if (!yuvaSizes[i].isEmpty()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400311 return nullptr;
312 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000313 }
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400314
315 // Get lazy proxies
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400316 sk_sp<GrTextureProxy> proxies[4];
Jim Van Verthf00b1622018-10-10 13:03:23 -0400317 for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
Brian Salomonf391d0f2018-12-14 09:18:50 -0500318 GrPixelConfig config =
Robert Phillips9da87e02019-02-04 13:26:26 -0500319 context->priv().caps()->getYUVAConfigFromBackendFormat(yuvaFormats[texIdx]);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500320 if (config == kUnknown_GrPixelConfig) {
Jim Van Verthf00b1622018-10-10 13:03:23 -0400321 return nullptr;
322 }
Brian Salomonbe5a0932018-12-10 10:03:26 -0500323 proxies[texIdx] = MakePromiseImageLazyProxy(
324 context, yuvaSizes[texIdx].width(), yuvaSizes[texIdx].height(), imageOrigin, config,
325 yuvaFormats[texIdx], GrMipMapped::kNo, textureFulfillProc, textureReleaseProc,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500326 promiseDoneProc, textureContexts[texIdx], delayReleaseCallback);
Brian Salomonbe5a0932018-12-10 10:03:26 -0500327 ++proxiesCreated;
Jim Van Verthf00b1622018-10-10 13:03:23 -0400328 if (!proxies[texIdx]) {
329 return nullptr;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400330 }
331 }
332
Jim Van Verthcea39022018-10-12 16:15:34 -0400333 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight,
Jim Van Verth0e671942018-11-09 12:03:57 -0500334 kNeedNewImageUniqueID, yuvColorSpace, proxies, numTextures,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500335 yuvaIndices, imageOrigin, std::move(imageColorSpace));
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400336}