1 /* 2 * Copyright 2014 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 // This test only works with the GPU backend. 9 10 #include "gm/gm.h" 11 #include "include/core/SkBitmap.h" 12 #include "include/core/SkColor.h" 13 #include "include/core/SkImageInfo.h" 14 #include "include/core/SkMatrix.h" 15 #include "include/core/SkRect.h" 16 #include "include/core/SkScalar.h" 17 #include "include/core/SkShader.h" 18 #include "include/core/SkSize.h" 19 #include "include/core/SkString.h" 20 #include "include/core/SkYUVAInfo.h" 21 #include "include/core/SkYUVAPixmaps.h" 22 #include "include/gpu/ganesh/GrDirectContext.h" 23 #include "src/core/SkCanvasPriv.h" 24 #include "src/gpu/ganesh/SkGr.h" 25 #include "tools/gpu/YUVUtils.h" 26 27 #include <memory> 28 #include <utility> 29 30 class SkCanvas; 31 32 namespace skiagm { 33 34 ////////////////////////////////////////////////////////////////////////////// 35 36 // This GM tests subsetting YUV multiplanar images where the U and V 37 // planes have different resolution from Y. See skbug:8959 38 39 class YUVtoRGBSubsetEffect : public GM { 40 public: YUVtoRGBSubsetEffect()41 YUVtoRGBSubsetEffect() { 42 this->setBGColor(0xFFFFFFFF); 43 } 44 45 protected: getName() const46 SkString getName() const override { return SkString("yuv_to_rgb_subset_effect"); } 47 getISize()48 SkISize getISize() override { return {1310, 540}; } 49 makePixmaps()50 void makePixmaps() { 51 SkYUVAInfo yuvaInfo = SkYUVAInfo({8, 8}, 52 SkYUVAInfo::PlaneConfig::kY_U_V, 53 SkYUVAInfo::Subsampling::k420, 54 kJPEG_Full_SkYUVColorSpace); 55 SkColorType colorTypes[] = {kAlpha_8_SkColorType, 56 kAlpha_8_SkColorType, 57 kAlpha_8_SkColorType}; 58 SkYUVAPixmapInfo pmapInfo(yuvaInfo, colorTypes, nullptr); 59 fPixmaps = SkYUVAPixmaps::Allocate(pmapInfo); 60 61 unsigned char innerY[16] = {149, 160, 130, 105, 62 160, 130, 105, 149, 63 130, 105, 149, 160, 64 105, 149, 160, 130}; 65 unsigned char innerU[4] = {43, 75, 145, 200}; 66 unsigned char innerV[4] = {88, 180, 200, 43}; 67 int outerYUV[] = {128, 128, 128}; 68 SkBitmap bitmaps[3]; 69 for (int i = 0; i < 3; ++i) { 70 bitmaps[i].installPixels(fPixmaps.plane(i)); 71 bitmaps[i].eraseColor(SkColorSetARGB(outerYUV[i], 0, 0, 0)); 72 } 73 SkPixmap innerYPM(SkImageInfo::MakeA8(4, 4), innerY, 4); 74 SkPixmap innerUPM(SkImageInfo::MakeA8(2, 2), innerU, 2); 75 SkPixmap innerVPM(SkImageInfo::MakeA8(2, 2), innerV, 2); 76 bitmaps[0].writePixels(innerYPM, 2, 2); 77 bitmaps[1].writePixels(innerUPM, 1, 1); 78 bitmaps[2].writePixels(innerVPM, 1, 1); 79 } 80 onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)81 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override { 82 auto context = GrAsDirectContext(canvas->recordingContext()); 83 skgpu::graphite::Recorder* recorder = nullptr; 84 #if defined(SK_GRAPHITE) 85 recorder = canvas->recorder(); 86 #endif 87 if (!context && !recorder) { 88 return DrawResult::kSkip; 89 } 90 91 if (!fPixmaps.isValid()) { 92 this->makePixmaps(); 93 } 94 95 auto lazyYUV = sk_gpu_test::LazyYUVImage::Make(fPixmaps); 96 #if defined(SK_GRAPHITE) 97 if (recorder) { 98 fYUVImage = lazyYUV->refImage(recorder, sk_gpu_test::LazyYUVImage::Type::kFromPixmaps); 99 } else 100 #endif 101 { 102 fYUVImage = lazyYUV->refImage(context, sk_gpu_test::LazyYUVImage::Type::kFromPixmaps); 103 } 104 105 return DrawResult::kOk; 106 } 107 onGpuTeardown()108 void onGpuTeardown() override { fYUVImage.reset(); } 109 onDraw(SkCanvas * canvas,SkString * errorMsg)110 DrawResult onDraw(SkCanvas* canvas, 111 SkString* errorMsg) override { 112 auto context = GrAsDirectContext(canvas->recordingContext()); 113 skgpu::graphite::Recorder* recorder = nullptr; 114 #if defined(SK_GRAPHITE) 115 recorder = canvas->recorder(); 116 #endif 117 if (!context && !recorder) { 118 *errorMsg = kErrorMsg_DrawSkippedGpuOnly; 119 return DrawResult::kSkip; 120 } 121 122 if (!fYUVImage) { 123 *errorMsg = "No valid YUV image generated -- skipping"; 124 return DrawResult::kSkip; 125 } 126 127 static const SkFilterMode kFilters[] = {SkFilterMode::kNearest, 128 SkFilterMode::kLinear}; 129 static const SkIRect kColorRect = SkIRect::MakeLTRB(2, 2, 6, 6); 130 131 // Outset to visualize wrap modes. 132 SkRect rect = SkRect::Make(fYUVImage->dimensions()); 133 rect = rect.makeOutset(fYUVImage->width()/2.f, fYUVImage->height()/2.f); 134 135 SkScalar y = kTestPad; 136 // Rows are filter modes. 137 for (uint32_t i = 0; i < std::size(kFilters); ++i) { 138 SkScalar x = kTestPad; 139 // Columns are non-subsetted followed by subsetted with each TileMode in a row 140 for (uint32_t j = 0; j < kSkTileModeCount + 1; ++j) { 141 SkMatrix ctm = SkMatrix::Translate(x, y); 142 ctm.postScale(10.f, 10.f); 143 144 const SkIRect* subset = j > 0 ? &kColorRect : nullptr; 145 146 auto tm = SkTileMode::kClamp; 147 if (j > 0) { 148 tm = static_cast<SkTileMode>(j - 1); 149 } 150 151 canvas->save(); 152 canvas->concat(ctm); 153 SkSamplingOptions sampling(kFilters[i]); 154 SkPaint paint; 155 // Draw black rectangle in background so rendering with Decal tilemode matches 156 // the previously used ClampToBorder wrapmode. 157 paint.setColor(SK_ColorBLACK); 158 canvas->drawRect(rect, paint); 159 if (subset) { 160 sk_sp<SkImage> subsetImg; 161 #if defined(SK_GRAPHITE) 162 if (recorder) { 163 subsetImg = fYUVImage->makeSubset(recorder, *subset, {false}); 164 } else 165 #endif 166 { 167 subsetImg = fYUVImage->makeSubset(context, *subset); 168 } 169 SkASSERT(subsetImg); 170 paint.setShader(subsetImg->makeShader(tm, tm, 171 sampling, SkMatrix::Translate(2, 2))); 172 } else { 173 paint.setShader(fYUVImage->makeShader(tm, tm, 174 sampling, SkMatrix::I())); 175 } 176 canvas->drawRect(rect, paint); 177 canvas->restore(); 178 x += rect.width() + kTestPad; 179 } 180 181 y += rect.height() + kTestPad; 182 } 183 184 return DrawResult::kOk; 185 } 186 187 private: 188 SkYUVAPixmaps fPixmaps; 189 sk_sp<SkImage> fYUVImage; 190 191 inline static constexpr SkScalar kTestPad = 10.f; 192 193 using INHERITED = GM; 194 }; 195 196 DEF_GM(return new YUVtoRGBSubsetEffect;) 197 } // namespace skiagm 198