Adding the map of existing shaders and programs and ways to identify them to avoid recompiling them

This commit is contained in:
samcake 2018-01-31 17:28:45 -08:00
parent 0885b00ab8
commit 89f4fe1c04
2 changed files with 132 additions and 32 deletions

View file

@ -17,59 +17,112 @@
using namespace gpu; using namespace gpu;
std::atomic<uint32_t> Shader::_nextShaderID( 1 );
Shader::DomainShaderMaps Shader::_domainShaderMaps;
Shader::ProgramMap Shader::_programMap;
Shader::Shader(Type type, const Source& source) : Shader::Shader(Type type, const Source& source) :
_source(source), _source(source),
_type(type) _type(type),
_ID(_nextShaderID++)
{ {
} }
Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
_type(type)
{
_shaders.resize(2);
_shaders[VERTEX] = vertex;
_shaders[PIXEL] = pixel;
}
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel): Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
_type(type) { _type(type),
_ID(_nextShaderID++)
{
if (geometry) {
_shaders.resize(3); _shaders.resize(3);
_shaders[VERTEX] = vertex; _shaders[VERTEX] = vertex;
_shaders[GEOMETRY] = geometry; _shaders[GEOMETRY] = geometry;
_shaders[PIXEL] = pixel; _shaders[PIXEL] = pixel;
} else {
_shaders.resize(2);
_shaders[VERTEX] = vertex;
_shaders[PIXEL] = pixel;
}
} }
Shader::~Shader() Shader::~Shader()
{ {
} }
Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
auto found = _domainShaderMaps[type].find(source);
if (found != _domainShaderMaps[type].end()) {
auto sharedShader = (*found).second.lock();
if (sharedShader) {
return sharedShader;
}
}
auto shader = Pointer(new Shader(type, source));
_domainShaderMaps[type].emplace(source, std::weak_ptr<Shader>(shader));
return shader;
}
Shader::Pointer Shader::createVertex(const Source& source) { Shader::Pointer Shader::createVertex(const Source& source) {
return Pointer(new Shader(VERTEX, source)); return createOrReuseDomainShader(VERTEX, source);
} }
Shader::Pointer Shader::createPixel(const Source& source) { Shader::Pointer Shader::createPixel(const Source& source) {
return Pointer(new Shader(PIXEL, source)); return createOrReuseDomainShader(PIXEL, source);
} }
Shader::Pointer Shader::createGeometry(const Source& source) { Shader::Pointer Shader::createGeometry(const Source& source) {
return Pointer(new Shader(GEOMETRY, source)); return createOrReuseDomainShader(GEOMETRY, source);
} }
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
if (vertexShader && vertexShader->getType() == VERTEX && ProgramMapKey key(0);
pixelShader && pixelShader->getType() == PIXEL) {
return Pointer(new Shader(PROGRAM, vertexShader, pixelShader)); if (vertexShader && vertexShader->getType() == VERTEX) {
} key.x = vertexShader->getID();
} else {
// Shader is not valid, exit
return Pointer(); return Pointer();
} }
if (pixelShader && pixelShader->getType() == PIXEL) {
key.y = pixelShader->getID();
} else {
// Shader is not valid, exit
return Pointer();
}
if (geometryShader) {
if (geometryShader->getType() == GEOMETRY) {
key.z = geometryShader->getID();
} else {
// Shader is not valid, exit
return Pointer();
}
}
// program key is defined, now try to reuse
auto found = _programMap.find(key);
if (found != _programMap.end()) {
auto sharedShader = (*found).second.lock();
if (sharedShader) {
return sharedShader;
}
}
// Program is a new one, let's create it
auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
_programMap.emplace(key, std::weak_ptr<Shader>(program));
return program;
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) { Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
if (vertexShader && vertexShader->getType() == VERTEX && return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
geometryShader && geometryShader->getType() == GEOMETRY &&
pixelShader && pixelShader->getType() == PIXEL) {
return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
}
return Pointer();
} }
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
@ -99,3 +152,4 @@ void Shader::setCompilationLogs(const CompilationLogs& logs) const {
void Shader::incrementCompilationAttempt() const { void Shader::incrementCompilationAttempt() const {
_numCompilationAttempts++; _numCompilationAttempts++;
} }

View file

@ -15,6 +15,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <set> #include <set>
#include <map>
#include <QUrl> #include <QUrl>
@ -22,6 +23,8 @@ namespace gpu {
class Shader { class Shader {
public: public:
// unique identifier of a shader
using ID = uint32_t;
typedef std::shared_ptr< Shader > Pointer; typedef std::shared_ptr< Shader > Pointer;
typedef std::vector< Pointer > Shaders; typedef std::vector< Pointer > Shaders;
@ -39,6 +42,11 @@ public:
virtual const std::string& getCode() const { return _code; } virtual const std::string& getCode() const { return _code; }
class Less {
public:
bool operator() (const Source& x, const Source& y) const { if (x._lang == y._lang) { return x._code < y._code; } else { return (x._lang < y._lang); } }
};
protected: protected:
std::string _code; std::string _code;
Language _lang = GLSL; Language _lang = GLSL;
@ -134,6 +142,8 @@ public:
~Shader(); ~Shader();
ID getID() const { return _ID; }
Type getType() const { return _type; } Type getType() const { return _type; }
bool isProgram() const { return getType() > NUM_DOMAINS; } bool isProgram() const { return getType() > NUM_DOMAINS; }
bool isDomain() const { return getType() < NUM_DOMAINS; } bool isDomain() const { return getType() < NUM_DOMAINS; }
@ -197,12 +207,12 @@ public:
protected: protected:
Shader(Type type, const Source& source); Shader(Type type, const Source& source);
Shader(Type type, const Pointer& vertex, const Pointer& pixel);
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel); Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
Shader(const Shader& shader); // deep copy of the sysmem shader Shader(const Shader& shader); // deep copy of the sysmem shader
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
// Source contains the actual source code or nothing if the shader is a program // Source contains the actual source code or nothing if the shader is a program
Source _source; Source _source;
@ -221,6 +231,9 @@ protected:
// The type of the shader, the master key // The type of the shader, the master key
Type _type; Type _type;
// The unique identifier of a shader in the GPU lib
uint32_t _ID{ 0 };
// Number of attempts to compile the shader // Number of attempts to compile the shader
mutable uint32_t _numCompilationAttempts{ 0 }; mutable uint32_t _numCompilationAttempts{ 0 };
// Compilation logs (one for each versions generated) // Compilation logs (one for each versions generated)
@ -228,6 +241,39 @@ protected:
// Whether or not the shader compilation failed // Whether or not the shader compilation failed
bool _compilationHasFailed { false }; bool _compilationHasFailed { false };
// Global maps of the shaders
// Unique shader ID
static std::atomic<ID> _nextShaderID;
using ShaderMap = std::map<Source, std::weak_ptr<Shader>, Source::Less>;
using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
static DomainShaderMaps _domainShaderMaps;
static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
using ProgramMapKey = glm::uvec3; // THe IDs of the shaders in a progrma make its key
class ProgramKeyLess {
public:
bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {
if (l.x == r.x) {
if (l.y == r.y) {
return (l.z < l.z);
}
else {
return (l.y < l.y);
}
}
else {
return (l.x < r.x);
}
}
};
using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
static ProgramMap _programMap;
static ShaderPointer createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
}; };
typedef Shader::Pointer ShaderPointer; typedef Shader::Pointer ShaderPointer;