blob: 3c6c7f794c4ee88bc2119b0253e0368843a10aa2 [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"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050021#include "effects/GrYUVtoRGBEffect.h"
reed43fe6182015-09-08 08:37:36 -070022
Greg Daniel1445da62018-01-04 10:27:29 -050023sk_sp<SkCachedData> init_provider(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo,
24 void* planes[3]) {
25 sk_sp<SkCachedData> data;
26 data.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo));
reed43fe6182015-09-08 08:37:36 -070027
Greg Daniel1445da62018-01-04 10:27:29 -050028 if (data.get()) {
29 planes[0] = (void*)data->data();
msarett4984c3c2016-03-10 05:44:43 -080030 planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
31 yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
32 planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
33 yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
reed43fe6182015-09-08 08:37:36 -070034 } else {
msarett4984c3c2016-03-10 05:44:43 -080035 // Fetch yuv plane sizes for memory allocation.
36 if (!provider->onQueryYUV8(&yuvInfo->fSizeInfo, &yuvInfo->fColorSpace)) {
Greg Daniel1445da62018-01-04 10:27:29 -050037 return nullptr;
reed43fe6182015-09-08 08:37:36 -070038 }
39
40 // Allocate the memory for YUV
41 size_t totalSize(0);
msarett4984c3c2016-03-10 05:44:43 -080042 for (int i = 0; i < 3; i++) {
43 totalSize += yuvInfo->fSizeInfo.fWidthBytes[i] * yuvInfo->fSizeInfo.fSizes[i].fHeight;
reed43fe6182015-09-08 08:37:36 -070044 }
Greg Daniel1445da62018-01-04 10:27:29 -050045 data.reset(SkResourceCache::NewCachedData(totalSize));
46 planes[0] = data->writable_data();
msarett4984c3c2016-03-10 05:44:43 -080047 planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
48 yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
49 planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
50 yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
reed43fe6182015-09-08 08:37:36 -070051
msarett4984c3c2016-03-10 05:44:43 -080052 // Get the YUV planes.
53 if (!provider->onGetYUV8Planes(yuvInfo->fSizeInfo, planes)) {
Greg Daniel1445da62018-01-04 10:27:29 -050054 return nullptr;
reed43fe6182015-09-08 08:37:36 -070055 }
56
Greg Daniel1445da62018-01-04 10:27:29 -050057 // Decoding is done, cache the resulting YUV planes
58 SkYUVPlanesCache::Add(provider->onGetID(), data.get(), yuvInfo);
reed43fe6182015-09-08 08:37:36 -070059 }
Greg Daniel1445da62018-01-04 10:27:29 -050060 return data;
reed43fe6182015-09-08 08:37:36 -070061}
62
Greg Danielfb3abcd2018-02-02 15:48:33 -050063void GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) {
64 SkCachedData* cachedData = static_cast<SkCachedData*>(data);
65 SkASSERT(cachedData);
66 cachedData->unref();
67}
68
Christopher Cameron77e96662017-07-08 01:47:47 -070069sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc,
Brian Osman861ea5b2018-06-14 09:14:03 -040070 SkColorSpace* srcColorSpace,
71 SkColorSpace* dstColorSpace) {
reed43fe6182015-09-08 08:37:36 -070072 SkYUVPlanesCache::Info yuvInfo;
73 void* planes[3];
Greg Daniel1445da62018-01-04 10:27:29 -050074
75 sk_sp<SkCachedData> dataStorage = init_provider(this, &yuvInfo, planes);
76 if (!dataStorage) {
reed43fe6182015-09-08 08:37:36 -070077 return nullptr;
78 }
79
Greg Danielfb3abcd2018-02-02 15:48:33 -050080 sk_sp<GrTextureProxy> yuvTextureProxies[3];
msarett4984c3c2016-03-10 05:44:43 -080081 for (int i = 0; i < 3; i++) {
Greg Danielfb3abcd2018-02-02 15:48:33 -050082 int componentWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth;
83 int componentHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight;
84 // If the sizes of the components are not all the same we choose to create exact-match
85 // textures for the smaller onces rather than add a texture domain to the draw.
86 // TODO: revisit this decision to imporve texture reuse?
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050087 SkBackingFit fit =
Greg Danielfb3abcd2018-02-02 15:48:33 -050088 (componentWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) ||
89 (componentHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight)
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050090 ? SkBackingFit::kExact : SkBackingFit::kApprox;
91
Greg Danielfb3abcd2018-02-02 15:48:33 -050092 SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
93 SkPixmap pixmap(imageInfo, planes[i], yuvInfo.fSizeInfo.fWidthBytes[i]);
94 SkCachedData* dataStoragePtr = dataStorage.get();
95 // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
96 // the YUVGen_DataReleaseProc which will release this ref.
97 // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
98 // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
99 // life time of the proxy and not just upload. For non-DDL draws we should look into
100 // releasing this SkImage after uploads (by deleting the lambda after instantiation).
101 dataStoragePtr->ref();
102 sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
103 dataStoragePtr);
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500104
Greg Danielfb3abcd2018-02-02 15:48:33 -0500105 auto proxyProvider = ctx->contextPriv().proxyProvider();
106 yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500107 1, SkBudgeted::kYes, fit);
Robert Phillipsc1b60662018-06-26 10:20:08 -0400108
109 SkASSERT(yuvTextureProxies[i]->width() == yuvInfo.fSizeInfo.fSizes[i].fWidth);
110 SkASSERT(yuvTextureProxies[i]->height() == yuvInfo.fSizeInfo.fSizes[i].fHeight);
reed43fe6182015-09-08 08:37:36 -0700111 }
112
Greg Daniele1da1d92017-10-06 15:59:27 -0400113 // TODO: investigate preallocating mip maps here
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500114 sk_sp<GrRenderTargetContext> renderTargetContext(
115 ctx->contextPriv().makeDeferredRenderTargetContext(
Brian Osman9363ac42018-06-01 16:10:53 -0400116 SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr,
Brian Salomon366093f2018-02-13 09:25:22 -0500117 desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400118 if (!renderTargetContext) {
reed43fe6182015-09-08 08:37:36 -0700119 return nullptr;
120 }
121
reed43fe6182015-09-08 08:37:36 -0700122 GrPaint paint;
Brian Salomonaff329b2017-08-11 09:40:37 -0400123 auto yuvToRgbProcessor =
Greg Danielfb3abcd2018-02-02 15:48:33 -0500124 GrYUVtoRGBEffect::Make(std::move(yuvTextureProxies[0]),
125 std::move(yuvTextureProxies[1]),
126 std::move(yuvTextureProxies[2]),
Weiliang Chen3e95e572018-05-30 15:15:23 -0400127 yuvInfo.fColorSpace, false);
bungeman06ca8ec2016-06-09 08:01:03 -0700128 paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
brianosman717abfd2016-05-11 11:43:35 -0700129
Christopher Cameron77e96662017-07-08 01:47:47 -0700130 // If the caller expects the pixels in a different color space than the one from the image,
131 // apply a color conversion to do this.
Brian Salomonaff329b2017-08-11 09:40:37 -0400132 std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
Brian Osman47c27512018-06-18 10:58:51 -0400133 GrColorSpaceXformEffect::Make(srcColorSpace, dstColorSpace);
Christopher Cameron77e96662017-07-08 01:47:47 -0700134 if (colorConversionProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400135 paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
Christopher Cameron77e96662017-07-08 01:47:47 -0700136 }
137
reed374772b2016-10-05 17:33:02 -0700138 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
msarett4984c3c2016-03-10 05:44:43 -0800139 const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
Robert Phillips67c18d62017-01-20 12:44:06 -0500140 yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
reed43fe6182015-09-08 08:37:36 -0700141
Brian Salomon82f44312017-01-11 13:42:54 -0500142 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
reed43fe6182015-09-08 08:37:36 -0700143
Robert Phillips538f1a32017-03-08 14:32:55 -0500144 return renderTargetContext->asTextureProxyRef();
reed43fe6182015-09-08 08:37:36 -0700145}