blob: beccd7d032ad33aa3de4ff647acc452382c351ca [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"
9#include "GrClip.h"
Brian Osman47c27512018-06-18 10:58:51 -040010#include "GrColorSpaceXform.h"
reed43fe6182015-09-08 08:37:36 -070011#include "GrContext.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050012#include "GrContextPriv.h"
Greg Danielfb3abcd2018-02-02 15:48:33 -050013#include "GrProxyProvider.h"
Brian Osman11052242016-10-27 14:47:55 -040014#include "GrRenderTargetContext.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050015#include "GrTextureProxy.h"
Hal Canary95e3c052017-01-11 12:44:43 -050016#include "SkAutoMalloc.h"
reed43fe6182015-09-08 08:37:36 -070017#include "SkCachedData.h"
18#include "SkRefCnt.h"
19#include "SkResourceCache.h"
20#include "SkYUVPlanesCache.h"
Robert Phillips94ade752018-10-09 12:32:31 -040021#include "SkYUVAIndex.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050022#include "effects/GrYUVtoRGBEffect.h"
reed43fe6182015-09-08 08:37:36 -070023
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040024sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVSizeInfo* size,
Jim Van Verth0c583af2018-10-18 10:31:59 -040025 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040026 SkYUVColorSpace* colorSpace,
Jim Van Verth0c583af2018-10-18 10:31:59 -040027 const void* constPlanes[SkYUVSizeInfo::kMaxCount]) {
Greg Daniel1445da62018-01-04 10:27:29 -050028 sk_sp<SkCachedData> data;
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040029 SkYUVPlanesCache::Info yuvInfo;
30 data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
31
Jim Van Verth0c583af2018-10-18 10:31:59 -040032 void* planes[SkYUVSizeInfo::kMaxCount];
reed43fe6182015-09-08 08:37:36 -070033
Greg Daniel1445da62018-01-04 10:27:29 -050034 if (data.get()) {
Jim Van Verth0c583af2018-10-18 10:31:59 -040035 planes[0] = (void*)data->data(); // we should always have at least one plane
36
37 for (int i = 1; i < SkYUVSizeInfo::kMaxCount; ++i) {
38 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
39 SkASSERT(kUnknown_SkColorType == yuvInfo.fSizeInfo.fColorTypes[i] &&
40 !yuvInfo.fSizeInfo.fWidthBytes[i] &&
41 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
42 planes[i] = nullptr;
43 continue;
44 }
45
46 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
47 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
48 }
reed43fe6182015-09-08 08:37:36 -070049 } else {
msarett4984c3c2016-03-10 05:44:43 -080050 // Fetch yuv plane sizes for memory allocation.
Jim Van Verth0c583af2018-10-18 10:31:59 -040051 if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050052 return nullptr;
reed43fe6182015-09-08 08:37:36 -070053 }
54
Jim Van Verth0c583af2018-10-18 10:31:59 -040055 // Allocate the memory for YUVA
reed43fe6182015-09-08 08:37:36 -070056 size_t totalSize(0);
Jim Van Verth0c583af2018-10-18 10:31:59 -040057 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; i++) {
58 SkASSERT(kUnknown_SkColorType != yuvInfo.fSizeInfo.fColorTypes[i] ||
59 (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
60
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040061 totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070062 }
Jim Van Verth0c583af2018-10-18 10:31:59 -040063
Greg Daniel1445da62018-01-04 10:27:29 -050064 data.reset(SkResourceCache::NewCachedData(totalSize));
Jim Van Verth0c583af2018-10-18 10:31:59 -040065
Greg Daniel1445da62018-01-04 10:27:29 -050066 planes[0] = data->writable_data();
Jim Van Verth0c583af2018-10-18 10:31:59 -040067
68 for (int i = 1; i < SkYUVSizeInfo::kMaxCount; ++i) {
69 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
70 SkASSERT(kUnknown_SkColorType == yuvInfo.fSizeInfo.fColorTypes[i] &&
71 !yuvInfo.fSizeInfo.fWidthBytes[i] &&
72 !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 Verth0c583af2018-10-18 10:31: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 Verth0c583af2018-10-18 10:31: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 Verth0c583af2018-10-18 10:31: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
Christopher Cameron77e96662017-07-08 01:47:47 -0700106sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc,
Brian Osman861ea5b2018-06-14 09:14:03 -0400107 SkColorSpace* srcColorSpace,
108 SkColorSpace* dstColorSpace) {
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400109 SkYUVSizeInfo yuvSizeInfo;
Jim Van Verth0c583af2018-10-18 10:31:59 -0400110 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400111 SkYUVColorSpace yuvColorSpace;
Jim Van Verth0c583af2018-10-18 10:31:59 -0400112 const void* planes[SkYUVSizeInfo::kMaxCount];
Greg Daniel1445da62018-01-04 10:27:29 -0500113
Jim Van Verth0c583af2018-10-18 10:31:59 -0400114 sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
115 &yuvColorSpace, planes);
Greg Daniel1445da62018-01-04 10:27:29 -0500116 if (!dataStorage) {
reed43fe6182015-09-08 08:37:36 -0700117 return nullptr;
118 }
119
Jim Van Verth0c583af2018-10-18 10:31:59 -0400120 sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVSizeInfo::kMaxCount];
121 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
122 if (kUnknown_SkColorType == yuvSizeInfo.fColorTypes[i]) {
123 SkASSERT(!yuvSizeInfo.fSizes[i].fWidth ||
124 !yuvSizeInfo.fSizes[i].fHeight ||
125 !yuvSizeInfo.fWidthBytes[i]);
126 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 Verth0c583af2018-10-18 10:31: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
Greg Danielfb3abcd2018-02-02 15:48:33 -0500152 auto proxyProvider = ctx->contextPriv().proxyProvider();
153 yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500154 1, SkBudgeted::kYes, fit);
Robert Phillipsc1b60662018-06-26 10:20:08 -0400155
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400156 SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth);
157 SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight);
reed43fe6182015-09-08 08:37:36 -0700158 }
159
Greg Daniele1da1d92017-10-06 15:59:27 -0400160 // TODO: investigate preallocating mip maps here
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500161 sk_sp<GrRenderTargetContext> renderTargetContext(
162 ctx->contextPriv().makeDeferredRenderTargetContext(
Brian Osman9363ac42018-06-01 16:10:53 -0400163 SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr,
Brian Salomon366093f2018-02-13 09:25:22 -0500164 desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400165 if (!renderTargetContext) {
reed43fe6182015-09-08 08:37:36 -0700166 return nullptr;
167 }
168
reed43fe6182015-09-08 08:37:36 -0700169 GrPaint paint;
Jim Van Verth0c583af2018-10-18 10:31:59 -0400170 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace);
bungeman06ca8ec2016-06-09 08:01:03 -0700171 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700172
Christopher Cameron77e96662017-07-08 01:47:47 -0700173 // If the caller expects the pixels in a different color space than the one from the image,
174 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400175 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400176 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
177 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700178 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400179 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700180 }
181
reed374772b2016-10-05 17:33:02 -0700182 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth0c583af2018-10-18 10:31:59 -0400183 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
184 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700185
Brian Salomon82f44312017-01-11 13:42:54 -0500186 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
reed43fe6182015-09-08 08:37:36 -0700187
Robert Phillips538f1a32017-03-08 14:32:55 -0500188 return renderTargetContext->asTextureProxyRef();
reed43fe6182015-09-08 08:37:36 -0700189}