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