/* * Copyright 2022 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_graphite_PipelineData_DEFINED #define skgpu_graphite_PipelineData_DEFINED #include #include "include/core/SkM44.h" #include "include/core/SkPoint.h" #include "include/core/SkRefCnt.h" #include "include/core/SkSamplingOptions.h" #include "include/core/SkSpan.h" #include "include/core/SkTileMode.h" #include "include/private/SkColorData.h" #include "src/core/SkEnumBitMask.h" #include "src/gpu/graphite/DrawTypes.h" #include "src/gpu/graphite/TextureProxy.h" #include "src/gpu/graphite/UniformManager.h" class SkArenaAlloc; namespace skgpu::graphite { enum class SnippetRequirementFlags : uint32_t; class Uniform; class UniformDataBlock { public: static UniformDataBlock* Make(const UniformDataBlock&, SkArenaAlloc*); UniformDataBlock(SkSpan data) : fData(data) {} UniformDataBlock() = default; const char* data() const { return fData.data(); } size_t size() const { return fData.size(); } uint32_t hash() const; bool operator==(const UniformDataBlock& that) const { return fData.size() == that.fData.size() && !memcmp(fData.data(), that.fData.data(), fData.size()); } bool operator!=(const UniformDataBlock& that) const { return !(*this == that); } private: SkSpan fData; }; class TextureDataBlock { public: using SampledTexture = std::pair, SamplerDesc>; static TextureDataBlock* Make(const TextureDataBlock&, SkArenaAlloc*); TextureDataBlock() = default; bool empty() const { return fTextureData.empty(); } int numTextures() const { return SkTo(fTextureData.size()); } const SampledTexture& texture(int index) const { return fTextureData[index]; } bool operator==(const TextureDataBlock&) const; bool operator!=(const TextureDataBlock& other) const { return !(*this == other); } uint32_t hash() const; void add(const SkSamplingOptions& sampling, const SkTileMode tileModes[2], sk_sp proxy) { fTextureData.push_back({std::move(proxy), {sampling, {tileModes[0], tileModes[1]}}}); } void reset() { fTextureData.clear(); } private: // TODO: Move this into a SkSpan that's managed by the gatherer or copied into the arena. std::vector fTextureData; }; // The PipelineDataGatherer is just used to collect information for a given PaintParams object. // The UniformData is added to a cache and uniquified. Only that unique ID is passed around. // The TextureData is also added to a cache and uniquified. Only that ID is passed around. // TODO: The current plan for fixing uniform padding is for the PipelineDataGatherer to hold a // persistent uniformManager. A stretch goal for this system would be for this combination // to accumulate all the uniforms and then rearrange them to minimize padding. This would, // obviously, vastly complicate uniform accumulation. class PipelineDataGatherer { public: PipelineDataGatherer(Layout layout); void resetWithNewLayout(Layout layout); // Check that the gatherer has been reset to its initial state prior to collecting new data. SkDEBUGCODE(void checkReset();) void add(const SkSamplingOptions& sampling, const SkTileMode tileModes[2], sk_sp proxy) { fTextureDataBlock.add(sampling, tileModes, std::move(proxy)); } bool hasTextures() const { return !fTextureDataBlock.empty(); } void addFlags(SkEnumBitMask flags); bool needsLocalCoords() const; const TextureDataBlock& textureDataBlock() { return fTextureDataBlock; } void write(const SkM44& mat) { fUniformManager.write(mat); } void write(const SkPMColor4f& premulColor) { fUniformManager.write(premulColor); } void write(const SkRect& rect) { fUniformManager.write(rect); } void write(const SkV2& v) { fUniformManager.write(v); } void write(const SkV4& v) { fUniformManager.write(v); } void write(const SkPoint& point) { fUniformManager.write(point); } void write(float f) { fUniformManager.write(f); } void write(int i) { fUniformManager.write(i); } void write(SkSLType t, const void* data) { fUniformManager.write(t, data); } void write(const Uniform& u, const uint8_t* data) { fUniformManager.write(u, data); } void writeArray(SkSpan colors) { fUniformManager.writeArray(colors); } void writeArray(SkSpan colors) { fUniformManager.writeArray(colors); } void writeArray(SkSpan floats) { fUniformManager.writeArray(floats); } void writeHalf(const SkMatrix& mat) { fUniformManager.writeHalf(mat); } void writeHalfArray(SkSpan floats) { fUniformManager.writeHalfArray(floats); } bool hasUniforms() const { return fUniformManager.size(); } // Returns the uniform data written so far. Will automatically pad the end of the data as needed // to the overall required alignment, and so should only be called when all writing is done. UniformDataBlock finishUniformDataBlock() { return fUniformManager.finishUniformDataBlock(); } private: #ifdef SK_DEBUG friend class UniformExpectationsValidator; void setExpectedUniforms(SkSpan expectedUniforms); void doneWithExpectedUniforms() { fUniformManager.doneWithExpectedUniforms(); } #endif // SK_DEBUG TextureDataBlock fTextureDataBlock; UniformManager fUniformManager; SkEnumBitMask fSnippetRequirementFlags; }; #ifdef SK_DEBUG class UniformExpectationsValidator { public: UniformExpectationsValidator(PipelineDataGatherer *gatherer, SkSpan expectedUniforms); ~UniformExpectationsValidator() { fGatherer->doneWithExpectedUniforms(); } private: PipelineDataGatherer *fGatherer; UniformExpectationsValidator(UniformExpectationsValidator &&) = delete; UniformExpectationsValidator(const UniformExpectationsValidator &) = delete; UniformExpectationsValidator &operator=(UniformExpectationsValidator &&) = delete; UniformExpectationsValidator &operator=(const UniformExpectationsValidator &) = delete; }; #endif // SK_DEBUG } // namespace skgpu::graphite #endif // skgpu_graphite_PipelineData_DEFINED