/* * 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 repeating meshes using a patterned index buffer. This class creates the space for the vertices and flushes the draws to the GrMeshDrawOp::Target. */ class PatternHelper { public: PatternHelper(GrPrimitiveType primitiveType) : fMesh(primitiveType) {} /** Returns the allocated storage for the vertices. The caller should populate the vertices before calling recordDraws(). */ void* init(Target*, size_t vertexStride, const GrBuffer*, int verticesPerRepetition, int indicesPerRepetition, int repeatCount); /** 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 PatternHelper { public: QuadHelper() : INHERITED(GrPrimitiveType::kTriangles) {} /** 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 PatternHelper::recordDraw; private: typedef PatternHelper 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 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