1/* 2 * Copyright 2016 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 "include/core/SkBitmap.h" 9#include "include/core/SkCanvas.h" 10#include "include/core/SkImage.h" 11#include "include/core/SkPixmap.h" 12#include "include/core/SkSurface.h" 13#include "include/gpu/GrBackendSurface.h" 14#include "include/gpu/GrDirectContext.h" 15#include "src/core/SkAutoPixmapStorage.h" 16#include "src/core/SkSpecialImage.h" 17#include "src/core/SkSpecialSurface.h" 18#include "src/gpu/GrDirectContextPriv.h" 19#include "src/gpu/GrProxyProvider.h" 20#include "src/gpu/GrSurfaceProxy.h" 21#include "src/gpu/GrTextureProxy.h" 22#include "src/gpu/SkGr.h" 23#include "tests/Test.h" 24 25// This test creates backing resources exactly sized to [kFullSize x kFullSize]. 26// It then wraps them in an SkSpecialImage with only the center (red) region being active. 27// It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none 28// of the inactive (green) region leaked out. 29 30static const int kSmallerSize = 10; 31static const int kPad = 3; 32static const int kFullSize = kSmallerSize + 2 * kPad; 33 34// Create a bitmap with red in the center and green around it 35static SkBitmap create_bm() { 36 SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType, 37 kPremul_SkAlphaType); 38 39 SkBitmap bm; 40 bm.allocPixels(ii); 41 42 SkCanvas temp(bm); 43 44 temp.clear(SK_ColorGREEN); 45 SkPaint p; 46 p.setColor(SK_ColorRED); 47 p.setAntiAlias(false); 48 49 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad), 50 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)), 51 p); 52 53 bm.setImmutable(); 54 return bm; 55} 56 57// Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw) 58static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter, 59 GrRecordingContext* rContext, bool isGPUBacked) { 60 const SkIRect subset = img->subset(); 61 REPORTER_ASSERT(reporter, kPad == subset.left()); 62 REPORTER_ASSERT(reporter, kPad == subset.top()); 63 REPORTER_ASSERT(reporter, kSmallerSize == subset.width()); 64 REPORTER_ASSERT(reporter, kSmallerSize == subset.height()); 65 66 //-------------- 67 // Test that isTextureBacked reports the correct backing type 68 REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked()); 69 70 //-------------- 71 // Test view - as long as there is a context this should succeed 72 if (rContext) { 73 GrSurfaceProxyView view = img->view(rContext); 74 REPORTER_ASSERT(reporter, view.asTextureProxy()); 75 } 76 77 //-------------- 78 // Test getROPixels - this only works for raster-backed special images 79 if (!img->isTextureBacked()) { 80 SkBitmap bitmap; 81 REPORTER_ASSERT(reporter, img->getROPixels(&bitmap)); 82 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width()); 83 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height()); 84 } 85 86 //-------------- 87 // Test that draw restricts itself to the subset 88 sk_sp<SkSpecialSurface> surf(img->makeSurface(kN32_SkColorType, img->getColorSpace(), 89 SkISize::Make(kFullSize, kFullSize), 90 kPremul_SkAlphaType, SkSurfaceProps())); 91 92 SkCanvas* canvas = surf->getCanvas(); 93 94 canvas->clear(SK_ColorBLUE); 95 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad)); 96 97 SkBitmap bm; 98 bm.allocN32Pixels(kFullSize, kFullSize, false); 99 100 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0); 101 SkASSERT_RELEASE(result); 102 103 // Only the center (red) portion should've been drawn into the canvas 104 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1)); 105 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad)); 106 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1, 107 kSmallerSize+kPad-1)); 108 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad, 109 kSmallerSize+kPad)); 110 111 //-------------- 112 // Test that asImage & makeTightSurface return appropriately sized objects 113 // of the correct backing type 114 SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height()); 115 { 116 sk_sp<SkImage> tightImg(img->asImage(&newSubset)); 117 118 REPORTER_ASSERT(reporter, tightImg->width() == subset.width()); 119 REPORTER_ASSERT(reporter, tightImg->height() == subset.height()); 120 REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked()); 121 SkPixmap tmpPixmap; 122 REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap)); 123 } 124 { 125 sk_sp<SkSurface> tightSurf(img->makeTightSurface(kN32_SkColorType, img->getColorSpace(), 126 subset.size())); 127 128 REPORTER_ASSERT(reporter, tightSurf->width() == subset.width()); 129 REPORTER_ASSERT(reporter, tightSurf->height() == subset.height()); 130 GrBackendTexture backendTex = tightSurf->getBackendTexture( 131 SkSurface::kDiscardWrite_BackendHandleAccess); 132 REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid()); 133 SkPixmap tmpPixmap; 134 REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap)); 135 } 136} 137 138DEF_TEST(SpecialImage_Raster, reporter) { 139 SkBitmap bm = create_bm(); 140 141 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster( 142 SkIRect::MakeWH(kFullSize, kFullSize), 143 bm, SkSurfaceProps())); 144 145 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 146 147 { 148 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm, 149 SkSurfaceProps())); 150 test_image(subSImg1, reporter, nullptr, false); 151 } 152 153 { 154 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset)); 155 test_image(subSImg2, reporter, nullptr, false); 156 } 157} 158 159static void test_specialimage_image(skiatest::Reporter* reporter) { 160 SkBitmap bm = create_bm(); 161 162 sk_sp<SkImage> fullImage(bm.asImage()); 163 164 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage( 165 nullptr, 166 SkIRect::MakeWH(kFullSize, kFullSize), 167 fullImage, 168 SkSurfaceProps())); 169 170 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 171 172 { 173 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage, 174 SkSurfaceProps())); 175 test_image(subSImg1, reporter, nullptr, false); 176 } 177 178 { 179 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset)); 180 test_image(subSImg2, reporter, nullptr, false); 181 } 182} 183 184DEF_TEST(SpecialImage_Image_Legacy, reporter) { 185 test_specialimage_image(reporter); 186} 187 188DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) { 189 auto context = ctxInfo.directContext(); 190 SkBitmap bm = create_bm(); 191 auto [view, ct] = GrMakeUncachedBitmapProxyView(context, bm); 192 if (!view) { 193 return; 194 } 195 196 sk_sp<SkSpecialImage> fullSImg = 197 SkSpecialImage::MakeDeferredFromGpu(context, 198 SkIRect::MakeWH(kFullSize, kFullSize), 199 kNeedNewImageUniqueID_SpecialImage, 200 view, 201 ct, 202 nullptr, 203 SkSurfaceProps()); 204 205 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 206 207 { 208 sk_sp<SkSpecialImage> subSImg1 = SkSpecialImage::MakeDeferredFromGpu( 209 context, 210 subset, 211 kNeedNewImageUniqueID_SpecialImage, 212 std::move(view), 213 ct, 214 nullptr, 215 SkSurfaceProps()); 216 test_image(subSImg1, reporter, context, true); 217 } 218 219 { 220 sk_sp<SkSpecialImage> subSImg2 = fullSImg->makeSubset(subset); 221 test_image(subSImg2, reporter, context, true); 222 } 223} 224