/* * 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 SkUniformData_DEFINED #define SkUniformData_DEFINED #include "include/core/SkRefCnt.h" #include "include/core/SkSpan.h" #include "src/core/SkUniform.h" #include /* * TODO: Here is the plan of record for SkUniformData * allocate them (and their ancillary data (offsets & data)) in an arena - and rm SkRefCnt * remove the offsets - these should be recomputable as/if needed * allow a scratch buffer to be used to collect the uniform data when processing a PaintParams * - this can be reset for each draw and be copied into a cache if it needs to be preserved * if possible, clear out the cache (and delete the arena) once the DrawPass is created/the * uniforms are copied into a buffer * - this will mean we'll get w/in DrawPass reuse but not cross-DrawPass reuse * - we could also explore getting w/in a Recording (i.e. cross-DrawPass) and w/in a * Recorder reuse (i.e., cross-Recordings, but single-threaded) * have the SkUniformData's data layout match what is required by the DrawList so we can just * copy it into the buffer */ class SkUniformData : public SkRefCnt { public: // TODO: should we require a name (e.g., "gradient_uniforms") for each uniform block so // we can better name the Metal FS uniform struct? static sk_sp Make(SkSpan, size_t dataSize); ~SkUniformData() override { // TODO: fOffsets and fData should just be allocated right after UniformData in an arena delete [] fOffsets; delete [] fData; } int count() const { return static_cast(fUniforms.size()); } SkSpan uniforms() const { return fUniforms; } uint32_t* offsets() { return fOffsets; } const uint32_t* offsets() const { return fOffsets; } uint32_t offset(int index) { SkASSERT(index >= 0 && static_cast(index) < fUniforms.size()); return fOffsets[index]; } char* data() { return fData; } const char* data() const { return fData; } size_t dataSize() const { return fDataSize; } bool operator==(const SkUniformData&) const; bool operator!=(const SkUniformData& other) const { return !(*this == other); } private: SkUniformData(SkSpan uniforms, uint32_t* offsets, char* data, size_t dataSize) : fUniforms(uniforms) , fOffsets(offsets) , fData(data) , fDataSize(dataSize) { } SkSpan fUniforms; uint32_t* fOffsets; // offset of each uniform in 'fData' char* fData; const size_t fDataSize; }; class SkUniformBlock { public: SkUniformBlock() = default; SkUniformBlock(sk_sp initial) { fUniformData.push_back(std::move(initial)); } void add(sk_sp); bool empty() const { return fUniformData.empty(); } size_t totalSize() const; // TODO: cache this? int count() const; // TODO: cache this? bool operator==(const SkUniformBlock&) const; bool operator!=(const SkUniformBlock& other) const { return !(*this == other); } size_t hash() const; using container = std::vector>; using iterator = container::iterator; using const_iterator = container::const_iterator; inline iterator begin() noexcept { return fUniformData.begin(); } inline const_iterator cbegin() const noexcept { return fUniformData.cbegin(); } inline iterator end() noexcept { return fUniformData.end(); } inline const_iterator cend() const noexcept { return fUniformData.cend(); } private: // TODO: SkUniformData should be held uniquely std::vector> fUniformData; }; #endif // SkUniformData_DEFINED