1 /* 2 * Copyright 2014 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 GrPathRange_DEFINED 9 #define GrPathRange_DEFINED 10 11 #include "GrGpuResource.h" 12 #include "SkPath.h" 13 #include "SkRefCnt.h" 14 #include "SkTArray.h" 15 16 class SkDescriptor; 17 18 /** 19 * Represents a contiguous range of GPU path objects. 20 * This object is immutable with the exception that individual paths may be 21 * initialized lazily. 22 */ 23 24 class GrPathRange : public GrGpuResource { 25 public: 26 27 28 enum PathIndexType { 29 kU8_PathIndexType, //!< uint8_t 30 kU16_PathIndexType, //!< uint16_t 31 kU32_PathIndexType, //!< uint32_t 32 33 kLast_PathIndexType = kU32_PathIndexType 34 }; 35 PathIndexSizeInBytes(PathIndexType type)36 static inline int PathIndexSizeInBytes(PathIndexType type) { 37 GR_STATIC_ASSERT(0 == kU8_PathIndexType); 38 GR_STATIC_ASSERT(1 == kU16_PathIndexType); 39 GR_STATIC_ASSERT(2 == kU32_PathIndexType); 40 GR_STATIC_ASSERT(kU32_PathIndexType == kLast_PathIndexType); 41 42 return 1 << type; 43 } 44 45 /** 46 * Class that generates the paths for a specific range. 47 */ 48 class PathGenerator : public SkRefCnt { 49 public: 50 virtual int getNumPaths() = 0; 51 virtual void generatePath(int index, SkPath* out) = 0; 52 #ifdef SK_DEBUG isEqualTo(const SkDescriptor &)53 virtual bool isEqualTo(const SkDescriptor&) const { return false; } 54 #endif ~PathGenerator()55 virtual ~PathGenerator() {} 56 }; 57 58 /** 59 * Initialize a lazy-loaded path range. This class will generate an SkPath and call 60 * onInitPath() for each path within the range before it is drawn for the first time. 61 */ 62 GrPathRange(GrGpu*, PathGenerator*); 63 64 /** 65 * Initialize an eager-loaded path range. The subclass is responsible for ensuring all 66 * the paths are initialized up front. 67 */ 68 GrPathRange(GrGpu*, int numPaths); 69 getNumPaths()70 int getNumPaths() const { return fNumPaths; } getPathGenerator()71 const PathGenerator* getPathGenerator() const { return fPathGenerator.get(); } 72 73 void loadPathsIfNeeded(const void* indices, PathIndexType, int count) const; 74 loadPathsIfNeeded(const IndexType * indices,int count)75 template<typename IndexType> void loadPathsIfNeeded(const IndexType* indices, int count) const { 76 if (!fPathGenerator) { 77 return; 78 } 79 80 bool didLoadPaths = false; 81 82 for (int i = 0; i < count; ++i) { 83 SkASSERT(indices[i] < static_cast<uint32_t>(fNumPaths)); 84 85 const int groupIndex = indices[i] / kPathsPerGroup; 86 const int groupByte = groupIndex / 8; 87 const uint8_t groupBit = 1 << (groupIndex % 8); 88 89 const bool hasPath = SkToBool(fGeneratedPaths[groupByte] & groupBit); 90 if (!hasPath) { 91 // We track which paths are loaded in groups of kPathsPerGroup. To 92 // mark a path as loaded we need to load the entire group. 93 const int groupFirstPath = groupIndex * kPathsPerGroup; 94 const int groupLastPath = SkTMin(groupFirstPath + kPathsPerGroup, fNumPaths) - 1; 95 96 SkPath path; 97 for (int pathIdx = groupFirstPath; pathIdx <= groupLastPath; ++pathIdx) { 98 fPathGenerator->generatePath(pathIdx, &path); 99 this->onInitPath(pathIdx, path); 100 } 101 102 fGeneratedPaths[groupByte] |= groupBit; 103 didLoadPaths = true; 104 } 105 } 106 107 if (didLoadPaths) { 108 this->didChangeGpuMemorySize(); 109 } 110 } 111 112 #ifdef SK_DEBUG 113 void assertPathsLoaded(const void* indices, PathIndexType, int count) const; 114 assertPathsLoaded(const IndexType * indices,int count)115 template<typename IndexType> void assertPathsLoaded(const IndexType* indices, int count) const { 116 if (!fPathGenerator) { 117 return; 118 } 119 120 for (int i = 0; i < count; ++i) { 121 SkASSERT(indices[i] < static_cast<uint32_t>(fNumPaths)); 122 123 const int groupIndex = indices[i] / kPathsPerGroup; 124 const int groupByte = groupIndex / 8; 125 const uint8_t groupBit = 1 << (groupIndex % 8); 126 127 SkASSERT(fGeneratedPaths[groupByte] & groupBit); 128 } 129 } 130 isEqualTo(const SkDescriptor & desc)131 virtual bool isEqualTo(const SkDescriptor& desc) const { 132 return nullptr != fPathGenerator.get() && fPathGenerator->isEqualTo(desc); 133 } 134 #endif 135 protected: 136 // Initialize a path in the range before drawing. This is only called when 137 // fPathGenerator is non-null. The child class need not call didChangeGpuMemorySize(), 138 // GrPathRange will take care of that after the call is complete. 139 virtual void onInitPath(int index, const SkPath&) const = 0; 140 141 private: 142 enum { 143 kPathsPerGroup = 16 // Paths get tracked in groups of 16 for lazy loading. 144 }; 145 146 mutable sk_sp<PathGenerator> fPathGenerator; 147 mutable SkTArray<uint8_t, true /*MEM_COPY*/> fGeneratedPaths; 148 const int fNumPaths; 149 150 typedef GrGpuResource INHERITED; 151 }; 152 153 #endif 154