1 /* 2 * Copyright 2024 Google LLC 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 Graphite. 9 10 #include "gm/gm.h" 11 #include "src/core/SkImageInfoPriv.h" 12 13 #if defined(SK_GRAPHITE) 14 #include "include/core/SkCanvas.h" 15 #include "include/core/SkColorFilter.h" 16 #include "include/core/SkPaint.h" 17 #include "include/core/SkSurface.h" 18 #include "include/core/SkYUVAInfo.h" 19 #include "include/effects/SkColorMatrix.h" 20 #include "include/gpu/graphite/Image.h" 21 #include "include/gpu/graphite/Recorder.h" 22 #include "include/gpu/graphite/Surface.h" 23 #include "src/core/SkYUVAInfoLocation.h" 24 #include "tools/DecodeUtils.h" 25 26 namespace skiagm { 27 class RenderToMipmappedYUVImagePlanes : public GM { 28 public: RenderToMipmappedYUVImagePlanes()29 RenderToMipmappedYUVImagePlanes() { this->setBGColor(0xFFFFFFFF); } 30 31 protected: getName() const32 SkString getName() const override { return SkString("render_to_mipmapped_yuv_image_planes"); } 33 getISize()34 SkISize getISize() override { return {96, 32}; } 35 onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)36 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override { 37 auto* recorder = canvas->recorder(); 38 if (!recorder) { 39 *errorMsg = "graphite-only test"; 40 return DrawResult::kSkip; 41 } 42 if (!fSrcImage) { 43 fSrcImage = ToolUtils::GetResourceAsImage("images/mandrill_512.png"); 44 if (!fSrcImage) { 45 *errorMsg = "Could not load src image."; 46 return DrawResult::kFail; 47 } 48 } 49 50 return DrawResult::kOk; 51 } 52 onDraw(SkCanvas * canvas,SkString * errorMsg)53 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { 54 auto* recorder = canvas->recorder(); 55 if (!recorder) { 56 *errorMsg = "direct to graphite test"; 57 return DrawResult::kSkip; 58 } 59 using PlaneConfig = SkYUVAInfo::PlaneConfig; 60 using Subsampling = SkYUVAInfo::Subsampling; 61 struct TestCase { 62 PlaneConfig config; 63 Subsampling subsampling; 64 }; 65 for (const auto& tc : {TestCase{PlaneConfig::kY_U_V, Subsampling::k420}, 66 TestCase{PlaneConfig::kY_UV, Subsampling::k422}, 67 TestCase{PlaneConfig::kYUV, Subsampling::k444}}) { 68 SkYUVAInfo yuvaInfo(fSrcImage->dimensions(), 69 tc.config, 70 tc.subsampling, 71 kJPEG_Full_SkYUVColorSpace); 72 73 float rgbToYuv[20]; 74 SkColorMatrix::RGBtoYUV(yuvaInfo.yuvColorSpace()).getRowMajor(rgbToYuv); 75 sk_sp<SkImage> planes[SkYUVAInfo::kMaxPlanes]; 76 SkISize dimensions[SkYUVAInfo::kMaxPlanes]; 77 int numPlanes = yuvaInfo.planeDimensions(dimensions); 78 79 SkColorType colorTypes [SkYUVAInfo::kMaxPlanes]; 80 uint32_t channelFlags[SkYUVAInfo::kMaxPlanes]; 81 for (int i = 0; i < numPlanes; ++i) { 82 switch (yuvaInfo.numChannelsInPlane(i)) { 83 case 1: colorTypes[i] = kAlpha_8_SkColorType; break; 84 case 2: colorTypes[i] = kR8G8_unorm_SkColorType; break; 85 case 3: colorTypes[i] = kRGB_888x_SkColorType; break; 86 case 4: colorTypes[i] = kRGBA_8888_SkColorType; break; 87 88 default: SkUNREACHABLE; 89 } 90 channelFlags[i] = SkColorTypeChannelFlags(colorTypes[i]); 91 } 92 SkYUVAInfo::YUVALocations locations = yuvaInfo.toYUVALocations(channelFlags); 93 94 for (int i = 0; i < numPlanes; ++i) { 95 auto info = SkImageInfo::Make(dimensions[i], colorTypes[i], kPremul_SkAlphaType); 96 auto surf = SkSurfaces::RenderTarget(recorder, info, skgpu::Mipmapped::kYes); 97 if (!surf) { 98 continue; 99 } 100 101 float matrix[20] { 102 1, 0, 0, 0, 0, 103 0, 1, 0, 0, 0, 104 0, 0, 1, 0, 0, 105 0, 0, 0, 1, 0 106 }; 107 108 for (int c = 0; c < SkYUVAInfo::kYUVAChannelCount; ++c) { 109 if (locations[c].fPlane == i) { 110 auto d = static_cast<int>(locations[c].fChannel); 111 std::copy_n(rgbToYuv + 5 * c, 5, matrix + 5 * d); 112 } 113 } 114 115 auto cf = SkColorFilters::Matrix(matrix); 116 SkPaint paint; 117 paint.setColorFilter(SkColorFilters::Matrix(matrix)); 118 surf->getCanvas()->drawImageRect(fSrcImage, 119 SkRect::Make(surf->imageInfo().dimensions()), 120 SkFilterMode::kLinear, 121 &paint); 122 planes[i] = SkSurfaces::AsImage(std::move(surf)); 123 } 124 auto yuvaImage = SkImages::TextureFromYUVAImages(recorder, 125 yuvaInfo, 126 planes, 127 /*imageColorSpace=*/nullptr); 128 if (yuvaImage) { 129 auto dstRect = SkRect::MakeWH(yuvaImage->width() / 16.f, 130 yuvaImage->height() / 16.f); 131 canvas->drawImageRect(yuvaImage.get(), 132 dstRect, 133 SkSamplingOptions(SkFilterMode::kLinear, 134 SkMipmapMode::kLinear)); 135 } 136 canvas->translate(std::ceil(yuvaInfo.width()/16.f), 0); 137 } 138 return DrawResult::kOk; 139 } 140 141 private: 142 sk_sp<SkImage> fSrcImage; 143 }; 144 145 DEF_GM(return new RenderToMipmappedYUVImagePlanes();) 146 } // namespace skiagm 147 #endif 148