samplelocations.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright 2019 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. #include "gm/gm.h"
  8. #include "include/core/SkBlendMode.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColorSpace.h"
  11. #include "include/core/SkMatrix.h"
  12. #include "include/core/SkRect.h"
  13. #include "include/core/SkRefCnt.h"
  14. #include "include/core/SkSize.h"
  15. #include "include/core/SkString.h"
  16. #include "include/core/SkTypes.h"
  17. #include "include/gpu/GrContext.h"
  18. #include "include/gpu/GrSamplerState.h"
  19. #include "include/gpu/GrTypes.h"
  20. #include "include/private/GrRecordingContext.h"
  21. #include "include/private/GrTypesPriv.h"
  22. #include "include/private/SkColorData.h"
  23. #include "src/gpu/GrBuffer.h"
  24. #include "src/gpu/GrCaps.h"
  25. #include "src/gpu/GrClip.h"
  26. #include "src/gpu/GrColorSpaceXform.h"
  27. #include "src/gpu/GrContextPriv.h"
  28. #include "src/gpu/GrGeometryProcessor.h"
  29. #include "src/gpu/GrGpuCommandBuffer.h"
  30. #include "src/gpu/GrMemoryPool.h"
  31. #include "src/gpu/GrMesh.h"
  32. #include "src/gpu/GrOpFlushState.h"
  33. #include "src/gpu/GrPaint.h"
  34. #include "src/gpu/GrPipeline.h"
  35. #include "src/gpu/GrPrimitiveProcessor.h"
  36. #include "src/gpu/GrProcessor.h"
  37. #include "src/gpu/GrProcessorSet.h"
  38. #include "src/gpu/GrRecordingContextPriv.h"
  39. #include "src/gpu/GrRenderTargetContext.h"
  40. #include "src/gpu/GrRenderTargetContextPriv.h"
  41. #include "src/gpu/GrShaderCaps.h"
  42. #include "src/gpu/GrShaderVar.h"
  43. #include "src/gpu/GrSurfaceProxy.h"
  44. #include "src/gpu/GrTextureProxy.h"
  45. #include "src/gpu/GrUserStencilSettings.h"
  46. #include "src/gpu/effects/GrPorterDuffXferProcessor.h"
  47. #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
  48. #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
  49. #include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
  50. #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
  51. #include "src/gpu/glsl/GrGLSLVarying.h"
  52. #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
  53. #include "src/gpu/ops/GrDrawOp.h"
  54. #include "src/gpu/ops/GrOp.h"
  55. #include <memory>
  56. #include <utility>
  57. class GrAppliedClip;
  58. class GrGLSLProgramDataManager;
  59. namespace skiagm {
  60. enum class GradType : bool {
  61. kHW,
  62. kSW
  63. };
  64. /**
  65. * This test ensures that the shaderBuilder's sample offsets and sample mask are correlated with
  66. * actual HW sample locations. It does so by drawing pseudo-random subpixel boxes, and only turning
  67. * off the samples whose locations fall inside the boxes.
  68. */
  69. class SampleLocationsGM : public GpuGM {
  70. public:
  71. SampleLocationsGM(GradType gradType, GrSurfaceOrigin origin)
  72. : fGradType(gradType)
  73. , fOrigin(origin) {}
  74. private:
  75. SkString onShortName() override {
  76. return SkStringPrintf("samplelocations%s%s",
  77. (GradType::kHW == fGradType) ? "_hwgrad" : "_swgrad",
  78. (kTopLeft_GrSurfaceOrigin == fOrigin) ? "_topleft" : "_botleft");
  79. }
  80. SkISize onISize() override { return SkISize::Make(200, 200); }
  81. DrawResult onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*, SkString* errorMsg) override;
  82. const GradType fGradType;
  83. const GrSurfaceOrigin fOrigin;
  84. };
  85. ////////////////////////////////////////////////////////////////////////////////////////////////////
  86. // SkSL code.
  87. class SampleLocationsTestProcessor : public GrGeometryProcessor {
  88. public:
  89. SampleLocationsTestProcessor(GradType gradType)
  90. : GrGeometryProcessor(kSampleLocationsTestProcessor_ClassID)
  91. , fGradType(gradType) {
  92. this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
  93. }
  94. const char* name() const override { return "SampleLocationsTestProcessor"; }
  95. void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
  96. b->add32((uint32_t)fGradType);
  97. }
  98. GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
  99. private:
  100. const GradType fGradType;
  101. class Impl;
  102. };
  103. class SampleLocationsTestProcessor::Impl : public GrGLSLGeometryProcessor {
  104. void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
  105. const auto& proc = args.fGP.cast<SampleLocationsTestProcessor>();
  106. auto* v = args.fVertBuilder;
  107. auto* f = args.fFragBuilder;
  108. GrGLSLVarying coord(kFloat2_GrSLType);
  109. GrGLSLVarying grad(kFloat2_GrSLType);
  110. args.fVaryingHandler->addVarying("coord", &coord);
  111. if (GradType::kSW == proc.fGradType) {
  112. args.fVaryingHandler->addVarying("grad", &grad);
  113. }
  114. // Pixel grid.
  115. v->codeAppendf("int x = sk_InstanceID %% 200;");
  116. v->codeAppendf("int y = sk_InstanceID / 200;");
  117. // Create pseudo-random rectangles inside a 16x16 subpixel grid. This works out nicely
  118. // because there are 17 positions on the grid (including both edges), and 17 is a great
  119. // prime number for generating pseudo-random numbers.
  120. v->codeAppendf("int ileft = (sk_InstanceID*929) %% 17;");
  121. v->codeAppendf("int iright = ileft + 1 + ((sk_InstanceID*1637) %% (17 - ileft));");
  122. v->codeAppendf("int itop = (sk_InstanceID*313) %% 17;");
  123. v->codeAppendf("int ibot = itop + 1 + ((sk_InstanceID*1901) %% (17 - itop));");
  124. // Outset (or inset) the rectangle, for the very likely scenario that samples fall on exact
  125. // 16ths of a pixel. GL_SUBPIXEL_BITS is allowed to be as low as 4, so try not to let the
  126. // outset value to get too small.
  127. v->codeAppendf("float outset = 1/32.0;");
  128. v->codeAppendf("outset = (0 == (x + y) %% 2) ? -outset : +outset;");
  129. v->codeAppendf("float l = ileft/16.0 - outset;");
  130. v->codeAppendf("float r = iright/16.0 + outset;");
  131. v->codeAppendf("float t = itop/16.0 - outset;");
  132. v->codeAppendf("float b = ibot/16.0 + outset;");
  133. v->codeAppendf("float2 vertexpos;");
  134. v->codeAppendf("vertexpos.x = float(x) + ((0 == (sk_VertexID %% 2)) ? l : r);");
  135. v->codeAppendf("vertexpos.y = float(y) + ((0 == (sk_VertexID / 2)) ? t : b);");
  136. gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
  137. v->codeAppendf("%s.x = (0 == (sk_VertexID %% 2)) ? -1 : +1;", coord.vsOut());
  138. v->codeAppendf("%s.y = (0 == (sk_VertexID / 2)) ? -1 : +1;", coord.vsOut());
  139. if (GradType::kSW == proc.fGradType) {
  140. v->codeAppendf("%s = 2/float2(r - l, b - t);", grad.vsOut());
  141. }
  142. // Fragment shader: Output RED.
  143. f->codeAppendf("%s = half4(1,0,0,1);", args.fOutputColor);
  144. f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
  145. // Now turn off all the samples inside our sub-rectangle. As long as the shaderBuilder's
  146. // sample offsets and sample mask are correlated with actual HW sample locations, no red
  147. // will bleed through.
  148. f->codeAppendf("for (int i = 0; i < %i; ++i) {",
  149. f->getProgramBuilder()->effectiveSampleCnt());
  150. if (GradType::kHW == proc.fGradType) {
  151. f->codeAppendf("float2x2 grad = float2x2(dFdx(%s), dFdy(%s));",
  152. coord.fsIn(), coord.fsIn());
  153. } else {
  154. f->codeAppendf("float2x2 grad = float2x2(%s.x, 0, 0, %s.y);", grad.fsIn(), grad.fsIn());
  155. }
  156. f->codeAppendf( "float2 samplecoord = %s[i] * grad + %s;",
  157. f->sampleOffsets(), coord.fsIn());
  158. f->codeAppendf( "if (all(lessThanEqual(abs(samplecoord), float2(1)))) {");
  159. f->maskOffMultisampleCoverage(
  160. "~(1 << i)", GrGLSLFPFragmentBuilder::ScopeFlags::kInsideLoop);
  161. f->codeAppendf( "}");
  162. f->codeAppendf("}");
  163. }
  164. void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
  165. FPCoordTransformIter&&) override {}
  166. };
  167. GrGLSLPrimitiveProcessor* SampleLocationsTestProcessor::createGLSLInstance(
  168. const GrShaderCaps&) const {
  169. return new Impl();
  170. }
  171. ////////////////////////////////////////////////////////////////////////////////////////////////////
  172. // Draw Op.
  173. class SampleLocationsTestOp : public GrDrawOp {
  174. public:
  175. DEFINE_OP_CLASS_ID
  176. static std::unique_ptr<GrDrawOp> Make(
  177. GrRecordingContext* ctx, const SkMatrix& viewMatrix, GradType gradType) {
  178. GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
  179. return pool->allocate<SampleLocationsTestOp>(gradType);
  180. }
  181. private:
  182. SampleLocationsTestOp(GradType gradType) : GrDrawOp(ClassID()), fGradType(gradType) {
  183. this->setBounds(SkRect::MakeIWH(200, 200), HasAABloat::kNo, IsZeroArea::kNo);
  184. }
  185. const char* name() const override { return "SampleLocationsTestOp"; }
  186. FixedFunctionFlags fixedFunctionFlags() const override {
  187. return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
  188. }
  189. GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
  190. bool hasMixedSampledCoverage, GrClampType) override {
  191. return GrProcessorSet::EmptySetAnalysis();
  192. }
  193. void onPrepare(GrOpFlushState*) override {}
  194. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  195. static constexpr GrUserStencilSettings kStencilWrite(
  196. GrUserStencilSettings::StaticInit<
  197. 0x0001,
  198. GrUserStencilTest::kAlways,
  199. 0xffff,
  200. GrUserStencilOp::kReplace,
  201. GrUserStencilOp::kKeep,
  202. 0xffff>()
  203. );
  204. GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
  205. flushState->drawOpArgs().fOutputSwizzle,
  206. GrPipeline::InputFlags::kHWAntialias, &kStencilWrite);
  207. GrMesh mesh(GrPrimitiveType::kTriangleStrip);
  208. mesh.setInstanced(nullptr, 200*200, 0, 4);
  209. flushState->rtCommandBuffer()->draw(
  210. SampleLocationsTestProcessor(fGradType), pipeline, nullptr, nullptr, &mesh, 1,
  211. SkRect::MakeIWH(200, 200));
  212. }
  213. const GradType fGradType;
  214. friend class ::GrOpMemoryPool; // for ctor
  215. };
  216. ////////////////////////////////////////////////////////////////////////////////////////////////////
  217. // Test.
  218. DrawResult SampleLocationsGM::onDraw(
  219. GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas, SkString* errorMsg) {
  220. if (!ctx->priv().caps()->sampleLocationsSupport()) {
  221. *errorMsg = "Requires support for sample locations.";
  222. return DrawResult::kSkip;
  223. }
  224. if (!ctx->priv().caps()->shaderCaps()->sampleVariablesSupport()) {
  225. *errorMsg = "Requires support for sample variables.";
  226. return DrawResult::kSkip;
  227. }
  228. if (rtc->numSamples() <= 1 && !ctx->priv().caps()->mixedSamplesSupport()) {
  229. *errorMsg = "MSAA and mixed samples only.";
  230. return DrawResult::kSkip;
  231. }
  232. auto offscreenRTC = ctx->priv().makeDeferredRenderTargetContext(
  233. SkBackingFit::kExact, 200, 200, rtc->colorSpaceInfo().colorType(), nullptr,
  234. rtc->numSamples(), GrMipMapped::kNo, fOrigin);
  235. if (!offscreenRTC) {
  236. *errorMsg = "Failed to create offscreen render target.";
  237. return DrawResult::kFail;
  238. }
  239. if (offscreenRTC->numSamples() <= 1 &&
  240. !offscreenRTC->proxy()->canUseMixedSamples(*ctx->priv().caps())) {
  241. *errorMsg = "MSAA and mixed samples only.";
  242. return DrawResult::kSkip;
  243. }
  244. static constexpr GrUserStencilSettings kStencilCover(
  245. GrUserStencilSettings::StaticInit<
  246. 0x0000,
  247. GrUserStencilTest::kNotEqual,
  248. 0xffff,
  249. GrUserStencilOp::kZero,
  250. GrUserStencilOp::kKeep,
  251. 0xffff>()
  252. );
  253. offscreenRTC->clear(nullptr, {0,1,0,1}, GrRenderTargetContext::CanClearFullscreen::kYes);
  254. // Stencil.
  255. offscreenRTC->priv().testingOnly_addDrawOp(
  256. SampleLocationsTestOp::Make(ctx, canvas->getTotalMatrix(), fGradType));
  257. // Cover.
  258. GrPaint coverPaint;
  259. coverPaint.setColor4f({1,0,0,1});
  260. coverPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrcOver));
  261. rtc->priv().stencilRect(GrNoClip(), &kStencilCover, std::move(coverPaint), GrAA::kNo,
  262. SkMatrix::I(), SkRect::MakeWH(200, 200));
  263. // Copy offscreen texture to canvas.
  264. rtc->drawTexture(
  265. GrNoClip(), sk_ref_sp(offscreenRTC->asTextureProxy()),
  266. GrSamplerState::Filter::kNearest, SkBlendMode::kSrc, SK_PMColor4fWHITE,
  267. {0,0,200,200}, {0,0,200,200}, GrAA::kNo, GrQuadAAFlags::kNone,
  268. SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(), nullptr);
  269. return skiagm::DrawResult::kOk;
  270. }
  271. DEF_GM( return new SampleLocationsGM(GradType::kHW, kTopLeft_GrSurfaceOrigin); )
  272. DEF_GM( return new SampleLocationsGM(GradType::kHW, kBottomLeft_GrSurfaceOrigin); )
  273. DEF_GM( return new SampleLocationsGM(GradType::kSW, kTopLeft_GrSurfaceOrigin); )
  274. DEF_GM( return new SampleLocationsGM(GradType::kSW, kBottomLeft_GrSurfaceOrigin); )
  275. }