blob: 115374275766c1172aadb1f999e8c8ed0d8a8168 [file] [log] [blame]
reed43fe6182015-09-08 08:37:36 -07001/*
2 * Copyright 2015 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
Brian Salomonc65aec92017-03-09 09:03:58 -05008#include "GrYUVProvider.h"
Kevin Lubickf58e49f2019-04-08 12:14:21 -04009
10#include "GrCaps.h"
Brian Salomonc65aec92017-03-09 09:03:58 -050011#include "GrClip.h"
Brian Osman47c27512018-06-18 10:58:51 -040012#include "GrColorSpaceXform.h"
Greg Danielfb3abcd2018-02-02 15:48:33 -050013#include "GrProxyProvider.h"
Robert Phillips9338c602019-02-19 12:52:29 -050014#include "GrRecordingContext.h"
15#include "GrRecordingContextPriv.h"
Brian Osman11052242016-10-27 14:47:55 -040016#include "GrRenderTargetContext.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050017#include "GrTextureProxy.h"
Hal Canary95e3c052017-01-11 12:44:43 -050018#include "SkAutoMalloc.h"
reed43fe6182015-09-08 08:37:36 -070019#include "SkCachedData.h"
20#include "SkRefCnt.h"
21#include "SkResourceCache.h"
Robert Phillips94ade752018-10-09 12:32:31 -040022#include "SkYUVAIndex.h"
Kevin Lubickf58e49f2019-04-08 12:14:21 -040023#include "SkYUVPlanesCache.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050024#include "effects/GrYUVtoRGBEffect.h"
reed43fe6182015-09-08 08:37:36 -070025
Jim Van Verthe24b5872018-10-29 16:26:02 -040026sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVASizeInfo* size,
Jim Van Verth8f11e432018-10-18 14:36:59 -040027 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040028 SkYUVColorSpace* colorSpace,
Jim Van Verthe24b5872018-10-29 16:26:02 -040029 const void* constPlanes[SkYUVASizeInfo::kMaxCount]) {
Greg Daniel1445da62018-01-04 10:27:29 -050030 sk_sp<SkCachedData> data;
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040031 SkYUVPlanesCache::Info yuvInfo;
32 data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
33
Jim Van Verthe24b5872018-10-29 16:26:02 -040034 void* planes[SkYUVASizeInfo::kMaxCount];
reed43fe6182015-09-08 08:37:36 -070035
Greg Daniel1445da62018-01-04 10:27:29 -050036 if (data.get()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040037 planes[0] = (void*)data->data(); // we should always have at least one plane
38
Jim Van Verthe24b5872018-10-29 16:26:02 -040039 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040040 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040041 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040042 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
43 planes[i] = nullptr;
44 continue;
45 }
46
47 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
48 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
49 }
reed43fe6182015-09-08 08:37:36 -070050 } else {
msarett4984c3c2016-03-10 05:44:43 -080051 // Fetch yuv plane sizes for memory allocation.
Jim Van Verth8f11e432018-10-18 14:36:59 -040052 if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050053 return nullptr;
reed43fe6182015-09-08 08:37:36 -070054 }
55
Jim Van Verth8f11e432018-10-18 14:36:59 -040056 // Allocate the memory for YUVA
reed43fe6182015-09-08 08:37:36 -070057 size_t totalSize(0);
Jim Van Verthe24b5872018-10-29 16:26:02 -040058 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; i++) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040059 SkASSERT((yuvInfo.fSizeInfo.fWidthBytes[i] && yuvInfo.fSizeInfo.fSizes[i].fHeight) ||
Jim Van Verth8f11e432018-10-18 14:36:59 -040060 (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
61
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040062 totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070063 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040064
Greg Daniel1445da62018-01-04 10:27:29 -050065 data.reset(SkResourceCache::NewCachedData(totalSize));
Jim Van Verth8f11e432018-10-18 14:36:59 -040066
Greg Daniel1445da62018-01-04 10:27:29 -050067 planes[0] = data->writable_data();
Jim Van Verth8f11e432018-10-18 14:36:59 -040068
Jim Van Verthe24b5872018-10-29 16:26:02 -040069 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040070 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040071 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040072 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
73 planes[i] = nullptr;
74 continue;
75 }
76
77 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
78 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
79 }
reed43fe6182015-09-08 08:37:36 -070080
msarett4984c3c2016-03-10 05:44:43 -080081 // Get the YUV planes.
Jim Van Verth8f11e432018-10-18 14:36:59 -040082 if (!this->onGetYUVA8Planes(yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, planes)) {
Greg Daniel1445da62018-01-04 10:27:29 -050083 return nullptr;
reed43fe6182015-09-08 08:37:36 -070084 }
85
Greg Daniel1445da62018-01-04 10:27:29 -050086 // Decoding is done, cache the resulting YUV planes
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040087 SkYUVPlanesCache::Add(this->onGetID(), data.get(), &yuvInfo);
reed43fe6182015-09-08 08:37:36 -070088 }
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040089
90 *size = yuvInfo.fSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -040091 memcpy(yuvaIndices, yuvInfo.fYUVAIndices, sizeof(yuvInfo.fYUVAIndices));
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040092 *colorSpace = yuvInfo.fColorSpace;
93 constPlanes[0] = planes[0];
94 constPlanes[1] = planes[1];
95 constPlanes[2] = planes[2];
Jim Van Verth8f11e432018-10-18 14:36:59 -040096 constPlanes[3] = planes[3];
Greg Daniel1445da62018-01-04 10:27:29 -050097 return data;
reed43fe6182015-09-08 08:37:36 -070098}
99
Greg Danielfb3abcd2018-02-02 15:48:33 -0500100void GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) {
101 SkCachedData* cachedData = static_cast<SkCachedData*>(data);
102 SkASSERT(cachedData);
103 cachedData->unref();
104}
105
Robert Phillips9338c602019-02-19 12:52:29 -0500106sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrRecordingContext* ctx,
Greg Daniel4065d452018-11-16 15:43:41 -0500107 const GrBackendFormat& format,
108 const GrSurfaceDesc& desc,
Brian Osman861ea5b2018-06-14 09:14:03 -0400109 SkColorSpace* srcColorSpace,
110 SkColorSpace* dstColorSpace) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400111 SkYUVASizeInfo yuvSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400112 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400113 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400114 const void* planes[SkYUVASizeInfo::kMaxCount];
Greg Daniel1445da62018-01-04 10:27:29 -0500115
Jim Van Verth8f11e432018-10-18 14:36:59 -0400116 sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
117 &yuvColorSpace, planes);
Greg Daniel1445da62018-01-04 10:27:29 -0500118 if (!dataStorage) {
reed43fe6182015-09-08 08:37:36 -0700119 return nullptr;
120 }
121
Jim Van Verthe24b5872018-10-29 16:26:02 -0400122 sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVASizeInfo::kMaxCount];
123 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400124 if (yuvSizeInfo.fSizes[i].isEmpty()) {
125 SkASSERT(!yuvSizeInfo.fWidthBytes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400126 continue;
127 }
128
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400129 int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
130 int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
Greg Danielfb3abcd2018-02-02 15:48:33 -0500131 // If the sizes of the components are not all the same we choose to create exact-match
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400132 // textures for the smaller ones rather than add a texture domain to the draw.
133 // TODO: revisit this decision to improve texture reuse?
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500134 SkBackingFit fit =
Jim Van Verth8f11e432018-10-18 14:36:59 -0400135 (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
136 (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500137 ? SkBackingFit::kExact : SkBackingFit::kApprox;
138
Greg Danielfb3abcd2018-02-02 15:48:33 -0500139 SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400140 SkPixmap pixmap(imageInfo, planes[i], yuvSizeInfo.fWidthBytes[i]);
Greg Danielfb3abcd2018-02-02 15:48:33 -0500141 SkCachedData* dataStoragePtr = dataStorage.get();
142 // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
143 // the YUVGen_DataReleaseProc which will release this ref.
144 // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
145 // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
146 // life time of the proxy and not just upload. For non-DDL draws we should look into
147 // releasing this SkImage after uploads (by deleting the lambda after instantiation).
148 dataStoragePtr->ref();
149 sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
150 dataStoragePtr);
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500151
Robert Phillips9da87e02019-02-04 13:26:26 -0500152 auto proxyProvider = ctx->priv().proxyProvider();
Kevin Lubickf58e49f2019-04-08 12:14:21 -0400153 auto clearFlag = kNone_GrSurfaceFlags;
154 if (ctx->priv().caps()->shouldInitializeTextures() && fit == SkBackingFit::kApprox) {
155 clearFlag = kPerformInitialClear_GrSurfaceFlag;
156 }
157 yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, clearFlag,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500158 1, SkBudgeted::kYes, fit);
Robert Phillipsc1b60662018-06-26 10:20:08 -0400159
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400160 SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth);
161 SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight);
reed43fe6182015-09-08 08:37:36 -0700162 }
163
Greg Daniele1da1d92017-10-06 15:59:27 -0400164 // TODO: investigate preallocating mip maps here
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500165 sk_sp<GrRenderTargetContext> renderTargetContext(
Robert Phillips9da87e02019-02-04 13:26:26 -0500166 ctx->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500167 format, SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr,
Brian Salomon366093f2018-02-13 09:25:22 -0500168 desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400169 if (!renderTargetContext) {
reed43fe6182015-09-08 08:37:36 -0700170 return nullptr;
171 }
172
reed43fe6182015-09-08 08:37:36 -0700173 GrPaint paint;
Jim Van Verth30e0d7f2018-11-02 13:36:42 -0400174 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace,
175 GrSamplerState::Filter::kNearest);
bungeman06ca8ec2016-06-09 08:01:03 -0700176 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700177
Christopher Cameron77e96662017-07-08 01:47:47 -0700178 // If the caller expects the pixels in a different color space than the one from the image,
179 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400180 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400181 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
182 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700183 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400184 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700185 }
186
reed374772b2016-10-05 17:33:02 -0700187 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400188 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
189 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700190
Brian Osmanc337a632018-11-30 10:39:32 -0500191 SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
192 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, r);
reed43fe6182015-09-08 08:37:36 -0700193
Robert Phillips538f1a32017-03-08 14:32:55 -0500194 return renderTargetContext->asTextureProxyRef();
reed43fe6182015-09-08 08:37:36 -0700195}