| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 1 | /* | 
 | 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 Salomon | c65aec9 | 2017-03-09 09:03:58 -0500 | [diff] [blame] | 8 | #include "GrYUVProvider.h" | 
 | 9 | #include "GrClip.h" | 
| Brian Osman | 47c2751 | 2018-06-18 10:58:51 -0400 | [diff] [blame] | 10 | #include "GrColorSpaceXform.h" | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 11 | #include "GrContext.h" | 
| Robert Phillips | bc7a4fb | 2017-01-23 15:30:35 -0500 | [diff] [blame] | 12 | #include "GrContextPriv.h" | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 13 | #include "GrProxyProvider.h" | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 14 | #include "GrRenderTargetContext.h" | 
| Robert Phillips | bc7a4fb | 2017-01-23 15:30:35 -0500 | [diff] [blame] | 15 | #include "GrTextureProxy.h" | 
| Hal Canary | 95e3c05 | 2017-01-11 12:44:43 -0500 | [diff] [blame] | 16 | #include "SkAutoMalloc.h" | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 17 | #include "SkCachedData.h" | 
 | 18 | #include "SkRefCnt.h" | 
 | 19 | #include "SkResourceCache.h" | 
 | 20 | #include "SkYUVPlanesCache.h" | 
| Robert Phillips | 94ade75 | 2018-10-09 12:32:31 -0400 | [diff] [blame] | 21 | #include "SkYUVAIndex.h" | 
| Ethan Nicholas | 7461a4a | 2017-12-21 14:18:01 -0500 | [diff] [blame] | 22 | #include "effects/GrYUVtoRGBEffect.h" | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 23 |  | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 24 | sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVSizeInfo* size, | 
 | 25 |                                              SkYUVColorSpace* colorSpace, | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 26 |                                              const void* constPlanes[3]) { | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 27 |     sk_sp<SkCachedData> data; | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 28 |     SkYUVPlanesCache::Info yuvInfo; | 
 | 29 |     data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo)); | 
 | 30 |  | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 31 |     void* planes[3]; | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 32 |  | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 33 |     if (data.get()) { | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 34 |         planes[0] = (void*)data->data(); | 
 | 35 |         planes[1] = (uint8_t*)planes[0] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * | 
 | 36 |                                            yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); | 
 | 37 |         planes[2] = (uint8_t*)planes[1] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * | 
 | 38 |                                            yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 39 |     } else { | 
| msarett | 4984c3c | 2016-03-10 05:44:43 -0800 | [diff] [blame] | 40 |         // Fetch yuv plane sizes for memory allocation. | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 41 |         if (!this->onQueryYUV8(&yuvInfo.fSizeInfo, &yuvInfo.fColorSpace)) { | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 42 |             return nullptr; | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 43 |         } | 
 | 44 |  | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 45 |         // Allocate the memory for YUV | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 46 |         size_t totalSize(0); | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 47 |         for (int i = 0; i < 3; i++) { | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 48 |             totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight; | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 49 |         } | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 50 |         data.reset(SkResourceCache::NewCachedData(totalSize)); | 
 | 51 |         planes[0] = data->writable_data(); | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 52 |         planes[1] = (uint8_t*)planes[0] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * | 
 | 53 |                                            yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); | 
 | 54 |         planes[2] = (uint8_t*)planes[1] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * | 
 | 55 |                                            yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 56 |  | 
| msarett | 4984c3c | 2016-03-10 05:44:43 -0800 | [diff] [blame] | 57 |         // Get the YUV planes. | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 58 |         if (!this->onGetYUV8Planes(yuvInfo.fSizeInfo, planes)) { | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 59 |             return nullptr; | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 60 |         } | 
 | 61 |  | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 62 |         // Decoding is done, cache the resulting YUV planes | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 63 |         SkYUVPlanesCache::Add(this->onGetID(), data.get(), &yuvInfo); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 64 |     } | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 65 |  | 
 | 66 |     *size = yuvInfo.fSizeInfo; | 
 | 67 |     *colorSpace = yuvInfo.fColorSpace; | 
 | 68 |     constPlanes[0] = planes[0]; | 
 | 69 |     constPlanes[1] = planes[1]; | 
 | 70 |     constPlanes[2] = planes[2]; | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 71 |     return data; | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 72 | } | 
 | 73 |  | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 74 | void GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) { | 
 | 75 |     SkCachedData* cachedData = static_cast<SkCachedData*>(data); | 
 | 76 |     SkASSERT(cachedData); | 
 | 77 |     cachedData->unref(); | 
 | 78 | } | 
 | 79 |  | 
| Christopher Cameron | 77e9666 | 2017-07-08 01:47:47 -0700 | [diff] [blame] | 80 | sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc, | 
| Brian Osman | 861ea5b | 2018-06-14 09:14:03 -0400 | [diff] [blame] | 81 |                                                        SkColorSpace* srcColorSpace, | 
 | 82 |                                                        SkColorSpace* dstColorSpace) { | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 83 |     SkYUVSizeInfo yuvSizeInfo; | 
 | 84 |     SkYUVColorSpace yuvColorSpace; | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 85 |     const void* planes[3]; | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 86 |  | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 87 |     sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, &yuvColorSpace, planes); | 
| Greg Daniel | 1445da6 | 2018-01-04 10:27:29 -0500 | [diff] [blame] | 88 |     if (!dataStorage) { | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 89 |         return nullptr; | 
 | 90 |     } | 
 | 91 |  | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 92 |     sk_sp<GrTextureProxy> yuvTextureProxies[3]; | 
 | 93 |     for (int i = 0; i < 3; i++) { | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 94 |         int componentWidth  = yuvSizeInfo.fSizes[i].fWidth; | 
 | 95 |         int componentHeight = yuvSizeInfo.fSizes[i].fHeight; | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 96 |         // If the sizes of the components are not all the same we choose to create exact-match | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 97 |         // textures for the smaller ones rather than add a texture domain to the draw. | 
 | 98 |         // TODO: revisit this decision to improve texture reuse? | 
| Robert Phillips | bc7a4fb | 2017-01-23 15:30:35 -0500 | [diff] [blame] | 99 |         SkBackingFit fit = | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 100 |                 (componentWidth  != yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || | 
 | 101 |                 (componentHeight != yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight) | 
| Robert Phillips | bc7a4fb | 2017-01-23 15:30:35 -0500 | [diff] [blame] | 102 |                     ? SkBackingFit::kExact : SkBackingFit::kApprox; | 
 | 103 |  | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 104 |         SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight); | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 105 |         SkPixmap pixmap(imageInfo, planes[i], yuvSizeInfo.fWidthBytes[i]); | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 106 |         SkCachedData* dataStoragePtr = dataStorage.get(); | 
 | 107 |         // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call | 
 | 108 |         // the YUVGen_DataReleaseProc which will release this ref. | 
 | 109 |         // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the | 
 | 110 |         // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the | 
 | 111 |         // life time of the proxy and not just upload. For non-DDL draws we should look into | 
 | 112 |         // releasing this SkImage after uploads (by deleting the lambda after instantiation). | 
 | 113 |         dataStoragePtr->ref(); | 
 | 114 |         sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc, | 
 | 115 |                                                           dataStoragePtr); | 
| Robert Phillips | bc7a4fb | 2017-01-23 15:30:35 -0500 | [diff] [blame] | 116 |  | 
| Greg Daniel | fb3abcd | 2018-02-02 15:48:33 -0500 | [diff] [blame] | 117 |         auto proxyProvider = ctx->contextPriv().proxyProvider(); | 
 | 118 |         yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags, | 
| Brian Salomon | bdecacf | 2018-02-02 20:32:49 -0500 | [diff] [blame] | 119 |                                                                  1, SkBudgeted::kYes, fit); | 
| Robert Phillips | c1b6066 | 2018-06-26 10:20:08 -0400 | [diff] [blame] | 120 |  | 
| Robert Phillips | b4a8eac | 2018-09-21 08:26:33 -0400 | [diff] [blame] | 121 |         SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth); | 
 | 122 |         SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 123 |     } | 
 | 124 |  | 
| Greg Daniel | e1da1d9 | 2017-10-06 15:59:27 -0400 | [diff] [blame] | 125 |     // TODO: investigate preallocating mip maps here | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 126 |     sk_sp<GrRenderTargetContext> renderTargetContext( | 
 | 127 |         ctx->contextPriv().makeDeferredRenderTargetContext( | 
| Brian Osman | 9363ac4 | 2018-06-01 16:10:53 -0400 | [diff] [blame] | 128 |             SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, nullptr, | 
| Brian Salomon | 366093f | 2018-02-13 09:25:22 -0500 | [diff] [blame] | 129 |             desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin)); | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 130 |     if (!renderTargetContext) { | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 131 |         return nullptr; | 
 | 132 |     } | 
 | 133 |  | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 134 |     // This code path only generates I420 (i.e., 3 separate plane) YUVs | 
 | 135 |     SkYUVAIndex yuvaIndices[4] = { | 
 | 136 |         {  0, SkColorChannel::kA }, | 
 | 137 |         {  1, SkColorChannel::kA }, | 
 | 138 |         {  2, SkColorChannel::kA }, | 
 | 139 |         { -1, SkColorChannel::kA }, // no alpha | 
 | 140 |     }; | 
 | 141 |  | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 142 |     GrPaint paint; | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 143 |     auto yuvToRgbProcessor = | 
 | 144 |             GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace); | 
| bungeman | 06ca8ec | 2016-06-09 08:01:03 -0700 | [diff] [blame] | 145 |     paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); | 
| brianosman | 717abfd | 2016-05-11 11:43:35 -0700 | [diff] [blame] | 146 |  | 
| Christopher Cameron | 77e9666 | 2017-07-08 01:47:47 -0700 | [diff] [blame] | 147 |     // If the caller expects the pixels in a different color space than the one from the image, | 
 | 148 |     // apply a color conversion to do this. | 
| Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 149 |     std::unique_ptr<GrFragmentProcessor> colorConversionProcessor = | 
| Brian Osman | 15f0f29 | 2018-10-01 14:14:46 -0400 | [diff] [blame] | 150 |             GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType, | 
 | 151 |                                           dstColorSpace, kOpaque_SkAlphaType); | 
| Christopher Cameron | 77e9666 | 2017-07-08 01:47:47 -0700 | [diff] [blame] | 152 |     if (colorConversionProcessor) { | 
| Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 153 |         paint.addColorFragmentProcessor(std::move(colorConversionProcessor)); | 
| Christopher Cameron | 77e9666 | 2017-07-08 01:47:47 -0700 | [diff] [blame] | 154 |     } | 
 | 155 |  | 
| reed | 374772b | 2016-10-05 17:33:02 -0700 | [diff] [blame] | 156 |     paint.setPorterDuffXPFactory(SkBlendMode::kSrc); | 
| Jim Van Verth | f99a674 | 2018-10-18 16:13:18 +0000 | [diff] [blame^] | 157 |     const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, | 
 | 158 |                                      yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 159 |  | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 160 |     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 161 |  | 
| Robert Phillips | 538f1a3 | 2017-03-08 14:32:55 -0500 | [diff] [blame] | 162 |     return renderTargetContext->asTextureProxyRef(); | 
| reed | 43fe618 | 2015-09-08 08:37:36 -0700 | [diff] [blame] | 163 | } |