CCPR: Don't use instanced draw calls with geometry shaders

It isn't necessary for the vertex shader to know all the points
because everything happens in the geometry shader. It's simpler to use
regular vertex arrays instead.

Bug: skia:
Change-Id: I7bf83180476fbe0ab01492611cd72e72b3f7d4f2
Reviewed-on: https://skia-review.googlesource.com/82881
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2017-12-10 16:41:45 -07:00 committed by Skia Commit-Bot
parent 30c48065dd
commit 2326177e34
7 changed files with 156 additions and 160 deletions

View File

@ -251,51 +251,45 @@ void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) {
GrGLGpu* glGpu = kOpenGL_GrBackend == context->contextPriv().getBackend() ?
static_cast<GrGLGpu*>(state->gpu()) : nullptr;
bool isCubic = GrCCPRCoverageProcessor::RenderPassIsCubic(fView->fRenderPass);
GrMesh mesh(isCubic ? GrPrimitiveType::kLinesAdjacency : GrPrimitiveType::kTriangles);
if (isCubic) {
if (fView->fCubicInstances.empty()) {
return;
}
GrCCPRCoverageProcessor proc(fView->fRenderPass);
SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat);)
SkSTArray<1, GrMesh, true> mesh;
if (GrCCPRCoverageProcessor::RenderPassIsCubic(fView->fRenderPass)) {
sk_sp<GrBuffer> instBuff(rp->createBuffer(fView->fCubicInstances.count() *
sizeof(CubicInstance), kVertex_GrBufferType,
kDynamic_GrAccessPattern,
GrResourceProvider::kNoPendingIO_Flag |
GrResourceProvider::kRequireGpuMemory_Flag,
fView->fCubicInstances.begin()));
if (!instBuff) {
return;
if (!fView->fCubicInstances.empty() && instBuff) {
proc.appendMesh(instBuff.get(), fView->fCubicInstances.count(), 0, &mesh);
}
mesh.setInstanced(instBuff.get(), fView->fCubicInstances.count(), 0, 4);
} else {
if (fView->fTriangleInstances.empty()) {
return;
}
sk_sp<GrBuffer> instBuff(rp->createBuffer(fView->fTriangleInstances.count() *
sizeof(TriangleInstance), kVertex_GrBufferType,
kDynamic_GrAccessPattern,
GrResourceProvider::kNoPendingIO_Flag |
GrResourceProvider::kRequireGpuMemory_Flag,
fView->fTriangleInstances.begin()));
if (!instBuff) {
return;
if (!fView->fTriangleInstances.empty() && instBuff) {
proc.appendMesh(instBuff.get(), fView->fTriangleInstances.count(), 0, &mesh);
}
mesh.setInstanced(instBuff.get(), fView->fTriangleInstances.count(), 0, 3);
}
GrPipeline pipeline(state->drawOpArgs().fProxy, GrPipeline::ScissorState::kDisabled,
SkBlendMode::kSrcOver);
GrCCPRCoverageProcessor ccprProc(fView->fRenderPass);
SkDEBUGCODE(ccprProc.enableDebugVisualizations(kDebugBloat);)
if (glGpu) {
glGpu->handleDirtyContext();
GR_GL_CALL(glGpu->glInterface(), PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
GR_GL_CALL(glGpu->glInterface(), Enable(GR_GL_LINE_SMOOTH));
}
state->rtCommandBuffer()->draw(pipeline, ccprProc, &mesh, nullptr, 1, this->bounds());
if (!mesh.empty()) {
SkASSERT(1 == mesh.count());
state->rtCommandBuffer()->draw(pipeline, proc, mesh.begin(), nullptr, 1, this->bounds());
}
if (glGpu) {
context->resetContext(kMisc_GrGLBackendState);

View File

@ -393,32 +393,28 @@ void GrCCPRCoverageOp::onExecute(GrOpFlushState* flushState) {
fDynamicStatesScratchBuffer.reserve(1 + fScissorBatches.count());
// Triangles.
auto constexpr kTrianglesGrPrimitiveType = GrCCPRCoverageProcessor::kTrianglesGrPrimitiveType;
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleHulls,
kTrianglesGrPrimitiveType, 3, &PrimitiveTallies::fTriangles);
&PrimitiveTallies::fTriangles);
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleEdges,
kTrianglesGrPrimitiveType, 3, &PrimitiveTallies::fTriangles);
&PrimitiveTallies::fTriangles);
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleCorners,
kTrianglesGrPrimitiveType, 3, &PrimitiveTallies::fTriangles);
&PrimitiveTallies::fTriangles);
// Quadratics.
auto constexpr kQuadraticsGrPrimitiveType = GrCCPRCoverageProcessor::kQuadraticsGrPrimitiveType;
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kQuadraticHulls,
kQuadraticsGrPrimitiveType, 3, &PrimitiveTallies::fQuadratics);
&PrimitiveTallies::fQuadratics);
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kQuadraticCorners,
kQuadraticsGrPrimitiveType, 3, &PrimitiveTallies::fQuadratics);
&PrimitiveTallies::fQuadratics);
// Cubics.
auto constexpr kCubicsGrPrimitiveType = GrCCPRCoverageProcessor::kCubicsGrPrimitiveType;
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kCubicHulls,
kCubicsGrPrimitiveType, 4, &PrimitiveTallies::fCubics);
&PrimitiveTallies::fCubics);
this->drawMaskPrimitives(flushState, pipeline, RenderPass::kCubicCorners,
kCubicsGrPrimitiveType, 4, &PrimitiveTallies::fCubics);
&PrimitiveTallies::fCubics);
}
void GrCCPRCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
GrCCPRCoverageProcessor::RenderPass renderPass,
GrPrimitiveType primType, int vertexCount,
int PrimitiveTallies::* instanceType) const {
using ScissorMode = GrCCPRCoverageOpsBuilder::ScissorMode;
SkASSERT(pipeline.getScissorState().enabled());
@ -426,11 +422,12 @@ void GrCCPRCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPi
fMeshesScratchBuffer.reset();
fDynamicStatesScratchBuffer.reset();
GrCCPRCoverageProcessor proc(renderPass);
if (const int instanceCount = fInstanceCounts[(int)ScissorMode::kNonScissored].*instanceType) {
SkASSERT(instanceCount > 0);
const int baseInstance = fBaseInstances[(int)ScissorMode::kNonScissored].*instanceType;
GrMesh& mesh = fMeshesScratchBuffer.emplace_back(primType);
mesh.setInstanced(fInstanceBuffer.get(), instanceCount, baseInstance, vertexCount);
proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance, &fMeshesScratchBuffer);
fDynamicStatesScratchBuffer.push_back().fScissorRect.setXYWH(0, 0, fDrawBounds.width(),
fDrawBounds.height());
}
@ -444,8 +441,8 @@ void GrCCPRCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPi
continue;
}
SkASSERT(instanceCount > 0);
GrMesh& mesh = fMeshesScratchBuffer.emplace_back(primType);
mesh.setInstanced(fInstanceBuffer.get(), instanceCount, baseInstance, vertexCount);
proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance,
&fMeshesScratchBuffer);
fDynamicStatesScratchBuffer.push_back().fScissorRect = batch.fScissor;
baseInstance += instanceCount;
}
@ -454,7 +451,6 @@ void GrCCPRCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPi
SkASSERT(fMeshesScratchBuffer.count() == fDynamicStatesScratchBuffer.count());
if (!fMeshesScratchBuffer.empty()) {
GrCCPRCoverageProcessor proc(renderPass);
SkASSERT(flushState->rtCommandBuffer());
flushState->rtCommandBuffer()->draw(pipeline, proc, fMeshesScratchBuffer.begin(),
fDynamicStatesScratchBuffer.begin(),

View File

@ -158,9 +158,8 @@ private:
const PrimitiveTallies baseInstances[kNumScissorModes],
const PrimitiveTallies endInstances[kNumScissorModes]);
void drawMaskPrimitives(GrOpFlushState*, const GrPipeline&,
const GrCCPRCoverageProcessor::RenderPass, GrPrimitiveType,
int vertexCount, int PrimitiveTallies::* instanceType) const;
void drawMaskPrimitives(GrOpFlushState*, const GrPipeline&, GrCCPRCoverageProcessor::RenderPass,
int PrimitiveTallies::* instanceType) const;
sk_sp<GrBuffer> fInstanceBuffer;
PrimitiveTallies fBaseInstances[kNumScissorModes];
@ -168,8 +167,8 @@ private:
const SkTArray<ScissorBatch, true> fScissorBatches;
const SkISize fDrawBounds;
mutable SkTArray<GrMesh> fMeshesScratchBuffer;
mutable SkTArray<GrPipeline::DynamicState> fDynamicStatesScratchBuffer;
mutable SkTArray<GrMesh, true> fMeshesScratchBuffer;
mutable SkTArray<GrPipeline::DynamicState, true> fDynamicStatesScratchBuffer;
friend class GrCCPRCoverageOpsBuilder;

View File

@ -13,32 +13,6 @@
#include "ccpr/GrCCPRTriangleShader.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
GrCCPRCoverageProcessor::GrCCPRCoverageProcessor(RenderPass renderPass)
: INHERITED(kGrCCPRCoverageProcessor_ClassID)
, fRenderPass(renderPass) {
if (RenderPassIsCubic(fRenderPass)) {
this->addInstanceAttrib("X", kFloat4_GrVertexAttribType);
this->addInstanceAttrib("Y", kFloat4_GrVertexAttribType);
SkASSERT(offsetof(CubicInstance, fX) ==
this->getInstanceAttrib(InstanceAttribs::kX).fOffsetInRecord);
SkASSERT(offsetof(CubicInstance, fY) ==
this->getInstanceAttrib(InstanceAttribs::kY).fOffsetInRecord);
SkASSERT(sizeof(CubicInstance) == this->getInstanceStride());
} else {
this->addInstanceAttrib("X", kFloat3_GrVertexAttribType);
this->addInstanceAttrib("Y", kFloat3_GrVertexAttribType);
SkASSERT(offsetof(TriangleInstance, fX) ==
this->getInstanceAttrib(InstanceAttribs::kX).fOffsetInRecord);
SkASSERT(offsetof(TriangleInstance, fY) ==
this->getInstanceAttrib(InstanceAttribs::kY).fOffsetInRecord);
SkASSERT(sizeof(TriangleInstance) == this->getInstanceStride());
}
this->setWillUseGeoShader();
}
void GrCCPRCoverageProcessor::Shader::emitVaryings(GrGLSLVaryingHandler* varyingHandler,
SkString* code, const char* position,
const char* coverage, const char* wind) {

View File

@ -15,6 +15,7 @@
class GrGLSLPPFragmentBuilder;
class GrGLSLShaderBuilder;
class GrMesh;
/**
* This is the geometry processor for the simple convex primitive shapes (triangles and closed curve
@ -26,22 +27,12 @@ class GrGLSLShaderBuilder;
* below). Once all of a path's primitives have been drawn, the render target contains a composite
* coverage count that can then be used to draw the path (see GrCCPRPathProcessor).
*
* Draw calls are instanced. They use use the corresponding GrPrimitiveTypes as defined below.
* Caller fills out the primitives' atlas-space vertices and control points in instance arrays
* using the provided structs below. There are no vertex attribs.
* To draw a renderer pass, see appendMesh below.
*/
class GrCCPRCoverageProcessor : public GrGeometryProcessor {
public:
static constexpr GrPrimitiveType kTrianglesGrPrimitiveType = GrPrimitiveType::kTriangles;
static constexpr GrPrimitiveType kQuadraticsGrPrimitiveType = GrPrimitiveType::kTriangles;
static constexpr GrPrimitiveType kCubicsGrPrimitiveType = GrPrimitiveType::kLinesAdjacency;
enum class InstanceAttribs : int {
kX,
kY
};
struct TriangleInstance { // Also used by quadratics.
// Defines a single triangle or closed quadratic bezier, with transposed x,y point values.
struct TriangleInstance {
float fX[3];
float fY[3];
@ -49,6 +40,7 @@ public:
void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans);
};
// Defines a single closed cubic bezier, with transposed x,y point values.
struct CubicInstance {
float fX[4];
float fY[4];
@ -56,11 +48,9 @@ public:
void set(const SkPoint[4], float dx, float dy);
};
/**
* All primitive shapes (triangles and convex closed curve segments) require more than one
* 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.
*/
// All primitive shapes (triangles and convex closed curve segments) require more than one
// 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.
enum class RenderPass {
// Triangles.
kTriangleHulls,
@ -75,42 +65,44 @@ public:
kCubicHulls,
kCubicCorners
};
static bool RenderPassIsCubic(RenderPass);
static const char* RenderPassName(RenderPass);
static inline bool RenderPassIsCubic(RenderPass pass) {
switch (pass) {
case RenderPass::kTriangleHulls:
case RenderPass::kTriangleEdges:
case RenderPass::kTriangleCorners:
case RenderPass::kQuadraticHulls:
case RenderPass::kQuadraticCorners:
return false;
case RenderPass::kCubicHulls:
case RenderPass::kCubicCorners:
return true;
}
SK_ABORT("Invalid GrCCPRCoverageProcessor::RenderPass");
return false;
GrCCPRCoverageProcessor(RenderPass pass)
: INHERITED(kGrCCPRCoverageProcessor_ClassID)
, fRenderPass(pass) {
this->initGS();
}
static inline const char* RenderPassName(RenderPass pass) {
switch (pass) {
case RenderPass::kTriangleHulls: return "kTriangleHulls";
case RenderPass::kTriangleEdges: return "kTriangleEdges";
case RenderPass::kTriangleCorners: return "kTriangleCorners";
case RenderPass::kQuadraticHulls: return "kQuadraticHulls";
case RenderPass::kQuadraticCorners: return "kQuadraticCorners";
case RenderPass::kCubicHulls: return "kCubicHulls";
case RenderPass::kCubicCorners: return "kCubicCorners";
}
SK_ABORT("Invalid GrCCPRCoverageProcessor::RenderPass");
return "";
// Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
// of either TriangleInstance or CubicInstance, depending on this processor's RendererPass, with
// coordinates in the desired shape's final atlas-space position.
//
// NOTE: Quadratics use TriangleInstance since both have 3 points.
void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
SkTArray<GrMesh, true>* out) {
this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out);
}
/**
* This serves as the base class for each RenderPass's Shader. It indicates what type of
* geometry the Impl should generate and provides implementation-independent code to process
* the inputs and calculate coverage in the fragment Shader.
*/
// GrPrimitiveProcessor overrides.
const char* name() const override { return RenderPassName(fRenderPass); }
SkString dumpInfo() const override {
return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
}
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
#ifdef SK_DEBUG
// Increases the 1/2 pixel AA bloat by a factor of debugBloat and outputs color instead of
// coverage (coverage=+1 -> green, coverage=0 -> black, coverage=-1 -> red).
void enableDebugVisualizations(float debugBloat) { fDebugBloat = debugBloat; }
bool debugVisualizationsEnabled() const { return fDebugBloat > 0; }
float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
#endif
// This serves as the base class for each RenderPass's Shader. It indicates what type of
// geometry the Impl should generate and provides implementation-independent code to process the
// inputs and calculate coverage in the fragment Shader.
class Shader {
public:
using TexelBufferHandle = GrGLSLGeometryProcessor::TexelBufferHandle;
@ -211,27 +203,6 @@ public:
GrGLSLVarying fWind{kHalf_GrSLType, GrGLSLVarying::Scope::kGeoToFrag};
};
GrCCPRCoverageProcessor(RenderPass);
const char* name() const override { return RenderPassName(fRenderPass); }
SkString dumpInfo() const override {
return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
}
const Attribute& getInstanceAttrib(InstanceAttribs attribID) const {
return this->getAttrib((int)attribID);
}
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
#ifdef SK_DEBUG
// Increases the 1/2 pixel AA bloat by a factor of debugBloat and outputs color instead of
// coverage (coverage=+1 -> green, coverage=0 -> black, coverage=-1 -> red).
void enableDebugVisualizations(float debugBloat) { fDebugBloat = debugBloat; }
bool debugVisualizationsEnabled() const { return fDebugBloat > 0; }
float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
#endif
class GSImpl;
private:
@ -239,6 +210,10 @@ private:
// accidentally bleed into neighbor pixels.
static constexpr float kAABloatRadius = 0.491111f;
void initGS();
void appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
SkTArray<GrMesh, true>* out);
int numInputPoints() const {
return RenderPassIsCubic(fRenderPass) ? 4 : 3;
}
@ -270,4 +245,34 @@ inline void GrCCPRCoverageProcessor::CubicInstance::set(const SkPoint p[4], floa
(Y + dy).store(&fY);
}
inline bool GrCCPRCoverageProcessor::RenderPassIsCubic(RenderPass pass) {
switch (pass) {
case RenderPass::kTriangleHulls:
case RenderPass::kTriangleEdges:
case RenderPass::kTriangleCorners:
case RenderPass::kQuadraticHulls:
case RenderPass::kQuadraticCorners:
return false;
case RenderPass::kCubicHulls:
case RenderPass::kCubicCorners:
return true;
}
SK_ABORT("Invalid GrCCPRCoverageProcessor::RenderPass");
return false;
}
inline const char* GrCCPRCoverageProcessor::RenderPassName(RenderPass pass) {
switch (pass) {
case RenderPass::kTriangleHulls: return "kTriangleHulls";
case RenderPass::kTriangleEdges: return "kTriangleEdges";
case RenderPass::kTriangleCorners: return "kTriangleCorners";
case RenderPass::kQuadraticHulls: return "kQuadraticHulls";
case RenderPass::kQuadraticCorners: return "kQuadraticCorners";
case RenderPass::kCubicHulls: return "kCubicHulls";
case RenderPass::kCubicCorners: return "kCubicCorners";
}
SK_ABORT("Invalid GrCCPRCoverageProcessor::RenderPass");
return "";
}
#endif

View File

@ -7,6 +7,7 @@
#include "GrCCPRCoverageProcessor.h"
#include "GrMesh.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
using Shader = GrCCPRCoverageProcessor::Shader;
@ -26,17 +27,16 @@ protected:
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
const GrCCPRCoverageProcessor& proc = args.fGP.cast<GrCCPRCoverageProcessor>();
// Vertex shader.
GrGLSLVertexBuilder* v = args.fVertBuilder;
v->codeAppendf("float2 self = float2(%s[sk_VertexID], %s[sk_VertexID]);",
proc.getInstanceAttrib(InstanceAttribs::kX).fName,
proc.getInstanceAttrib(InstanceAttribs::kY).fName);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "self");
// The vertex shader simply forwards transposed x or y values to the geometry shader.
SkASSERT(1 == proc.numAttribs());
gpArgs->fPositionVar.set(4 == proc.numInputPoints() ? kFloat4_GrSLType : kFloat3_GrSLType,
proc.getAttrib(0).fName);
// Geometry shader.
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
this->emitGeometryShader(proc, varyingHandler, args.fGeomBuilder, args.fRTAdjustName);
varyingHandler->emitAttributes(proc);
varyingHandler->setNoPerspective();
SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
// Fragment shader.
@ -52,12 +52,9 @@ protected:
int numInputPoints = proc.numInputPoints();
SkASSERT(3 == numInputPoints || 4 == numInputPoints);
g->codeAppendf("float%ix2 pts = float%ix2(", numInputPoints, numInputPoints);
for (int i = 0; i < numInputPoints; ++i) {
g->codeAppend (i ? ", " : "");
g->codeAppendf("sk_in[%i].sk_Position.xy", i);
}
g->codeAppend (");");
const char* posValues = (4 == numInputPoints) ? "sk_Position" : "sk_Position.xyz";
g->codeAppendf("float%ix2 pts = transpose(float2x%i(sk_in[0].%s, sk_in[1].%s));",
numInputPoints, numInputPoints, posValues, posValues);
GrShaderVar wind("wind", kHalf_GrSLType);
g->declareGlobal(wind);
@ -89,9 +86,8 @@ protected:
Shader::GeometryVars vars;
fShader->emitSetupCode(g, "pts", "sk_InvocationID", wind.c_str(), &vars);
int maxPoints = this->onEmitGeometryShader(g, wind, emitVertexFn.c_str(), vars);
InputType inputType = (3 == numInputPoints) ? InputType::kTriangles
: InputType::kLinesAdjacency;
g->configure(inputType, OutputType::kTriangleStrip, maxPoints, fShader->getNumSegments());
g->configure(InputType::kLines, OutputType::kTriangleStrip, maxPoints,
fShader->getNumSegments());
}
virtual int onEmitGeometryShader(GrGLSLGeometryBuilder*, const GrShaderVar& wind,
@ -255,6 +251,17 @@ public:
}
};
void GrCCPRCoverageProcessor::initGS() {
if (RenderPassIsCubic(fRenderPass)) {
this->addVertexAttrib("x_or_y_values", kFloat4_GrVertexAttribType); // (See appendMesh.)
SkASSERT(sizeof(CubicInstance) == this->getVertexStride() * 2);
} else {
this->addVertexAttrib("x_or_y_values", kFloat3_GrVertexAttribType); // (See appendMesh.)
SkASSERT(sizeof(TriangleInstance) == this->getVertexStride() * 2);
}
this->setWillUseGeoShader();
}
GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::CreateGSImpl(std::unique_ptr<Shader> shader) {
switch (shader->getGeometryType()) {
case Shader::GeometryType::kHull:
@ -267,3 +274,14 @@ GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::CreateGSImpl(std::unique_ptr<
SK_ABORT("Unexpected Shader::GeometryType.");
return nullptr;
}
void GrCCPRCoverageProcessor::appendGSMesh(GrBuffer* instanceBuffer, int instanceCount,
int baseInstance, SkTArray<GrMesh, true>* out) {
// 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.
GrMesh& mesh = out->emplace_back(GrPrimitiveType::kLines);
mesh.setNonIndexedNonInstanced(instanceCount * 2);
mesh.setVertexData(instanceBuffer, baseInstance * 2);
}

View File

@ -16,27 +16,37 @@
void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) {
GrGPArgs gpArgs;
this->onEmitCode(args, &gpArgs);
SkASSERT(kFloat2_GrSLType == gpArgs.fPositionVar.getType() ||
kFloat3_GrSLType == gpArgs.fPositionVar.getType());
GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
if (!args.fGP.willUseGeoShader()) {
// Emit the vertex position to the hardware in the normalized window coordinates it expects.
SkASSERT(kFloat2_GrSLType == gpArgs.fPositionVar.getType() ||
kFloat3_GrSLType == gpArgs.fPositionVar.getType());
vBuilder->emitNormalizedSkPosition(gpArgs.fPositionVar.c_str(), args.fRTAdjustName,
gpArgs.fPositionVar.getType());
if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
args.fVaryingHandler->setNoPerspective();
}
} else {
// Since we have a geometry shader, leave the vertex position in Skia device space for now.
// The geometry Shader will operate in device space, and then convert the final positions to
// normalized hardware window coordinates under the hood, once everything else has finished.
// The subclass must call setNoPerspective on the varying handler, if applicable.
vBuilder->codeAppendf("sk_Position = float4(%s", gpArgs.fPositionVar.c_str());
if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
vBuilder->codeAppend(", 0");
switch (gpArgs.fPositionVar.getType()) {
case kFloat_GrSLType:
vBuilder->codeAppend(", 0"); // fallthru.
case kFloat2_GrSLType:
vBuilder->codeAppend(", 0"); // fallthru.
case kFloat3_GrSLType:
vBuilder->codeAppend(", 1"); // fallthru.
case kFloat4_GrSLType:
vBuilder->codeAppend(");");
break;
default:
SK_ABORT("Invalid position var type");
break;
}
vBuilder->codeAppend(", 1);");
}
if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
args.fVaryingHandler->setNoPerspective();
}
}