skia2/gm/fwidth_squircle.cpp
Brian Salomon ae64c194fe Convert GrBufferType to enum class, rename, and remove dead values
Renamed to GrGpuBufferType in anticipation of splitting GrBuffer
into GrGpuBuffer and GrCpuBuffer types.

There were two unused values in the enum that are removed, DrawIndirect
and Texel.

Change-Id: Icb6b3da689adbd8e10495c10fd0470a6ee0120b5
Reviewed-on: https://skia-review.googlesource.com/c/189280
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
2019-02-05 15:04:48 +00:00

191 lines
6.8 KiB
C++

/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "sk_tool_utils.h"
#include "SkTextUtils.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "GrGpuCommandBuffer.h"
#include "GrMemoryPool.h"
#include "GrRenderTargetContext.h"
#include "GrRenderTargetContextPriv.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
namespace skiagm {
static constexpr GrGeometryProcessor::Attribute gVertex =
{"bboxcoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
/**
* This ensures that fwidth() works properly on GPU configs by drawing a squircle.
*/
class FwidthSquircleGM : public GM {
private:
SkString onShortName() final { return SkString("fwidth_squircle"); }
SkISize onISize() override { return SkISize::Make(200, 200); }
void onDraw(SkCanvas*) override;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// SkSL code.
class FwidthSquircleTestProcessor : public GrGeometryProcessor {
public:
FwidthSquircleTestProcessor(const SkMatrix& viewMatrix)
: GrGeometryProcessor(kFwidthSquircleTestProcessor_ClassID)
, fViewMatrix(viewMatrix) {
this->setVertexAttributes(&gVertex, 1);
}
const char* name() const override { return "FwidthSquircleTestProcessor"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
private:
const SkMatrix fViewMatrix;
class Impl;
};
class FwidthSquircleTestProcessor::Impl : public GrGLSLGeometryProcessor {
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
const auto& proc = args.fGP.cast<FwidthSquircleTestProcessor>();
auto* uniforms = args.fUniformHandler;
fViewMatrixHandle =
uniforms->addUniform(kVertex_GrShaderFlag, kFloat3x3_GrSLType, "viewmatrix");
auto* varyings = args.fVaryingHandler;
varyings->emitAttributes(proc);
GrGLSLVarying squircleCoord(kFloat2_GrSLType);
varyings->addVarying("bboxcoord", &squircleCoord);
auto* v = args.fVertBuilder;
v->codeAppendf("float2x2 R = float2x2(cos(.05), sin(.05), -sin(.05), cos(.05));");
v->codeAppendf("%s = bboxcoord * 1.25;", squircleCoord.vsOut());
v->codeAppendf("float3 vertexpos = float3(bboxcoord * 100 * R + 100, 1);");
v->codeAppendf("vertexpos = %s * vertexpos;", uniforms->getUniformCStr(fViewMatrixHandle));
gpArgs->fPositionVar.set(kFloat3_GrSLType, "vertexpos");
auto* f = args.fFragBuilder;
f->codeAppendf("float golden_ratio = 1.61803398875;");
f->codeAppendf("float pi = 3.141592653589793;");
f->codeAppendf("float x = abs(%s.x), y = abs(%s.y);",
squircleCoord.fsIn(), squircleCoord.fsIn());
// Squircle function!
f->codeAppendf("float fn = pow(x, golden_ratio*pi) + pow(y, golden_ratio*pi) - 1;");
f->codeAppendf("float fnwidth = fwidth(fn);");
f->codeAppendf("fnwidth += 1e-10;"); // Guard against divide-by-zero.
f->codeAppendf("half coverage = clamp(.5 - fn/fnwidth, 0, 1);");
f->codeAppendf("%s = half4(.51, .42, .71, 1) * .89;", args.fOutputColor);
f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
}
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
FPCoordTransformIter&& transformIter) override {
const auto& proc = primProc.cast<FwidthSquircleTestProcessor>();
pdman.setSkMatrix(fViewMatrixHandle, proc.fViewMatrix);
}
UniformHandle fViewMatrixHandle;
};
GrGLSLPrimitiveProcessor* FwidthSquircleTestProcessor::createGLSLInstance(
const GrShaderCaps&) const {
return new Impl();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Draw Op.
class FwidthSquircleTestOp : public GrDrawOp {
public:
DEFINE_OP_CLASS_ID
static std::unique_ptr<GrDrawOp> Make(GrContext* ctx, const SkMatrix& viewMatrix) {
GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
return pool->allocate<FwidthSquircleTestOp>(viewMatrix);
}
private:
FwidthSquircleTestOp(const SkMatrix& viewMatrix)
: GrDrawOp(ClassID())
, fViewMatrix(viewMatrix) {
this->setBounds(SkRect::MakeIWH(200, 200), HasAABloat::kNo, IsZeroArea::kNo);
}
const char* name() const override { return "ClockwiseTestOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*) override {
return GrProcessorSet::EmptySetAnalysis();
}
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
SkPoint vertices[4] = {
{-1, -1},
{+1, -1},
{-1, +1},
{+1, +1},
};
sk_sp<const GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer(
sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern,
GrResourceProvider::Flags::kNone, vertices));
if (!vertexBuffer) {
return;
}
GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver);
GrMesh mesh(GrPrimitiveType::kTriangleStrip);
mesh.setNonIndexedNonInstanced(4);
mesh.setVertexData(std::move(vertexBuffer));
flushState->rtCommandBuffer()->draw(FwidthSquircleTestProcessor(fViewMatrix), pipeline,
nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100));
}
const SkMatrix fViewMatrix;
friend class ::GrOpMemoryPool; // for ctor
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Test.
void FwidthSquircleGM::onDraw(SkCanvas* canvas) {
GrContext* ctx = canvas->getGrContext();
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
canvas->clear(SK_ColorWHITE);
if (!ctx || !rtc) {
DrawGpuOnlyMessage(canvas);
return;
}
if (!ctx->priv().caps()->shaderCaps()->shaderDerivativeSupport()) {
SkFont font(sk_tool_utils::create_portable_typeface(), 15);
DrawFailureMessage(canvas, "Shader derivatives not supported.");
return;
}
// Draw the test directly to the frame buffer.
rtc->priv().testingOnly_addDrawOp(FwidthSquircleTestOp::Make(ctx, canvas->getTotalMatrix()));
}
DEF_GM( return new FwidthSquircleGM(); )
}
#endif // SK_SUPPORT_GPU