| 1 | /* | 
|---|
| 2 | * Copyright 2013 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 GrPrimitiveProcessor_DEFINED | 
|---|
| 9 | #define GrPrimitiveProcessor_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "src/gpu/GrColor.h" | 
|---|
| 12 | #include "src/gpu/GrNonAtomicRef.h" | 
|---|
| 13 | #include "src/gpu/GrProcessor.h" | 
|---|
| 14 | #include "src/gpu/GrShaderVar.h" | 
|---|
| 15 | #include "src/gpu/GrSwizzle.h" | 
|---|
| 16 |  | 
|---|
| 17 | class GrCoordTransform; | 
|---|
| 18 |  | 
|---|
| 19 | /* | 
|---|
| 20 | * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape | 
|---|
| 21 | * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is | 
|---|
| 22 | * responsible for providing a color and coverage input into the Ganesh rendering pipeline.  Through | 
|---|
| 23 | * optimization, Ganesh may decide a different color, no color, and / or no coverage are required | 
|---|
| 24 | * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this | 
|---|
| 25 | * functionality. | 
|---|
| 26 | * | 
|---|
| 27 | * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the | 
|---|
| 28 | * GrPrimitiveProcessor. These loops run on the CPU and to determine known properties of the final | 
|---|
| 29 | * color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve | 
|---|
| 30 | * correctness. The GrDrawOp seeds these loops with initial color and coverage, in its | 
|---|
| 31 | * getProcessorAnalysisInputs implementation. These seed values are processed by the | 
|---|
| 32 | * subsequent | 
|---|
| 33 | * stages of the rendering pipeline and the output is then fed back into the GrDrawOp in | 
|---|
| 34 | * the applyPipelineOptimizations call, where the op can use the information to inform decisions | 
|---|
| 35 | * about GrPrimitiveProcessor creation. | 
|---|
| 36 | */ | 
|---|
| 37 |  | 
|---|
| 38 | class GrGLSLPrimitiveProcessor; | 
|---|
| 39 |  | 
|---|
| 40 | /** | 
|---|
| 41 | * GrPrimitiveProcessor defines an interface which all subclasses must implement.  All | 
|---|
| 42 | * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage | 
|---|
| 43 | * pipelines, and they must provide some notion of equality | 
|---|
| 44 | * | 
|---|
| 45 | * TODO: This class does not really need to be ref counted. Instances should be allocated using | 
|---|
| 46 | * GrOpFlushState's arena and destroyed when the arena is torn down. | 
|---|
| 47 | */ | 
|---|
| 48 | class GrPrimitiveProcessor : public GrProcessor, public GrNonAtomicRef<GrPrimitiveProcessor> { | 
|---|
| 49 | public: | 
|---|
| 50 | class TextureSampler; | 
|---|
| 51 |  | 
|---|
| 52 | /** Describes a vertex or instance attribute. */ | 
|---|
| 53 | class Attribute { | 
|---|
| 54 | public: | 
|---|
| 55 | constexpr Attribute() = default; | 
|---|
| 56 | constexpr Attribute(const char* name, | 
|---|
| 57 | GrVertexAttribType cpuType, | 
|---|
| 58 | GrSLType gpuType) | 
|---|
| 59 | : fName(name), fCPUType(cpuType), fGPUType(gpuType) {} | 
|---|
| 60 | constexpr Attribute(const Attribute&) = default; | 
|---|
| 61 |  | 
|---|
| 62 | Attribute& operator=(const Attribute&) = default; | 
|---|
| 63 |  | 
|---|
| 64 | constexpr bool isInitialized() const { return SkToBool(fName); } | 
|---|
| 65 |  | 
|---|
| 66 | constexpr const char* name() const { return fName; } | 
|---|
| 67 | constexpr GrVertexAttribType cpuType() const { return fCPUType; } | 
|---|
| 68 | constexpr GrSLType           gpuType() const { return fGPUType; } | 
|---|
| 69 |  | 
|---|
| 70 | inline constexpr size_t size() const; | 
|---|
| 71 | constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); } | 
|---|
| 72 |  | 
|---|
| 73 | GrShaderVar asShaderVar() const { | 
|---|
| 74 | return {fName, fGPUType, GrShaderVar::TypeModifier::In}; | 
|---|
| 75 | } | 
|---|
| 76 |  | 
|---|
| 77 | private: | 
|---|
| 78 | const char* fName = nullptr; | 
|---|
| 79 | GrVertexAttribType fCPUType = kFloat_GrVertexAttribType; | 
|---|
| 80 | GrSLType fGPUType = kFloat_GrSLType; | 
|---|
| 81 | }; | 
|---|
| 82 |  | 
|---|
| 83 | class Iter { | 
|---|
| 84 | public: | 
|---|
| 85 | Iter() : fCurr(nullptr), fRemaining(0) {} | 
|---|
| 86 | Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {} | 
|---|
| 87 | Iter& operator= (const Iter& iter) { | 
|---|
| 88 | fCurr = iter.fCurr; | 
|---|
| 89 | fRemaining = iter.fRemaining; | 
|---|
| 90 | return *this; | 
|---|
| 91 | } | 
|---|
| 92 | Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) { | 
|---|
| 93 | this->skipUninitialized(); | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | bool operator!=(const Iter& that) const { return fCurr != that.fCurr; } | 
|---|
| 97 | const Attribute& operator*() const { return *fCurr; } | 
|---|
| 98 | void operator++() { | 
|---|
| 99 | if (fRemaining) { | 
|---|
| 100 | fRemaining--; | 
|---|
| 101 | fCurr++; | 
|---|
| 102 | this->skipUninitialized(); | 
|---|
| 103 | } | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | private: | 
|---|
| 107 | void skipUninitialized() { | 
|---|
| 108 | if (!fRemaining) { | 
|---|
| 109 | fCurr = nullptr; | 
|---|
| 110 | } else { | 
|---|
| 111 | while (!fCurr->isInitialized()) { | 
|---|
| 112 | ++fCurr; | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 | const Attribute* fCurr; | 
|---|
| 118 | int fRemaining; | 
|---|
| 119 | }; | 
|---|
| 120 |  | 
|---|
| 121 | class AttributeSet { | 
|---|
| 122 | public: | 
|---|
| 123 | Iter begin() const { return Iter(fAttributes, fCount); } | 
|---|
| 124 | Iter end() const { return Iter(); } | 
|---|
| 125 |  | 
|---|
| 126 | private: | 
|---|
| 127 | friend class GrPrimitiveProcessor; | 
|---|
| 128 |  | 
|---|
| 129 | void init(const Attribute* attrs, int count) { | 
|---|
| 130 | fAttributes = attrs; | 
|---|
| 131 | fRawCount = count; | 
|---|
| 132 | fCount = 0; | 
|---|
| 133 | fStride = 0; | 
|---|
| 134 | for (int i = 0; i < count; ++i) { | 
|---|
| 135 | if (attrs[i].isInitialized()) { | 
|---|
| 136 | fCount++; | 
|---|
| 137 | fStride += attrs[i].sizeAlign4(); | 
|---|
| 138 | } | 
|---|
| 139 | } | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | const Attribute* fAttributes = nullptr; | 
|---|
| 143 | int              fRawCount = 0; | 
|---|
| 144 | int              fCount = 0; | 
|---|
| 145 | size_t           fStride = 0; | 
|---|
| 146 | }; | 
|---|
| 147 |  | 
|---|
| 148 | GrPrimitiveProcessor(ClassID); | 
|---|
| 149 |  | 
|---|
| 150 | int numTextureSamplers() const { return fTextureSamplerCnt; } | 
|---|
| 151 | const TextureSampler& textureSampler(int index) const; | 
|---|
| 152 | int numVertexAttributes() const { return fVertexAttributes.fCount; } | 
|---|
| 153 | const AttributeSet& vertexAttributes() const { return fVertexAttributes; } | 
|---|
| 154 | int numInstanceAttributes() const { return fInstanceAttributes.fCount; } | 
|---|
| 155 | const AttributeSet& instanceAttributes() const { return fInstanceAttributes; } | 
|---|
| 156 |  | 
|---|
| 157 | bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); } | 
|---|
| 158 | bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); } | 
|---|
| 159 |  | 
|---|
| 160 | /** | 
|---|
| 161 | * A common practice is to populate the the vertex/instance's memory using an implicit array of | 
|---|
| 162 | * structs. In this case, it is best to assert that: | 
|---|
| 163 | *     stride == sizeof(struct) | 
|---|
| 164 | */ | 
|---|
| 165 | size_t vertexStride() const { return fVertexAttributes.fStride; } | 
|---|
| 166 | size_t instanceStride() const { return fInstanceAttributes.fStride; } | 
|---|
| 167 |  | 
|---|
| 168 | bool willUseTessellationShaders() const { | 
|---|
| 169 | return fShaders & (kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag); | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | bool willUseGeoShader() const { | 
|---|
| 173 | return fShaders & kGeometry_GrShaderFlag; | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | /** | 
|---|
| 177 | * Computes a key for the transforms owned by an FP based on the shader code that will be | 
|---|
| 178 | * emitted by the primitive processor to implement them. | 
|---|
| 179 | */ | 
|---|
| 180 | uint32_t computeCoordTransformsKey(const GrFragmentProcessor& fp) const; | 
|---|
| 181 |  | 
|---|
| 182 | /** | 
|---|
| 183 | * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry | 
|---|
| 184 | * processor's GL backend implementation. | 
|---|
| 185 | * | 
|---|
| 186 | * TODO: A better name for this function  would be "compute" instead of "get". | 
|---|
| 187 | */ | 
|---|
| 188 | virtual void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; | 
|---|
| 189 |  | 
|---|
| 190 |  | 
|---|
| 191 | void getAttributeKey(GrProcessorKeyBuilder* b) const { | 
|---|
| 192 | // Ensure that our CPU and GPU type fields fit together in a 32-bit value, and we never | 
|---|
| 193 | // collide with the "uninitialized" value. | 
|---|
| 194 | static_assert(kGrVertexAttribTypeCount < (1 << 8), ""); | 
|---|
| 195 | static_assert(kGrSLTypeCount           < (1 << 8), ""); | 
|---|
| 196 |  | 
|---|
| 197 | auto add_attributes = [=](const Attribute* attrs, int attrCount) { | 
|---|
| 198 | for (int i = 0; i < attrCount; ++i) { | 
|---|
| 199 | b->add32(attrs[i].isInitialized() ? (attrs[i].cpuType() << 16) | attrs[i].gpuType() | 
|---|
| 200 | : ~0); | 
|---|
| 201 | } | 
|---|
| 202 | }; | 
|---|
| 203 | add_attributes(fVertexAttributes.fAttributes, fVertexAttributes.fRawCount); | 
|---|
| 204 | add_attributes(fInstanceAttributes.fAttributes, fInstanceAttributes.fRawCount); | 
|---|
| 205 | } | 
|---|
| 206 |  | 
|---|
| 207 | /** Returns a new instance of the appropriate *GL* implementation class | 
|---|
| 208 | for the given GrProcessor; caller is responsible for deleting | 
|---|
| 209 | the object. */ | 
|---|
| 210 | virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0; | 
|---|
| 211 |  | 
|---|
| 212 | virtual bool isPathRendering() const { return false; } | 
|---|
| 213 |  | 
|---|
| 214 | // We use these methods as a temporary back door to inject OpenGL tessellation code. Once | 
|---|
| 215 | // tessellation is supported by SkSL we can remove these. | 
|---|
| 216 | virtual SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls, | 
|---|
| 217 | const GrShaderCaps&) const { | 
|---|
| 218 | SK_ABORT( "Not implemented."); | 
|---|
| 219 | } | 
|---|
| 220 | virtual SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, | 
|---|
| 221 | const GrShaderCaps&) const { | 
|---|
| 222 | SK_ABORT( "Not implemented."); | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 | protected: | 
|---|
| 226 | void setVertexAttributes(const Attribute* attrs, int attrCount) { | 
|---|
| 227 | fVertexAttributes.init(attrs, attrCount); | 
|---|
| 228 | } | 
|---|
| 229 | void setInstanceAttributes(const Attribute* attrs, int attrCount) { | 
|---|
| 230 | SkASSERT(attrCount >= 0); | 
|---|
| 231 | fInstanceAttributes.init(attrs, attrCount); | 
|---|
| 232 | } | 
|---|
| 233 | void setWillUseTessellationShaders() { | 
|---|
| 234 | fShaders |= kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag; | 
|---|
| 235 | } | 
|---|
| 236 | void setWillUseGeoShader() { fShaders |= kGeometry_GrShaderFlag; } | 
|---|
| 237 | void setTextureSamplerCnt(int cnt) { | 
|---|
| 238 | SkASSERT(cnt >= 0); | 
|---|
| 239 | fTextureSamplerCnt = cnt; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | /** | 
|---|
| 243 | * Helper for implementing onTextureSampler(). E.g.: | 
|---|
| 244 | * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler); | 
|---|
| 245 | */ | 
|---|
| 246 | template <typename... Args> | 
|---|
| 247 | static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0, | 
|---|
| 248 | const Args&... samps) { | 
|---|
| 249 | return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...); | 
|---|
| 250 | } | 
|---|
| 251 | inline static const TextureSampler& IthTextureSampler(int i); | 
|---|
| 252 |  | 
|---|
| 253 | private: | 
|---|
| 254 | virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); } | 
|---|
| 255 |  | 
|---|
| 256 | GrShaderFlags fShaders = kVertex_GrShaderFlag | kFragment_GrShaderFlag; | 
|---|
| 257 |  | 
|---|
| 258 | AttributeSet fVertexAttributes; | 
|---|
| 259 | AttributeSet fInstanceAttributes; | 
|---|
| 260 |  | 
|---|
| 261 | int fTextureSamplerCnt = 0; | 
|---|
| 262 | typedef GrProcessor INHERITED; | 
|---|
| 263 | }; | 
|---|
| 264 |  | 
|---|
| 265 | ////////////////////////////////////////////////////////////////////////////// | 
|---|
| 266 |  | 
|---|
| 267 | /** | 
|---|
| 268 | * Used to capture the properties of the GrTextureProxies required/expected by a primitiveProcessor | 
|---|
| 269 | * along with an associated GrSamplerState. The actual proxies used are stored in either the | 
|---|
| 270 | * fixed or dynamic state arrays. TextureSamplers don't perform any coord manipulation to account | 
|---|
| 271 | * for texture origin. | 
|---|
| 272 | */ | 
|---|
| 273 | class GrPrimitiveProcessor::TextureSampler { | 
|---|
| 274 | public: | 
|---|
| 275 | TextureSampler() = default; | 
|---|
| 276 |  | 
|---|
| 277 | TextureSampler(GrSamplerState, const GrBackendFormat&, const GrSwizzle&); | 
|---|
| 278 |  | 
|---|
| 279 | TextureSampler(const TextureSampler&) = delete; | 
|---|
| 280 | TextureSampler& operator=(const TextureSampler&) = delete; | 
|---|
| 281 |  | 
|---|
| 282 | void reset(GrSamplerState, const GrBackendFormat&, const GrSwizzle&); | 
|---|
| 283 |  | 
|---|
| 284 | const GrBackendFormat& backendFormat() const { return fBackendFormat; } | 
|---|
| 285 | GrTextureType textureType() const { return fBackendFormat.textureType(); } | 
|---|
| 286 |  | 
|---|
| 287 | GrSamplerState samplerState() const { return fSamplerState; } | 
|---|
| 288 | const GrSwizzle& swizzle() const { return fSwizzle; } | 
|---|
| 289 |  | 
|---|
| 290 | bool isInitialized() const { return fIsInitialized; } | 
|---|
| 291 |  | 
|---|
| 292 | private: | 
|---|
| 293 | GrSamplerState  fSamplerState; | 
|---|
| 294 | GrBackendFormat fBackendFormat; | 
|---|
| 295 | GrSwizzle       fSwizzle; | 
|---|
| 296 | bool            fIsInitialized = false; | 
|---|
| 297 | }; | 
|---|
| 298 |  | 
|---|
| 299 | const GrPrimitiveProcessor::TextureSampler& GrPrimitiveProcessor::IthTextureSampler(int i) { | 
|---|
| 300 | SK_ABORT( "Illegal texture sampler index"); | 
|---|
| 301 | static const TextureSampler kBogus; | 
|---|
| 302 | return kBogus; | 
|---|
| 303 | } | 
|---|
| 304 |  | 
|---|
| 305 | ////////////////////////////////////////////////////////////////////////////// | 
|---|
| 306 |  | 
|---|
| 307 | /** | 
|---|
| 308 | * Returns the size of the attrib type in bytes. | 
|---|
| 309 | * This was moved from include/private/GrTypesPriv.h in service of Skia dependents that build | 
|---|
| 310 | * with C++11. | 
|---|
| 311 | */ | 
|---|
| 312 | static constexpr inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) { | 
|---|
| 313 | switch (type) { | 
|---|
| 314 | case kFloat_GrVertexAttribType: | 
|---|
| 315 | return sizeof(float); | 
|---|
| 316 | case kFloat2_GrVertexAttribType: | 
|---|
| 317 | return 2 * sizeof(float); | 
|---|
| 318 | case kFloat3_GrVertexAttribType: | 
|---|
| 319 | return 3 * sizeof(float); | 
|---|
| 320 | case kFloat4_GrVertexAttribType: | 
|---|
| 321 | return 4 * sizeof(float); | 
|---|
| 322 | case kHalf_GrVertexAttribType: | 
|---|
| 323 | return sizeof(uint16_t); | 
|---|
| 324 | case kHalf2_GrVertexAttribType: | 
|---|
| 325 | return 2 * sizeof(uint16_t); | 
|---|
| 326 | case kHalf4_GrVertexAttribType: | 
|---|
| 327 | return 4 * sizeof(uint16_t); | 
|---|
| 328 | case kInt2_GrVertexAttribType: | 
|---|
| 329 | return 2 * sizeof(int32_t); | 
|---|
| 330 | case kInt3_GrVertexAttribType: | 
|---|
| 331 | return 3 * sizeof(int32_t); | 
|---|
| 332 | case kInt4_GrVertexAttribType: | 
|---|
| 333 | return 4 * sizeof(int32_t); | 
|---|
| 334 | case kByte_GrVertexAttribType: | 
|---|
| 335 | return 1 * sizeof(char); | 
|---|
| 336 | case kByte2_GrVertexAttribType: | 
|---|
| 337 | return 2 * sizeof(char); | 
|---|
| 338 | case kByte4_GrVertexAttribType: | 
|---|
| 339 | return 4 * sizeof(char); | 
|---|
| 340 | case kUByte_GrVertexAttribType: | 
|---|
| 341 | return 1 * sizeof(char); | 
|---|
| 342 | case kUByte2_GrVertexAttribType: | 
|---|
| 343 | return 2 * sizeof(char); | 
|---|
| 344 | case kUByte4_GrVertexAttribType: | 
|---|
| 345 | return 4 * sizeof(char); | 
|---|
| 346 | case kUByte_norm_GrVertexAttribType: | 
|---|
| 347 | return 1 * sizeof(char); | 
|---|
| 348 | case kUByte4_norm_GrVertexAttribType: | 
|---|
| 349 | return 4 * sizeof(char); | 
|---|
| 350 | case kShort2_GrVertexAttribType: | 
|---|
| 351 | return 2 * sizeof(int16_t); | 
|---|
| 352 | case kShort4_GrVertexAttribType: | 
|---|
| 353 | return 4 * sizeof(int16_t); | 
|---|
| 354 | case kUShort2_GrVertexAttribType: // fall through | 
|---|
| 355 | case kUShort2_norm_GrVertexAttribType: | 
|---|
| 356 | return 2 * sizeof(uint16_t); | 
|---|
| 357 | case kInt_GrVertexAttribType: | 
|---|
| 358 | return sizeof(int32_t); | 
|---|
| 359 | case kUint_GrVertexAttribType: | 
|---|
| 360 | return sizeof(uint32_t); | 
|---|
| 361 | case kUShort_norm_GrVertexAttribType: | 
|---|
| 362 | return sizeof(uint16_t); | 
|---|
| 363 | case kUShort4_norm_GrVertexAttribType: | 
|---|
| 364 | return 4 * sizeof(uint16_t); | 
|---|
| 365 | } | 
|---|
| 366 | // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is | 
|---|
| 367 | // unreachable and don't complain. | 
|---|
| 368 | #if defined(__clang__) || !defined(__GNUC__) | 
|---|
| 369 | SK_ABORT( "Unsupported type conversion"); | 
|---|
| 370 | #endif | 
|---|
| 371 | return 0; | 
|---|
| 372 | } | 
|---|
| 373 |  | 
|---|
| 374 | constexpr size_t GrPrimitiveProcessor::Attribute::size() const { | 
|---|
| 375 | return GrVertexAttribTypeSize(fCPUType); | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | #endif | 
|---|
| 379 |  | 
|---|