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;
Shader::Shader(Type type, const Source& source):
std::atomic<uint32_t> Shader::_nextShaderID( 1 );
Shader::DomainShaderMaps Shader::_domainShaderMaps;
Shader::ProgramMap Shader::_programMap;
Shader::Shader(Type type, const Source& source) :
_source(source),
_type(type)
_type(type),
_ID(_nextShaderID++)
{
}
Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
_type(type)
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
_type(type),
_ID(_nextShaderID++)
{
_shaders.resize(2);
_shaders[VERTEX] = vertex;
_shaders[PIXEL] = pixel;
}
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) :
_type(type) {
_shaders.resize(3);
_shaders[VERTEX] = vertex;
_shaders[GEOMETRY] = geometry;
_shaders[PIXEL] = pixel;
if (geometry) {
_shaders.resize(3);
_shaders[VERTEX] = vertex;
_shaders[GEOMETRY] = geometry;
_shaders[PIXEL] = pixel;
} else {
_shaders.resize(2);
_shaders[VERTEX] = vertex;
_shaders[PIXEL] = pixel;
}
}
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) {
return Pointer(new Shader(VERTEX, source));
return createOrReuseDomainShader(VERTEX, 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) {
return Pointer(new Shader(GEOMETRY, source));
return createOrReuseDomainShader(GEOMETRY, source);
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
if (vertexShader && vertexShader->getType() == VERTEX &&
pixelShader && pixelShader->getType() == PIXEL) {
return Pointer(new Shader(PROGRAM, vertexShader, pixelShader));
ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
ProgramMapKey key(0);
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) {
if (vertexShader && vertexShader->getType() == VERTEX &&
geometryShader && geometryShader->getType() == GEOMETRY &&
pixelShader && pixelShader->getType() == PIXEL) {
return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
}
return Pointer();
return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
}
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
@ -98,4 +151,5 @@ void Shader::setCompilationLogs(const CompilationLogs& logs) const {
void Shader::incrementCompilationAttempt() const {
_numCompilationAttempts++;
}
}

View file

@ -15,6 +15,7 @@
#include <string>
#include <memory>
#include <set>
#include <map>
#include <QUrl>
@ -22,6 +23,8 @@ namespace gpu {
class Shader {
public:
// unique identifier of a shader
using ID = uint32_t;
typedef std::shared_ptr< Shader > Pointer;
typedef std::vector< Pointer > Shaders;
@ -39,6 +42,11 @@ public:
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:
std::string _code;
Language _lang = GLSL;
@ -134,6 +142,8 @@ public:
~Shader();
ID getID() const { return _ID; }
Type getType() const { return _type; }
bool isProgram() const { return getType() > NUM_DOMAINS; }
bool isDomain() const { return getType() < NUM_DOMAINS; }
@ -194,15 +204,15 @@ public:
const GPUObjectPointer gpuObject {};
protected:
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(const Shader& shader); // deep copy of the sysmem shader
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 _source;
@ -221,6 +231,9 @@ protected:
// The type of the shader, the master key
Type _type;
// The unique identifier of a shader in the GPU lib
uint32_t _ID{ 0 };
// Number of attempts to compile the shader
mutable uint32_t _numCompilationAttempts{ 0 };
// Compilation logs (one for each versions generated)
@ -228,6 +241,39 @@ protected:
// Whether or not the shader compilation failed
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;