#include <set>
#include <msp/core/hash.h>
#include <msp/core/maputils.h>
+#include <msp/gl/extensions/arb_fragment_shader.h>
+#include <msp/gl/extensions/arb_geometry_shader4.h>
#include <msp/gl/extensions/arb_shader_objects.h>
#include <msp/gl/extensions/arb_uniform_buffer_object.h>
#include <msp/gl/extensions/arb_vertex_shader.h>
#include "buffer.h"
#include "error.h"
#include "misc.h"
+#include "module.h"
#include "program.h"
-#include "programcompiler.h"
#include "resources.h"
#include "shader.h"
+#include "glsl/compiler.h"
using namespace std;
{
init();
- ProgramCompiler compiler;
- if(source.find(';')==string::npos && source.size()>5 && !source.compare(source.size()-5, 5, ".glsl"))
- {
- if(RefPtr<IO::Seekable> io = Resources::get_builtins().open(source))
- compiler.compile(*io, source);
- else
- throw IO::file_not_found(source);
- }
- else
- compiler.compile(source);
- compiler.add_shaders(*this);
+ Module mod;
+ mod.set_source(source);
+ add_stages(mod);
+
link();
+ module = 0;
}
Program::Program(const string &vert, const string &frag)
{
init();
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
attach_shader_owned(new VertexShader(vert));
attach_shader_owned(new FragmentShader(frag));
+#pragma GCC diagnostic pop
+ link();
+}
+
+Program::Program(const Module &mod, const map<string, int> &spec_values)
+{
+ init();
+ add_stages(mod, spec_values);
link();
}
{
static Require _req(ARB_shader_objects);
- linked = false;
id = glCreateProgram();
+ module = 0;
+ linked = false;
}
Program::~Program()
{
- for(ShaderList::iterator i=owned_data.begin(); i!=owned_data.end(); ++i)
- delete *i;
+ for(vector<unsigned>::iterator i=shader_ids.begin(); i!=shader_ids.end(); ++i)
+ glDeleteShader(*i);
glDeleteProgram(id);
}
-void Program::attach_shader(Shader &shader)
+void Program::add_stages(const Module &mod, const map<string, int> &spec_values)
{
- if(find(shaders.begin(), shaders.end(), &shader)==shaders.end())
+ module = &mod;
+
+ SL::Compiler compiler;
+ compiler.set_source(module->get_prepared_source(), "<module>");
+ compiler.specialize(spec_values);
+ compiler.compile(SL::Compiler::PROGRAM);
+#ifdef DEBUG
+ string diagnostics = compiler.get_diagnostics();
+ if(!diagnostics.empty())
+ IO::print("Program diagnostics:\n%s\n", diagnostics);
+#endif
+
+ vector<SL::Stage::Type> stages = compiler.get_stages();
+ for(vector<SL::Stage::Type>::const_iterator i=stages.begin(); i!=stages.end(); ++i)
{
- glAttachShader(id, shader.get_id());
- shaders.push_back(&shader);
+ GLenum type;
+ switch(*i)
+ {
+ case SL::Stage::VERTEX:
+ { static Require _req(ARB_vertex_shader); }
+ type = GL_VERTEX_SHADER;
+ break;
+ case SL::Stage::GEOMETRY:
+ { static Require _req(ARB_geometry_shader4); }
+ type = GL_GEOMETRY_SHADER;
+ break;
+ case SL::Stage::FRAGMENT:
+ { static Require _req(ARB_fragment_shader); }
+ type = GL_FRAGMENT_SHADER;
+ break;
+ default:
+ throw invalid_operation("Program::add_stages");
+ }
+
+ unsigned stage_id = glCreateShader(type);
+ shader_ids.push_back(stage_id);
+ glAttachShader(id, stage_id);
+
+ string stage_src = compiler.get_stage_glsl(*i);
+ const char *src_ptr = stage_src.data();
+ int src_len = stage_src.size();
+ glShaderSource(stage_id, 1, &src_ptr, &src_len);
+
+ if(*i==SL::Stage::VERTEX)
+ {
+ const map<string, unsigned> &attribs = compiler.get_vertex_attributes();
+ for(map<string, unsigned>::const_iterator j=attribs.begin(); j!=attribs.end(); ++j)
+ glBindAttribLocation(id, j->second, j->first.c_str());
+ }
+
+ if(*i==SL::Stage::FRAGMENT && EXT_gpu_shader4)
+ {
+ const map<string, unsigned> &frag_outs = compiler.get_fragment_outputs();
+ for(map<string, unsigned>::const_iterator j=frag_outs.begin(); j!=frag_outs.end(); ++j)
+ glBindFragDataLocation(id, j->second, j->first.c_str());
+ }
}
}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+void Program::attach_shader(Shader &shader)
+{
+ unsigned shader_id = shader.steal_id();
+ if(!shader_id)
+ throw invalid_argument("Program::attach_shader");
+ shader_ids.push_back(shader_id);
+}
+
void Program::attach_shader_owned(Shader *shader)
{
attach_shader(*shader);
- if(find(owned_data.begin(), owned_data.end(), shader)==owned_data.end())
- owned_data.push_back(shader);
+ delete shader;
}
-void Program::detach_shader(Shader &shader)
+void Program::detach_shader(Shader &)
{
- ShaderList::iterator i = remove(shaders.begin(), shaders.end(), &shader);
- if(i!=shaders.end())
- {
- shaders.erase(i, shaders.end());
- glDetachShader(id, shader.get_id());
- }
+}
+
+const vector<Shader *> &Program::get_attached_shaders() const
+{
+ static vector<Shader *> dummy;
+ return dummy;
}
void Program::bind_attribute(unsigned index, const string &name)
glBindAttribLocation(id, index, name.c_str());
}
-void Program::bind_attribute(VertexComponent comp, const string &name)
+void Program::bind_attribute(VertexAttribute attr, const string &name)
{
- bind_attribute(get_component_type(comp), name);
+ bind_attribute(get_attribute_semantic(attr), name);
}
void Program::bind_fragment_data(unsigned index, const string &name)
static Require _req(EXT_gpu_shader4);
glBindFragDataLocation(id, index, name.c_str());
}
+#pragma GCC diagnostic pop
void Program::link()
{
- for(ShaderList::iterator i=shaders.begin(); i!=shaders.end(); ++i)
- if(!(*i)->is_compiled())
- (*i)->compile();
+ for(vector<unsigned>::const_iterator i=shader_ids.begin(); i!=shader_ids.end(); ++i)
+ {
+ glCompileShader(*i);
+ bool compiled = get_shader_i(*i, GL_COMPILE_STATUS);
+
+ GLsizei info_log_len = get_shader_i(*i, GL_INFO_LOG_LENGTH);
+ string info_log(info_log_len+1, 0);
+ glGetShaderInfoLog(*i, info_log_len+1, &info_log_len, &info_log[0]);
+ info_log.erase(info_log_len);
+ info_log = module->get_source_map().translate_errors(info_log);
+
+ if(!compiled)
+ throw compile_error(info_log);
+#ifdef DEBUG
+ if(!info_log.empty())
+ IO::print("Shader compile info log:\n%s", info_log);
+#endif
+ }
uniforms.clear();
glLinkProgram(id);
linked = get_program_i(id, GL_LINK_STATUS);
- if(!linked)
- throw compile_error(get_info_log());
+ GLsizei info_log_len = get_program_i(id, GL_INFO_LOG_LENGTH);
+ string info_log(info_log_len+1, 0);
+ glGetProgramInfoLog(id, info_log_len+1, &info_log_len, &info_log[0]);
+ info_log.erase(info_log_len);
+ info_log = module->get_source_map().translate_errors(info_log);
+
+ if(!linked)
+ throw compile_error(info_log);
#ifdef DEBUG
- std::string info_log = get_info_log();
if(!info_log.empty())
IO::print("Program link info log:\n%s", info_log);
#endif
}
-Program::Loader::Loader(Program &p):
- DataFile::ObjectLoader<Program>(p)
+Program::Loader::Loader(Program &p, Collection &c):
+ DataFile::CollectionObjectLoader<Program>(p, &c)
{
+ add("module", &Loader::module);
+
+ // Deprecated
add("attribute", &Loader::attribute);
add("fragment_shader", &Loader::fragment_shader);
add("geometry_shader", &Loader::geometry_shader);
obj.link();
}
+void Program::Loader::module(const string &n)
+{
+ map<string, int> spec_values;
+ SpecializationLoader ldr(spec_values);
+ load_sub_with(ldr);
+ obj.add_stages(get_collection().get<Module>(n), spec_values);
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void Program::Loader::attribute(unsigned i, const string &n)
{
obj.bind_attribute(i, n);
{
obj.attach_shader_owned(new VertexShader(src));
}
+#pragma GCC diagnostic pop
+
+
+DataFile::Loader::ActionMap Program::SpecializationLoader::shared_actions;
+
+Program::SpecializationLoader::SpecializationLoader(map<string, int> &sv):
+ spec_values(sv)
+{
+ set_actions(shared_actions);
+}
+
+void Program::SpecializationLoader::init_actions()
+{
+ add("specialize", &SpecializationLoader::specialize_bool);
+ add("specialize", &SpecializationLoader::specialize_int);
+}
+
+void Program::SpecializationLoader::specialize_bool(const string &name, bool value)
+{
+ spec_values[name] = value;
+}
+
+void Program::SpecializationLoader::specialize_int(const string &name, int value)
+{
+ spec_values[name] = value;
+}
} // namespace GL
} // namespace Msp