1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifndef GrBatch_DEFINED 9#define GrBatch_DEFINED 10 11#include <new> 12#include "GrBatchTarget.h" 13#include "GrGeometryProcessor.h" 14#include "GrVertices.h" 15#include "SkRefCnt.h" 16#include "SkThread.h" 17#include "SkTypes.h" 18 19class GrGpu; 20class GrPipeline; 21 22struct GrInitInvariantOutput; 23 24/* 25 * GrBatch is the base class for all Ganesh deferred geometry generators. To facilitate 26 * reorderable batching, Ganesh does not generate geometry inline with draw calls. Instead, it 27 * captures the arguments to the draw and then generates the geometry on demand. This gives GrBatch 28 * subclasses complete freedom to decide how / what they can batch. 29 * 30 * Batches are created when GrContext processes a draw call. Batches of the same subclass may be 31 * merged using combineIfPossible. When two batches merge, one takes on the union of the data 32 * and the other is left empty. The merged batch becomes responsible for drawing the data from both 33 * the original batches. 34 * 35 * If there are any possible optimizations which might require knowing more about the full state of 36 * the draw, ie whether or not the GrBatch is allowed to tweak alpha for coverage, then this 37 * information will be communicated to the GrBatch prior to geometry generation. 38 */ 39 40class GrBatch : public SkRefCnt { 41public: 42 SK_DECLARE_INST_COUNT(GrBatch) 43 GrBatch() : fClassID(kIllegalBatchClassID), fNumberOfDraws(0) { SkDEBUGCODE(fUsed = false;) } 44 virtual ~GrBatch() {} 45 46 virtual const char* name() const = 0; 47 virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0; 48 virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0; 49 50 /* 51 * initBatchTracker is a hook for the some additional overrides / optimization possibilities 52 * from the GrXferProcessor. 53 */ 54 virtual void initBatchTracker(const GrPipelineInfo& init) = 0; 55 56 bool combineIfPossible(GrBatch* that) { 57 if (this->classID() != that->classID()) { 58 return false; 59 } 60 61 return this->onCombineIfPossible(that); 62 } 63 64 virtual bool onCombineIfPossible(GrBatch*) = 0; 65 66 virtual void generateGeometry(GrBatchTarget*, const GrPipeline*) = 0; 67 68 const SkRect& bounds() const { return fBounds; } 69 70 // TODO this goes away when batches are everywhere 71 void setNumberOfDraws(int numberOfDraws) { fNumberOfDraws = numberOfDraws; } 72 int numberOfDraws() const { return fNumberOfDraws; } 73 74 void* operator new(size_t size); 75 void operator delete(void* target); 76 77 void* operator new(size_t size, void* placement) { 78 return ::operator new(size, placement); 79 } 80 void operator delete(void* target, void* placement) { 81 ::operator delete(target, placement); 82 } 83 84 /** 85 * Helper for down-casting to a GrBatch subclass 86 */ 87 template <typename T> const T& cast() const { return *static_cast<const T*>(this); } 88 template <typename T> T* cast() { return static_cast<T*>(this); } 89 90 uint32_t classID() const { SkASSERT(kIllegalBatchClassID != fClassID); return fClassID; } 91 92 // TODO no GrPrimitiveProcessors yet read fragment position 93 bool willReadFragmentPosition() const { return false; } 94 95 SkDEBUGCODE(bool isUsed() const { return fUsed; }) 96 97protected: 98 template <typename PROC_SUBCLASS> void initClassID() { 99 static uint32_t kClassID = GenClassID(); 100 fClassID = kClassID; 101 } 102 103 uint32_t fClassID; 104 105 // NOTE, compute some bounds, even if extremely conservative. Do *NOT* setLargest on the bounds 106 // rect because we outset it for dst copy textures 107 void setBounds(const SkRect& newBounds) { fBounds = newBounds; } 108 109 void joinBounds(const SkRect& otherBounds) { 110 return fBounds.joinPossiblyEmptyRect(otherBounds); 111 } 112 113 /** Helper for rendering instances using an instanced index index buffer. This class creates the 114 space for the vertices and flushes the draws to the batch target.*/ 115 class InstancedHelper { 116 public: 117 InstancedHelper() {} 118 /** Returns the allocated storage for the vertices. The caller should populate the before 119 vertices before calling issueDraws(). */ 120 void* init(GrBatchTarget* batchTarget, GrPrimitiveType, size_t vertexStride, 121 const GrIndexBuffer*, int verticesPerInstance, int indicesPerInstance, 122 int instancesToDraw); 123 124 /** Call after init() to issue draws to the batch target.*/ 125 void issueDraw(GrBatchTarget* batchTarget) { 126 SkASSERT(fVertices.instanceCount()); 127 batchTarget->draw(fVertices); 128 } 129 private: 130 GrVertices fVertices; 131 }; 132 133 static const int kVerticesPerQuad = 4; 134 static const int kIndicesPerQuad = 6; 135 136 /** A specialization of InstanceHelper for quad rendering. */ 137 class QuadHelper : private InstancedHelper { 138 public: 139 QuadHelper() : INHERITED() {} 140 /** Finds the cached quad index buffer and reserves vertex space. Returns NULL on failure 141 and on sucess a pointer to the vertex data that the caller should populate before 142 calling issueDraws(). */ 143 void* init(GrBatchTarget* batchTarget, size_t vertexStride, int quadsToDraw); 144 145 using InstancedHelper::issueDraw; 146 147 private: 148 typedef InstancedHelper INHERITED; 149 }; 150 151 SkRect fBounds; 152 153private: 154 static uint32_t GenClassID() { 155 // fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The 156 // atomic inc returns the old value not the incremented value. So we add 157 // 1 to the returned value. 158 uint32_t id = static_cast<uint32_t>(sk_atomic_inc(&gCurrBatchClassID)) + 1; 159 if (!id) { 160 SkFAIL("This should never wrap as it should only be called once for each GrBatch " 161 "subclass."); 162 } 163 return id; 164 } 165 166 enum { 167 kIllegalBatchClassID = 0, 168 }; 169 static int32_t gCurrBatchClassID; 170 171 SkDEBUGCODE(bool fUsed;) 172 173 int fNumberOfDraws; 174 175 typedef SkRefCnt INHERITED; 176}; 177 178#endif 179