blob: e477d225ecc64bac2af4d68e0a3e65976c385fa5 [file] [log] [blame]
/*
* 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 <vector>
#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<const char> 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<const char> fData;
};
class TextureDataBlock {
public:
using SampledTexture = std::pair<sk_sp<TextureProxy>, SamplerDesc>;
static TextureDataBlock* Make(const TextureDataBlock&, SkArenaAlloc*);
TextureDataBlock() = default;
bool empty() const { return fTextureData.empty(); }
int numTextures() const { return SkTo<int>(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<TextureProxy> 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<SampledTexture> 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<TextureProxy> proxy) {
fTextureDataBlock.add(sampling, tileModes, std::move(proxy));
}
bool hasTextures() const { return !fTextureDataBlock.empty(); }
void addFlags(SkEnumBitMask<SnippetRequirementFlags> 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<const SkColor4f> colors) { fUniformManager.writeArray(colors); }
void writeArray(SkSpan<const float> floats) { fUniformManager.writeArray(floats); }
void writeHalf(const SkMatrix& mat) { fUniformManager.writeHalf(mat); }
void writeHalfArray(SkSpan<const float> 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<const Uniform> expectedUniforms);
void doneWithExpectedUniforms() { fUniformManager.doneWithExpectedUniforms(); }
#endif // SK_DEBUG
TextureDataBlock fTextureDataBlock;
UniformManager fUniformManager;
SkEnumBitMask<SnippetRequirementFlags> fSnippetRequirementFlags;
};
#ifdef SK_DEBUG
class UniformExpectationsValidator {
public:
UniformExpectationsValidator(PipelineDataGatherer *gatherer,
SkSpan<const Uniform> 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