/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPrimitiveProcessor_DEFINED
#define GrPrimitiveProcessor_DEFINED
#include "GrColor.h"
#include "GrProcessor.h"
#include "GrShaderVar.h"
/*
* The GrPrimitiveProcessor represents some kind of geometric primitive. This includes the shape
* of the primitive and the inherent color of the primitive. The GrPrimitiveProcessor is
* responsible for providing a color and coverage input into the Ganesh rendering pipeline. Through
* optimization, Ganesh may decide a different color, no color, and / or no coverage are required
* from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this
* functionality.
*
* There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
* GrPrimitiveProcessor. These loops run on the CPU and to determine known properties of the final
* color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve
* correctness. The GrDrawOp seeds these loops with initial color and coverage, in its
* getProcessorAnalysisInputs implementation. These seed values are processed by the
* subsequent
* stages of the rendering pipeline and the output is then fed back into the GrDrawOp in
* the applyPipelineOptimizations call, where the op can use the information to inform decisions
* about GrPrimitiveProcessor creation.
*/
class GrGLSLPrimitiveProcessor;
/*
* GrPrimitiveProcessor defines an interface which all subclasses must implement. All
* GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
* pipelines, and they must provide some notion of equality
*/
class GrPrimitiveProcessor : public GrResourceIOProcessor, public GrProgramElement {
public:
struct Attribute {
enum class InputRate : bool {
kPerVertex,
kPerInstance
};
GrShaderVar asShaderVar() const {
return GrShaderVar(fName, GrVertexAttribTypeToSLType(fType),
GrShaderVar::kIn_TypeModifier);
}
bool isInitialized() const { return SkToBool(fName); }
Attribute() = default;
Attribute(const char* name, GrVertexAttribType type, int offset, InputRate rate)
: fName(name), fType(type), fOffsetInRecord(offset), fInputRate(rate) {}
const char* fName = nullptr;
GrVertexAttribType fType;
int fOffsetInRecord;
InputRate fInputRate;
};
GrPrimitiveProcessor(ClassID classID)
: GrResourceIOProcessor(classID) {}
int numAttribs() const { return fAttribs.count(); }
const Attribute& getAttrib(int index) const { return fAttribs[index]; }
bool hasVertexAttribs() const { return SkToBool(fVertexStride); }
bool hasInstanceAttribs() const { return SkToBool(fInstanceStride); }
/**
* These return the strides of the vertex and instance buffers. Attributes are expected to be
* laid out interleaved in their corresponding buffer (vertex or instance). fOffsetInRecord
* indicates an attribute's location in bytes relative to the first attribute. (These are padded
* to the nearest 4 bytes for performance reasons.)
*
* A common practice is to populate the buffer's memory using an implicit array of structs. In
* this case, it is best to assert:
*
* stride == sizeof(struct) and
* offsetof(struct, field[i]) == attrib[i].fOffsetInRecord
*
* NOTE: for instanced draws the vertex buffer has a single record that each instance reuses.
*/
int getVertexStride() const { return fVertexStride; }
int getInstanceStride() const { return fInstanceStride; }
// Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but
// we put these calls on the base class to prevent having to cast
virtual bool willUseGeoShader() const = 0;
bool willUsePrimitiveRestart() const { return fWillUsePrimitiveRestart; }
/**
* Computes a transformKey from an array of coord transforms. Will only look at the first
* <numCoords> transforms in the array.
*
* TODO: A better name for this function would be "compute" instead of "get".
*/
uint32_t getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords,
int numCoords) const;
/**
* Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
* processor's GL backend implementation.
*
* TODO: A better name for this function would be "compute" instead of "get".
*/
virtual void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
/** Returns a new instance of the appropriate *GL* implementation class
for the given GrProcessor; caller is responsible for deleting
the object. */
virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0;
virtual bool isPathRendering() const { return false; }
/**
* If non-null, overrides the dest color returned by GrGLSLFragmentShaderBuilder::dstColor().
*/
virtual const char* getDestColorOverride() const { return nullptr; }
virtual float getSampleShading() const {
return 0.0;
}
protected:
/**
* Subclasses call these from their constructor to register vertex and instance attributes.
*/
const Attribute& addVertexAttrib(const char* name, GrVertexAttribType type) {
fAttribs.push_back() = {name, type, fVertexStride, Attribute::InputRate::kPerVertex};
fVertexStride += static_cast<int>(SkAlign4(GrVertexAttribTypeSize(type)));
return fAttribs.back();
}
const Attribute& addInstanceAttrib(const char* name, GrVertexAttribType type) {
fAttribs.push_back() = {name, type, fInstanceStride, Attribute::InputRate::kPerInstance};
fInstanceStride += static_cast<int>(SkAlign4(GrVertexAttribTypeSize(type)));
return fAttribs.back();
}
void setWillUsePrimitiveRestart() { fWillUsePrimitiveRestart = true; }
private:
void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); }
void removeRefs() const override { GrResourceIOProcessor::removeRefs(); }
void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); }
void notifyRefCntIsZero() const final {}
virtual bool hasExplicitLocalCoords() const = 0;
SkSTArray<8, Attribute> fAttribs;
int fVertexStride = 0;
int fInstanceStride = 0;
bool fWillUsePrimitiveRestart = false;
typedef GrProcessor INHERITED;
};
#endif