blob: a4b172d3572151ac0223b0f3d40173ee7d37d28b [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMeshDrawOp_DEFINED
#define GrMeshDrawOp_DEFINED
#include "GrDrawOp.h"
#include "GrGeometryProcessor.h"
#include "GrMesh.h"
#include "GrPendingProgramElement.h"
#include "GrPipelineBuilder.h"
#include "SkTLList.h"
class GrCaps;
class GrOpFlushState;
/**
* Base class for mesh-drawing GrDrawOps.
*/
class GrMeshDrawOp : public GrDrawOp {
public:
class Target;
protected:
GrMeshDrawOp(uint32_t classID);
/** Helper for rendering instances using an instanced index buffer. This class creates the space
for the vertices and flushes the draws to the GrMeshDrawOp::Target. */
class InstancedHelper {
public:
InstancedHelper() {}
/** Returns the allocated storage for the vertices. The caller should populate the vertices
before calling recordDraws(). */
void* init(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
int verticesPerInstance, int indicesPerInstance, int instancesToDraw);
/** Call after init() to issue draws to the GrMeshDrawOp::Target.*/
void recordDraw(Target*, const GrGeometryProcessor*, const GrPipeline*);
private:
GrMesh fMesh;
};
static const int kVerticesPerQuad = 4;
static const int kIndicesPerQuad = 6;
/** A specialization of InstanceHelper for quad rendering. */
class QuadHelper : private InstancedHelper {
public:
QuadHelper() : INHERITED() {}
/** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure
and on success a pointer to the vertex data that the caller should populate before
calling recordDraws(). */
void* init(Target*, size_t vertexStride, int quadsToDraw);
using InstancedHelper::recordDraw;
private:
typedef InstancedHelper INHERITED;
};
private:
void onPrepare(GrOpFlushState* state) final;
void onExecute(GrOpFlushState* state) final;
virtual void onPrepareDraws(Target*) const = 0;
// A set of contiguous draws that share a draw token and primitive processor. The draws all use
// the op's pipeline. The meshes for the draw are stored in the fMeshes array and each
// Queued draw uses fMeshCnt meshes from the fMeshes array. The reason for coallescing meshes
// that share a primitive processor into a QueuedDraw is that it allows the Gpu object to setup
// the shared state once and then issue draws for each mesh.
struct QueuedDraw {
int fMeshCnt = 0;
GrPendingProgramElement<const GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
};
// All draws in all the GrMeshDrawOps have implicit tokens based on the order they are enqueued
// globally across all ops. This is the offset of the first entry in fQueuedDraws.
// fQueuedDraws[i]'s token is fBaseDrawToken + i.
GrDrawOpUploadToken fBaseDrawToken;
SkSTArray<4, GrMesh> fMeshes;
SkSTArray<4, QueuedDraw, true> fQueuedDraws;
typedef GrDrawOp INHERITED;
};
/**
* Many of our ops derive from this class which initializes a GrPipeline just before being recorded.
* We are migrating away from use of this class.
*/
class GrLegacyMeshDrawOp : public GrMeshDrawOp {
public:
/**
* Performs analysis of the fragment processors in GrProcessorSet and GrAppliedClip using the
* initial color and coverage from this op's geometry processor.
*/
GrProcessorSet::Analysis analyzeUpdateAndRecordProcessors(GrPipelineBuilder* pipelineBuilder,
const GrAppliedClip* appliedClip,
bool isMixedSamples,
const GrCaps& caps,
GrColor* overrideColor) const {
GrProcessorAnalysisColor inputColor;
GrProcessorAnalysisCoverage inputCoverage;
this->getProcessorAnalysisInputs(&inputColor, &inputCoverage);
return pipelineBuilder->finalizeProcessors(inputColor, inputCoverage, appliedClip,
isMixedSamples, caps, overrideColor);
}
void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis,
GrColor overrideColor) {
fPipeline.init(args);
this->applyPipelineOptimizations(PipelineOptimizations(analysis, overrideColor));
}
void addDependenciesTo(GrRenderTargetProxy* rtp) {
fPipeline.addDependenciesTo(rtp);
}
/**
* Mesh draw ops use a legacy system in GrRenderTargetContext where the pipeline is created when
* the op is recorded. These methods are unnecessary as this information is in the pipeline.
*/
FixedFunctionFlags fixedFunctionFlags() const override {
SkFAIL("This should never be called for legacy mesh draw ops.");
return FixedFunctionFlags::kNone;
}
bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override {
SkFAIL("Should never be called for legacy mesh draw ops.");
return false;
}
protected:
GrLegacyMeshDrawOp(uint32_t classID) : INHERITED(classID) {}
/**
* This is a legacy class only used by GrLegacyMeshDrawOp and will be removed. It presents some
* aspects of GrProcessorSet::Analysis to GrLegacyMeshDrawOp subclasses.
*/
class PipelineOptimizations {
public:
PipelineOptimizations(const GrProcessorSet::Analysis& analysis, GrColor overrideColor) {
fFlags = 0;
if (analysis.inputColorIsOverridden()) {
fFlags |= kUseOverrideColor_Flag;
fOverrideColor = overrideColor;
}
if (analysis.usesLocalCoords()) {
fFlags |= kReadsLocalCoords_Flag;
}
if (analysis.isCompatibleWithCoverageAsAlpha()) {
fFlags |= kCanTweakAlphaForCoverage_Flag;
}
}
/** Does the pipeline require access to (implicit or explicit) local coordinates? */
bool readsLocalCoords() const { return SkToBool(kReadsLocalCoords_Flag & fFlags); }
/** Does the pipeline allow the GrPrimitiveProcessor to combine color and coverage into one
color output ? */
bool canTweakAlphaForCoverage() const {
return SkToBool(kCanTweakAlphaForCoverage_Flag & fFlags);
}
/** Does the pipeline require the GrPrimitiveProcessor to specify a specific color (and if
so get the color)? */
bool getOverrideColorIfSet(GrColor* overrideColor) const {
if (SkToBool(kUseOverrideColor_Flag & fFlags)) {
if (overrideColor) {
*overrideColor = fOverrideColor;
}
return true;
}
return false;
}
private:
enum {
// If this is not set the primitive processor need not produce local coordinates
kReadsLocalCoords_Flag = 0x1,
// If this flag is set then the primitive processor may produce color*coverage as
// its color output (and not output a separate coverage).
kCanTweakAlphaForCoverage_Flag = 0x2,
// If this flag is set the GrPrimitiveProcessor must produce fOverrideColor as its
// output color. If not set fOverrideColor is to be ignored.
kUseOverrideColor_Flag = 0x4,
};
uint32_t fFlags;
GrColor fOverrideColor;
};
const GrPipeline* pipeline() const {
SkASSERT(fPipeline.isInitialized());
return &fPipeline;
}
private:
/**
* Provides information about the GrPrimitiveProccesor color and coverage outputs which become
* inputs to the first color and coverage fragment processors.
*/
virtual void getProcessorAnalysisInputs(GrProcessorAnalysisColor*,
GrProcessorAnalysisCoverage*) const = 0;
/**
* After processor analysis is complete this is called so that the op can use the analysis
* results when constructing its GrPrimitiveProcessor.
*/
virtual void applyPipelineOptimizations(const PipelineOptimizations&) = 0;
GrPipeline fPipeline;
typedef GrMeshDrawOp INHERITED;
};
#endif