1 /* 2 * Copyright 2022 Google LLC 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 skgpu_graphite_PipelineData_DEFINED 9 #define skgpu_graphite_PipelineData_DEFINED 10 11 #include <vector> 12 #include "include/core/SkM44.h" 13 #include "include/core/SkPoint.h" 14 #include "include/core/SkRefCnt.h" 15 #include "include/core/SkSamplingOptions.h" 16 #include "include/core/SkSpan.h" 17 #include "include/core/SkTileMode.h" 18 #include "include/private/SkColorData.h" 19 #include "src/base/SkEnumBitMask.h" 20 #include "src/gpu/graphite/Caps.h" 21 #include "src/gpu/graphite/DrawTypes.h" 22 #include "src/gpu/graphite/TextureProxy.h" 23 #include "src/gpu/graphite/UniformManager.h" 24 25 class SkArenaAlloc; 26 27 namespace skgpu::graphite { 28 29 class Uniform; 30 31 class UniformDataBlock { 32 public: 33 static UniformDataBlock* Make(const UniformDataBlock&, SkArenaAlloc*); 34 UniformDataBlock(SkSpan<const char> data)35 UniformDataBlock(SkSpan<const char> data) : fData(data) {} 36 UniformDataBlock() = default; 37 data()38 const char* data() const { return fData.data(); } size()39 size_t size() const { return fData.size(); } 40 41 uint32_t hash() const; 42 43 bool operator==(const UniformDataBlock& that) const { 44 return fData.size() == that.fData.size() && 45 !memcmp(fData.data(), that.fData.data(), fData.size()); 46 } 47 bool operator!=(const UniformDataBlock& that) const { return !(*this == that); } 48 49 private: 50 SkSpan<const char> fData; 51 }; 52 53 class TextureDataBlock { 54 public: 55 using SampledTexture = std::pair<sk_sp<TextureProxy>, SamplerDesc>; 56 57 static TextureDataBlock* Make(const TextureDataBlock&, SkArenaAlloc*); 58 TextureDataBlock() = default; 59 empty()60 bool empty() const { return fTextureData.empty(); } numTextures()61 int numTextures() const { return SkTo<int>(fTextureData.size()); } texture(int index)62 const SampledTexture& texture(int index) const { return fTextureData[index]; } 63 64 bool operator==(const TextureDataBlock&) const; 65 bool operator!=(const TextureDataBlock& other) const { return !(*this == other); } 66 uint32_t hash() const; 67 add(const Caps * caps,const SkSamplingOptions & sampling,const SkTileMode tileModes[2],sk_sp<TextureProxy> proxy)68 void add(const Caps* caps, 69 const SkSamplingOptions& sampling, 70 const SkTileMode tileModes[2], 71 sk_sp<TextureProxy> proxy) { 72 // Before relinquishing ownership of the proxy, query Caps to gather any relevant sampler 73 // conversion information for the SamplerDesc. 74 ImmutableSamplerInfo info = caps->getImmutableSamplerInfo(proxy); 75 fTextureData.push_back({std::move(proxy), SamplerDesc{sampling, tileModes, info}}); 76 } 77 reset()78 void reset() { 79 fTextureData.clear(); 80 } 81 82 private: 83 // TODO: Move this into a SkSpan that's managed by the gatherer or copied into the arena. 84 std::vector<SampledTexture> fTextureData; 85 }; 86 87 // The PipelineDataGatherer is just used to collect information for a given PaintParams object. 88 // The UniformData is added to a cache and uniquified. Only that unique ID is passed around. 89 // The TextureData is also added to a cache and uniquified. Only that ID is passed around. 90 91 // TODO: The current plan for fixing uniform padding is for the PipelineDataGatherer to hold a 92 // persistent uniformManager. A stretch goal for this system would be for this combination 93 // to accumulate all the uniforms and then rearrange them to minimize padding. This would, 94 // obviously, vastly complicate uniform accumulation. 95 class PipelineDataGatherer { 96 public: 97 PipelineDataGatherer(const Caps* caps, Layout layout); 98 99 void resetWithNewLayout(Layout layout); 100 101 // Check that the gatherer has been reset to its initial state prior to collecting new data. SkDEBUGCODE(void checkReset ();)102 SkDEBUGCODE(void checkReset();) 103 104 void add(const SkSamplingOptions& sampling, 105 const SkTileMode tileModes[2], 106 sk_sp<TextureProxy> proxy) { 107 fTextureDataBlock.add(fCaps, sampling, tileModes, std::move(proxy)); 108 } hasTextures()109 bool hasTextures() const { return !fTextureDataBlock.empty(); } 110 textureDataBlock()111 const TextureDataBlock& textureDataBlock() { return fTextureDataBlock; } 112 113 // Mimic the type-safe API available in UniformManager write(const T & t)114 template <typename T> void write(const T& t) { fUniformManager.write(t); } writeHalf(const T & t)115 template <typename T> void writeHalf(const T& t) { fUniformManager.writeHalf(t); } writeArray(SkSpan<const T> t)116 template <typename T> void writeArray(SkSpan<const T> t) { fUniformManager.writeArray(t); } writeHalfArray(SkSpan<const T> t)117 template <typename T> void writeHalfArray(SkSpan<const T> t) { 118 fUniformManager.writeHalfArray(t); 119 } 120 write(const Uniform & u,const void * data)121 void write(const Uniform& u, const void* data) { fUniformManager.write(u, data); } 122 writePaintColor(const SkPMColor4f & color)123 void writePaintColor(const SkPMColor4f& color) { fUniformManager.writePaintColor(color); } 124 hasUniforms()125 bool hasUniforms() const { return fUniformManager.size(); } 126 hasGradientBufferData()127 bool hasGradientBufferData() const { return !fGradientStorage.empty(); } 128 gradientBufferData()129 SkSpan<const float> gradientBufferData() const { return fGradientStorage; } 130 131 // Returns the uniform data written so far. Will automatically pad the end of the data as needed 132 // to the overall required alignment, and so should only be called when all writing is done. finishUniformDataBlock()133 UniformDataBlock finishUniformDataBlock() { return fUniformManager.finishUniformDataBlock(); } 134 135 // Allocates the data for the requested number of stops and returns the 136 // pointer and buffer index offset the data will begin at. allocateGradientData(int size)137 std::pair<float*, int> allocateGradientData(int size) { 138 int lastSize = fGradientStorage.size(); 139 fGradientStorage.resize(lastSize + size); 140 float* startPtr = fGradientStorage.begin() + lastSize; 141 142 return std::make_pair(startPtr, lastSize); 143 } 144 145 private: 146 #ifdef SK_DEBUG 147 friend class UniformExpectationsValidator; 148 149 void setExpectedUniforms(SkSpan<const Uniform> expectedUniforms); doneWithExpectedUniforms()150 void doneWithExpectedUniforms() { fUniformManager.doneWithExpectedUniforms(); } 151 #endif // SK_DEBUG 152 153 const Caps* const fCaps; 154 TextureDataBlock fTextureDataBlock; 155 UniformManager fUniformManager; 156 157 SkTDArray<float> fGradientStorage; 158 }; 159 160 #ifdef SK_DEBUG 161 class UniformExpectationsValidator { 162 public: 163 UniformExpectationsValidator(PipelineDataGatherer *gatherer, 164 SkSpan<const Uniform> expectedUniforms); 165 ~UniformExpectationsValidator()166 ~UniformExpectationsValidator() { 167 fGatherer->doneWithExpectedUniforms(); 168 } 169 170 private: 171 PipelineDataGatherer *fGatherer; 172 173 UniformExpectationsValidator(UniformExpectationsValidator &&) = delete; 174 UniformExpectationsValidator(const UniformExpectationsValidator &) = delete; 175 UniformExpectationsValidator &operator=(UniformExpectationsValidator &&) = delete; 176 UniformExpectationsValidator &operator=(const UniformExpectationsValidator &) = delete; 177 }; 178 #endif // SK_DEBUG 179 180 } // namespace skgpu::graphite 181 182 #endif // skgpu_graphite_PipelineData_DEFINED 183