#define GL_GLEXT_PROTOTYPES 1
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
-#include <locale.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
delete nodes[i];
}
for (unsigned i = 0; i < phases.size(); ++i) {
- glBindVertexArray(phases[i]->vao);
- check_error();
-
- cleanup_vertex_attribute(phases[i]->glsl_program_num, "position", phases[i]->position_vbo);
- cleanup_vertex_attribute(phases[i]->glsl_program_num, "texcoord", phases[i]->texcoord_vbo);
-
- glBindVertexArray(0);
- check_error();
-
resource_pool->release_glsl_program(phases[i]->glsl_program_num);
delete phases[i];
}
node->output_color_space = COLORSPACE_INVALID;
node->output_gamma_curve = GAMMA_INVALID;
node->output_alpha_type = ALPHA_INVALID;
+ node->needs_mipmaps = false;
nodes.push_back(node);
node_map[effect] = node;
void EffectChain::compile_glsl_program(Phase *phase)
{
- string frag_shader = read_file("header.frag");
+ string frag_shader = read_version_dependent_file("header", "frag");
// Create functions for all the texture inputs that we need.
for (unsigned i = 0; i < phase->inputs.size(); ++i) {
frag_shader += string("uniform sampler2D tex_") + effect_id + ";\n";
frag_shader += string("vec4 ") + effect_id + "(vec2 tc) {\n";
- frag_shader += "\treturn texture2D(tex_" + string(effect_id) + ", tc);\n";
+ frag_shader += "\treturn tex2D(tex_" + string(effect_id) + ", tc);\n";
frag_shader += "}\n";
frag_shader += "\n";
}
frag_shader += "\n";
}
frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
- frag_shader.append(read_file("footer.frag"));
-
- phase->glsl_program_num = resource_pool->compile_glsl_program(read_file("vs.vert"), frag_shader);
-
- // Prepare the geometry for the fullscreen quad used in this phase.
- // (We have separate VAOs per shader, since the bindings can in theory
- // be different.)
- float vertices[] = {
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- 1.0f, 1.0f,
- 1.0f, 0.0f
- };
-
- glGenVertexArrays(1, &phase->vao);
- check_error();
- glBindVertexArray(phase->vao);
- check_error();
-
- phase->position_vbo = fill_vertex_attribute(phase->glsl_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
- phase->texcoord_vbo = fill_vertex_attribute(phase->glsl_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices); // Same as vertices.
+ frag_shader.append(read_version_dependent_file("footer", "frag"));
- glBindVertexArray(0);
- check_error();
+ string vert_shader = read_version_dependent_file("vs", "vert");
+ phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader);
}
// Construct GLSL programs, starting at the given effect and following
Node *node = effects_todo_this_phase.top();
effects_todo_this_phase.pop();
+ if (node->effect->needs_mipmaps()) {
+ node->needs_mipmaps = true;
+ }
+
// This should currently only happen for effects that are inputs
// (either true inputs or phase outputs). We special-case inputs,
// and then deduplicate phase outputs below.
start_new_phase = true;
}
+ // Propagate information about needing mipmaps down the chain,
+ // breaking the phase if we notice an incompatibility.
+ //
+ // Note that we cannot do this propagation as a normal pass,
+ // because it needs information about where the phases end
+ // (we should not propagate the flag across phases).
+ if (node->needs_mipmaps) {
+ if (deps[i]->effect->num_inputs() == 0) {
+ Input *input = static_cast<Input *>(deps[i]->effect);
+ start_new_phase |= !input->can_supply_mipmaps();
+ } else {
+ deps[i]->needs_mipmaps = true;
+ }
+ }
+
if (deps[i]->outgoing_links.size() > 1) {
if (!deps[i]->effect->is_single_texture()) {
// More than one effect uses this as the input,
for (unsigned i = 0; i < phase->effects.size(); ++i) {
Node *node = phase->effects[i];
if (node->effect->num_inputs() == 0) {
- CHECK(node->effect->set_int("needs_mipmaps", phase->input_needs_mipmaps));
+ Input *input = static_cast<Input *>(node->effect);
+ assert(!phase->input_needs_mipmaps || input->can_supply_mipmaps());
+ CHECK(input->set_int("needs_mipmaps", phase->input_needs_mipmaps));
}
}
void EffectChain::finalize()
{
- // Save the current locale, and set it to C, so that we can output decimal
- // numbers with printf and be sure to get them in the format mandated by GLSL.
- char *saved_locale = setlocale(LC_NUMERIC, "C");
-
// Output the graph as it is before we do any conversions on it.
output_dot("step0-start.dot");
assert(phases[0]->inputs.empty());
finalized = true;
- setlocale(LC_NUMERIC, saved_locale);
}
void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
check_error();
- glBindVertexArray(0);
- check_error();
glUseProgram(0);
check_error();
}
// And now the output. (Already set up for us if it is the last phase.)
if (!last_phase) {
- void *context = get_gl_context_identifier();
- fbo = resource_pool->create_fbo(context, (*output_textures)[phase]);
+ fbo = resource_pool->create_fbo((*output_textures)[phase]);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, phase->output_width, phase->output_height);
}
}
}
- glBindVertexArray(phase->vao);
+ // Now draw!
+ float vertices[] = {
+ 0.0f, 1.0f,
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+ };
+
+ GLuint vao;
+ glGenVertexArrays(1, &vao);
+ check_error();
+ glBindVertexArray(vao);
check_error();
+
+ GLuint position_vbo = fill_vertex_attribute(glsl_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
+ GLuint texcoord_vbo = fill_vertex_attribute(glsl_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices); // Same as vertices.
+
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
check_error();
+ cleanup_vertex_attribute(glsl_program_num, "position", position_vbo);
+ cleanup_vertex_attribute(glsl_program_num, "texcoord", texcoord_vbo);
+
+ glUseProgram(0);
+ check_error();
+
for (unsigned i = 0; i < phase->effects.size(); ++i) {
Node *node = phase->effects[i];
node->effect->clear_gl_state();
if (!last_phase) {
resource_pool->release_fbo(fbo);
}
+
+ glDeleteVertexArrays(1, &vao);
+ check_error();
}
void EffectChain::setup_rtt_sampler(GLuint glsl_program_num, int sampler_num, const string &effect_id, bool use_mipmaps)