bsalomon | 045802d | 2015-10-20 07:58:01 -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 | |
| 8 | #include "GrTextureParamsAdjuster.h" |
| 9 | |
| 10 | #include "GrCaps.h" |
| 11 | #include "GrContext.h" |
| 12 | #include "GrDrawContext.h" |
| 13 | #include "GrGpu.h" |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 14 | #include "GrGpuResourcePriv.h" |
| 15 | #include "GrResourceKey.h" |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 16 | #include "GrTexture.h" |
| 17 | #include "GrTextureParams.h" |
| 18 | #include "GrTextureProvider.h" |
| 19 | #include "SkCanvas.h" |
| 20 | #include "SkGr.h" |
| 21 | #include "SkGrPriv.h" |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 22 | #include "effects/GrTextureDomain.h" |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 23 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 24 | typedef GrTextureProducer::CopyParams CopyParams; |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 25 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 26 | ////////////////////////////////////////////////////////////////////////////// |
| 27 | |
| 28 | static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, |
| 29 | const CopyParams& copyParams) { |
| 30 | SkASSERT(!subset || !subset->isEmpty()); |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 31 | GrContext* context = inputTexture->getContext(); |
| 32 | SkASSERT(context); |
| 33 | const GrCaps* caps = context->caps(); |
| 34 | |
| 35 | // Either it's a cache miss or the original wasn't cached to begin with. |
| 36 | GrSurfaceDesc rtDesc = inputTexture->desc(); |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 37 | rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; |
| 38 | rtDesc.fWidth = copyParams.fWidth; |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 39 | rtDesc.fHeight = copyParams.fHeight; |
| 40 | rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); |
| 41 | |
| 42 | // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise, |
| 43 | // fail. |
| 44 | if (!caps->isConfigRenderable(rtDesc.fConfig, false)) { |
| 45 | if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) { |
| 46 | if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
| 47 | rtDesc.fConfig = kAlpha_8_GrPixelConfig; |
| 48 | } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { |
| 49 | rtDesc.fConfig = kSkia8888_GrPixelConfig; |
| 50 | } else { |
| 51 | return nullptr; |
| 52 | } |
| 53 | } else if (kRGB_GrColorComponentFlags == |
| 54 | (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) { |
| 55 | if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { |
| 56 | rtDesc.fConfig = kSkia8888_GrPixelConfig; |
| 57 | } else { |
| 58 | return nullptr; |
| 59 | } |
| 60 | } else { |
| 61 | return nullptr; |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, true)); |
| 66 | if (!copy) { |
| 67 | return nullptr; |
| 68 | } |
| 69 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 70 | // TODO: If no scaling is being performed then use copySurface. |
| 71 | |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 72 | GrPaint paint; |
| 73 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 74 | SkScalar sx; |
| 75 | SkScalar sy; |
| 76 | if (subset) { |
| 77 | sx = 1.f / inputTexture->width(); |
| 78 | sy = 1.f / inputTexture->height(); |
| 79 | } |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 80 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 81 | if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset && |
| 82 | (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) { |
| 83 | SkRect domain; |
| 84 | domain.fLeft = (subset->fLeft + 0.5f) * sx; |
| 85 | domain.fTop = (subset->fTop + 0.5f)* sy; |
| 86 | domain.fRight = (subset->fRight - 0.5f) * sx; |
| 87 | domain.fBottom = (subset->fBottom - 0.5f) * sy; |
| 88 | // This would cause us to read values from outside the subset. Surely, the caller knows |
| 89 | // better! |
| 90 | SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode); |
| 91 | paint.addColorFragmentProcessor( |
| 92 | GrTextureDomainEffect::Create(inputTexture, SkMatrix::I(), domain, |
| 93 | GrTextureDomain::kClamp_Mode, |
| 94 | copyParams.fFilter))->unref(); |
| 95 | } else { |
| 96 | GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter); |
| 97 | paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); |
| 98 | } |
| 99 | |
| 100 | SkRect localRect; |
| 101 | if (subset) { |
| 102 | localRect = SkRect::Make(*subset); |
| 103 | localRect.fLeft *= sx; |
| 104 | localRect.fTop *= sy; |
| 105 | localRect.fRight *= sx; |
| 106 | localRect.fBottom *= sy; |
| 107 | } else { |
| 108 | localRect = SkRect::MakeWH(1.f, 1.f); |
| 109 | } |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 110 | |
| 111 | SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget())); |
| 112 | if (!drawContext) { |
| 113 | return nullptr; |
| 114 | } |
| 115 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 116 | SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); |
bsalomon | a2e69fc | 2015-11-05 10:41:43 -0800 | [diff] [blame] | 117 | drawContext->fillRectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), dstRect, localRect); |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 118 | return copy.detach(); |
| 119 | } |
| 120 | |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 121 | GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, const SkIRect& contentArea) |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 122 | : fOriginal(original) { |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 123 | if (contentArea.fLeft > 0 || contentArea.fTop > 0 || |
| 124 | contentArea.fRight < original->width() || contentArea.fBottom < original->height()) { |
| 125 | fContentArea.set(contentArea); |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 126 | } |
| 127 | } |
| 128 | |
| 129 | GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params, |
| 130 | SkIPoint* outOffset) { |
| 131 | GrTexture* texture = this->originalTexture(); |
| 132 | GrContext* context = texture->getContext(); |
| 133 | CopyParams copyParams; |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 134 | const SkIRect* contentArea = this->contentArea(); |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 135 | |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 136 | if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) { |
| 137 | // If we generate a MIP chain for texture it will read pixel values from outside the content |
| 138 | // area. |
| 139 | copyParams.fWidth = contentArea->width(); |
| 140 | copyParams.fHeight = contentArea->height(); |
| 141 | copyParams.fFilter = GrTextureParams::kBilerp_FilterMode; |
| 142 | } else if (!context->getGpu()->makeCopyForTextureParams(texture->width(), texture->height(), |
| 143 | params, ©Params)) { |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 144 | if (outOffset) { |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 145 | if (contentArea) { |
| 146 | outOffset->set(contentArea->fLeft, contentArea->fRight); |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 147 | } else { |
| 148 | outOffset->set(0, 0); |
| 149 | } |
| 150 | } |
| 151 | return SkRef(texture); |
| 152 | } |
| 153 | GrUniqueKey key; |
| 154 | this->makeCopyKey(copyParams, &key); |
| 155 | if (key.isValid()) { |
| 156 | GrTexture* result = context->textureProvider()->findAndRefTextureByUniqueKey(key); |
| 157 | if (result) { |
| 158 | return result; |
| 159 | } |
| 160 | } |
bsalomon | c75be34 | 2015-10-29 12:34:31 -0700 | [diff] [blame] | 161 | GrTexture* result = copy_on_gpu(texture, contentArea, copyParams); |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 162 | if (result) { |
| 163 | if (key.isValid()) { |
| 164 | result->resourcePriv().setUniqueKey(key); |
| 165 | this->didCacheCopy(key); |
| 166 | } |
| 167 | if (outOffset) { |
| 168 | outOffset->set(0, 0); |
| 169 | } |
| 170 | } |
| 171 | return result; |
| 172 | } |
| 173 | |
| 174 | ////////////////////////////////////////////////////////////////////////////// |
| 175 | |
| 176 | GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTextureParams& params) { |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 177 | CopyParams copyParams; |
| 178 | if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, |
| 179 | ©Params)) { |
| 180 | return this->refOriginalTexture(ctx); |
| 181 | } |
| 182 | GrUniqueKey copyKey; |
| 183 | this->makeCopyKey(copyParams, ©Key); |
| 184 | if (copyKey.isValid()) { |
| 185 | GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(copyKey); |
| 186 | if (result) { |
| 187 | return result; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | GrTexture* result = this->generateTextureForParams(ctx, copyParams); |
| 192 | if (!result) { |
| 193 | return nullptr; |
| 194 | } |
| 195 | |
| 196 | if (copyKey.isValid()) { |
| 197 | ctx->textureProvider()->assignUniqueKeyToTexture(copyKey, result); |
| 198 | this->didCacheCopy(copyKey); |
| 199 | } |
| 200 | return result; |
| 201 | } |
| 202 | |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 203 | GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyParams& copyParams) { |
bsalomon | 100b8f8 | 2015-10-28 08:37:44 -0700 | [diff] [blame] | 204 | SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); |
| 205 | if (!original) { |
| 206 | return nullptr; |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 207 | } |
bsalomon | 89fe56b | 2015-10-29 10:49:28 -0700 | [diff] [blame] | 208 | return copy_on_gpu(original, nullptr, copyParams); |
bsalomon | 045802d | 2015-10-20 07:58:01 -0700 | [diff] [blame] | 209 | } |