blob: 3b5e5d8d518af3dfbd82b96f1460987767d5bf36 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/GrYUVProvider.h"
Kevin Lubickf58e49f2019-04-08 12:14:21 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkRefCnt.h"
11#include "include/core/SkYUVAIndex.h"
12#include "include/private/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkAutoMalloc.h"
14#include "src/core/SkCachedData.h"
15#include "src/core/SkResourceCache.h"
16#include "src/core/SkYUVPlanesCache.h"
Greg Daniel6f5441a2020-01-28 17:02:49 -050017#include "src/gpu/GrBitmapTextureMaker.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrCaps.h"
19#include "src/gpu/GrClip.h"
20#include "src/gpu/GrColorSpaceXform.h"
21#include "src/gpu/GrProxyProvider.h"
22#include "src/gpu/GrRecordingContextPriv.h"
23#include "src/gpu/GrRenderTargetContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040024#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/effects/GrYUVtoRGBEffect.h"
reed43fe6182015-09-08 08:37:36 -070026
Jim Van Verthe24b5872018-10-29 16:26:02 -040027sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVASizeInfo* size,
Jim Van Verth8f11e432018-10-18 14:36:59 -040028 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040029 SkYUVColorSpace* colorSpace,
Jim Van Verthe24b5872018-10-29 16:26:02 -040030 const void* constPlanes[SkYUVASizeInfo::kMaxCount]) {
Greg Daniel1445da62018-01-04 10:27:29 -050031 sk_sp<SkCachedData> data;
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040032 SkYUVPlanesCache::Info yuvInfo;
33 data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
34
Jim Van Verthe24b5872018-10-29 16:26:02 -040035 void* planes[SkYUVASizeInfo::kMaxCount];
reed43fe6182015-09-08 08:37:36 -070036
Greg Daniel1445da62018-01-04 10:27:29 -050037 if (data.get()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040038 planes[0] = (void*)data->data(); // we should always have at least one plane
39
Jim Van Verthe24b5872018-10-29 16:26:02 -040040 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040041 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040042 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040043 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
44 planes[i] = nullptr;
45 continue;
46 }
47
48 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
49 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
50 }
reed43fe6182015-09-08 08:37:36 -070051 } else {
msarett4984c3c2016-03-10 05:44:43 -080052 // Fetch yuv plane sizes for memory allocation.
Jim Van Verth8f11e432018-10-18 14:36:59 -040053 if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050054 return nullptr;
reed43fe6182015-09-08 08:37:36 -070055 }
56
Jim Van Verth8f11e432018-10-18 14:36:59 -040057 // Allocate the memory for YUVA
reed43fe6182015-09-08 08:37:36 -070058 size_t totalSize(0);
Jim Van Verthe24b5872018-10-29 16:26:02 -040059 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; i++) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040060 SkASSERT((yuvInfo.fSizeInfo.fWidthBytes[i] && yuvInfo.fSizeInfo.fSizes[i].fHeight) ||
Jim Van Verth8f11e432018-10-18 14:36:59 -040061 (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
62
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040063 totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070064 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040065
Greg Daniel1445da62018-01-04 10:27:29 -050066 data.reset(SkResourceCache::NewCachedData(totalSize));
Jim Van Verth8f11e432018-10-18 14:36:59 -040067
Greg Daniel1445da62018-01-04 10:27:29 -050068 planes[0] = data->writable_data();
Jim Van Verth8f11e432018-10-18 14:36:59 -040069
Jim Van Verthe24b5872018-10-29 16:26:02 -040070 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040071 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040072 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040073 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
74 planes[i] = nullptr;
75 continue;
76 }
77
78 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
79 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
80 }
reed43fe6182015-09-08 08:37:36 -070081
msarett4984c3c2016-03-10 05:44:43 -080082 // Get the YUV planes.
Jim Van Verth8f11e432018-10-18 14:36:59 -040083 if (!this->onGetYUVA8Planes(yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, planes)) {
Greg Daniel1445da62018-01-04 10:27:29 -050084 return nullptr;
reed43fe6182015-09-08 08:37:36 -070085 }
86
Greg Daniel1445da62018-01-04 10:27:29 -050087 // Decoding is done, cache the resulting YUV planes
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040088 SkYUVPlanesCache::Add(this->onGetID(), data.get(), &yuvInfo);
reed43fe6182015-09-08 08:37:36 -070089 }
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040090
91 *size = yuvInfo.fSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -040092 memcpy(yuvaIndices, yuvInfo.fYUVAIndices, sizeof(yuvInfo.fYUVAIndices));
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040093 *colorSpace = yuvInfo.fColorSpace;
94 constPlanes[0] = planes[0];
95 constPlanes[1] = planes[1];
96 constPlanes[2] = planes[2];
Jim Van Verth8f11e432018-10-18 14:36:59 -040097 constPlanes[3] = planes[3];
Greg Daniel1445da62018-01-04 10:27:29 -050098 return data;
reed43fe6182015-09-08 08:37:36 -070099}
100
Greg Daniel6f5441a2020-01-28 17:02:49 -0500101void GrYUVProvider::YUVGen_DataReleaseProc(void*, void* data) {
Greg Danielfb3abcd2018-02-02 15:48:33 -0500102 SkCachedData* cachedData = static_cast<SkCachedData*>(data);
103 SkASSERT(cachedData);
104 cachedData->unref();
105}
106
Greg Danielcc104db2020-02-03 14:17:08 -0500107GrSurfaceProxyView GrYUVProvider::refAsTextureProxyView(GrRecordingContext* ctx,
108 const GrSurfaceDesc& desc,
109 GrColorType colorType,
110 SkColorSpace* srcColorSpace,
111 SkColorSpace* dstColorSpace) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400112 SkYUVASizeInfo yuvSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400113 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400114 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400115 const void* planes[SkYUVASizeInfo::kMaxCount];
Greg Daniel1445da62018-01-04 10:27:29 -0500116
Jim Van Verth8f11e432018-10-18 14:36:59 -0400117 sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
118 &yuvColorSpace, planes);
Greg Daniel1445da62018-01-04 10:27:29 -0500119 if (!dataStorage) {
Greg Danielcc104db2020-02-03 14:17:08 -0500120 return {};
reed43fe6182015-09-08 08:37:36 -0700121 }
122
Jim Van Verthe24b5872018-10-29 16:26:02 -0400123 sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVASizeInfo::kMaxCount];
124 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400125 if (yuvSizeInfo.fSizes[i].isEmpty()) {
126 SkASSERT(!yuvSizeInfo.fWidthBytes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400127 continue;
128 }
129
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400130 int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
131 int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
Greg Danielfb3abcd2018-02-02 15:48:33 -0500132 // If the sizes of the components are not all the same we choose to create exact-match
Robert Phillipsb4a8eac2018-09-21 08:26:33 -0400133 // textures for the smaller ones rather than add a texture domain to the draw.
134 // TODO: revisit this decision to improve texture reuse?
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500135 SkBackingFit fit =
Jim Van Verth8f11e432018-10-18 14:36:59 -0400136 (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
137 (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500138 ? SkBackingFit::kExact : SkBackingFit::kApprox;
139
Greg Danielfb3abcd2018-02-02 15:48:33 -0500140 SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
Greg Danielfb3abcd2018-02-02 15:48:33 -0500141 SkCachedData* dataStoragePtr = dataStorage.get();
Greg Daniel6f5441a2020-01-28 17:02:49 -0500142 // We grab a ref to cached yuv data. When the SkBitmap we create below goes away it will
143 // call the YUVGen_DataReleaseProc which will release this ref.
Greg Danielfb3abcd2018-02-02 15:48:33 -0500144 // 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();
Greg Daniel6f5441a2020-01-28 17:02:49 -0500149 SkBitmap bitmap;
150 SkAssertResult(bitmap.installPixels(imageInfo, const_cast<void*>(planes[i]),
151 yuvSizeInfo.fWidthBytes[i],
152 YUVGen_DataReleaseProc, dataStoragePtr));
153 bitmap.setImmutable();
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500154
Greg Daniel6f5441a2020-01-28 17:02:49 -0500155 GrBitmapTextureMaker maker(ctx, bitmap, GrBitmapTextureMaker::Cached::kNo, fit);
Greg Danielc61d7e32020-02-04 14:27:45 -0500156 auto[view, grCT] = maker.view(GrMipMapped::kNo);
Greg Danielcc104db2020-02-03 14:17:08 -0500157 yuvTextureProxies[i] = view.asTextureProxyRef();
Greg Daniel6f5441a2020-01-28 17:02:49 -0500158
Greg Daniel8ec605e2020-01-08 11:14:15 -0500159 if (!yuvTextureProxies[i]) {
Greg Danielcc104db2020-02-03 14:17:08 -0500160 return {};
Greg Daniel8ec605e2020-01-08 11:14:15 -0500161 }
Robert Phillipsc1b60662018-06-26 10:20:08 -0400162
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400163 SkASSERT(yuvTextureProxies[i]->dimensions() == yuvSizeInfo.fSizes[i]);
reed43fe6182015-09-08 08:37:36 -0700164 }
165
Greg Daniele1da1d92017-10-06 15:59:27 -0400166 // TODO: investigate preallocating mip maps here
Greg Daniele20fcad2020-01-08 11:52:34 -0500167 auto renderTargetContext = GrRenderTargetContext::Make(
168 ctx, colorType, nullptr, SkBackingFit::kExact, {desc.fWidth, desc.fHeight}, 1,
169 GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Osman11052242016-10-27 14:47:55 -0400170 if (!renderTargetContext) {
Greg Danielcc104db2020-02-03 14:17:08 -0500171 return {};
reed43fe6182015-09-08 08:37:36 -0700172 }
173
reed43fe6182015-09-08 08:37:36 -0700174 GrPaint paint;
Brian Salomonca6b2f42020-01-24 11:31:21 -0500175 const auto& caps = *ctx->priv().caps();
Jim Van Verth30e0d7f2018-11-02 13:36:42 -0400176 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace,
Brian Salomonca6b2f42020-01-24 11:31:21 -0500177 GrSamplerState::Filter::kNearest, caps);
bungeman06ca8ec2016-06-09 08:01:03 -0700178 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700179
Christopher Cameron77e96662017-07-08 01:47:47 -0700180 // If the caller expects the pixels in a different color space than the one from the image,
181 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400182 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400183 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
184 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700185 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400186 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700187 }
188
reed374772b2016-10-05 17:33:02 -0700189 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400190 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
191 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700192
Brian Osmanc337a632018-11-30 10:39:32 -0500193 SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
194 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, r);
reed43fe6182015-09-08 08:37:36 -0700195
Greg Danielcc104db2020-02-03 14:17:08 -0500196 SkASSERT(renderTargetContext->asTextureProxy());
197 return renderTargetContext->readSurfaceView();
reed43fe6182015-09-08 08:37:36 -0700198}