blob: ffa801c9a2dc54eb87927bf18a4d8e2079ffde8e [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"
Robert Phillips6603a172019-03-05 12:35:44 -050016#include "GrRecordingContext.h"
17#include "GrRecordingContextPriv.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040018#include "GrRenderTargetContext.h"
19#include "GrTexture.h"
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040020#include "GrTextureProducer.h"
Jim Van Verthc8429ad2018-11-20 11:12:37 -050021#include "SkAutoPixmapStorage.h"
Jim Van Verth803a5022018-11-05 15:55:53 -050022#include "SkGr.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040023#include "SkImage_Gpu.h"
24#include "SkImage_GpuYUVA.h"
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040025#include "SkMipMap.h"
Brian Salomonbe5a0932018-12-10 10:03:26 -050026#include "SkScopeExit.h"
Jim Van Verthe24b5872018-10-29 16:26:02 -040027#include "SkYUVASizeInfo.h"
Jim Van Verthf49262d2018-10-02 12:07:20 -040028#include "effects/GrYUVtoRGBEffect.h"
29
Jim Van Verthcea39022018-10-12 16:15:34 -040030SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
Jim Van Verthf49262d2018-10-02 12:07:20 -040031 SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
Jim Van Verth0e671942018-11-09 12:03:57 -050032 int numProxies, const SkYUVAIndex yuvaIndices[4],
Brian Salomonf05e6d32018-12-20 08:41:41 -050033 GrSurfaceOrigin origin, sk_sp<SkColorSpace> imageColorSpace)
Jim Van Verthcea39022018-10-12 16:15:34 -040034 : INHERITED(std::move(context), width, height, uniqueID,
Jim Van Verth8026ccc2018-10-04 13:10:39 -040035 // If an alpha channel is present we always switch to kPremul. This is because,
36 // although the planar data is always un-premul, the final interleaved RGB image
37 // is/would-be premul.
Brian Salomonf05e6d32018-12-20 08:41:41 -050038 GetAlphaTypeFromYUVAIndices(yuvaIndices), imageColorSpace)
Jim Van Verth0e671942018-11-09 12:03:57 -050039 , fNumProxies(numProxies)
Jim Van Verth8026ccc2018-10-04 13:10:39 -040040 , fYUVColorSpace(colorSpace)
41 , fOrigin(origin) {
Jim Van Verth0e671942018-11-09 12:03:57 -050042 // The caller should have done this work, just verifying
43 SkDEBUGCODE(int textureCount;)
44 SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &textureCount));
45 SkASSERT(textureCount == fNumProxies);
46
47 for (int i = 0; i < numProxies; ++i) {
Jim Van Verthf49262d2018-10-02 12:07:20 -040048 fProxies[i] = std::move(proxies[i]);
49 }
50 memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
Jim Van Verthf49262d2018-10-02 12:07:20 -040051}
52
Jim Van Verth3e4c2f32019-01-11 13:32:45 -050053// For onMakeColorSpace()
54SkImage_GpuYUVA::SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace> targetCS)
55 : INHERITED(image->fContext, image->width(), image->height(), kNeedNewImageUniqueID,
56 // If an alpha channel is present we always switch to kPremul. This is because,
57 // although the planar data is always un-premul, the final interleaved RGB image
58 // is/would-be premul.
59 GetAlphaTypeFromYUVAIndices(image->fYUVAIndices), image->fColorSpace)
60 , fNumProxies(image->fNumProxies)
61 , fYUVColorSpace(image->fYUVColorSpace)
62 , fOrigin(image->fOrigin)
63 , fTargetColorSpace(targetCS) {
64 // The caller should have done this work, just verifying
65 SkDEBUGCODE(int textureCount;)
66 SkASSERT(SkYUVAIndex::AreValidIndices(image->fYUVAIndices, &textureCount));
67 SkASSERT(textureCount == fNumProxies);
68
69 for (int i = 0; i < fNumProxies; ++i) {
70 fProxies[i] = image->fProxies[i]; // we ref in this case, not move
71 }
72 memcpy(fYUVAIndices, image->fYUVAIndices, 4 * sizeof(SkYUVAIndex));
73}
74
Jim Van Verthf49262d2018-10-02 12:07:20 -040075SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
76
77SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
78 // Note: this is the imageInfo for the flattened image, not the YUV planes
79 return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
Brian Osmane9560492019-02-05 17:00:03 -050080 fAlphaType, fTargetColorSpace ? fTargetColorSpace : fColorSpace);
Jim Van Verthf49262d2018-10-02 12:07:20 -040081}
82
Robert Phillips8defcc12019-03-05 15:58:59 -050083bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
84 if (!context || !fContext->priv().matches(context)) {
85 return false;
86 }
87
Jim Van Verth0e671942018-11-09 12:03:57 -050088 for (int i = 0; i < fNumProxies; ++i) {
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040089 GrTextureProducer::CopyParams copyParams;
90 int mipCount = SkMipMap::ComputeLevelCount(fProxies[i]->width(), fProxies[i]->height());
Robert Phillips9da87e02019-02-04 13:26:26 -050091 if (mipCount && GrGpu::IsACopyNeededForMips(fContext->priv().caps(),
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040092 fProxies[i].get(),
93 GrSamplerState::Filter::kMipMap,
94 &copyParams)) {
Robert Phillips8defcc12019-03-05 15:58:59 -050095 auto mippedProxy = GrCopyBaseMipMapToTextureProxy(context, fProxies[i].get());
Jim Van Verthf542cab2018-11-07 12:08:21 -050096 if (!mippedProxy) {
97 return false;
98 }
99 fProxies[i] = mippedProxy;
Jim Van Verth30e0d7f2018-11-02 13:36:42 -0400100 }
101 }
102 return true;
103}
104
Jim Van Verthf49262d2018-10-02 12:07:20 -0400105//////////////////////////////////////////////////////////////////////////////////////////////////
Jim Van Verthf49262d2018-10-02 12:07:20 -0400106
Robert Phillips193c4212019-03-04 12:18:53 -0500107GrTextureProxy* SkImage_GpuYUVA::peekProxy() const {
108 return fRGBProxy.get();
109}
110
Robert Phillips6603a172019-03-05 12:35:44 -0500111sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef(GrRecordingContext* context) const {
112 if (fRGBProxy) {
113 return fRGBProxy;
Jim Van Verthf49262d2018-10-02 12:07:20 -0400114 }
115
Robert Phillips6603a172019-03-05 12:35:44 -0500116 if (!context || !fContext->priv().matches(context)) {
117 return nullptr;
118 }
119
120 const GrBackendFormat format =
121 fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
122
123 // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
124 sk_sp<GrRenderTargetContext> renderTargetContext(
125 context->priv().makeDeferredRenderTargetContext(
126 format, SkBackingFit::kExact, this->width(), this->height(),
127 kRGBA_8888_GrPixelConfig, fColorSpace, 1, GrMipMapped::kNo, fOrigin));
128 if (!renderTargetContext) {
129 return nullptr;
130 }
131
132 auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), fAlphaType,
133 fTargetColorSpace.get(), fAlphaType);
134 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
135 if (!RenderYUVAToRGBA(fContext.get(), renderTargetContext.get(), rect, fYUVColorSpace,
136 std::move(colorSpaceXform), fProxies, fYUVAIndices)) {
137 return nullptr;
138 }
139
140 fRGBProxy = renderTargetContext->asTextureProxyRef();
Jim Van Verthf49262d2018-10-02 12:07:20 -0400141 return fRGBProxy;
142}
143
Robert Phillips6603a172019-03-05 12:35:44 -0500144sk_sp<GrTextureProxy> SkImage_GpuYUVA::asMippedTextureProxyRef(GrRecordingContext* context) const {
145 if (!context || !fContext->priv().matches(context)) {
146 return nullptr;
147 }
148
Jim Van Verth803a5022018-11-05 15:55:53 -0500149 // if invalid or already has miplevels
Robert Phillips6603a172019-03-05 12:35:44 -0500150 auto proxy = this->asTextureProxyRef(context);
Jim Van Verth803a5022018-11-05 15:55:53 -0500151 if (!proxy || GrMipMapped::kYes == fRGBProxy->mipMapped()) {
152 return proxy;
153 }
154
155 // need to generate mips for the proxy
Robert Phillips8defcc12019-03-05 15:58:59 -0500156 if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(context, proxy.get())) {
Jim Van Verth803a5022018-11-05 15:55:53 -0500157 fRGBProxy = mippedProxy;
158 return mippedProxy;
159 }
160
161 // failed to generate mips
162 return nullptr;
163}
164
Jim Van Verth9bf81202018-10-30 15:53:36 -0400165//////////////////////////////////////////////////////////////////////////////////////////////////
166
Robert Phillips6603a172019-03-05 12:35:44 -0500167sk_sp<SkImage> SkImage_GpuYUVA::onMakeColorTypeAndColorSpace(GrRecordingContext*,
168 SkColorType,
Brian Osmanf48c9962019-01-14 11:15:50 -0500169 sk_sp<SkColorSpace> targetCS) const {
170 // We explicitly ignore color type changes, for now.
171
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500172 // we may need a mutex here but for now we expect usage to be in a single thread
173 if (fOnMakeColorSpaceTarget &&
Brian Osmanf48c9962019-01-14 11:15:50 -0500174 SkColorSpace::Equals(targetCS.get(), fOnMakeColorSpaceTarget.get())) {
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500175 return fOnMakeColorSpaceResult;
176 }
Brian Osmanf48c9962019-01-14 11:15:50 -0500177 sk_sp<SkImage> result = sk_sp<SkImage>(new SkImage_GpuYUVA(this, targetCS));
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500178 if (result) {
Brian Osmanf48c9962019-01-14 11:15:50 -0500179 fOnMakeColorSpaceTarget = targetCS;
Jim Van Verth3e4c2f32019-01-11 13:32:45 -0500180 fOnMakeColorSpaceResult = result;
181 }
182 return result;
183}
184
185//////////////////////////////////////////////////////////////////////////////////////////////////
186
Jim Van Verth9bf81202018-10-30 15:53:36 -0400187sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
188 SkYUVColorSpace colorSpace,
189 const GrBackendTexture yuvaTextures[],
190 const SkYUVAIndex yuvaIndices[4],
191 SkISize imageSize,
192 GrSurfaceOrigin imageOrigin,
193 sk_sp<SkColorSpace> imageColorSpace) {
Jim Van Verth0e671942018-11-09 12:03:57 -0500194 int numTextures;
195 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
196 return nullptr;
Jim Van Verth9bf81202018-10-30 15:53:36 -0400197 }
198
Jim Van Verth0e671942018-11-09 12:03:57 -0500199 sk_sp<GrTextureProxy> tempTextureProxies[4];
Jim Van Verth53275362018-11-09 15:42:35 -0500200 if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
201 imageOrigin, tempTextureProxies)) {
Jim Van Verth0e671942018-11-09 12:03:57 -0500202 return nullptr;
Jim Van Verth9bf81202018-10-30 15:53:36 -0400203 }
204
205 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
206 kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500207 numTextures, yuvaIndices, imageOrigin, imageColorSpace);
Jim Van Verth9bf81202018-10-30 15:53:36 -0400208}
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500209
210sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(
211 GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[],
212 const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin,
213 bool buildMips, bool limitToMaxTextureSize, sk_sp<SkColorSpace> imageColorSpace) {
214 int numPixmaps;
215 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numPixmaps)) {
216 return nullptr;
217 }
218
219 // Make proxies
Robert Phillips9da87e02019-02-04 13:26:26 -0500220 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500221 sk_sp<GrTextureProxy> tempTextureProxies[4];
222 for (int i = 0; i < numPixmaps; ++i) {
223 const SkPixmap* pixmap = &yuvaPixmaps[i];
224 SkAutoPixmapStorage resized;
Robert Phillips9da87e02019-02-04 13:26:26 -0500225 int maxTextureSize = context->priv().caps()->maxTextureSize();
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500226 int maxDim = SkTMax(yuvaPixmaps[i].width(), yuvaPixmaps[i].height());
227 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
228 float scale = static_cast<float>(maxTextureSize) / maxDim;
229 int newWidth = SkTMin(static_cast<int>(yuvaPixmaps[i].width() * scale),
230 maxTextureSize);
231 int newHeight = SkTMin(static_cast<int>(yuvaPixmaps[i].height() * scale),
232 maxTextureSize);
233 SkImageInfo info = yuvaPixmaps[i].info().makeWH(newWidth, newHeight);
234 if (!resized.tryAlloc(info) ||
235 !yuvaPixmaps[i].scalePixels(resized, kLow_SkFilterQuality)) {
236 return nullptr;
237 }
238 pixmap = &resized;
239 }
240 // Turn the pixmap into a GrTextureProxy
241 if (buildMips) {
242 SkBitmap bmp;
243 bmp.installPixels(*pixmap);
244 tempTextureProxies[i] = proxyProvider->createMipMapProxyFromBitmap(bmp);
Jim Van Verthbd975d42018-12-06 15:16:14 +0000245 }
246 if (!tempTextureProxies[i]) {
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500247 if (SkImageInfoIsValid(pixmap->info())) {
248 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]",
249 pixmap->width(), pixmap->height());
250 // We don't need a release proc on the data in pixmap since we know we are in a
251 // GrContext that has a resource provider. Thus the createTextureProxy call will
252 // immediately upload the data.
253 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
254 tempTextureProxies[i] =
255 proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
256 SkBudgeted::kYes, SkBackingFit::kExact);
257 }
258 }
259
260 if (!tempTextureProxies[i]) {
261 return nullptr;
262 }
263 }
264
265 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageSize.width(), imageSize.height(),
266 kNeedNewImageUniqueID, yuvColorSpace, tempTextureProxies,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500267 numPixmaps, yuvaIndices, imageOrigin, imageColorSpace);
Jim Van Verthc8429ad2018-11-20 11:12:37 -0500268}
269
270
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400271/////////////////////////////////////////////////////////////////////////////////////////////////
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500272sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
273 GrContext* context,
274 SkYUVColorSpace yuvColorSpace,
275 const GrBackendFormat yuvaFormats[],
276 const SkISize yuvaSizes[],
277 const SkYUVAIndex yuvaIndices[4],
278 int imageWidth,
279 int imageHeight,
280 GrSurfaceOrigin imageOrigin,
281 sk_sp<SkColorSpace> imageColorSpace,
282 PromiseImageTextureFulfillProc textureFulfillProc,
283 PromiseImageTextureReleaseProc textureReleaseProc,
284 PromiseImageTextureDoneProc promiseDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500285 PromiseImageTextureContext textureContexts[],
286 PromiseImageApiVersion version) {
Jim Van Verthf00b1622018-10-10 13:03:23 -0400287 int numTextures;
288 bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);
289
Brian Salomonbe5a0932018-12-10 10:03:26 -0500290 // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
291 // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
292 // responsibility for calling the done proc.
293 if (!promiseDoneProc) {
294 return nullptr;
Jim Van Verthf00b1622018-10-10 13:03:23 -0400295 }
Brian Salomonbe5a0932018-12-10 10:03:26 -0500296 int proxiesCreated = 0;
297 SkScopeExit callDone([promiseDoneProc, textureContexts, numTextures, &proxiesCreated]() {
298 for (int i = proxiesCreated; i < numTextures; ++i) {
299 promiseDoneProc(textureContexts[i]);
300 }
301 });
Jim Van Verthf00b1622018-10-10 13:03:23 -0400302
303 if (!valid) {
304 return nullptr;
305 }
Robert Phillipsef85d192018-10-09 11:24:09 -0400306
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400307 if (!context) {
308 return nullptr;
309 }
310
Greg Kaiser9a2169e2019-02-10 17:29:46 -0800311 if (imageWidth <= 0 || imageHeight <= 0) {
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400312 return nullptr;
313 }
314
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400315 SkAlphaType at = (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) ? kPremul_SkAlphaType
316 : kOpaque_SkAlphaType;
Jim Van Verthcea39022018-10-12 16:15:34 -0400317 SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kRGBA_8888_SkColorType,
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400318 at, imageColorSpace);
319 if (!SkImageInfoIsValid(info)) {
320 return nullptr;
321 }
322
Jim Van Verthf9f07352018-10-24 10:32:20 -0400323 // verify sizes with expected texture count
Jim Van Verth8f11e432018-10-18 14:36:59 -0400324 for (int i = 0; i < numTextures; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400325 if (yuvaSizes[i].isEmpty()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400326 return nullptr;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400327 }
328 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400329 for (int i = numTextures; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400330 if (!yuvaSizes[i].isEmpty()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400331 return nullptr;
332 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000333 }
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400334
335 // Get lazy proxies
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400336 sk_sp<GrTextureProxy> proxies[4];
Jim Van Verthf00b1622018-10-10 13:03:23 -0400337 for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
Brian Salomonf391d0f2018-12-14 09:18:50 -0500338 GrPixelConfig config =
Robert Phillips9da87e02019-02-04 13:26:26 -0500339 context->priv().caps()->getYUVAConfigFromBackendFormat(yuvaFormats[texIdx]);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500340 if (config == kUnknown_GrPixelConfig) {
Jim Van Verthf00b1622018-10-10 13:03:23 -0400341 return nullptr;
342 }
Brian Salomonbe5a0932018-12-10 10:03:26 -0500343 proxies[texIdx] = MakePromiseImageLazyProxy(
344 context, yuvaSizes[texIdx].width(), yuvaSizes[texIdx].height(), imageOrigin, config,
345 yuvaFormats[texIdx], GrMipMapped::kNo, textureFulfillProc, textureReleaseProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500346 promiseDoneProc, textureContexts[texIdx], version);
Brian Salomonbe5a0932018-12-10 10:03:26 -0500347 ++proxiesCreated;
Jim Van Verthf00b1622018-10-10 13:03:23 -0400348 if (!proxies[texIdx]) {
349 return nullptr;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400350 }
351 }
352
Jim Van Verthcea39022018-10-12 16:15:34 -0400353 return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight,
Jim Van Verth0e671942018-11-09 12:03:57 -0500354 kNeedNewImageUniqueID, yuvColorSpace, proxies, numTextures,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500355 yuvaIndices, imageOrigin, std::move(imageColorSpace));
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400356}