blob: c16a5933e8773b3d12c13eadbe4d03e6ff42db81 [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 SkShaderCodeDictionary_DEFINED
#define SkShaderCodeDictionary_DEFINED
#include <array>
#include <unordered_map>
#include <string>
#include <vector>
#include "include/core/SkSpan.h"
#include "include/private/SkSpinlock.h"
#include "include/private/SkUniquePaintParamsID.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkPaintParamsKey.h"
#include "src/core/SkUniform.h"
class SkShaderInfo {
public:
struct SnippetEntry;
using GenerateGlueCodeForEntry = std::string (*)(const std::string& resultName,
int entryIndex, // for uniform name mangling
const SnippetEntry&,
const std::vector<std::string>& childNames,
int indent);
struct SnippetEntry {
SkSpan<const SkUniform> fUniforms;
const char* fStaticFunctionName;
const char* fStaticSkSL;
GenerateGlueCodeForEntry fGlueCodeGenerator;
int fNumChildren;
};
void add(const SnippetEntry& entry) {
fEntries.push_back(entry);
}
// TODO: writing to color should be a property of the SnippetEntries and accumulated as the
// entries are added. _Not_ set manually via 'setWritesColor'.
void setWritesColor() { fWritesColor = true; }
bool writesColor() const { return fWritesColor; }
#if SK_SUPPORT_GPU && defined(SK_GRAPHITE_ENABLED) && defined(SK_METAL)
std::string toSkSL() const;
#endif
private:
std::string emitGlueCodeForEntry(int* entryIndex, std::string* result, int indent) const;
std::vector<SnippetEntry> fEntries;
bool fWritesColor = false;
};
class SkShaderCodeDictionary {
public:
SkShaderCodeDictionary();
struct Entry {
public:
SkUniquePaintParamsID uniqueID() const {
SkASSERT(fUniqueID.isValid());
return fUniqueID;
}
const SkPaintParamsKey* paintParamsKey() const { return fKey.get(); }
private:
friend class SkShaderCodeDictionary;
Entry(std::unique_ptr<SkPaintParamsKey> key) : fKey(std::move(key)) {}
void setUniqueID(uint32_t newID) {
SkASSERT(!fUniqueID.isValid());
fUniqueID = SkUniquePaintParamsID(newID);
}
SkUniquePaintParamsID fUniqueID; // fixed-size (uint32_t) unique ID assigned to a key
std::unique_ptr<SkPaintParamsKey> fKey; // variable-length paint key descriptor
};
const Entry* findOrCreate(std::unique_ptr<SkPaintParamsKey>) SK_EXCLUDES(fSpinLock);
const Entry* lookup(SkUniquePaintParamsID) const SK_EXCLUDES(fSpinLock);
SkSpan<const SkUniform> getUniforms(SkBuiltInCodeSnippetID) const;
const SkShaderInfo::SnippetEntry* getEntry(SkBuiltInCodeSnippetID) const;
void getShaderInfo(SkUniquePaintParamsID, SkShaderInfo*);
int maxCodeSnippetID() const {
return static_cast<int>(SkBuiltInCodeSnippetID::kLast) + fUserDefinedCodeSnippets.size();
}
// TODO: this is still experimental but, most likely, it will need to be made thread-safe
// It returns the code snippet ID to use to identify the supplied user-defined code
// TODO: add hooks for user to actually provide code.
int addUserDefinedSnippet();
private:
Entry* makeEntry(std::unique_ptr<SkPaintParamsKey>);
struct Hash {
size_t operator()(const SkPaintParamsKey*) const;
};
std::array<SkShaderInfo::SnippetEntry, kBuiltInCodeSnippetIDCount> fBuiltInCodeSnippets;
std::vector<SkShaderInfo::SnippetEntry> fUserDefinedCodeSnippets;
// TODO: can we do something better given this should have write-seldom/read-often behavior?
mutable SkSpinlock fSpinLock;
std::unordered_map<const SkPaintParamsKey*, Entry*, Hash> fHash SK_GUARDED_BY(fSpinLock);
std::vector<Entry*> fEntryVector SK_GUARDED_BY(fSpinLock);
SkArenaAlloc fArena{256};
};
#endif // SkShaderCodeDictionary_DEFINED