From a8f6aef13d0592305e05baf19ee724f31a53b466 Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Wed, 20 Dec 2017 10:07:49 -0700 Subject: CCPR: Initial semi-optimized vertex shader Impl Bug: skia: Change-Id: If22f47a3b945ce7336f8e609c2e0c911f09e1d18 Reviewed-on: https://skia-review.googlesource.com/86820 Reviewed-by: Brian Salomon Commit-Queue: Chris Dalton --- gn/gpu.gni | 1 + samplecode/SampleCCPRGeometry.cpp | 12 +- src/gpu/ccpr/GrCCPRCoverageOp.cpp | 14 +- src/gpu/ccpr/GrCCPRCoverageOp.h | 2 +- src/gpu/ccpr/GrCCPRCoverageProcessor.cpp | 28 +- src/gpu/ccpr/GrCCPRCoverageProcessor.h | 74 +++- src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp | 9 +- src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp | 441 ++++++++++++++++++++++++ src/gpu/ccpr/GrCCPRCubicShader.cpp | 25 +- src/gpu/ccpr/GrCCPRCubicShader.h | 18 +- src/gpu/ccpr/GrCCPRQuadraticShader.cpp | 22 +- src/gpu/ccpr/GrCCPRQuadraticShader.h | 18 +- src/gpu/ccpr/GrCCPRTriangleShader.cpp | 17 +- src/gpu/ccpr/GrCCPRTriangleShader.h | 25 +- src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 4 +- src/gpu/glsl/GrGLSLVarying.cpp | 1 + src/gpu/glsl/GrGLSLVarying.h | 11 +- 17 files changed, 633 insertions(+), 89 deletions(-) create mode 100644 src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp diff --git a/gn/gpu.gni b/gn/gpu.gni index fb512bf10b..63a7920bf6 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -301,6 +301,7 @@ skia_gpu_sources = [ "$_src/gpu/ccpr/GrCCPRCoverageOp.h", "$_src/gpu/ccpr/GrCCPRCoverageProcessor.cpp", "$_src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp", + "$_src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp", "$_src/gpu/ccpr/GrCCPRCoverageProcessor.h", "$_src/gpu/ccpr/GrCCPRCubicShader.cpp", "$_src/gpu/ccpr/GrCCPRCubicShader.h", diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp index 92892c239b..2efb0e6b14 100644 --- a/samplecode/SampleCCPRGeometry.cpp +++ b/samplecode/SampleCCPRGeometry.cpp @@ -236,6 +236,10 @@ void CCPRGeometryView::updateGpuData() { GrCCPRGeometry::Verb::kEndClosedContour == verb) { continue; } + if (GrCCPRGeometry::Verb::kLineTo == verb) { + ++ptsIdx; + continue; + } SkASSERT(GrCCPRGeometry::Verb::kMonotonicQuadraticTo == verb); fTriangleInstances.push_back().set(&geometry.points()[ptsIdx], Sk2f(0, 0)); ptsIdx += 2; @@ -251,10 +255,14 @@ void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) { GrGLGpu* glGpu = kOpenGL_GrBackend == context->contextPriv().getBackend() ? static_cast(state->gpu()) : nullptr; - GrCCPRCoverageProcessor proc(fView->fRenderPass); + if (!GrCCPRCoverageProcessor::DoesRenderPass(fView->fRenderPass, *state->caps().shaderCaps())) { + return; + } + + GrCCPRCoverageProcessor proc(rp, fView->fRenderPass, *state->caps().shaderCaps()); SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat);) - SkSTArray<1, GrMesh, true> mesh; + SkSTArray<1, GrMesh> mesh; if (GrCCPRCoverageProcessor::RenderPassIsCubic(fView->fRenderPass)) { sk_sp instBuff(rp->createBuffer(fView->fCubicInstances.count() * sizeof(CubicInstance), kVertex_GrBufferType, diff --git a/src/gpu/ccpr/GrCCPRCoverageOp.cpp b/src/gpu/ccpr/GrCCPRCoverageOp.cpp index 57b73bf935..5cd35cd2c6 100644 --- a/src/gpu/ccpr/GrCCPRCoverageOp.cpp +++ b/src/gpu/ccpr/GrCCPRCoverageOp.cpp @@ -7,6 +7,7 @@ #include "GrCCPRCoverageOp.h" +#include "GrCaps.h" #include "GrGpuCommandBuffer.h" #include "GrOnFlushResourceProvider.h" #include "GrOpFlushState.h" @@ -396,7 +397,7 @@ void GrCCPRCoverageOp::onExecute(GrOpFlushState* flushState) { this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleHulls, &PrimitiveTallies::fTriangles); this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleEdges, - &PrimitiveTallies::fTriangles); + &PrimitiveTallies::fTriangles); // Might get skipped. this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleCorners, &PrimitiveTallies::fTriangles); @@ -419,14 +420,19 @@ void GrCCPRCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPi using ScissorMode = GrCCPRCoverageOpsBuilder::ScissorMode; SkASSERT(pipeline.getScissorState().enabled()); + if (!GrCCPRCoverageProcessor::DoesRenderPass(renderPass, *flushState->caps().shaderCaps())) { + return; + } + fMeshesScratchBuffer.reset(); fDynamicStatesScratchBuffer.reset(); - GrCCPRCoverageProcessor proc(renderPass); + GrCCPRCoverageProcessor proc(flushState->resourceProvider(), renderPass, + *flushState->caps().shaderCaps()); - if (const int instanceCount = fInstanceCounts[(int)ScissorMode::kNonScissored].*instanceType) { + if (int instanceCount = fInstanceCounts[(int)ScissorMode::kNonScissored].*instanceType) { SkASSERT(instanceCount > 0); - const int baseInstance = fBaseInstances[(int)ScissorMode::kNonScissored].*instanceType; + int baseInstance = fBaseInstances[(int)ScissorMode::kNonScissored].*instanceType; proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance, &fMeshesScratchBuffer); fDynamicStatesScratchBuffer.push_back().fScissorRect.setXYWH(0, 0, fDrawBounds.width(), fDrawBounds.height()); diff --git a/src/gpu/ccpr/GrCCPRCoverageOp.h b/src/gpu/ccpr/GrCCPRCoverageOp.h index 7957586958..e3eee48899 100644 --- a/src/gpu/ccpr/GrCCPRCoverageOp.h +++ b/src/gpu/ccpr/GrCCPRCoverageOp.h @@ -167,7 +167,7 @@ private: const SkTArray fScissorBatches; const SkISize fDrawBounds; - mutable SkTArray fMeshesScratchBuffer; + mutable SkTArray fMeshesScratchBuffer; mutable SkTArray fDynamicStatesScratchBuffer; friend class GrCCPRCoverageOpsBuilder; diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor.cpp b/src/gpu/ccpr/GrCCPRCoverageProcessor.cpp index 3a456fda00..11e847fcc6 100644 --- a/src/gpu/ccpr/GrCCPRCoverageProcessor.cpp +++ b/src/gpu/ccpr/GrCCPRCoverageProcessor.cpp @@ -11,17 +11,21 @@ #include "ccpr/GrCCPRCubicShader.h" #include "ccpr/GrCCPRQuadraticShader.h" #include "ccpr/GrCCPRTriangleShader.h" +#include "glsl/GrGLSLVertexGeoBuilder.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLVertexGeoBuilder.h" void GrCCPRCoverageProcessor::Shader::emitVaryings(GrGLSLVaryingHandler* varyingHandler, - SkString* code, const char* position, - const char* coverage, const char* wind) { - WindHandling windHandling = this->onEmitVaryings(varyingHandler, code, position, coverage, - wind); + GrGLSLVarying::Scope scope, SkString* code, + const char* position, const char* coverage, + const char* wind) { + SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope); + WindHandling windHandling = this->onEmitVaryings(varyingHandler, scope, code, position, + coverage, wind); if (WindHandling::kNotHandled == windHandling) { + fWind.reset(kHalf_GrSLType, scope); varyingHandler->addFlatVarying("wind", &fWind); - code->appendf("%s = %s;", fWind.gsOut(), wind); + code->appendf("%s = %s;", OutName(fWind), wind); } } @@ -80,7 +84,16 @@ int GrCCPRCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLPPFragmentB void GrCCPRCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { - b->add32((int)fRenderPass); + int key = (int)fRenderPass << 1; + if (Impl::kGeometryShader == fImpl) { + key |= 1; + } +#ifdef SK_DEBUG + uint32_t bloatBits; + memcpy(&bloatBits, &fDebugBloat, 4); + b->add32(bloatBits); +#endif + b->add32(key); } GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const { @@ -106,5 +119,6 @@ GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::createGLSLInstance(const GrSh shader = skstd::make_unique(); break; } - return this->createGSImpl(std::move(shader)); + return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader)) + : this->createVSImpl(std::move(shader)); } diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor.h b/src/gpu/ccpr/GrCCPRCoverageProcessor.h index 7210d3975e..3de36f1f52 100644 --- a/src/gpu/ccpr/GrCCPRCoverageProcessor.h +++ b/src/gpu/ccpr/GrCCPRCoverageProcessor.h @@ -9,6 +9,7 @@ #define GrCCPRCoverageProcessor_DEFINED #include "GrGeometryProcessor.h" +#include "GrShaderCaps.h" #include "SkNx.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLVarying.h" @@ -52,14 +53,15 @@ public: // render pass. Here we enumerate every render pass needed in order to produce a complete // coverage count mask. This is an exhaustive list of all ccpr coverage shaders. // - // During a render pass, the "Impl" (currently only GSImpl) generates conservative geometry for + // During a render pass, the "Impl" (GSImpl or VSimpl) generates conservative geometry for // rasterization, and the Shader decides the coverage value at each pixel. enum class RenderPass { // For a Hull, the Impl generates a "conservative raster hull" around the input points. This // is the geometry that causes a pixel to be rasterized if it is touched anywhere by the - // input polygon. Initial coverage values sent to the Shader at each vertex will be null. - // Logically, the conservative raster hull is equivalent to the convex hull of pixel size - // boxes centered on each input point. + // input polygon. The initial coverage values sent to the Shader at each vertex are either + // null, or +1 all around if the Impl combines this pass with kTriangleEdges. Logically, + // the conservative raster hull is equivalent to the convex hull of pixel size boxes + // centered on each input point. kTriangleHulls, kQuadraticHulls, kCubicHulls, @@ -70,6 +72,9 @@ public: // edge geometry and 0 on the inside. This is the only geometry type that associates // coverage values with the output vertices. Interpolated, these coverage values convert // jagged conservative raster edges into a smooth antialiased edge. + // + // NOTE: The Impl may combine this pass with kTriangleHulls, in which case DoesRenderPass() + // will be false for kTriangleEdges and it must not be used. kTriangleEdges, // For Corners, the Impl Generates the conservative rasters of corner points (i.e. @@ -82,10 +87,20 @@ public: static bool RenderPassIsCubic(RenderPass); static const char* RenderPassName(RenderPass); - GrCCPRCoverageProcessor(RenderPass pass) + constexpr static bool DoesRenderPass(RenderPass renderPass, const GrShaderCaps& caps) { + return RenderPass::kTriangleEdges != renderPass || caps.geometryShaderSupport(); + } + + GrCCPRCoverageProcessor(GrResourceProvider* rp, RenderPass pass, const GrShaderCaps& caps) : INHERITED(kGrCCPRCoverageProcessor_ClassID) - , fRenderPass(pass) { - this->initGS(); + , fRenderPass(pass) + , fImpl(caps.geometryShaderSupport() ? Impl::kGeometryShader : Impl::kVertexShader) { + SkASSERT(DoesRenderPass(pass, caps)); + if (Impl::kGeometryShader == fImpl) { + this->initGS(); + } else { + this->initVS(rp); + } } // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array @@ -94,8 +109,12 @@ public: // // NOTE: Quadratics use TriangleInstance since both have 3 points. void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance, - SkTArray* out) { - this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out); + SkTArray* out) { + if (Impl::kGeometryShader == fImpl) { + this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out); + } else { + this->appendVSMesh(instanceBuffer, instanceCount, baseInstance, out); + } } // GrPrimitiveProcessor overrides. @@ -140,8 +159,8 @@ public: const char* repetitionID, const char* wind, GeometryVars*) const {} - void emitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position, - const char* coverage, const char* wind); + void emitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, + const char* position, const char* coverage, const char* wind); void emitFragmentCode(const GrCCPRCoverageProcessor& proc, GrGLSLPPFragmentBuilder*, const char* skOutputColor, const char* skOutputCoverage) const; @@ -169,15 +188,23 @@ public: // // NOTE: the coverage parameter is only relevant for edges (see comments in RenderPass). // Otherwise it is +1 all around. - virtual WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, - const char* position, const char* coverage, - const char* wind) = 0; + virtual WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, + SkString* code, const char* position, + const char* coverage, const char* wind) = 0; // Emits the fragment code that calculates a pixel's coverage value. If using // WindHandling::kHandled, this value must be signed appropriately. virtual void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const = 0; + // Returns the name of a Shader's internal varying at the point where where its value is + // assigned. This is intended to work whether called for a vertex or a geometry shader. + const char* OutName(const GrGLSLVarying& varying) const { + using Scope = GrGLSLVarying::Scope; + SkASSERT(Scope::kVertToGeo != varying.scope()); + return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut(); + } + // Defines a global float2 array that contains MSAA sample locations as offsets from pixel // center. Subclasses can use this for software multisampling. // @@ -185,10 +212,11 @@ public: static int DefineSoftSampleLocations(GrGLSLPPFragmentBuilder* f, const char* samplesName); private: - GrGLSLVarying fWind{kHalf_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fWind; }; class GSImpl; + class VSImpl; private: // Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't @@ -198,12 +226,26 @@ private: // Number of bezier points for curves, or 3 for triangles. int numInputPoints() const { return RenderPassIsCubic(fRenderPass) ? 4 : 3; } + enum class Impl : bool { + kGeometryShader, + kVertexShader + }; + void initGS(); + void initVS(GrResourceProvider*); + void appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance, - SkTArray* out) const; + SkTArray* out) const; + void appendVSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance, + SkTArray* out) const; + GrGLSLPrimitiveProcessor* createGSImpl(std::unique_ptr) const; + GrGLSLPrimitiveProcessor* createVSImpl(std::unique_ptr) const; const RenderPass fRenderPass; + const Impl fImpl; + sk_sp fVertexBuffer; // Used by VSImpl. + sk_sp fIndexBuffer; // Used by VSImpl. SkDEBUGCODE(float fDebugBloat = 0;) typedef GrGeometryProcessor INHERITED; diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp index 5006ff5a4b..4d1df8ced2 100644 --- a/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp +++ b/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp @@ -72,7 +72,8 @@ protected: } g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() { SkString fnBody; - fShader->emitVaryings(varyingHandler, &fnBody, position, coverage, wind.c_str()); + fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kGeoToFrag, &fnBody, + position, coverage, wind.c_str()); g->emitVertex(&fnBody, position, rtAdjust); return fnBody; }().c_str(), &emitVertexFn); @@ -292,7 +293,7 @@ public: }; /** - * Generates conservatives around corners. (See comments for RenderPass) + * Generates conservative rasters around corners. (See comments for RenderPass) */ class GSCornerImpl : public GrCCPRCoverageProcessor::GSImpl { public: @@ -320,6 +321,7 @@ private: }; void GrCCPRCoverageProcessor::initGS() { + SkASSERT(Impl::kGeometryShader == fImpl); if (RenderPassIsCubic(fRenderPass)) { this->addVertexAttrib("x_or_y_values", kFloat4_GrVertexAttribType); // (See appendMesh.) SkASSERT(sizeof(CubicInstance) == this->getVertexStride() * 2); @@ -331,11 +333,12 @@ void GrCCPRCoverageProcessor::initGS() { } void GrCCPRCoverageProcessor::appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, - int baseInstance, SkTArray* out) const { + int baseInstance, SkTArray* out) const { // GSImpl doesn't actually make instanced draw calls. Instead, we feed transposed x,y point // values to the GPU in a regular vertex array and draw kLines (see initGS). Then, each vertex // invocation receives either the shape's x or y values as inputs, which it forwards to the // geometry shader. + SkASSERT(Impl::kGeometryShader == fImpl); GrMesh& mesh = out->emplace_back(GrPrimitiveType::kLines); mesh.setNonIndexedNonInstanced(instanceCount * 2); mesh.setVertexData(instanceBuffer, baseInstance * 2); diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp new file mode 100644 index 0000000000..fdd304d5f4 --- /dev/null +++ b/src/gpu/ccpr/GrCCPRCoverageProcessor_VSImpl.cpp @@ -0,0 +1,441 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrCCPRCoverageProcessor.h" + +#include "GrMesh.h" +#include "glsl/GrGLSLVertexGeoBuilder.h" + +using Shader = GrCCPRCoverageProcessor::Shader; + +static constexpr int kAttribIdx_X = 0; +static constexpr int kAttribIdx_Y = 1; +static constexpr int kAttribIdx_VertexData = 2; + +/** + * This class and its subclasses implement the coverage processor with vertex shaders. + */ +class GrCCPRCoverageProcessor::VSImpl : public GrGLSLGeometryProcessor { +protected: + VSImpl(std::unique_ptr shader) : fShader(std::move(shader)) {} + + void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, + FPCoordTransformIter&& transformIter) final { + this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); + } + + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final { + const GrCCPRCoverageProcessor& proc = args.fGP.cast(); + + // Vertex shader. + GrGLSLVertexBuilder* v = args.fVertBuilder; + int numInputPoints = proc.numInputPoints(); + + v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s, %s));", + numInputPoints, numInputPoints, proc.getAttrib(kAttribIdx_X).fName, + proc.getAttrib(kAttribIdx_Y).fName); + + v->codeAppend ("float area_x2 = determinant(float2x2(pts[0] - pts[1], pts[0] - pts[2]));"); + if (4 == numInputPoints) { + v->codeAppend ("area_x2 += determinant(float2x2(pts[0] - pts[2], pts[0] - pts[3]));"); + } + v->codeAppend ("half wind = sign(area_x2);"); + + float bloat = kAABloatRadius; +#ifdef SK_DEBUG + if (proc.debugVisualizationsEnabled()) { + bloat *= proc.debugBloat(); + } +#endif + v->defineConstant("bloat", bloat); + + const char* coverage = this->emitVertexPosition(proc, v, gpArgs); + SkASSERT(kFloat2_GrSLType == gpArgs->fPositionVar.getType()); + + GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + SkString varyingCode; + fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &varyingCode, + gpArgs->fPositionVar.c_str(), coverage, "wind"); + v->codeAppend(varyingCode.c_str()); + + varyingHandler->emitAttributes(proc); + SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform()); + + // Fragment shader. + fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage); + } + + virtual const char* emitVertexPosition(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*, + GrGPArgs*) const = 0; + + virtual ~VSImpl() {} + + const std::unique_ptr fShader; + + typedef GrGLSLGeometryProcessor INHERITED; +}; + +/** + * Vertex data tells the shader how to offset vertices for conservative raster, and how/whether to + * calculate initial coverage values for edges. See VSHullAndEdgeImpl. + */ +static constexpr int32_t pack_vertex_data(int32_t bloatIdx, int32_t edgeData, + int32_t cornerVertexID, int32_t cornerIdx) { + return (bloatIdx << 6) | (edgeData << 4) | (cornerVertexID << 2) | cornerIdx; +} + +static constexpr int32_t hull_vertex_data(int32_t cornerIdx, int32_t cornerVertexID, int n) { + return pack_vertex_data((cornerIdx + (2 == cornerVertexID ? 1 : n - 1)) % n, 0, cornerVertexID, + cornerIdx); +} + +static constexpr int32_t edge_vertex_data(int32_t edgeID, int32_t endptIdx, int32_t endptVertexID, + int n) { + return pack_vertex_data(0 == endptIdx ? (edgeID + 1) % n : edgeID, (endptIdx << 1) | 1, + endptVertexID, 0 == endptIdx ? edgeID : (edgeID + 1) % n); +} + +static constexpr int32_t kHull3AndEdgeVertices[] = { + hull_vertex_data(0, 0, 3), + hull_vertex_data(0, 1, 3), + hull_vertex_data(0, 2, 3), + hull_vertex_data(1, 0, 3), + hull_vertex_data(1, 1, 3), + hull_vertex_data(1, 2, 3), + hull_vertex_data(2, 0, 3), + hull_vertex_data(2, 1, 3), + hull_vertex_data(2, 2, 3), + + edge_vertex_data(0, 0, 0, 3), + edge_vertex_data(0, 0, 1, 3), + edge_vertex_data(0, 0, 2, 3), + edge_vertex_data(0, 1, 0, 3), + edge_vertex_data(0, 1, 1, 3), + edge_vertex_data(0, 1, 2, 3), + + edge_vertex_data(1, 0, 0, 3), + edge_vertex_data(1, 0, 1, 3), + edge_vertex_data(1, 0, 2, 3), + edge_vertex_data(1, 1, 0, 3), + edge_vertex_data(1, 1, 1, 3), + edge_vertex_data(1, 1, 2, 3), + + edge_vertex_data(2, 0, 0, 3), + edge_vertex_data(2, 0, 1, 3), + edge_vertex_data(2, 0, 2, 3), + edge_vertex_data(2, 1, 0, 3), + edge_vertex_data(2, 1, 1, 3), + edge_vertex_data(2, 1, 2, 3), +}; + +GR_DECLARE_STATIC_UNIQUE_KEY(gHull3AndEdgeVertexBufferKey); + +static constexpr uint16_t kHull3AndEdgeIndices[] = { + // First corner and main body of the hull. + 1, 2, 0, + 2, 3, 0, + 0, 3, 8, // Main body. + + // Opposite side and corners of the hull. + 4, 5, 3, + 5, 6, 3, + 3, 6, 8, + 6, 7, 8, + + // First edge. + 10, 9, 11, + 9, 14, 11, + 11, 14, 12, + 14, 13, 12, + + // Second edge. + 16, 15, 17, + 15, 20, 17, + 17, 20, 18, + 20, 19, 18, + + // Third edge. + 22, 21, 23, + 21, 26, 23, + 23, 26, 24, + 26, 25, 24, +}; + +GR_DECLARE_STATIC_UNIQUE_KEY(gHull3AndEdgeIndexBufferKey); + +static constexpr int32_t kHull4Vertices[] = { + hull_vertex_data(0, 0, 4), + hull_vertex_data(0, 1, 4), + hull_vertex_data(0, 2, 4), + hull_vertex_data(1, 0, 4), + hull_vertex_data(1, 1, 4), + hull_vertex_data(1, 2, 4), + hull_vertex_data(2, 0, 4), + hull_vertex_data(2, 1, 4), + hull_vertex_data(2, 2, 4), + hull_vertex_data(3, 0, 4), + hull_vertex_data(3, 1, 4), + hull_vertex_data(3, 2, 4), + + // No edges for now (beziers don't use edges). +}; + +GR_DECLARE_STATIC_UNIQUE_KEY(gHull4VertexBufferKey); + +static constexpr uint16_t kHull4Indices[] = { + // First half of the hull (split diagonally). + 1, 0, 2, + 0, 11, 2, + 2, 11, 3, + 11, 5, 3, + 3, 5, 4, + + // Second half of the hull. + 7, 6, 8, + 6, 5, 8, + 8, 5, 9, + 5, 11, 9, + 9, 11, 10, +}; + +GR_DECLARE_STATIC_UNIQUE_KEY(gHull4IndexBufferKey); + +/** + * Generates a conservative raster hull around a convex polygon. For triangles, we also generate + * independent conservative rasters around each edge. (See comments for RenderPass) + */ +class VSHullAndEdgeImpl : public GrCCPRCoverageProcessor::VSImpl { +public: + VSHullAndEdgeImpl(std::unique_ptr shader, int numSides) + : VSImpl(std::move(shader)), fNumSides(numSides) {} + + const char* emitVertexPosition(const GrCCPRCoverageProcessor& proc, GrGLSLVertexBuilder* v, + GrGPArgs* gpArgs) const override { + Shader::GeometryVars vars; + fShader->emitSetupCode(v, "pts", nullptr, "wind", &vars); + + const char* hullPts = vars.fHullVars.fAlternatePoints; + if (!hullPts) { + hullPts = "pts"; + } + + // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0]. + v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;", + proc.getAttrib(kAttribIdx_VertexData).fName, + ((fNumSides - 1) << 6) | (0xf << 2) | (fNumSides - 1), + proc.getAttrib(kAttribIdx_VertexData).fName); + + // Here we generate conservative raster geometry for the input polygon. It is the convex + // hull of N pixel-size boxes, one centered on each the input points. Each corner has three + // vertices, where one or two may cause degenerate triangles. The vertex data tells us how + // to offset each vertex. Triangle edges are also handled here (see kHull3AndEdgeIndices). + // For more details on conservative raster, see: + // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html + v->codeAppendf("float2 corner = %s[clockwise_indices & 3];", hullPts); + v->codeAppendf("float2 bloatpoint = %s[clockwise_indices >> 6];", hullPts); + v->codeAppend ("float2 vertexbloat = float2(bloatpoint.y > corner.y ? -bloat : +bloat, " + "bloatpoint.x > corner.x ? +bloat : -bloat);"); + + v->codeAppendf("if ((1 << 2) == (%s & (3 << 2))) {", + proc.getAttrib(kAttribIdx_VertexData).fName); + // We are the corner's middle vertex (of 3). + v->codeAppend ( "vertexbloat = float2(-vertexbloat.y, vertexbloat.x);"); + v->codeAppend ("}"); + + v->codeAppendf("if ((2 << 2) == (%s & (3 << 2))) {", + proc.getAttrib(kAttribIdx_VertexData).fName); + // We are the corner's third vertex (of 3). + v->codeAppend ( "vertexbloat = -vertexbloat;"); + v->codeAppend ("}"); + + v->codeAppend ("float2 vertex = corner + vertexbloat;"); + gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex"); + + if (4 == fNumSides) { + // We don't generate edges around 4-sided polygons. + return nullptr; // Known hull vertices don't need an initial coverage value. + } + + // Find coverage for edge vertices. + Shader::EmitEdgeDistanceEquation(v, "bloatpoint", "corner", + "float3 edge_distance_equation"); + v->codeAppend ("half coverage = dot(edge_distance_equation.xy, vertex) + " + "edge_distance_equation.z;"); + v->codeAppendf("if (0 == (%s & (1 << 5))) {", proc.getAttrib(kAttribIdx_VertexData).fName); + // We are the opposite endpoint. Invert coverage. + v->codeAppend ( "coverage = -1 - coverage;"); + v->codeAppend ("}"); + v->codeAppendf("if (0 == (%s & (1 << 4))) {", proc.getAttrib(kAttribIdx_VertexData).fName); + // We are actually a hull vertex. Hull coverage is +1 all around. + v->codeAppend ( "coverage = +1;"); + v->codeAppend ("}"); + + return "coverage"; + } + +private: + const int fNumSides; +}; + +static constexpr uint16_t kCornerIndices[] = { + // First corner. + 0, 1, 2, + 1, 3, 2, + + // Second corner. + 4, 5, 6, + 5, 7, 6, + + // Third corner. + 8, 9, 10, + 9, 11, 10, +}; + +GR_DECLARE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey); + +/** + * Generates conservative rasters around corners. (See comments for RenderPass) + */ +class VSCornerImpl : public GrCCPRCoverageProcessor::VSImpl { +public: + VSCornerImpl(std::unique_ptr shader) : VSImpl(std::move(shader)) {} + + const char* emitVertexPosition(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder* v, + GrGPArgs* gpArgs) const override { + Shader::GeometryVars vars; + v->codeAppend ("int corner_id = sk_VertexID / 4;"); + fShader->emitSetupCode(v, "pts", "corner_id", "wind", &vars); + + v->codeAppendf("float2 vertex = %s;", vars.fCornerVars.fPoint); + v->codeAppend ("vertex.x += (0 == (sk_VertexID & 2)) ? -bloat : +bloat;"); + v->codeAppend ("vertex.y += (0 == (sk_VertexID & 1)) ? -bloat : +bloat;"); + + gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex"); + return nullptr; // Corner vertices don't have an initial coverage value. + } +}; + +void GrCCPRCoverageProcessor::initVS(GrResourceProvider* rp) { + SkASSERT(Impl::kVertexShader == fImpl); + + GrVertexAttribType inputPtsType = RenderPassIsCubic(fRenderPass) ? + kFloat4_GrVertexAttribType : kFloat3_GrVertexAttribType; + + SkASSERT(kAttribIdx_X == this->numAttribs()); + this->addInstanceAttrib("X", inputPtsType); + + SkASSERT(kAttribIdx_Y == this->numAttribs()); + this->addInstanceAttrib("Y", inputPtsType); + + switch (fRenderPass) { + case RenderPass::kTriangleHulls: { + GR_DEFINE_STATIC_UNIQUE_KEY(gHull3AndEdgeVertexBufferKey); + fVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType, + sizeof(kHull3AndEdgeVertices), + kHull3AndEdgeVertices, + gHull3AndEdgeVertexBufferKey); + GR_DEFINE_STATIC_UNIQUE_KEY(gHull3AndEdgeIndexBufferKey); + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kHull3AndEdgeIndices), + kHull3AndEdgeIndices, + gHull3AndEdgeIndexBufferKey); + SkASSERT(kAttribIdx_VertexData == this->numAttribs()); + this->addVertexAttrib("vertexdata", kInt_GrVertexAttribType); + break; + } + case RenderPass::kQuadraticHulls: + case RenderPass::kCubicHulls: { + GR_DEFINE_STATIC_UNIQUE_KEY(gHull4VertexBufferKey); + fVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType, sizeof(kHull4Vertices), + kHull4Vertices, gHull4VertexBufferKey); + GR_DEFINE_STATIC_UNIQUE_KEY(gHull4IndexBufferKey); + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kHull4Indices), + kHull4Indices, gHull4IndexBufferKey); + SkASSERT(kAttribIdx_VertexData == this->numAttribs()); + this->addVertexAttrib("vertexdata", kInt_GrVertexAttribType); + break; + } + case RenderPass::kTriangleEdges: + SK_ABORT("kTriangleEdges RenderPass is not used by VSImpl."); + break; + case RenderPass::kTriangleCorners: + case RenderPass::kQuadraticCorners: + case RenderPass::kCubicCorners: { + GR_DEFINE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey); + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kCornerIndices), + kCornerIndices, gCornerIndexBufferKey); + break; + } + } + +#ifdef SK_DEBUG + if (RenderPassIsCubic(fRenderPass)) { + SkASSERT(offsetof(CubicInstance, fX) == this->getAttrib(kAttribIdx_X).fOffsetInRecord); + SkASSERT(offsetof(CubicInstance, fY) == this->getAttrib(kAttribIdx_Y).fOffsetInRecord); + SkASSERT(sizeof(CubicInstance) == this->getInstanceStride()); + } else { + SkASSERT(offsetof(TriangleInstance, fX) == this->getAttrib(kAttribIdx_X).fOffsetInRecord); + SkASSERT(offsetof(TriangleInstance, fY) == this->getAttrib(kAttribIdx_Y).fOffsetInRecord); + SkASSERT(sizeof(TriangleInstance) == this->getInstanceStride()); + } + if (fVertexBuffer) { + SkASSERT(sizeof(int32_t) == this->getVertexStride()); + } +#endif +} + +static int num_indices_per_instance(GrCCPRCoverageProcessor::RenderPass pass) { + switch (pass) { + using RenderPass = GrCCPRCoverageProcessor::RenderPass; + case RenderPass::kTriangleHulls: + return SK_ARRAY_COUNT(kHull3AndEdgeIndices); + case RenderPass::kQuadraticHulls: + case RenderPass::kCubicHulls: + return SK_ARRAY_COUNT(kHull4Indices); + case RenderPass::kTriangleEdges: + SK_ABORT("kTriangleEdges RenderPass is not used by VSImpl."); + return 0; + case RenderPass::kTriangleCorners: + return SK_ARRAY_COUNT(kCornerIndices); + case RenderPass::kQuadraticCorners: + case RenderPass::kCubicCorners: + return SK_ARRAY_COUNT(kCornerIndices) * 2/3; + } + SK_ABORT("Invalid RenderPass"); + return 0; +} + +void GrCCPRCoverageProcessor::appendVSMesh(GrBuffer* instanceBuffer, int instanceCount, + int baseInstance, SkTArray* out) const { + SkASSERT(Impl::kVertexShader == fImpl); + GrMesh& mesh = out->emplace_back(GrPrimitiveType::kTriangles); + mesh.setIndexedInstanced(fIndexBuffer.get(), num_indices_per_instance(fRenderPass), + instanceBuffer, instanceCount, baseInstance); + if (fVertexBuffer) { + mesh.setVertexData(fVertexBuffer.get(), 0); + } +} + +GrGLSLPrimitiveProcessor* +GrCCPRCoverageProcessor::createVSImpl(std::unique_ptr shader) const { + switch (fRenderPass) { + case RenderPass::kTriangleHulls: + return new VSHullAndEdgeImpl(std::move(shader), 3); + case RenderPass::kQuadraticHulls: + case RenderPass::kCubicHulls: + return new VSHullAndEdgeImpl(std::move(shader), 4); + case RenderPass::kTriangleEdges: + SK_ABORT("kTriangleEdges RenderPass is not used by VSImpl."); + return nullptr; + case RenderPass::kTriangleCorners: + case RenderPass::kQuadraticCorners: + case RenderPass::kCubicCorners: + return new VSCornerImpl(std::move(shader)); + } + SK_ABORT("Invalid RenderPass"); + return nullptr; +} diff --git a/src/gpu/ccpr/GrCCPRCubicShader.cpp b/src/gpu/ccpr/GrCCPRCubicShader.cpp index c9e546a74b..f2ef861fc2 100644 --- a/src/gpu/ccpr/GrCCPRCubicShader.cpp +++ b/src/gpu/ccpr/GrCCPRCubicShader.cpp @@ -76,25 +76,29 @@ void GrCCPRCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts } Shader::WindHandling GrCCPRCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, const char* /*wind*/) { SkASSERT(!coverage); + fKLMD.reset(kFloat4_GrSLType, scope); varyingHandler->addVarying("klmd", &fKLMD); code->appendf("float3 klm = float3(%s, 1) * %s;", position, fKLMMatrix.c_str()); code->appendf("float d = dot(float3(%s, 1), %s);", position, fEdgeDistanceEquation.c_str()); - code->appendf("%s = float4(klm, d);", fKLMD.gsOut()); + code->appendf("%s = float4(klm, d);", OutName(fKLMD)); - this->onEmitVaryings(varyingHandler, code); + this->onEmitVaryings(varyingHandler, scope, code); return WindHandling::kNotHandled; } -void GrCCPRCubicHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, SkString* code) { - // "klm" was just defined by the base class. +void GrCCPRCubicHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code) { + fGradMatrix.reset(kFloat2x2_GrSLType, scope); varyingHandler->addVarying("grad_matrix", &fGradMatrix); - code->appendf("%s[0] = 3 * klm[0] * %s[0].xy;", fGradMatrix.gsOut(), fKLMMatrix.c_str()); + // "klm" was just defined by the base class. + code->appendf("%s[0] = 3 * klm[0] * %s[0].xy;", OutName(fGradMatrix), fKLMMatrix.c_str()); code->appendf("%s[1] = -klm[1] * %s[2].xy - klm[2] * %s[1].xy;", - fGradMatrix.gsOut(), fKLMMatrix.c_str(), fKLMMatrix.c_str()); + OutName(fGradMatrix), fKLMMatrix.c_str(), fKLMMatrix.c_str()); } void GrCCPRCubicHullShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, @@ -113,15 +117,18 @@ void GrCCPRCubicCornerShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const c vars->fCornerVars.fPoint = "corner"; } -void GrCCPRCubicCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, SkString* code) { +void GrCCPRCubicCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code) { + fdKLMDdx.reset(kFloat4_GrSLType, scope); varyingHandler->addFlatVarying("dklmddx", &fdKLMDdx); code->appendf("%s = float4(%s[0].x, %s[1].x, %s[2].x, %s.x);", - fdKLMDdx.gsOut(), fKLMMatrix.c_str(), fKLMMatrix.c_str(), + OutName(fdKLMDdx), fKLMMatrix.c_str(), fKLMMatrix.c_str(), fKLMMatrix.c_str(), fEdgeDistanceEquation.c_str()); + fdKLMDdy.reset(kFloat4_GrSLType, scope); varyingHandler->addFlatVarying("dklmddy", &fdKLMDdy); code->appendf("%s = float4(%s[0].y, %s[1].y, %s[2].y, %s.y);", - fdKLMDdy.gsOut(), fKLMMatrix.c_str(), fKLMMatrix.c_str(), + OutName(fdKLMDdy), fKLMMatrix.c_str(), fKLMMatrix.c_str(), fKLMMatrix.c_str(), fEdgeDistanceEquation.c_str()); } diff --git a/src/gpu/ccpr/GrCCPRCubicShader.h b/src/gpu/ccpr/GrCCPRCubicShader.h index 10f4dffd76..bb578782f4 100644 --- a/src/gpu/ccpr/GrCCPRCubicShader.h +++ b/src/gpu/ccpr/GrCCPRCubicShader.h @@ -29,31 +29,31 @@ protected: virtual void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const {} - WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position, - const char* coverage, const char* wind) final; + WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, + const char* position, const char* coverage, const char* wind) final; - virtual void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) = 0; + virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) = 0; GrShaderVar fKLMMatrix{"klm_matrix", kFloat3x3_GrSLType}; GrShaderVar fEdgeDistanceEquation{"edge_distance_equation", kFloat3_GrSLType}; - GrGLSLVarying fKLMD{kFloat4_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fKLMD; }; class GrCCPRCubicHullShader : public GrCCPRCubicShader { - void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) override; + void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; - GrGLSLVarying fGradMatrix{kFloat2x2_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fGradMatrix; }; class GrCCPRCubicCornerShader : public GrCCPRCubicShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; - void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) override; + void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; - GrGLSLVarying fdKLMDdx{kFloat4_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; - GrGLSLVarying fdKLMDdy{kFloat4_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fdKLMDdx; + GrGLSLVarying fdKLMDdy; }; #endif diff --git a/src/gpu/ccpr/GrCCPRQuadraticShader.cpp b/src/gpu/ccpr/GrCCPRQuadraticShader.cpp index 308e3ff927..429cb4efc3 100644 --- a/src/gpu/ccpr/GrCCPRQuadraticShader.cpp +++ b/src/gpu/ccpr/GrCCPRQuadraticShader.cpp @@ -7,6 +7,7 @@ #include "GrCCPRQuadraticShader.h" +#include "glsl/GrGLSLVertexGeoBuilder.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLVertexGeoBuilder.h" @@ -33,19 +34,21 @@ void GrCCPRQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* } Shader::WindHandling GrCCPRQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, const char* /*wind*/) { SkASSERT(!coverage); + fXYD.reset(kFloat3_GrSLType, scope); varyingHandler->addVarying("xyd", &fXYD); code->appendf("%s.xy = (%s * float3(%s, 1)).xy;", - fXYD.gsOut(), fCanonicalMatrix.c_str(), position); + OutName(fXYD), fCanonicalMatrix.c_str(), position); code->appendf("%s.z = dot(%s.xy, %s) + %s.z;", - fXYD.gsOut(), fEdgeDistanceEquation.c_str(), position, + OutName(fXYD), fEdgeDistanceEquation.c_str(), position, fEdgeDistanceEquation.c_str()); - this->onEmitVaryings(varyingHandler, code); + this->onEmitVaryings(varyingHandler, scope, code); return WindHandling::kNotHandled; } @@ -69,10 +72,11 @@ void GrCCPRQuadraticHullShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const } void GrCCPRQuadraticHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, - SkString* code) { + GrGLSLVarying::Scope scope, SkString* code) { + fGrad.reset(kFloat2_GrSLType, scope); varyingHandler->addVarying("grad", &fGrad); code->appendf("%s = float2(2 * %s.x, -1) * float2x2(%s);", - fGrad.gsOut(), fXYD.gsOut(), fCanonicalMatrix.c_str()); + OutName(fGrad), OutName(fXYD), fCanonicalMatrix.c_str()); } void GrCCPRQuadraticHullShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, @@ -91,15 +95,17 @@ void GrCCPRQuadraticCornerShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, con } void GrCCPRQuadraticCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, - SkString* code) { + GrGLSLVarying::Scope scope, SkString* code) { + fdXYDdx.reset(kFloat3_GrSLType, scope); varyingHandler->addFlatVarying("dXYDdx", &fdXYDdx); code->appendf("%s = float3(%s[0].x, %s[0].y, %s.x);", - fdXYDdx.gsOut(), fCanonicalMatrix.c_str(), fCanonicalMatrix.c_str(), + OutName(fdXYDdx), fCanonicalMatrix.c_str(), fCanonicalMatrix.c_str(), fEdgeDistanceEquation.c_str()); + fdXYDdy.reset(kFloat3_GrSLType, scope); varyingHandler->addFlatVarying("dXYDdy", &fdXYDdy); code->appendf("%s = float3(%s[1].x, %s[1].y, %s.y);", - fdXYDdy.gsOut(), fCanonicalMatrix.c_str(), fCanonicalMatrix.c_str(), + OutName(fdXYDdy), fCanonicalMatrix.c_str(), fCanonicalMatrix.c_str(), fEdgeDistanceEquation.c_str()); } diff --git a/src/gpu/ccpr/GrCCPRQuadraticShader.h b/src/gpu/ccpr/GrCCPRQuadraticShader.h index 14505c6e2e..76b2563e43 100644 --- a/src/gpu/ccpr/GrCCPRQuadraticShader.h +++ b/src/gpu/ccpr/GrCCPRQuadraticShader.h @@ -28,14 +28,14 @@ protected: virtual void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const = 0; - WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position, - const char* coverage, const char* wind) final; + WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, + const char* position, const char* coverage, const char* wind) final; - virtual void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) = 0; + virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) {} const GrShaderVar fCanonicalMatrix{"canonical_matrix", kFloat3x3_GrSLType}; const GrShaderVar fEdgeDistanceEquation{"edge_distance_equation", kFloat3_GrSLType}; - GrGLSLVarying fXYD{kFloat3_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fXYD; }; /** @@ -47,10 +47,10 @@ protected: class GrCCPRQuadraticHullShader : public GrCCPRQuadraticShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; - void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) override; + void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; - GrGLSLVarying fGrad{kFloat2_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fGrad; }; /** @@ -59,11 +59,11 @@ class GrCCPRQuadraticHullShader : public GrCCPRQuadraticShader { class GrCCPRQuadraticCornerShader : public GrCCPRQuadraticShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; - void onEmitVaryings(GrGLSLVaryingHandler*, SkString* code) override; + void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; - GrGLSLVarying fdXYDdx{kFloat3_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; - GrGLSLVarying fdXYDdy{kFloat3_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fdXYDdx; + GrGLSLVarying fdXYDdy; }; #endif diff --git a/src/gpu/ccpr/GrCCPRTriangleShader.cpp b/src/gpu/ccpr/GrCCPRTriangleShader.cpp index ce05697dbf..130580125c 100644 --- a/src/gpu/ccpr/GrCCPRTriangleShader.cpp +++ b/src/gpu/ccpr/GrCCPRTriangleShader.cpp @@ -13,14 +13,16 @@ using Shader = GrCCPRCoverageProcessor::Shader; Shader::WindHandling GrCCPRTriangleShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code, const char* /*position*/, const char* coverage, const char* wind) { + fCoverageTimesWind.reset(kHalf_GrSLType, scope); if (!coverage) { varyingHandler->addFlatVarying("wind", &fCoverageTimesWind); - code->appendf("%s = %s;", fCoverageTimesWind.gsOut(), wind); + code->appendf("%s = %s;", OutName(fCoverageTimesWind), wind); } else { varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind); - code->appendf("%s = %s * %s;", fCoverageTimesWind.gsOut(), coverage, wind); + code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), coverage, wind); } return WindHandling::kHandled; } @@ -85,18 +87,23 @@ void GrCCPRTriangleCornerShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const } Shader::WindHandling -GrCCPRTriangleCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, SkString* code, +GrCCPRTriangleCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, + GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, const char* /*wind*/) { SkASSERT(!coverage); + fCornerLocationInAABoxes.reset(kFloat2x2_GrSLType, scope); varyingHandler->addVarying("corner_location_in_aa_boxes", &fCornerLocationInAABoxes); + + fBisectInAABoxes.reset(kFloat2x2_GrSLType, scope); varyingHandler->addFlatVarying("bisect_in_aa_boxes", &fBisectInAABoxes); + code->appendf("for (int i = 0; i < 2; ++i) {"); code->appendf( "%s[i] = %s * %s[i] + %s[i];", - fCornerLocationInAABoxes.gsOut(), position, fAABoxMatrices.c_str(), + OutName(fCornerLocationInAABoxes), position, fAABoxMatrices.c_str(), fAABoxTranslates.c_str()); - code->appendf( "%s[i] = %s[i];", fBisectInAABoxes.gsOut(), fGeoShaderBisects.c_str()); + code->appendf( "%s[i] = %s[i];", OutName(fBisectInAABoxes), fGeoShaderBisects.c_str()); code->appendf("}"); return WindHandling::kNotHandled; diff --git a/src/gpu/ccpr/GrCCPRTriangleShader.h b/src/gpu/ccpr/GrCCPRTriangleShader.h index 1f58e84d78..02eb77174b 100644 --- a/src/gpu/ccpr/GrCCPRTriangleShader.h +++ b/src/gpu/ccpr/GrCCPRTriangleShader.h @@ -11,35 +11,38 @@ #include "ccpr/GrCCPRCoverageProcessor.h" /** - * Passes 1 & 2: Draw the triangle's conservative raster hull with a coverage of 1, then smooth the - * edges by drawing the conservative rasters of all 3 edges and interpolating from - * coverage=-1 on the outside to coverage=0 on the inside. + * Steps 1 & 2: Draw the triangle's conservative raster hull with a coverage of +1, then smooth the + * edges by drawing the conservative rasters of all 3 edges and interpolating from + * coverage=-1 on the outside to coverage=0 on the inside. The Impl may choose to + * implement these steps in either one or two actual render passes. */ class GrCCPRTriangleShader : public GrCCPRCoverageProcessor::Shader { - WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position, - const char* coverage, const char* wind) override; + WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, + const char* position, const char* coverage, + const char* wind) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; - GrGLSLVarying fCoverageTimesWind{kHalf_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fCoverageTimesWind; }; /** - * Pass 3: Touch up the corner pixels. Here we fix the simple distance-to-edge coverage analysis + * Step 3: Touch up the corner pixels. Here we fix the simple distance-to-edge coverage analysis * done previously so that it takes into account the region that is outside both edges at * the same time. */ class GrCCPRTriangleCornerShader : public GrCCPRCoverageProcessor::Shader { void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, const char* wind, GeometryVars*) const override; - WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position, - const char* coverage, const char* wind) override; + WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, + const char* position, const char* coverage, + const char* wind) override; void onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const override; GrShaderVar fAABoxMatrices{"aa_box_matrices", kFloat2x2_GrSLType, 2}; GrShaderVar fAABoxTranslates{"aa_box_translates", kFloat2_GrSLType, 2}; GrShaderVar fGeoShaderBisects{"bisects", kFloat2_GrSLType, 2}; - GrGLSLVarying fCornerLocationInAABoxes{kFloat2x2_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; - GrGLSLVarying fBisectInAABoxes{kFloat2x2_GrSLType, GrGLSLVarying::Scope::kGeoToFrag}; + GrGLSLVarying fCornerLocationInAABoxes; + GrGLSLVarying fBisectInAABoxes; }; #endif diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index a239569b3e..6a38ee099b 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -38,14 +38,12 @@ static void crop_path(const SkPath& path, const SkIRect& cropbox, SkPath* out) { bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps) { const GrShaderCaps& shaderCaps = *caps.shaderCaps(); - return shaderCaps.geometryShaderSupport() && - shaderCaps.integerSupport() && + return shaderCaps.integerSupport() && shaderCaps.flatInterpolationSupport() && caps.instanceAttribSupport() && GrCaps::kNone_MapFlags != caps.mapBufferFlags() && caps.isConfigTexturable(kAlpha_half_GrPixelConfig) && caps.isConfigRenderable(kAlpha_half_GrPixelConfig, /*withMSAA=*/false) && - GrCaps::kNone_MapFlags != caps.mapBufferFlags() && !caps.blacklistCoverageCounting(); } diff --git a/src/gpu/glsl/GrGLSLVarying.cpp b/src/gpu/glsl/GrGLSLVarying.cpp index 4bcce0391a..5a57613b3a 100644 --- a/src/gpu/glsl/GrGLSLVarying.cpp +++ b/src/gpu/glsl/GrGLSLVarying.cpp @@ -37,6 +37,7 @@ void GrGLSLVaryingHandler::internalAddVarying(const char* name, GrGLSLVarying* v VaryingInfo& v = fVaryings.push_back(); SkASSERT(varying); + SkASSERT(kVoid_GrSLType != varying->fType); v.fType = varying->fType; v.fIsFlat = flat; fProgramBuilder->nameVariable(&v.fVsOut, 'v', name); diff --git a/src/gpu/glsl/GrGLSLVarying.h b/src/gpu/glsl/GrGLSLVarying.h index e6174a6197..dac9bb771f 100644 --- a/src/gpu/glsl/GrGLSLVarying.h +++ b/src/gpu/glsl/GrGLSLVarying.h @@ -24,8 +24,15 @@ public: kGeoToFrag }; + GrGLSLVarying() = default; GrGLSLVarying(GrSLType type, Scope scope = Scope::kVertToFrag) : fType(type), fScope(scope) {} + void reset(GrSLType type, Scope scope = Scope::kVertToFrag) { + *this = GrGLSLVarying(); + fType = type; + fScope = scope; + } + GrSLType type() const { return fType; } Scope scope() const { return fScope; } bool isInVertexShader() const { return Scope::kGeoToFrag != fScope; } @@ -37,8 +44,8 @@ public: const char* fsIn() const { SkASSERT(this->isInFragmentShader()); return fFsIn; } private: - const GrSLType fType; - const Scope fScope; + GrSLType fType = kVoid_GrSLType; + Scope fScope = Scope::kVertToFrag; const char* fVsOut = nullptr; const char* fGsIn = nullptr; const char* fGsOut = nullptr; -- cgit v1.2.3