1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkBlendMode.h" 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 12cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 14cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 15cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 16cb93a386Sopenharmony_ci#include "include/core/SkString.h" 17cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 18cb93a386Sopenharmony_ci#include "include/private/GrTypesPriv.h" 19cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrBuffer.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrGpuBuffer.h" 25cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 26cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 27cb93a386Sopenharmony_ci#include "src/gpu/GrOpsRenderPass.h" 28cb93a386Sopenharmony_ci#include "src/gpu/GrPipeline.h" 29cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h" 30cb93a386Sopenharmony_ci#include "src/gpu/GrProcessorSet.h" 31cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 32cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 33cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 34cb93a386Sopenharmony_ci#include "src/gpu/GrShaderCaps.h" 35cb93a386Sopenharmony_ci#include "src/gpu/GrShaderVar.h" 36cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 37cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 38cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 39cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 40cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 41cb93a386Sopenharmony_ci#include "src/gpu/ops/GrDrawOp.h" 42cb93a386Sopenharmony_ci#include "src/gpu/ops/GrOp.h" 43cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 44cb93a386Sopenharmony_ci#include "tools/gpu/ProxyUtils.h" 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci#include <memory> 47cb93a386Sopenharmony_ci#include <utility> 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ciclass GrAppliedClip; 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci/** 52cb93a386Sopenharmony_ci * This test ensures that fwidth() works properly on GPU configs by drawing a squircle. 53cb93a386Sopenharmony_ci */ 54cb93a386Sopenharmony_cinamespace { 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_cistatic constexpr GrGeometryProcessor::Attribute gVertex = 57cb93a386Sopenharmony_ci {"bboxcoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////// 60cb93a386Sopenharmony_ci// SkSL code. 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ciclass FwidthSquircleTestProcessor : public GrGeometryProcessor { 63cb93a386Sopenharmony_cipublic: 64cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix) { 65cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 66cb93a386Sopenharmony_ci return new (ptr) FwidthSquircleTestProcessor(viewMatrix); 67cb93a386Sopenharmony_ci }); 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci const char* name() const override { return "FwidthSquircleTestProcessor"; } 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ciprivate: 77cb93a386Sopenharmony_ci FwidthSquircleTestProcessor(const SkMatrix& viewMatrix) 78cb93a386Sopenharmony_ci : GrGeometryProcessor(kFwidthSquircleTestProcessor_ClassID) 79cb93a386Sopenharmony_ci , fViewMatrix(viewMatrix) { 80cb93a386Sopenharmony_ci this->setVertexAttributes(&gVertex, 1); 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci const SkMatrix fViewMatrix; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci using INHERITED = GrGeometryProcessor; 86cb93a386Sopenharmony_ci}; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> FwidthSquircleTestProcessor::makeProgramImpl( 89cb93a386Sopenharmony_ci const GrShaderCaps&) const { 90cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 91cb93a386Sopenharmony_ci public: 92cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 93cb93a386Sopenharmony_ci const GrShaderCaps&, 94cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 95cb93a386Sopenharmony_ci const auto& proc = geomProc.cast<FwidthSquircleTestProcessor>(); 96cb93a386Sopenharmony_ci pdman.setSkMatrix(fViewMatrixHandle, proc.fViewMatrix); 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci private: 100cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 101cb93a386Sopenharmony_ci const auto& proc = args.fGeomProc.cast<FwidthSquircleTestProcessor>(); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci auto* uniforms = args.fUniformHandler; 104cb93a386Sopenharmony_ci fViewMatrixHandle = uniforms->addUniform(nullptr, 105cb93a386Sopenharmony_ci kVertex_GrShaderFlag, 106cb93a386Sopenharmony_ci kFloat3x3_GrSLType, 107cb93a386Sopenharmony_ci "viewmatrix"); 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci auto* varyings = args.fVaryingHandler; 110cb93a386Sopenharmony_ci varyings->emitAttributes(proc); 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci GrGLSLVarying squircleCoord(kFloat2_GrSLType); 113cb93a386Sopenharmony_ci varyings->addVarying("bboxcoord", &squircleCoord); 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci auto* v = args.fVertBuilder; 116cb93a386Sopenharmony_ci v->codeAppendf("float2x2 R = float2x2(cos(.05), sin(.05), -sin(.05), cos(.05));"); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci v->codeAppendf("%s = bboxcoord * 1.25;", squircleCoord.vsOut()); 119cb93a386Sopenharmony_ci v->codeAppendf("float3 vertexpos = float3(bboxcoord * 100 * R + 100, 1);"); 120cb93a386Sopenharmony_ci v->codeAppendf("vertexpos = %s * vertexpos;", 121cb93a386Sopenharmony_ci uniforms->getUniformCStr(fViewMatrixHandle)); 122cb93a386Sopenharmony_ci gpArgs->fPositionVar.set(kFloat3_GrSLType, "vertexpos"); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci auto* f = args.fFragBuilder; 125cb93a386Sopenharmony_ci f->codeAppendf("float golden_ratio = 1.61803398875;"); 126cb93a386Sopenharmony_ci f->codeAppendf("float pi = 3.141592653589793;"); 127cb93a386Sopenharmony_ci f->codeAppendf("float x = abs(%s.x), y = abs(%s.y);", 128cb93a386Sopenharmony_ci squircleCoord.fsIn(), squircleCoord.fsIn()); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci // Squircle function! 131cb93a386Sopenharmony_ci f->codeAppendf("float fn = half(pow(x, golden_ratio*pi) + " 132cb93a386Sopenharmony_ci "pow(y, golden_ratio*pi) - 1);"); 133cb93a386Sopenharmony_ci f->codeAppendf("float fnwidth = fwidth(fn);"); 134cb93a386Sopenharmony_ci f->codeAppendf("fnwidth += 1e-10;"); // Guard against divide-by-zero. 135cb93a386Sopenharmony_ci f->codeAppendf("half coverage = clamp(half(.5 - fn/fnwidth), 0, 1);"); 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci f->codeAppendf("half4 %s = half4(.51, .42, .71, 1) * .89;", args.fOutputColor); 138cb93a386Sopenharmony_ci f->codeAppendf("half4 %s = half4(coverage);", args.fOutputCoverage); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci UniformHandle fViewMatrixHandle; 142cb93a386Sopenharmony_ci }; 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 145cb93a386Sopenharmony_ci} 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////// 148cb93a386Sopenharmony_ci// Draw Op. 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ciclass FwidthSquircleTestOp : public GrDrawOp { 151cb93a386Sopenharmony_cipublic: 152cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* ctx, const SkMatrix& viewMatrix) { 155cb93a386Sopenharmony_ci return GrOp::Make<FwidthSquircleTestOp>(ctx, viewMatrix); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ciprivate: 159cb93a386Sopenharmony_ci FwidthSquircleTestOp(const SkMatrix& viewMatrix) 160cb93a386Sopenharmony_ci : GrDrawOp(ClassID()) 161cb93a386Sopenharmony_ci , fViewMatrix(viewMatrix) { 162cb93a386Sopenharmony_ci this->setBounds(SkRect::MakeIWH(kWidth, kHeight), HasAABloat::kNo, IsHairline::kNo); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci const char* name() const override { return "FwidthSquircleTestOp"; } 166cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 167cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override { 168cb93a386Sopenharmony_ci return GrProcessorSet::EmptySetAnalysis(); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci GrProgramInfo* createProgramInfo(const GrCaps* caps, 172cb93a386Sopenharmony_ci SkArenaAlloc* arena, 173cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 174cb93a386Sopenharmony_ci bool usesMSAASurface, 175cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 176cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 177cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 178cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) const { 179cb93a386Sopenharmony_ci GrGeometryProcessor* geomProc = FwidthSquircleTestProcessor::Make(arena, fViewMatrix); 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci return sk_gpu_test::CreateProgramInfo(caps, arena, writeView, usesMSAASurface, 182cb93a386Sopenharmony_ci std::move(appliedClip), dstProxyView, 183cb93a386Sopenharmony_ci geomProc, SkBlendMode::kSrcOver, 184cb93a386Sopenharmony_ci GrPrimitiveType::kTriangleStrip, 185cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const { 189cb93a386Sopenharmony_ci return this->createProgramInfo(&flushState->caps(), 190cb93a386Sopenharmony_ci flushState->allocator(), 191cb93a386Sopenharmony_ci flushState->writeView(), 192cb93a386Sopenharmony_ci flushState->usesMSAASurface(), 193cb93a386Sopenharmony_ci flushState->detachAppliedClip(), 194cb93a386Sopenharmony_ci flushState->dstProxyView(), 195cb93a386Sopenharmony_ci flushState->renderPassBarriers(), 196cb93a386Sopenharmony_ci flushState->colorLoadOp()); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci void onPrePrepare(GrRecordingContext* context, 200cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 201cb93a386Sopenharmony_ci GrAppliedClip* clip, 202cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 203cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 204cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) final { 205cb93a386Sopenharmony_ci SkArenaAlloc* arena = context->priv().recordTimeAllocator(); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci // DMSAA is not supported on DDL. 208cb93a386Sopenharmony_ci bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1; 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci // This is equivalent to a GrOpFlushState::detachAppliedClip 211cb93a386Sopenharmony_ci GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled(); 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, writeView, 214cb93a386Sopenharmony_ci usesMSAASurface, std::move(appliedClip), 215cb93a386Sopenharmony_ci dstProxyView, renderPassXferBarriers, colorLoadOp); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci context->priv().recordProgramInfo(fProgramInfo); 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci void onPrepare(GrOpFlushState* flushState) final { 221cb93a386Sopenharmony_ci SkPoint vertices[4] = { 222cb93a386Sopenharmony_ci {-1, -1}, 223cb93a386Sopenharmony_ci {+1, -1}, 224cb93a386Sopenharmony_ci {-1, +1}, 225cb93a386Sopenharmony_ci {+1, +1}, 226cb93a386Sopenharmony_ci }; 227cb93a386Sopenharmony_ci fVertexBuffer = flushState->resourceProvider()->createBuffer( 228cb93a386Sopenharmony_ci sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices); 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final { 232cb93a386Sopenharmony_ci if (!fVertexBuffer) { 233cb93a386Sopenharmony_ci return; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci if (!fProgramInfo) { 237cb93a386Sopenharmony_ci fProgramInfo = this->createProgramInfo(flushState); 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci flushState->bindPipeline(*fProgramInfo, SkRect::MakeIWH(kWidth, kHeight)); 241cb93a386Sopenharmony_ci flushState->bindBuffers(nullptr, nullptr, std::move(fVertexBuffer)); 242cb93a386Sopenharmony_ci flushState->draw(4, 0); 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci static const int kWidth = 200; 247cb93a386Sopenharmony_ci static const int kHeight = 200; 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci sk_sp<GrBuffer> fVertexBuffer; 250cb93a386Sopenharmony_ci const SkMatrix fViewMatrix; 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci // The program info (and both the GrPipeline and GrGeometryProcessor it relies on), when 253cb93a386Sopenharmony_ci // allocated, are allocated in either the ddl-record-time or flush-time arena. It is the 254cb93a386Sopenharmony_ci // arena's job to free up their memory so we just have a bare programInfo pointer here. We 255cb93a386Sopenharmony_ci // don't even store the GrPipeline and GrGeometryProcessor pointers here bc they are 256cb93a386Sopenharmony_ci // guaranteed to have the same lifetime as the program info. 257cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci friend class ::GrOp; // for ctor 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci using INHERITED = GrDrawOp; 262cb93a386Sopenharmony_ci}; 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci} // namespace 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////// 267cb93a386Sopenharmony_ci// Test. 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_cinamespace skiagm { 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(fwidth_squircle, rContext, canvas, errorMsg, 200, 200) { 272cb93a386Sopenharmony_ci if (!rContext->priv().caps()->shaderCaps()->shaderDerivativeSupport()) { 273cb93a386Sopenharmony_ci *errorMsg = "Shader derivatives not supported."; 274cb93a386Sopenharmony_ci return DrawResult::kSkip; 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 278cb93a386Sopenharmony_ci if (!sdc) { 279cb93a386Sopenharmony_ci *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly; 280cb93a386Sopenharmony_ci return DrawResult::kSkip; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci // Draw the test directly to the frame buffer. 284cb93a386Sopenharmony_ci canvas->clear(SK_ColorWHITE); 285cb93a386Sopenharmony_ci sdc->addDrawOp(FwidthSquircleTestOp::Make(rContext, canvas->getTotalMatrix())); 286cb93a386Sopenharmony_ci return skiagm::DrawResult::kOk; 287cb93a386Sopenharmony_ci} 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci} // namespace skiagm 290