1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include "Rendering/GL/myGL.h"
#include "Rendering/Shaders/ShaderHandler.h"
#include "Rendering/Shaders/Shader.h"
#include "Rendering/GlobalRendering.h"
#include "System/Log/ILog.h"
#include "System/Util.h"
#include <cassert>
// not extern'ed, so static
static CShaderHandler* gShaderHandler = nullptr;
static unsigned int gNumInstances = 0;
CShaderHandler* CShaderHandler::GetInstance(unsigned int instanceValue) {
assert(instanceValue <= 1);
if (gShaderHandler == nullptr) {
gShaderHandler = new CShaderHandler();
gNumInstances *= instanceValue;
gNumInstances += 1;
}
// nobody should bring us back to life after FreeInstance
// (unless n==0, which indicates we have just [re]loaded)
assert(gNumInstances <= 1);
return gShaderHandler;
}
void CShaderHandler::FreeInstance(CShaderHandler* sh) {
assert(sh == gShaderHandler);
delete sh;
gShaderHandler = nullptr;
}
CShaderHandler::~CShaderHandler() {
for (auto it = programObjects.begin(); it != programObjects.end(); ++it) {
// release by poMap (not poClass) to avoid erase-while-iterating pattern
ReleaseProgramObjectsMap(it->second);
}
programObjects.clear();
shaderCache.Clear();
}
void CShaderHandler::ReloadAll() {
for (auto it = programObjects.cbegin(); it != programObjects.cend(); ++it) {
for (auto jt = it->second.cbegin(); jt != it->second.cend(); ++jt) {
(jt->second)->Reload(true, true);
}
}
}
bool CShaderHandler::ReleaseProgramObjects(const std::string& poClass) {
if (programObjects.find(poClass) == programObjects.end())
return false;
ReleaseProgramObjectsMap(programObjects[poClass]);
programObjects.erase(poClass);
return true;
}
void CShaderHandler::ReleaseProgramObjectsMap(ProgramObjMap& poMap) {
for (auto it = poMap.cbegin(); it != poMap.cend(); ++it) {
Shader::IProgramObject* po = it->second;
// free the program object and its attachments
if (po != Shader::nullProgramObject) {
po->Release(); delete po;
}
}
poMap.clear();
}
Shader::IProgramObject* CShaderHandler::GetProgramObject(const std::string& poClass, const std::string& poName) {
if (programObjects.find(poClass) == programObjects.end())
return nullptr;
if (programObjects[poClass].find(poName) == programObjects[poClass].end())
return nullptr;
return (programObjects[poClass][poName]);
}
Shader::IProgramObject* CShaderHandler::CreateProgramObject(const std::string& poClass, const std::string& poName, bool arbProgram) {
Shader::IProgramObject* po = Shader::nullProgramObject;
if (programObjects.find(poClass) != programObjects.end()) {
if (programObjects[poClass].find(poName) != programObjects[poClass].end()) {
LOG_L(L_WARNING, "[%s] There is already a shader program named \"%s\"!",
__FUNCTION__, poName.c_str());
return (programObjects[poClass][poName]);
}
} else {
programObjects[poClass] = ProgramObjMap();
}
if (arbProgram) {
if (globalRendering->haveARB) {
po = new Shader::ARBProgramObject(poName);
}
} else {
if (globalRendering->haveGLSL) {
po = new Shader::GLSLProgramObject(poName);
}
}
if (po == Shader::nullProgramObject) {
LOG_L(L_ERROR, "[%s] Tried to create \"%s\" a %s shader program on hardware w/o support for it!",
__FUNCTION__, poName.c_str(), arbProgram ? "ARB" : "GLSL");
}
programObjects[poClass][poName] = po;
return po;
}
Shader::IShaderObject* CShaderHandler::CreateShaderObject(const std::string& soName, const std::string& soDefs, int soType) {
assert(!soName.empty());
Shader::IShaderObject* so = Shader::nullShaderObject;
switch (soType) {
case GL_VERTEX_PROGRAM_ARB:
case GL_FRAGMENT_PROGRAM_ARB: {
// assert(StringToLower(soName).find("arb") != std::string::npos);
if (globalRendering->haveARB) {
so = new Shader::ARBShaderObject(soType, soName);
}
} break;
default: {
// assume GLSL shaders by default
// assert(StringToLower(soName).find("arb") == std::string::npos);
if (globalRendering->haveGLSL) {
so = new Shader::GLSLShaderObject(soType, soName, soDefs);
}
} break;
}
if (so == Shader::nullShaderObject) {
LOG_L(L_ERROR, "[%s] Tried to create a shader (\"%s\") on hardware that does not support them!",
__FUNCTION__, soName.c_str());
return so;
}
return so;
}
|