blob: ca7dc6bd33d449fa7081645ae8aaace11c72e21a [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"
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040012#include "include/gpu/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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrColorSpaceXform.h"
20#include "src/gpu/GrProxyProvider.h"
21#include "src/gpu/GrRecordingContextPriv.h"
22#include "src/gpu/GrRenderTargetContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040023#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/effects/GrYUVtoRGBEffect.h"
reed43fe6182015-09-08 08:37:36 -070025
Jim Van Verthe24b5872018-10-29 16:26:02 -040026sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVASizeInfo* size,
Jim Van Verth8f11e432018-10-18 14:36:59 -040027 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040028 SkYUVColorSpace* colorSpace,
Jim Van Verthe24b5872018-10-29 16:26:02 -040029 const void* constPlanes[SkYUVASizeInfo::kMaxCount]) {
Greg Daniel1445da62018-01-04 10:27:29 -050030 sk_sp<SkCachedData> data;
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040031 SkYUVPlanesCache::Info yuvInfo;
32 data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
33
Jim Van Verthe24b5872018-10-29 16:26:02 -040034 void* planes[SkYUVASizeInfo::kMaxCount];
reed43fe6182015-09-08 08:37:36 -070035
Greg Daniel1445da62018-01-04 10:27:29 -050036 if (data.get()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040037 planes[0] = (void*)data->data(); // we should always have at least one plane
38
Jim Van Verthe24b5872018-10-29 16:26:02 -040039 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040040 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040041 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040042 !yuvInfo.fSizeInfo.fSizes[i].fHeight);
43 planes[i] = nullptr;
44 continue;
45 }
46
47 planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
48 yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
49 }
reed43fe6182015-09-08 08:37:36 -070050 } else {
msarett4984c3c2016-03-10 05:44:43 -080051 // Fetch yuv plane sizes for memory allocation.
Jim Van Verth8f11e432018-10-18 14:36:59 -040052 if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050053 return nullptr;
reed43fe6182015-09-08 08:37:36 -070054 }
55
Jim Van Verth8f11e432018-10-18 14:36:59 -040056 // Allocate the memory for YUVA
reed43fe6182015-09-08 08:37:36 -070057 size_t totalSize(0);
Jim Van Verthe24b5872018-10-29 16:26:02 -040058 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; i++) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040059 SkASSERT((yuvInfo.fSizeInfo.fWidthBytes[i] && yuvInfo.fSizeInfo.fSizes[i].fHeight) ||
Jim Van Verth8f11e432018-10-18 14:36:59 -040060 (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
61
Robert Phillipsb4a8eac2018-09-21 08:26:33 -040062 totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070063 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040064
Greg Daniel1445da62018-01-04 10:27:29 -050065 data.reset(SkResourceCache::NewCachedData(totalSize));
Jim Van Verth8f11e432018-10-18 14:36:59 -040066
Greg Daniel1445da62018-01-04 10:27:29 -050067 planes[0] = data->writable_data();
Jim Van Verth8f11e432018-10-18 14:36:59 -040068
Jim Van Verthe24b5872018-10-29 16:26:02 -040069 for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040070 if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -040071 SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
Jim Van Verth8f11e432018-10-18 14:36:59 -040072 !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 Verth8f11e432018-10-18 14:36: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 Verth8f11e432018-10-18 14:36: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 Verth8f11e432018-10-18 14:36: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 Daniel6f5441a2020-01-28 17:02:49 -0500100void GrYUVProvider::YUVGen_DataReleaseProc(void*, void* data) {
Greg Danielfb3abcd2018-02-02 15:48:33 -0500101 SkCachedData* cachedData = static_cast<SkCachedData*>(data);
102 SkASSERT(cachedData);
103 cachedData->unref();
104}
105
Greg Danielcc104db2020-02-03 14:17:08 -0500106GrSurfaceProxyView GrYUVProvider::refAsTextureProxyView(GrRecordingContext* ctx,
Brian Salomona56a7462020-02-07 14:17:25 -0500107 SkISize dimensions,
Greg Danielcc104db2020-02-03 14:17:08 -0500108 GrColorType colorType,
109 SkColorSpace* srcColorSpace,
Brian Salomonbc074a62020-03-18 10:06:13 -0400110 SkColorSpace* dstColorSpace,
111 SkBudgeted budgeted) {
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
Brian Salomonbc074a62020-03-18 10:06:13 -0400155 GrBitmapTextureMaker maker(ctx, bitmap, fit);
Brian Salomon7e67dca2020-07-21 09:27:25 -0400156 yuvViews[i] = 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 Salomon7e67dca2020-07-21 09:27:25 -0400167 ctx, colorType, nullptr, SkBackingFit::kExact, dimensions, 1, GrMipmapped::kNo,
Brian Salomonbc074a62020-03-18 10:06:13 -0400168 GrProtected::kNo, kTopLeft_GrSurfaceOrigin, budgeted);
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();
John Stiles3e627622020-06-29 12:47:04 -0400175 std::unique_ptr<GrFragmentProcessor> yuvToRgbProcessor = GrYUVtoRGBEffect::Make(
176 yuvViews, yuvaIndices, yuvColorSpace, GrSamplerState::Filter::kNearest, caps);
brianosman717abfd2016-05-11 11:43:35 -0700177
Christopher Cameron77e96662017-07-08 01:47:47 -0700178 // If the caller expects the pixels in a different color space than the one from the image,
179 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400180 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
John Stiles3e627622020-06-29 12:47:04 -0400181 GrColorSpaceXformEffect::Make(std::move(yuvToRgbProcessor),
182 srcColorSpace, kOpaque_SkAlphaType,
Brian Osman15f0f292018-10-01 14:14:46 -0400183 dstColorSpace, kOpaque_SkAlphaType);
John Stiles5933d7d2020-07-21 12:28:35 -0400184 paint.setColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700185
reed374772b2016-10-05 17:33:02 -0700186 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400187 const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
188 yuvSizeInfo.fSizes[0].fHeight);
reed43fe6182015-09-08 08:37:36 -0700189
Brian Osmanc337a632018-11-30 10:39:32 -0500190 SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
Michael Ludwig7c12e282020-05-29 09:54:07 -0400191 renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, m, r);
reed43fe6182015-09-08 08:37:36 -0700192
Greg Danielcc104db2020-02-03 14:17:08 -0500193 SkASSERT(renderTargetContext->asTextureProxy());
194 return renderTargetContext->readSurfaceView();
reed43fe6182015-09-08 08:37:36 -0700195}