blob: 6b3eb8867bde4a3098d1388d615fa7369b38e011 [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
Jim Van Verthe24b5872018-10-29 16:26:02 -040024sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVASizeInfo* 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 Verthe24b5872018-10-29 16:26:02 -040027 const void* constPlanes[SkYUVASizeInfo::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 Verthe24b5872018-10-29 16:26:02 -040032 void* planes[SkYUVASizeInfo::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
Jim Van Verthe24b5872018-10-29 16:26:02 -040037 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040038 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 Verthe24b5872018-10-29 16:26:02 -040056 for (int i = 0; i < SkYUVASizeInfo::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
Jim Van Verthe24b5872018-10-29 16:26:02 -040067 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040068 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
Greg Daniel4065d452018-11-16 15:43:41 -0500104sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx,
105 const GrBackendFormat& format,
106 const GrSurfaceDesc& desc,
Brian Osman861ea5b2018-06-14 09:14:03 -0400107 SkColorSpace* srcColorSpace,
108 SkColorSpace* dstColorSpace) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400109 SkYUVASizeInfo yuvSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400110 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400111 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400112 const void* planes[SkYUVASizeInfo::kMaxCount];
Greg Daniel1445da62018-01-04 10:27:29 -0500113
Jim Van Verth8f11e432018-10-18 14:36: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 Verthe24b5872018-10-29 16:26:02 -0400120 sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVASizeInfo::kMaxCount];
121 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400122 if (yuvSizeInfo.fSizes[i].isEmpty()) {
123 SkASSERT(!yuvSizeInfo.fWidthBytes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400124 continue;
125 }
126
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400127 int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
128 int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
Greg Danielfb3abcd2018-02-02 15:48:33 -0500129 // If the sizes of the components are not all the same we choose to create exact-match
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400130 // textures for the smaller ones rather than add a texture domain to the draw.
131 // TODO: revisit this decision to improve texture reuse?
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500132 SkBackingFit fit =
Jim Van Verth8f11e432018-10-18 14:36:59 -0400133 (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
134 (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500135 ? SkBackingFit::kExact : SkBackingFit::kApprox;
136
Greg Danielfb3abcd2018-02-02 15:48:33 -0500137 SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400138 SkPixmap pixmap(imageInfo, planes[i], yuvSizeInfo.fWidthBytes[i]);
Greg Danielfb3abcd2018-02-02 15:48:33 -0500139 SkCachedData* dataStoragePtr = dataStorage.get();
140 // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
141 // the YUVGen_DataReleaseProc which will release this ref.
142 // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
143 // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
144 // life time of the proxy and not just upload. For non-DDL draws we should look into
145 // releasing this SkImage after uploads (by deleting the lambda after instantiation).
146 dataStoragePtr->ref();
147 sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
148 dataStoragePtr);
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500149
Greg Danielfb3abcd2018-02-02 15:48:33 -0500150 auto proxyProvider = ctx->contextPriv().proxyProvider();
151 yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500152 1, SkBudgeted::kYes, fit);
Robert Phillipsc1b60662018-06-26 10:20:08 -0400153
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400154 SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth);
155 SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight);
reed43fe6182015-09-08 08:37:36 -0700156 }
157
Greg Daniele1da1d92017-10-06 15:59:27 -0400158 // TODO: investigate preallocating mip maps here
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500159 sk_sp<GrRenderTargetContext> renderTargetContext(
160 ctx->contextPriv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500161 format, SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr,
Brian Salomon366093f2018-02-13 09:25:22 -0500162 desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400163 if (!renderTargetContext) {
reed43fe6182015-09-08 08:37:36 -0700164 return nullptr;
165 }
166
reed43fe6182015-09-08 08:37:36 -0700167 GrPaint paint;
Jim Van Verth30e0d7f2018-11-02 13:36:42 -0400168 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace,
169 GrSamplerState::Filter::kNearest);
bungeman06ca8ec2016-06-09 08:01:03 -0700170 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700171
Christopher Cameron77e96662017-07-08 01:47:47 -0700172 // If the caller expects the pixels in a different color space than the one from the image,
173 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400174 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400175 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
176 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700177 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400178 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700179 }
180
reed374772b2016-10-05 17:33:02 -0700181 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400182 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
183 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700184
Brian Osmanc337a632018-11-30 10:39:32 -0500185 SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
186 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, 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}