blob: 470bf2a29bb8d4edec8ab2d8492ffd836a53a7df [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,
Brian Salomona56a7462020-02-07 14:17:25 -0500108 SkISize dimensions,
Greg Danielcc104db2020-02-03 14:17:08 -0500109 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
Greg Danielc7672092020-02-06 14:32:54 -0500123 GrSurfaceProxyView yuvViews[SkYUVASizeInfo::kMaxCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400124 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 Danielc7672092020-02-06 14:32:54 -0500156 std::tie(yuvViews[i], std::ignore) = maker.view(GrMipMapped::kNo);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500157
Greg Danielc7672092020-02-06 14:32:54 -0500158 if (!yuvViews[i]) {
Greg Danielcc104db2020-02-03 14:17:08 -0500159 return {};
Greg Daniel8ec605e2020-01-08 11:14:15 -0500160 }
Robert Phillipsc1b60662018-06-26 10:20:08 -0400161
Greg Danielc7672092020-02-06 14:32:54 -0500162 SkASSERT(yuvViews[i].proxy()->dimensions() == yuvSizeInfo.fSizes[i]);
reed43fe6182015-09-08 08:37:36 -0700163 }
164
Greg Daniele1da1d92017-10-06 15:59:27 -0400165 // TODO: investigate preallocating mip maps here
Greg Daniele20fcad2020-01-08 11:52:34 -0500166 auto renderTargetContext = GrRenderTargetContext::Make(
Brian Salomona56a7462020-02-07 14:17:25 -0500167 ctx, colorType, nullptr, SkBackingFit::kExact, dimensions, 1, GrMipMapped::kNo,
168 GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Osman11052242016-10-27 14:47:55 -0400169 if (!renderTargetContext) {
Greg Danielcc104db2020-02-03 14:17:08 -0500170 return {};
reed43fe6182015-09-08 08:37:36 -0700171 }
172
reed43fe6182015-09-08 08:37:36 -0700173 GrPaint paint;
Brian Salomonca6b2f42020-01-24 11:31:21 -0500174 const auto& caps = *ctx->priv().caps();
Greg Danielc7672092020-02-06 14:32:54 -0500175 auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvViews, yuvaIndices, yuvColorSpace,
Brian Salomonca6b2f42020-01-24 11:31:21 -0500176 GrSamplerState::Filter::kNearest, caps);
bungeman06ca8ec2016-06-09 08:01:03 -0700177 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700178
Christopher Cameron77e96662017-07-08 01:47:47 -0700179 // If the caller expects the pixels in a different color space than the one from the image,
180 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400181 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman15f0f292018-10-01 14:14:46 -0400182 GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
183 dstColorSpace, kOpaque_SkAlphaType);
Christopher Cameron77e96662017-07-08 01:47:47 -0700184 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400185 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700186 }
187
reed374772b2016-10-05 17:33:02 -0700188 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400189 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
190 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700191
Brian Osmanc337a632018-11-30 10:39:32 -0500192 SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
193 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, r);
reed43fe6182015-09-08 08:37:36 -0700194
Greg Danielcc104db2020-02-03 14:17:08 -0500195 SkASSERT(renderTargetContext->asTextureProxy());
196 return renderTargetContext->readSurfaceView();
reed43fe6182015-09-08 08:37:36 -0700197}