Index: src/gpu/GrTextureParamsAdjuster.cpp |
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9940f9e7d61261ddfe321c587ef7d951dc4071bb |
--- /dev/null |
+++ b/src/gpu/GrTextureParamsAdjuster.cpp |
@@ -0,0 +1,152 @@ |
+/* |
+ * Copyright 2015 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "GrTextureParamsAdjuster.h" |
+ |
+#include "GrCaps.h" |
+#include "GrContext.h" |
+#include "GrDrawContext.h" |
+#include "GrGpu.h" |
+#include "GrTexture.h" |
+#include "GrTextureParams.h" |
+#include "GrTextureProvider.h" |
+#include "SkCanvas.h" |
+#include "SkGr.h" |
+#include "SkGrPriv.h" |
+ |
+typedef GrTextureParamsAdjuster::CopyParams CopyParams; |
+ |
+static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyParams) { |
+ GrContext* context = inputTexture->getContext(); |
+ SkASSERT(context); |
+ const GrCaps* caps = context->caps(); |
+ |
+ // Either it's a cache miss or the original wasn't cached to begin with. |
+ GrSurfaceDesc rtDesc = inputTexture->desc(); |
+ rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; |
+ rtDesc.fWidth = copyParams.fWidth; |
+ rtDesc.fHeight = copyParams.fHeight; |
+ rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); |
+ |
+ // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise, |
+ // fail. |
+ if (!caps->isConfigRenderable(rtDesc.fConfig, false)) { |
+ if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) { |
+ if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
+ rtDesc.fConfig = kAlpha_8_GrPixelConfig; |
+ } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { |
+ rtDesc.fConfig = kSkia8888_GrPixelConfig; |
+ } else { |
+ return nullptr; |
+ } |
+ } else if (kRGB_GrColorComponentFlags == |
+ (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) { |
+ if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { |
+ rtDesc.fConfig = kSkia8888_GrPixelConfig; |
+ } else { |
+ return nullptr; |
+ } |
+ } else { |
+ return nullptr; |
+ } |
+ } |
+ |
+ SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, true)); |
+ if (!copy) { |
+ return nullptr; |
+ } |
+ |
+ GrPaint paint; |
+ |
+ // If filtering is not desired then we want to ensure all texels in the resampled image are |
+ // copies of texels from the original. |
+ GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter); |
+ paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); |
+ |
+ SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); |
+ SkRect localRect = SkRect::MakeWH(1.f, 1.f); |
+ |
+ SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget())); |
+ if (!drawContext) { |
+ return nullptr; |
+ } |
+ |
+ drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect); |
+ return copy.detach(); |
+} |
+ |
+static SkBitmap copy_on_cpu(const SkBitmap& bmp, const CopyParams& copyParams) { |
+ SkBitmap stretched; |
+ stretched.allocN32Pixels(copyParams.fWidth, copyParams.fHeight); |
+ SkCanvas canvas(stretched); |
+ SkPaint paint; |
+ switch (copyParams.fFilter) { |
+ case GrTextureParams::kNone_FilterMode: |
+ paint.setFilterQuality(kNone_SkFilterQuality); |
+ break; |
+ case GrTextureParams::kBilerp_FilterMode: |
+ paint.setFilterQuality(kLow_SkFilterQuality); |
+ break; |
+ case GrTextureParams::kMipMap_FilterMode: |
+ paint.setFilterQuality(kMedium_SkFilterQuality); |
+ break; |
+ } |
+ SkRect dstRect = SkRect::MakeWH(SkIntToScalar(copyParams.fWidth), |
+ SkIntToScalar(copyParams.fHeight)); |
+ canvas.drawBitmapRect(bmp, dstRect, &paint); |
+ return stretched; |
+} |
+ |
+GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx, |
+ const GrTextureParams& params) { |
+ CopyParams copyParams; |
+ if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, |
+ ©Params)) { |
+ return this->refOriginalTexture(ctx); |
+ } |
+ GrUniqueKey copyKey; |
+ this->makeCopyKey(copyParams, ©Key); |
+ if (copyKey.isValid()) { |
+ GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(copyKey); |
+ if (result) { |
+ return result; |
+ } |
+ } |
+ |
+ GrTexture* result = this->generateTextureForParams(ctx, copyParams); |
+ if (!result) { |
+ return nullptr; |
+ } |
+ |
+ if (copyKey.isValid()) { |
+ ctx->textureProvider()->assignUniqueKeyToTexture(copyKey, result); |
+ this->didCacheCopy(copyKey); |
+ } |
+ return result; |
+} |
+ |
+GrTexture* GrTextureParamsAdjuster::generateTextureForParams(GrContext* ctx, |
+ const CopyParams& copyParams) { |
+ if ((this->width() < ctx->caps()->minTextureSize() || |
+ this->height() < ctx->caps()->minTextureSize()) && !this->peekOriginalTexture()) |
+ { |
+ // we can't trust our ability to use HW to perform the stretch, so we request |
+ // a raster instead, and perform the stretch on the CPU. |
+ SkBitmap bitmap; |
+ if (!this->getROBitmap(&bitmap)) { |
+ return nullptr; |
+ } |
+ SkBitmap stretchedBmp = copy_on_cpu(bitmap, copyParams); |
+ return GrUploadBitmapToTexture(ctx, stretchedBmp); |
+ } else { |
+ SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); |
+ if (!original) { |
+ return nullptr; |
+ } |
+ return copy_on_gpu(original, copyParams); |
+ } |
+} |