blob: c85d29445c0ef9f1a6c1ecf62a2e958b8b91d947 [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 Verth8f11e432018-10-18 14:36:59 -040025 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040026 SkYUVColorSpace* colorSpace,
Jim Van Verth8f11e432018-10-18 14:36: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 Verth8f11e432018-10-18 14:36: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 Verth8f11e432018-10-18 14:36: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]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040039 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040040 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
41 planes[i] = nullptr;
42 continue;
43 }
44
45 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
46 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
47 }
reed43fe6182015-09-08 08:37:36 -070048 } else {
msarett4984c3c2016-03-10 05:44:43 -080049 // Fetch yuv plane sizes for memory allocation.
Jim Van Verth8f11e432018-10-18 14:36:59 -040050 if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050051 return nullptr;
reed43fe6182015-09-08 08:37:36 -070052 }
53
Jim Van Verth8f11e432018-10-18 14:36:59 -040054 // Allocate the memory for YUVA
reed43fe6182015-09-08 08:37:36 -070055 size_t totalSize(0);
Jim Van Verth8f11e432018-10-18 14:36:59 -040056 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; i++) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040057 SkASSERT((yuvInfo.fSizeInfo.fWidthBytes[i] && yuvInfo.fSizeInfo.fSizes[i].fHeight) ||
Jim Van Verth8f11e432018-10-18 14:36:59 -040058 (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
59
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040060 totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070061 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040062
Greg Daniel1445da62018-01-04 10:27:29 -050063 data.reset(SkResourceCache::NewCachedData(totalSize));
Jim Van Verth8f11e432018-10-18 14:36:59 -040064
Greg Daniel1445da62018-01-04 10:27:29 -050065 planes[0] = data->writable_data();
Jim Van Verth8f11e432018-10-18 14:36:59 -040066
67 for (int i = 1; i < SkYUVSizeInfo::kMaxCount; ++i) {
68 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040069 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040070 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
71 planes[i] = nullptr;
72 continue;
73 }
74
75 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
76 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
77 }
reed43fe6182015-09-08 08:37:36 -070078
msarett4984c3c2016-03-10 05:44:43 -080079 // Get the YUV planes.
Jim Van Verth8f11e432018-10-18 14:36:59 -040080 if (!this->onGetYUVA8Planes(yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, planes)) {
Greg Daniel1445da62018-01-04 10:27:29 -050081 return nullptr;
reed43fe6182015-09-08 08:37:36 -070082 }
83
Greg Daniel1445da62018-01-04 10:27:29 -050084 // Decoding is done, cache the resulting YUV planes
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040085 SkYUVPlanesCache::Add(this->onGetID(), data.get(), &yuvInfo);
reed43fe6182015-09-08 08:37:36 -070086 }
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040087
88 *size = yuvInfo.fSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -040089 memcpy(yuvaIndices, yuvInfo.fYUVAIndices, sizeof(yuvInfo.fYUVAIndices));
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040090 *colorSpace = yuvInfo.fColorSpace;
91 constPlanes[0] = planes[0];
92 constPlanes[1] = planes[1];
93 constPlanes[2] = planes[2];
Jim Van Verth8f11e432018-10-18 14:36:59 -040094 constPlanes[3] = planes[3];
Greg Daniel1445da62018-01-04 10:27:29 -050095 return data;
reed43fe6182015-09-08 08:37:36 -070096}
97
Greg Danielfb3abcd2018-02-02 15:48:33 -050098void GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) {
99 SkCachedData* cachedData = static_cast<SkCachedData*>(data);
100 SkASSERT(cachedData);
101 cachedData->unref();
102}
103
Christopher Cameron77e96662017-07-08 01:47:47 -0700104sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc,
Brian Osman861ea5b2018-06-14 09:14:03 -0400105 SkColorSpace* srcColorSpace,
106 SkColorSpace* dstColorSpace) {
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400107 SkYUVSizeInfo yuvSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400108 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400109 SkYUVColorSpace yuvColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400110 const void* planes[SkYUVSizeInfo::kMaxCount];
Greg Daniel1445da62018-01-04 10:27:29 -0500111
Jim Van Verth8f11e432018-10-18 14:36:59 -0400112 sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
113 &yuvColorSpace, planes);
Greg Daniel1445da62018-01-04 10:27:29 -0500114 if (!dataStorage) {
reed43fe6182015-09-08 08:37:36 -0700115 return nullptr;
116 }
117
Jim Van Verth8f11e432018-10-18 14:36:59 -0400118 sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVSizeInfo::kMaxCount];
119 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400120 if (yuvSizeInfo.fSizes[i].isEmpty()) {
121 SkASSERT(!yuvSizeInfo.fWidthBytes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400122 continue;
123 }
124
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400125 int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
126 int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
Greg Danielfb3abcd2018-02-02 15:48:33 -0500127 // If the sizes of the components are not all the same we choose to create exact-match
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400128 // textures for the smaller ones rather than add a texture domain to the draw.
129 // TODO: revisit this decision to improve texture reuse?
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500130 SkBackingFit fit =
Jim Van Verth8f11e432018-10-18 14:36:59 -0400131 (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
132 (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500133 ? SkBackingFit::kExact : SkBackingFit::kApprox;
134
Greg Danielfb3abcd2018-02-02 15:48:33 -0500135 SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400136 SkPixmap pixmap(imageInfo, planes[i], yuvSizeInfo.fWidthBytes[i]);
Greg Danielfb3abcd2018-02-02 15:48:33 -0500137 SkCachedData* dataStoragePtr = dataStorage.get();
138 // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
139 // the YUVGen_DataReleaseProc which will release this ref.
140 // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
141 // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
142 // life time of the proxy and not just upload. For non-DDL draws we should look into
143 // releasing this SkImage after uploads (by deleting the lambda after instantiation).
144 dataStoragePtr->ref();
145 sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
146 dataStoragePtr);
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500147
Greg Danielfb3abcd2018-02-02 15:48:33 -0500148 auto proxyProvider = ctx->contextPriv().proxyProvider();
149 yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500150 1, SkBudgeted::kYes, fit);
Robert Phillipsc1b60662018-06-26 10:20:08 -0400151
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400152 SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth);
153 SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight);
reed43fe6182015-09-08 08:37:36 -0700154 }
155
Greg Daniele1da1d92017-10-06 15:59:27 -0400156 // TODO: investigate preallocating mip maps here
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500157 sk_sp<GrRenderTargetContext> renderTargetContext(
158 ctx->contextPriv().makeDeferredRenderTargetContext(
Brian Osman9363ac42018-06-01 16:10:53 -0400159 SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr,
Brian Salomon366093f2018-02-13 09:25:22 -0500160 desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400161 if (!renderTargetContext) {
reed43fe6182015-09-08 08:37:36 -0700162 return nullptr;
163 }
164
reed43fe6182015-09-08 08:37:36 -0700165 GrPaint paint;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400166 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace);
bungeman06ca8ec2016-06-09 08:01:03 -0700167 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700168
Christopher Cameron77e96662017-07-08 01:47:47 -0700169 // If the caller expects the pixels in a different color space than the one from the image,
170 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400171 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400172 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
173 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700174 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400175 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700176 }
177
reed374772b2016-10-05 17:33:02 -0700178 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400179 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
180 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700181
Brian Salomon82f44312017-01-11 13:42:54 -0500182 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
reed43fe6182015-09-08 08:37:36 -0700183
Robert Phillips538f1a32017-03-08 14:32:55 -0500184 return renderTargetContext->asTextureProxyRef();
reed43fe6182015-09-08 08:37:36 -0700185}