#include <cstring>
#include <msp/core/algorithm.h>
+#include <msp/gl/extensions/arb_compute_shader.h>
#include <msp/gl/extensions/arb_es2_compatibility.h>
#include <msp/gl/extensions/arb_fragment_shader.h>
#include <msp/gl/extensions/arb_gl_spirv.h>
#include <msp/gl/extensions/arb_separate_shader_objects.h>
#include <msp/gl/extensions/arb_shader_objects.h>
#include <msp/gl/extensions/arb_uniform_buffer_object.h>
+#include <msp/gl/extensions/arb_tessellation_shader.h>
#include <msp/gl/extensions/arb_vertex_shader.h>
#include <msp/gl/extensions/ext_gpu_shader4.h>
#include <msp/gl/extensions/khr_debug.h>
switch(type)
{
case VERTEX: { static Require _req(ARB_vertex_shader); gl_type = GL_VERTEX_SHADER; } break;
+ case TESS_CONTROL: { static Require _req(ARB_tessellation_shader); gl_type = GL_TESS_CONTROL_SHADER; } break;
+ case TESS_EVAL: { static Require _req(ARB_tessellation_shader); gl_type = GL_TESS_EVALUATION_SHADER; } break;
case GEOMETRY: { static Require _req(ARB_geometry_shader4); gl_type = GL_GEOMETRY_SHADER; } break;
case FRAGMENT: { static Require _req(ARB_fragment_shader); gl_type = GL_FRAGMENT_SHADER; } break;
+ case COMPUTE: { static Require _req(ARB_compute_shader); gl_type = GL_COMPUTE_SHADER; } break;
default: throw invalid_argument("OpenGLProgram::add_stage");
}
return stage_id;
}
-void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int> &spec_values, TransientData &transient)
+void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int> &spec_values)
{
SL::Compiler compiler(Device::get_current().get_info().glsl_features);
compiler.set_source(mod.get_prepared_source(), "<module>");
switch(st)
{
case SL::Stage::VERTEX: stage_id = add_stage(VERTEX); break;
+ case SL::Stage::TESS_CONTROL: stage_id = add_stage(TESS_CONTROL); break;
+ case SL::Stage::TESS_EVAL: stage_id = add_stage(TESS_EVAL); break;
case SL::Stage::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
case SL::Stage::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
+ case SL::Stage::COMPUTE: stage_id = add_stage(COMPUTE); break;
default: throw invalid_operation("OpenGLProgram::add_glsl_stages");
}
compile_glsl_stage(mod, stage_id);
}
- transient.textures = compiler.get_texture_bindings();
- transient.blocks = compiler.get_uniform_block_bindings();
-
ReflectData &rd = static_cast<Program *>(this)->reflect_data;
rd.n_clip_distances = compiler.get_n_clip_distances();
+
+ link(mod);
+ query_uniforms();
+ query_attributes();
+ if(is_compute())
+ {
+ int wg_size[3];
+ glGetProgramiv(id, GL_COMPUTE_WORK_GROUP_SIZE, wg_size);
+ rd.compute_wg_size = LinAl::Vector<unsigned, 3>(wg_size[0], wg_size[1], wg_size[2]);
+ }
+
+ const map<string, unsigned> &block_bindings = compiler.get_uniform_block_bindings();
+ if(!block_bindings.empty())
+ {
+ for(unsigned i=0; i<rd.uniform_blocks.size(); ++i)
+ {
+ auto j = block_bindings.find(rd.uniform_blocks[i].name);
+ if(j!=block_bindings.end())
+ {
+ glUniformBlockBinding(id, i, j->second);
+ rd.uniform_blocks[i].bind_point = j->second;
+ }
+ }
+ }
+
+ const map<string, unsigned> &tex_bindings = compiler.get_texture_bindings();
+ if(!tex_bindings.empty())
+ {
+ if(!ARB_separate_shader_objects)
+ glUseProgram(id);
+ for(const auto &kvp: tex_bindings)
+ {
+ int location = static_cast<const Program *>(this)->get_uniform_location(kvp.first);
+ if(location>=0)
+ {
+ if(ARB_separate_shader_objects)
+ glProgramUniform1i(id, location, kvp.second);
+ else
+ glUniform1i(location, kvp.second);
+ }
+ }
+ }
}
void OpenGLProgram::compile_glsl_stage(const GlslModule &mod, unsigned stage_id)
switch(e.stage)
{
case SpirVModule::VERTEX: stage_id = add_stage(VERTEX); break;
+ case SpirVModule::TESS_CONTROL: stage_id = add_stage(TESS_CONTROL); break;
+ case SpirVModule::TESS_EVAL: stage_id = add_stage(TESS_EVAL); break;
case SpirVModule::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
case SpirVModule::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
+ case SpirVModule::COMPUTE: stage_id = add_stage(COMPUTE); break;
default: throw invalid_operation("OpenGLProgram::add_spirv_stages");
}
for(unsigned i=0; i<MAX_STAGES; ++i)
if(stage_ids[i])
glSpecializeShader(stage_ids[i], j->name.c_str(), spec_id_array.size(), &spec_id_array[0], &spec_value_array[0]);
+
+ link(mod);
}
-void OpenGLProgram::finalize(const Module &mod, TransientData &transient)
+void OpenGLProgram::link(const Module &mod)
{
glLinkProgram(id);
int status = 0;
if(!info_log.empty())
IO::print("Program link info log:\n%s", info_log);
#endif
-
- if(mod.get_format()==Module::GLSL)
- {
- query_uniforms();
- query_attributes();
- apply_bindings(transient);
- }
}
void OpenGLProgram::query_uniforms()
info.type = from_gl_type(type);
}
}
-}
-
-void OpenGLProgram::apply_bindings(const TransientData &transient)
-{
- ReflectData &rd = static_cast<Program *>(this)->reflect_data;
-
- for(unsigned i=0; i<rd.uniform_blocks.size(); ++i)
- {
- auto j = transient.blocks.find(rd.uniform_blocks[i].name);
- if(j!=transient.blocks.end())
- {
- glUniformBlockBinding(id, i, j->second);
- rd.uniform_blocks[i].bind_point = j->second;
- }
- }
- if(!ARB_separate_shader_objects)
- glUseProgram(id);
- for(const auto &kvp: transient.textures)
- {
- int location = static_cast<const Program *>(this)->get_uniform_location(kvp.first);
- if(location>=0)
- {
- if(ARB_separate_shader_objects)
- glProgramUniform1i(id, location, kvp.second);
- else
- glUniform1i(location, kvp.second);
- }
- }
+ sort_member(rd.attributes, &ReflectData::AttributeInfo::name);
}
void OpenGLProgram::finalize_uniforms()
void OpenGLProgram::set_stage_debug_name(unsigned stage_id, Stage type)
{
#ifdef DEBUG
- static const char *const suffixes[] = { " [VS]", " [GS]", " [FS]" };
+ static const char *const suffixes[] = { " [VS]", " [TCS]", " [TES]", " [GS]", " [FS]", " [CS]" };
string name = debug_name+suffixes[type];
glObjectLabel(GL_SHADER, stage_id, name.size(), name.c_str());
#else