return SkRef(src);
}
- return input->filterImage(src, this->mapContext(ctx), offset);
+ SkAutoTUnref<SkSpecialImage> result(input->filterImage(src, this->mapContext(ctx), offset));
+
+#if SK_SUPPORT_GPU
+ if (src->peekTexture() && result && !result->peekTexture()) {
+ // Keep the result on the GPU - this is still required for some
+ // image filters that don't support GPU in all cases
+ GrContext* context = src->peekTexture()->getContext();
+ return result->makeTextureImage(src->internal_getProxy(), context).release();
+ }
+#endif
+
+ return result.release();
}
#if SK_SUPPORT_GPU
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file
*/
+#include "SkSpecialImage.h"
+
+#if SK_SUPPORT_GPU
+#include "GrTexture.h"
+#include "GrTextureParams.h"
+#include "SkGr.h"
+#endif
#include "SkCanvas.h"
#include "SkImage_Base.h"
-#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
///////////////////////////////////////////////////////////////////////////////
return static_cast<const SkSpecialImage_Base*>(image);
}
+sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(SkImageFilter::Proxy* proxy,
+ GrContext* context) {
+#if SK_SUPPORT_GPU
+ if (!context) {
+ return nullptr;
+ }
+ if (GrTexture* peek = as_SIB(this)->peekTexture()) {
+ return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
+ }
+
+ SkBitmap bmp;
+ if (!this->internal_getBM(&bmp)) {
+ return nullptr;
+ }
+
+ SkAutoTUnref<GrTexture> resultTex(
+ GrRefCachedBitmapTexture(context, bmp, GrTextureParams::ClampNoFilter()));
+ if (!resultTex) {
+ return nullptr;
+ }
+
+ SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+
+ return SkSpecialImage::MakeFromGpu(proxy,
+ SkIRect::MakeWH(resultTex->width(), resultTex->height()),
+ this->uniqueID(),
+ resultTex, at);
+#else
+ return nullptr;
+#endif
+}
+
void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
return as_SIB(this)->onDraw(canvas, x, y, paint);
}
// remove this when internal_getProxy goes away (see skbug.com/4965)
#include "SkImageFilter.h"
+#include "SkImageInfo.h" // for SkAlphaType
+
+class GrContext;
class GrTexture;
class SkBitmap;
class SkCanvas;
class SkImage;
struct SkImageInfo;
class SkPaint;
+class SkPixmap;
class SkSpecialSurface;
enum {
virtual bool isOpaque() const { return false; }
virtual size_t getSize() const = 0;
+ /**
+ * Ensures that a special image is backed by a texture (when GrContext is non-null). If no
+ * transformation is required, the returned image may be the same as this special image.
+ * If this special image is from a different GrContext, this will fail.
+ */
+ sk_sp<SkSpecialImage> makeTextureImage(SkImageFilter::Proxy*, GrContext*);
+
/**
* Draw this SpecialImage into the canvas.
*/
#if SK_SUPPORT_GPU
+
+static void test_texture_backed(skiatest::Reporter* reporter,
+ const sk_sp<SkSpecialImage>& orig,
+ const sk_sp<SkSpecialImage>& gpuBacked) {
+ REPORTER_ASSERT(reporter, gpuBacked);
+ REPORTER_ASSERT(reporter, gpuBacked->peekTexture());
+ REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
+ REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
+ gpuBacked->subset().height() == orig->subset().height());
+}
+
+// Test out the SkSpecialImage::makeTextureImage entry point
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, context) {
+ SkBitmap bm = create_bm();
+
+ const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
+
+ {
+ // raster
+ sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
+ nullptr,
+ SkIRect::MakeWH(kFullSize,
+ kFullSize),
+ bm));
+
+ {
+ sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(nullptr, context));
+ test_texture_backed(reporter, rasterImage, fromRaster);
+ }
+
+ {
+ sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
+
+ sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(nullptr, context));
+ test_texture_backed(reporter, subRasterImage, fromSubRaster);
+ }
+ }
+
+ {
+ // gpu
+ GrSurfaceDesc desc;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fFlags = kNone_GrSurfaceFlags;
+ desc.fWidth = kFullSize;
+ desc.fHeight = kFullSize;
+
+ SkAutoTUnref<GrTexture> texture(context->textureProvider()->createTexture(desc,
+ SkBudgeted::kNo,
+ bm.getPixels(),
+ 0));
+ if (!texture) {
+ return;
+ }
+
+ sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeFromGpu(
+ nullptr,
+ SkIRect::MakeWH(kFullSize,
+ kFullSize),
+ kNeedNewImageUniqueID_SpecialImage,
+ texture));
+
+ {
+ sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(nullptr, context));
+ test_texture_backed(reporter, gpuImage, fromGPU);
+ }
+
+ {
+ sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset));
+
+ sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(nullptr, context));
+ test_texture_backed(reporter, subGPUImage, fromSubGPU);
+ }
+ }
+}
+
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, context) {
SkBitmap bm = create_bm();
desc.fWidth = kFullSize;
desc.fHeight = kFullSize;
- SkAutoTUnref<GrTexture> texture(context->textureProvider()->createTexture(desc, SkBudgeted::kNo,
+ SkAutoTUnref<GrTexture> texture(context->textureProvider()->createTexture(desc,
+ SkBudgeted::kNo,
bm.getPixels(), 0));
if (!texture) {
return;