mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-09 05:25:01 +00:00
Attempts to put in better OpenGL safety rails.
This commit is contained in:
@@ -22,4 +22,22 @@
|
|||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// To consider: might it be smarter to switch and log on error,
|
||||||
|
// rather than raising an exception? They're conventionally
|
||||||
|
// something you're permitted to ignore.
|
||||||
|
//
|
||||||
|
// (and, from that indecision, hence the pointless decision
|
||||||
|
// on whether to use an assert based on NDEBUG)
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define test_gl_error() assert(!glGetError());
|
||||||
|
#else
|
||||||
|
#define test_gl_error() while(false) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define test_gl(command, ...) do { command(__VA_ARGS__); test_gl_error(); } while(false);
|
||||||
|
#else
|
||||||
|
#define test_gl(command, ...) command(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* OpenGL_h */
|
#endif /* OpenGL_h */
|
||||||
|
@@ -33,16 +33,16 @@ Rectangle::Rectangle(float x, float y, float width, float height):
|
|||||||
){
|
){
|
||||||
pixel_shader_.bind();
|
pixel_shader_.bind();
|
||||||
|
|
||||||
glGenVertexArrays(1, &drawing_vertex_array_);
|
test_gl(glGenVertexArrays, 1, &drawing_vertex_array_);
|
||||||
glGenBuffers(1, &drawing_array_buffer_);
|
test_gl(glGenBuffers, 1, &drawing_array_buffer_);
|
||||||
|
|
||||||
glBindVertexArray(drawing_vertex_array_);
|
test_gl(glBindVertexArray, drawing_vertex_array_);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||||
|
|
||||||
GLint position_attribute = pixel_shader_.get_attrib_location("position");
|
GLint position_attribute = pixel_shader_.get_attrib_location("position");
|
||||||
glEnableVertexAttribArray(static_cast<GLuint>(position_attribute));
|
test_gl(glEnableVertexAttribArray, GLuint(position_attribute));
|
||||||
|
|
||||||
glVertexAttribPointer(
|
test_gl(glVertexAttribPointer,
|
||||||
(GLuint)position_attribute,
|
(GLuint)position_attribute,
|
||||||
2,
|
2,
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
@@ -61,14 +61,14 @@ Rectangle::Rectangle(float x, float y, float width, float height):
|
|||||||
buffer[6] = x + width; buffer[7] = y + height;
|
buffer[6] = x + width; buffer[7] = y + height;
|
||||||
|
|
||||||
// Upload buffer.
|
// Upload buffer.
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
|
test_gl(glBufferData, GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle::draw(float red, float green, float blue) {
|
void Rectangle::draw(float red, float green, float blue) {
|
||||||
pixel_shader_.bind();
|
pixel_shader_.bind();
|
||||||
glUniform4f(colour_uniform_, red, green, blue, 1.0);
|
test_gl(glUniform4f, colour_uniform_, red, green, blue, 1.0);
|
||||||
|
|
||||||
glBindVertexArray(drawing_vertex_array_);
|
test_gl(glBindVertexArray, drawing_vertex_array_);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
test_gl(glDrawArrays, GL_TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
}
|
||||||
|
@@ -21,18 +21,18 @@ namespace {
|
|||||||
GLuint Shader::compile_shader(const std::string &source, GLenum type) {
|
GLuint Shader::compile_shader(const std::string &source, GLenum type) {
|
||||||
GLuint shader = glCreateShader(type);
|
GLuint shader = glCreateShader(type);
|
||||||
const char *c_str = source.c_str();
|
const char *c_str = source.c_str();
|
||||||
glShaderSource(shader, 1, &c_str, NULL);
|
test_gl(glShaderSource, shader, 1, &c_str, NULL);
|
||||||
glCompileShader(shader);
|
test_gl(glCompileShader, shader);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GLint isCompiled = 0;
|
GLint isCompiled = 0;
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
|
test_gl(glGetShaderiv, shader, GL_COMPILE_STATUS, &isCompiled);
|
||||||
if(isCompiled == GL_FALSE) {
|
if(isCompiled == GL_FALSE) {
|
||||||
GLint logLength;
|
GLint logLength;
|
||||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
|
test_gl(glGetShaderiv, shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
if(logLength > 0) {
|
if(logLength > 0) {
|
||||||
GLchar *log = new GLchar[static_cast<std::size_t>(logLength)];
|
GLchar *log = new GLchar[std::size_t(logLength)];
|
||||||
glGetShaderInfoLog(shader, logLength, &logLength, log);
|
test_gl(glGetShaderInfoLog, shader, logLength, &logLength, log);
|
||||||
LOG("Compile log:\n" << log);
|
LOG("Compile log:\n" << log);
|
||||||
delete[] log;
|
delete[] log;
|
||||||
}
|
}
|
||||||
@@ -63,11 +63,11 @@ void Shader::init(const std::string &vertex_shader, const std::string &fragment_
|
|||||||
const GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER);
|
const GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER);
|
||||||
const GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
|
const GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
glAttachShader(shader_program_, vertex);
|
test_gl(glAttachShader, shader_program_, vertex);
|
||||||
glAttachShader(shader_program_, fragment);
|
test_gl(glAttachShader, shader_program_, fragment);
|
||||||
|
|
||||||
for(const auto &binding : attribute_bindings) {
|
for(const auto &binding : attribute_bindings) {
|
||||||
glBindAttribLocation(shader_program_, binding.index, binding.name.c_str());
|
test_gl(glBindAttribLocation, shader_program_, binding.index, binding.name.c_str());
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const auto error = glGetError();
|
const auto error = glGetError();
|
||||||
switch(error) {
|
switch(error) {
|
||||||
@@ -85,20 +85,20 @@ void Shader::init(const std::string &vertex_shader, const std::string &fragment_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
glLinkProgram(shader_program_);
|
test_gl(glLinkProgram, shader_program_);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GLint logLength;
|
GLint logLength;
|
||||||
glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength);
|
test_gl(glGetProgramiv, shader_program_, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
if(logLength > 0) {
|
if(logLength > 0) {
|
||||||
GLchar *log = new GLchar[static_cast<std::size_t>(logLength)];
|
GLchar *log = new GLchar[std::size_t(logLength)];
|
||||||
glGetProgramInfoLog(shader_program_, logLength, &logLength, log);
|
test_gl(glGetProgramInfoLog, shader_program_, logLength, &logLength, log);
|
||||||
LOG("Link log:\n" << log);
|
LOG("Link log:\n" << log);
|
||||||
delete[] log;
|
delete[] log;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint didLink = 0;
|
GLint didLink = 0;
|
||||||
glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink);
|
test_gl(glGetProgramiv, shader_program_, GL_LINK_STATUS, &didLink);
|
||||||
if(didLink == GL_FALSE) {
|
if(didLink == GL_FALSE) {
|
||||||
throw ProgramLinkageError;
|
throw ProgramLinkageError;
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ Shader::~Shader() {
|
|||||||
|
|
||||||
void Shader::bind() const {
|
void Shader::bind() const {
|
||||||
// if(bound_shader != this) {
|
// if(bound_shader != this) {
|
||||||
glUseProgram(shader_program_);
|
test_gl(glUseProgram, shader_program_);
|
||||||
// bound_shader = this;
|
// bound_shader = this;
|
||||||
// }
|
// }
|
||||||
flush_functions();
|
flush_functions();
|
||||||
@@ -120,7 +120,7 @@ void Shader::bind() const {
|
|||||||
|
|
||||||
void Shader::unbind() {
|
void Shader::unbind() {
|
||||||
// bound_shader = nullptr;
|
// bound_shader = nullptr;
|
||||||
glUseProgram(0);
|
test_gl(glUseProgram, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint Shader::get_attrib_location(const std::string &name) const {
|
GLint Shader::get_attrib_location(const std::string &name) const {
|
||||||
@@ -134,9 +134,9 @@ GLint Shader::get_uniform_location(const std::string &name) const {
|
|||||||
void Shader::enable_vertex_attribute_with_pointer(const std::string &name, GLint size, GLenum type, GLboolean normalised, GLsizei stride, const GLvoid *pointer, GLuint divisor) {
|
void Shader::enable_vertex_attribute_with_pointer(const std::string &name, GLint size, GLenum type, GLboolean normalised, GLsizei stride, const GLvoid *pointer, GLuint divisor) {
|
||||||
GLint location = get_attrib_location(name);
|
GLint location = get_attrib_location(name);
|
||||||
if(location >= 0) {
|
if(location >= 0) {
|
||||||
glEnableVertexAttribArray((GLuint)location);
|
test_gl(glEnableVertexAttribArray, GLuint(location));
|
||||||
glVertexAttribPointer((GLuint)location, size, type, normalised, stride, pointer);
|
test_gl(glVertexAttribPointer, GLuint(location), size, type, normalised, stride, pointer);
|
||||||
glVertexAttribDivisor((GLuint)location, divisor);
|
test_gl(glVertexAttribDivisor, GLuint(location), divisor);
|
||||||
} else {
|
} else {
|
||||||
LOG("Couldn't enable vertex attribute " << name);
|
LOG("Couldn't enable vertex attribute " << name);
|
||||||
}
|
}
|
||||||
@@ -227,7 +227,7 @@ void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLint *values) {
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLint *values) {
|
||||||
std::size_t number_of_values = static_cast<std::size_t>(count) * static_cast<std::size_t>(size);
|
std::size_t number_of_values = std::size_t(count) * std::size_t(size);
|
||||||
std::vector<GLint> values_copy(values, values + number_of_values);
|
std::vector<GLint> values_copy(values, values + number_of_values);
|
||||||
|
|
||||||
enqueue_function([name, size, count, values_copy, this] {
|
enqueue_function([name, size, count, values_copy, this] {
|
||||||
@@ -241,7 +241,7 @@ void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLfloat *values) {
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLfloat *values) {
|
||||||
std::size_t number_of_values = static_cast<std::size_t>(count) * static_cast<std::size_t>(size);
|
std::size_t number_of_values = std::size_t(count) * std::size_t(size);
|
||||||
std::vector<GLfloat> values_copy(values, values + number_of_values);
|
std::vector<GLfloat> values_copy(values, values + number_of_values);
|
||||||
|
|
||||||
enqueue_function([name, size, count, values_copy, this] {
|
enqueue_function([name, size, count, values_copy, this] {
|
||||||
@@ -255,7 +255,7 @@ void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLuint *values) {
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLuint *values) {
|
||||||
std::size_t number_of_values = static_cast<std::size_t>(count) * static_cast<std::size_t>(size);
|
std::size_t number_of_values = std::size_t(count) * std::size_t(size);
|
||||||
std::vector<GLuint> values_copy(values, values + number_of_values);
|
std::vector<GLuint> values_copy(values, values + number_of_values);
|
||||||
|
|
||||||
enqueue_function([name, size, count, values_copy, this] {
|
enqueue_function([name, size, count, values_copy, this] {
|
||||||
@@ -273,7 +273,7 @@ void Shader::set_uniform_matrix(const std::string &name, GLint size, bool transp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shader::set_uniform_matrix(const std::string &name, GLint size, GLsizei count, bool transpose, const GLfloat *values) {
|
void Shader::set_uniform_matrix(const std::string &name, GLint size, GLsizei count, bool transpose, const GLfloat *values) {
|
||||||
std::size_t number_of_values = static_cast<std::size_t>(count) * static_cast<std::size_t>(size) * static_cast<std::size_t>(size);
|
std::size_t number_of_values = std::size_t(count) * std::size_t(size) * std::size_t(size);
|
||||||
std::vector<GLfloat> values_copy(values, values + number_of_values);
|
std::vector<GLfloat> values_copy(values, values + number_of_values);
|
||||||
|
|
||||||
enqueue_function([name, size, count, transpose, values_copy, this] {
|
enqueue_function([name, size, count, transpose, values_copy, this] {
|
||||||
|
@@ -18,8 +18,8 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit,
|
|||||||
height_(height),
|
height_(height),
|
||||||
texture_unit_(texture_unit) {
|
texture_unit_(texture_unit) {
|
||||||
// Generate and bind a frame buffer.
|
// Generate and bind a frame buffer.
|
||||||
glGenFramebuffers(1, &framebuffer_);
|
test_gl(glGenFramebuffers, 1, &framebuffer_);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
|
test_gl(glBindFramebuffer, GL_FRAMEBUFFER, framebuffer_);
|
||||||
|
|
||||||
// Round the width and height up to the next power of two.
|
// Round the width and height up to the next power of two.
|
||||||
expanded_width_ = 1;
|
expanded_width_ = 1;
|
||||||
@@ -28,23 +28,23 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit,
|
|||||||
while(expanded_height_ < height) expanded_height_ <<= 1;
|
while(expanded_height_ < height) expanded_height_ <<= 1;
|
||||||
|
|
||||||
// Generate a texture and bind it to the nominated texture unit.
|
// Generate a texture and bind it to the nominated texture unit.
|
||||||
glGenTextures(1, &texture_);
|
test_gl(glGenTextures, 1, &texture_);
|
||||||
bind_texture();
|
bind_texture();
|
||||||
|
|
||||||
// Set dimensions and set the user-supplied magnification filter.
|
// Set dimensions and set the user-supplied magnification filter.
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(expanded_width_), static_cast<GLsizei>(expanded_height_), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
test_gl(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGBA, GLsizei(expanded_width_), GLsizei(expanded_height_), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
// Set the texture as colour attachment 0 on the frame buffer.
|
// Set the texture as colour attachment 0 on the frame buffer.
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
test_gl(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
||||||
|
|
||||||
// Also add a stencil buffer if requested.
|
// Also add a stencil buffer if requested.
|
||||||
if(has_stencil_buffer) {
|
if(has_stencil_buffer) {
|
||||||
glGenRenderbuffers(1, &renderbuffer_);
|
test_gl(glGenRenderbuffers, 1, &renderbuffer_);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
|
test_gl(glBindRenderbuffer, GL_RENDERBUFFER, renderbuffer_);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX1, expanded_width_, expanded_height_);
|
test_gl(glRenderbufferStorage, GL_RENDERBUFFER, GL_STENCIL_INDEX1, expanded_width_, expanded_height_);
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_);
|
test_gl(glFramebufferRenderbuffer, GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for successful construction.
|
// Check for successful construction.
|
||||||
@@ -61,13 +61,13 @@ TextureTarget::~TextureTarget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureTarget::bind_framebuffer() {
|
void TextureTarget::bind_framebuffer() {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
|
test_gl(glBindFramebuffer, GL_FRAMEBUFFER, framebuffer_);
|
||||||
glViewport(0, 0, width_, height_);
|
test_gl(glViewport, 0, 0, width_, height_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureTarget::bind_texture() const {
|
void TextureTarget::bind_texture() const {
|
||||||
glActiveTexture(texture_unit_);
|
test_gl(glActiveTexture, texture_unit_);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
test_gl(glBindTexture, GL_TEXTURE_2D, texture_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureTarget::draw(float aspect_ratio, float colour_threshold) const {
|
void TextureTarget::draw(float aspect_ratio, float colour_threshold) const {
|
||||||
@@ -102,24 +102,24 @@ void TextureTarget::draw(float aspect_ratio, float colour_threshold) const {
|
|||||||
pixel_shader_.reset(new Shader(vertex_shader, fragment_shader));
|
pixel_shader_.reset(new Shader(vertex_shader, fragment_shader));
|
||||||
pixel_shader_->bind();
|
pixel_shader_->bind();
|
||||||
|
|
||||||
glGenVertexArrays(1, &drawing_vertex_array_);
|
test_gl(glGenVertexArrays, 1, &drawing_vertex_array_);
|
||||||
glGenBuffers(1, &drawing_array_buffer_);
|
test_gl(glGenBuffers, 1, &drawing_array_buffer_);
|
||||||
|
|
||||||
glBindVertexArray(drawing_vertex_array_);
|
test_gl(glBindVertexArray, drawing_vertex_array_);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||||
|
|
||||||
const GLint position_attribute = pixel_shader_->get_attrib_location("position");
|
const GLint position_attribute = pixel_shader_->get_attrib_location("position");
|
||||||
const GLint tex_coord_attribute = pixel_shader_->get_attrib_location("texCoord");
|
const GLint tex_coord_attribute = pixel_shader_->get_attrib_location("texCoord");
|
||||||
|
|
||||||
glEnableVertexAttribArray(static_cast<GLuint>(position_attribute));
|
test_gl(glEnableVertexAttribArray, GLuint(position_attribute));
|
||||||
glEnableVertexAttribArray(static_cast<GLuint>(tex_coord_attribute));
|
test_gl(glEnableVertexAttribArray, GLuint(tex_coord_attribute));
|
||||||
|
|
||||||
const GLsizei vertex_stride = 4 * sizeof(GLfloat);
|
const GLsizei vertex_stride = 4 * sizeof(GLfloat);
|
||||||
glVertexAttribPointer((GLuint)position_attribute, 2, GL_FLOAT, GL_FALSE, vertex_stride, (void *)0);
|
test_gl(glVertexAttribPointer, GLuint(position_attribute), 2, GL_FLOAT, GL_FALSE, vertex_stride, (void *)0);
|
||||||
glVertexAttribPointer((GLuint)tex_coord_attribute, 2, GL_FLOAT, GL_FALSE, vertex_stride, (void *)(2 * sizeof(GLfloat)));
|
test_gl(glVertexAttribPointer, GLuint(tex_coord_attribute), 2, GL_FLOAT, GL_FALSE, vertex_stride, (void *)(2 * sizeof(GLfloat)));
|
||||||
|
|
||||||
const GLint texIDUniform = pixel_shader_->get_uniform_location("texID");
|
const GLint texIDUniform = pixel_shader_->get_uniform_location("texID");
|
||||||
glUniform1i(texIDUniform, static_cast<GLint>(texture_unit_ - GL_TEXTURE0));
|
test_gl(glUniform1i, texIDUniform, GLint(texture_unit_ - GL_TEXTURE0));
|
||||||
|
|
||||||
threshold_uniform_ = pixel_shader_->get_uniform_location("threshold");
|
threshold_uniform_ = pixel_shader_->get_uniform_location("threshold");
|
||||||
}
|
}
|
||||||
@@ -132,14 +132,14 @@ void TextureTarget::draw(float aspect_ratio, float colour_threshold) const {
|
|||||||
buffer[2] = 0.0f;
|
buffer[2] = 0.0f;
|
||||||
buffer[3] = 0.0f;
|
buffer[3] = 0.0f;
|
||||||
buffer[6] = 0.0f;
|
buffer[6] = 0.0f;
|
||||||
buffer[7] = static_cast<float>(height_) / static_cast<float>(expanded_height_);
|
buffer[7] = float(height_) / float(expanded_height_);
|
||||||
buffer[10] = static_cast<float>(width_) / static_cast<float>(expanded_width_);
|
buffer[10] = float(width_) / float(expanded_width_);
|
||||||
buffer[11] = 0.0f;
|
buffer[11] = 0.0f;
|
||||||
buffer[14] = buffer[10];
|
buffer[14] = buffer[10];
|
||||||
buffer[15] = buffer[7];
|
buffer[15] = buffer[7];
|
||||||
|
|
||||||
// determine positions; rule is to keep the same height and centre
|
// determine positions; rule is to keep the same height and centre
|
||||||
float internal_aspect_ratio = static_cast<float>(width_) / static_cast<float>(height_);
|
float internal_aspect_ratio = float(width_) / float(height_);
|
||||||
float aspect_ratio_ratio = internal_aspect_ratio / aspect_ratio;
|
float aspect_ratio_ratio = internal_aspect_ratio / aspect_ratio;
|
||||||
|
|
||||||
buffer[0] = -aspect_ratio_ratio; buffer[1] = -1.0f;
|
buffer[0] = -aspect_ratio_ratio; buffer[1] = -1.0f;
|
||||||
@@ -148,13 +148,13 @@ void TextureTarget::draw(float aspect_ratio, float colour_threshold) const {
|
|||||||
buffer[12] = aspect_ratio_ratio; buffer[13] = 1.0f;
|
buffer[12] = aspect_ratio_ratio; buffer[13] = 1.0f;
|
||||||
|
|
||||||
// upload buffer
|
// upload buffer
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
|
test_gl(glBufferData, GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixel_shader_->bind();
|
pixel_shader_->bind();
|
||||||
glUniform1f(threshold_uniform_, colour_threshold);
|
test_gl(glUniform1f, threshold_uniform_, colour_threshold);
|
||||||
|
|
||||||
glBindVertexArray(drawing_vertex_array_);
|
test_gl(glBindVertexArray, drawing_vertex_array_);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
test_gl(glDrawArrays, GL_TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "ScanTarget.hpp"
|
#include "ScanTarget.hpp"
|
||||||
|
|
||||||
|
#include "OpenGL.hpp"
|
||||||
#include "Primitives/Rectangle.hpp"
|
#include "Primitives/Rectangle.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -62,13 +63,13 @@ const GLenum formatForDepth(std::size_t depth) {
|
|||||||
|
|
||||||
template <typename T> void ScanTarget::allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name) {
|
template <typename T> void ScanTarget::allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name) {
|
||||||
const auto buffer_size = array.size() * sizeof(array[0]);
|
const auto buffer_size = array.size() * sizeof(array[0]);
|
||||||
glGenBuffers(1, &buffer_name);
|
test_gl(glGenBuffers, 1, &buffer_name);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffer_name);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, buffer_name);
|
||||||
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW);
|
test_gl(glBufferData, GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW);
|
||||||
|
|
||||||
glGenVertexArrays(1, &vertex_array_name);
|
test_gl(glGenVertexArrays, 1, &vertex_array_name);
|
||||||
glBindVertexArray(vertex_array_name);
|
test_gl(glBindVertexArray, vertex_array_name);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffer_name);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, buffer_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanTarget::ScanTarget(GLuint target_framebuffer, float output_gamma) :
|
ScanTarget::ScanTarget(GLuint target_framebuffer, float output_gamma) :
|
||||||
@@ -89,11 +90,11 @@ ScanTarget::ScanTarget(GLuint target_framebuffer, float output_gamma) :
|
|||||||
// and specify GL_MAP_PERSISTENT_BIT. Then map the buffer now, and let the client
|
// and specify GL_MAP_PERSISTENT_BIT. Then map the buffer now, and let the client
|
||||||
// write straight into it.
|
// write straight into it.
|
||||||
|
|
||||||
glGenTextures(1, &write_area_texture_name_);
|
test_gl(glGenTextures, 1, &write_area_texture_name_);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
test_gl(glClearColor, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR);
|
test_gl(glBlendFunc, GL_SRC_ALPHA, GL_CONSTANT_COLOR);
|
||||||
glBlendColor(0.4f, 0.4f, 0.4f, 1.0f);
|
test_gl(glBlendColor, 0.4f, 0.4f, 0.4f, 1.0f);
|
||||||
|
|
||||||
is_drawing_.clear();
|
is_drawing_.clear();
|
||||||
}
|
}
|
||||||
@@ -307,8 +308,8 @@ void ScanTarget::setup_pipeline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare to bind line shaders.
|
// Prepare to bind line shaders.
|
||||||
glBindVertexArray(line_vertex_array_);
|
test_gl(glBindVertexArray, line_vertex_array_);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, line_buffer_name_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, line_buffer_name_);
|
||||||
|
|
||||||
// Destroy or create a QAM buffer and shader, if appropriate.
|
// Destroy or create a QAM buffer and shader, if appropriate.
|
||||||
const bool needs_qam_buffer = (modals_.display_type == DisplayType::CompositeColour || modals_.display_type == DisplayType::SVideo);
|
const bool needs_qam_buffer = (modals_.display_type == DisplayType::CompositeColour || modals_.display_type == DisplayType::SVideo);
|
||||||
@@ -337,8 +338,8 @@ void ScanTarget::setup_pipeline() {
|
|||||||
|
|
||||||
// Establish an input shader.
|
// Establish an input shader.
|
||||||
input_shader_ = composition_shader();
|
input_shader_ = composition_shader();
|
||||||
glBindVertexArray(scan_vertex_array_);
|
test_gl(glBindVertexArray, scan_vertex_array_);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, scan_buffer_name_);
|
||||||
enable_vertex_attributes(ShaderType::Composition, *input_shader_);
|
enable_vertex_attributes(ShaderType::Composition, *input_shader_);
|
||||||
set_uniforms(ShaderType::Composition, *input_shader_);
|
set_uniforms(ShaderType::Composition, *input_shader_);
|
||||||
input_shader_->set_uniform("textureName", GLint(SourceDataTextureUnit - GL_TEXTURE0));
|
input_shader_->set_uniform("textureName", GLint(SourceDataTextureUnit - GL_TEXTURE0));
|
||||||
@@ -370,13 +371,14 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
// Submit scans; only the new ones need to be communicated.
|
// Submit scans; only the new ones need to be communicated.
|
||||||
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
||||||
if(new_scans) {
|
if(new_scans) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, scan_buffer_name_);
|
||||||
|
|
||||||
// Map only the required portion of the buffer.
|
// Map only the required portion of the buffer.
|
||||||
const size_t new_scans_size = new_scans * sizeof(Scan);
|
const size_t new_scans_size = new_scans * sizeof(Scan);
|
||||||
uint8_t *const destination = static_cast<uint8_t *>(
|
uint8_t *const destination = static_cast<uint8_t *>(
|
||||||
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
|
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
|
||||||
);
|
);
|
||||||
|
test_gl_error();
|
||||||
|
|
||||||
if(read_pointers.scan_buffer < submit_pointers.scan_buffer) {
|
if(read_pointers.scan_buffer < submit_pointers.scan_buffer) {
|
||||||
memcpy(destination, &scan_buffer_[read_pointers.scan_buffer], new_scans_size);
|
memcpy(destination, &scan_buffer_[read_pointers.scan_buffer], new_scans_size);
|
||||||
@@ -387,23 +389,23 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flush and unmap the buffer.
|
// Flush and unmap the buffer.
|
||||||
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size));
|
test_gl(glFlushMappedBufferRange, GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size));
|
||||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
test_gl(glUnmapBuffer, GL_ARRAY_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit texture.
|
// Submit texture.
|
||||||
if(submit_pointers.write_area != read_pointers.write_area) {
|
if(submit_pointers.write_area != read_pointers.write_area) {
|
||||||
glActiveTexture(SourceDataTextureUnit);
|
test_gl(glActiveTexture, SourceDataTextureUnit);
|
||||||
glBindTexture(GL_TEXTURE_2D, write_area_texture_name_);
|
test_gl(glBindTexture, GL_TEXTURE_2D, write_area_texture_name_);
|
||||||
|
|
||||||
// Create storage for the texture if it doesn't yet exist; this was deferred until here
|
// Create storage for the texture if it doesn't yet exist; this was deferred until here
|
||||||
// because the pixel format wasn't initially known.
|
// because the pixel format wasn't initially known.
|
||||||
if(!texture_exists_) {
|
if(!texture_exists_) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexImage2D(
|
test_gl(glTexImage2D,
|
||||||
GL_TEXTURE_2D,
|
GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
internalFormatForDepth(data_type_size_),
|
internalFormatForDepth(data_type_size_),
|
||||||
@@ -420,30 +422,33 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
const auto end_y = TextureAddressGetY(submit_pointers.write_area);
|
const auto end_y = TextureAddressGetY(submit_pointers.write_area);
|
||||||
if(end_y >= start_y) {
|
if(end_y >= start_y) {
|
||||||
// Submit the direct region from the submit pointer to the read pointer.
|
// Submit the direct region from the submit pointer to the read pointer.
|
||||||
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
test_gl(glTexSubImage2D,
|
||||||
0, start_y,
|
GL_TEXTURE_2D, 0,
|
||||||
WriteAreaWidth,
|
0, start_y,
|
||||||
1 + end_y - start_y,
|
WriteAreaWidth,
|
||||||
formatForDepth(data_type_size_),
|
1 + end_y - start_y,
|
||||||
GL_UNSIGNED_BYTE,
|
formatForDepth(data_type_size_),
|
||||||
&write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]);
|
GL_UNSIGNED_BYTE,
|
||||||
|
&write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]);
|
||||||
} else {
|
} else {
|
||||||
// The circular buffer wrapped around; submit the data from the read pointer to the end of
|
// The circular buffer wrapped around; submit the data from the read pointer to the end of
|
||||||
// the buffer and from the start of the buffer to the submit pointer.
|
// the buffer and from the start of the buffer to the submit pointer.
|
||||||
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
test_gl(glTexSubImage2D,
|
||||||
0, 0,
|
GL_TEXTURE_2D, 0,
|
||||||
WriteAreaWidth,
|
0, 0,
|
||||||
1 + end_y,
|
WriteAreaWidth,
|
||||||
formatForDepth(data_type_size_),
|
1 + end_y,
|
||||||
GL_UNSIGNED_BYTE,
|
formatForDepth(data_type_size_),
|
||||||
&write_area_texture_[0]);
|
GL_UNSIGNED_BYTE,
|
||||||
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
&write_area_texture_[0]);
|
||||||
0, start_y,
|
test_gl(glTexSubImage2D,
|
||||||
WriteAreaWidth,
|
GL_TEXTURE_2D, 0,
|
||||||
WriteAreaHeight - start_y,
|
0, start_y,
|
||||||
formatForDepth(data_type_size_),
|
WriteAreaWidth,
|
||||||
GL_UNSIGNED_BYTE,
|
WriteAreaHeight - start_y,
|
||||||
&write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]);
|
formatForDepth(data_type_size_),
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
&write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,25 +460,25 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
const uint16_t first_line_to_clear = (read_pointers.line+1)%line_buffer_.size();
|
const uint16_t first_line_to_clear = (read_pointers.line+1)%line_buffer_.size();
|
||||||
const uint16_t final_line_to_clear = submit_pointers.line;
|
const uint16_t final_line_to_clear = submit_pointers.line;
|
||||||
if(first_line_to_clear != final_line_to_clear) {
|
if(first_line_to_clear != final_line_to_clear) {
|
||||||
glEnable(GL_SCISSOR_TEST);
|
test_gl(glEnable, GL_SCISSOR_TEST);
|
||||||
|
|
||||||
if(first_line_to_clear < final_line_to_clear) {
|
if(first_line_to_clear < final_line_to_clear) {
|
||||||
glScissor(0, first_line_to_clear, unprocessed_line_texture_.get_width(), final_line_to_clear - first_line_to_clear);
|
test_gl(glScissor, 0, first_line_to_clear, unprocessed_line_texture_.get_width(), final_line_to_clear - first_line_to_clear);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
test_gl(glClear, GL_COLOR_BUFFER_BIT);
|
||||||
} else {
|
} else {
|
||||||
glScissor(0, 0, unprocessed_line_texture_.get_width(), final_line_to_clear);
|
test_gl(glScissor, 0, 0, unprocessed_line_texture_.get_width(), final_line_to_clear);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
test_gl(glClear, GL_COLOR_BUFFER_BIT);
|
||||||
glScissor(0, first_line_to_clear, unprocessed_line_texture_.get_width(), unprocessed_line_texture_.get_height() - first_line_to_clear);
|
test_gl(glScissor, 0, first_line_to_clear, unprocessed_line_texture_.get_width(), unprocessed_line_texture_.get_height() - first_line_to_clear);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
test_gl(glClear, GL_COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
test_gl(glDisable, GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply new spans. They definitely always go to the first buffer.
|
// Apply new spans. They definitely always go to the first buffer.
|
||||||
glBindVertexArray(scan_vertex_array_);
|
test_gl(glBindVertexArray, scan_vertex_array_);
|
||||||
input_shader_->bind();
|
input_shader_->bind();
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(new_scans));
|
test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(new_scans));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the accumulation buffer is properly sized.
|
// Ensure the accumulation buffer is properly sized.
|
||||||
@@ -488,13 +493,13 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
true));
|
true));
|
||||||
if(accumulation_texture_) {
|
if(accumulation_texture_) {
|
||||||
new_framebuffer->bind_framebuffer();
|
new_framebuffer->bind_framebuffer();
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
test_gl(glClear, GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
glActiveTexture(AccumulationTextureUnit);
|
test_gl(glActiveTexture, AccumulationTextureUnit);
|
||||||
accumulation_texture_->bind_texture();
|
accumulation_texture_->bind_texture();
|
||||||
accumulation_texture_->draw(float(output_width) / float(output_height));
|
accumulation_texture_->draw(float(output_width) / float(output_height));
|
||||||
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
test_gl(glClear, GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
new_framebuffer->bind_texture();
|
new_framebuffer->bind_texture();
|
||||||
}
|
}
|
||||||
@@ -510,7 +515,7 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
uint16_t new_lines = (submit_pointers.line + LineBufferHeight - read_pointers.line) % LineBufferHeight;
|
uint16_t new_lines = (submit_pointers.line + LineBufferHeight - read_pointers.line) % LineBufferHeight;
|
||||||
if(new_lines) {
|
if(new_lines) {
|
||||||
// Prepare to output lines.
|
// Prepare to output lines.
|
||||||
glBindVertexArray(line_vertex_array_);
|
test_gl(glBindVertexArray, line_vertex_array_);
|
||||||
|
|
||||||
// Bind the accumulation framebuffer, unless there's going to be QAM work first.
|
// Bind the accumulation framebuffer, unless there's going to be QAM work first.
|
||||||
if(!qam_separation_shader_ || line_metadata_buffer_[read_pointers.line].is_first_in_frame) {
|
if(!qam_separation_shader_ || line_metadata_buffer_[read_pointers.line].is_first_in_frame) {
|
||||||
@@ -518,16 +523,16 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
output_shader_->bind();
|
output_shader_->bind();
|
||||||
|
|
||||||
// Enable blending and stenciling.
|
// Enable blending and stenciling.
|
||||||
glEnable(GL_BLEND);
|
test_gl(glEnable, GL_BLEND);
|
||||||
glEnable(GL_STENCIL_TEST);
|
test_gl(glEnable, GL_STENCIL_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the proper stencil function regardless.
|
// Set the proper stencil function regardless.
|
||||||
glStencilFunc(GL_EQUAL, 0, GLuint(~0));
|
test_gl(glStencilFunc, GL_EQUAL, 0, GLuint(~0));
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
test_gl(glStencilOp, GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
|
|
||||||
// Prepare to upload data that will consitute lines.
|
// Prepare to upload data that will consitute lines.
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, line_buffer_name_);
|
test_gl(glBindBuffer, GL_ARRAY_BUFFER, line_buffer_name_);
|
||||||
|
|
||||||
// Divide spans by which frame they're in.
|
// Divide spans by which frame they're in.
|
||||||
uint16_t start_line = read_pointers.line;
|
uint16_t start_line = read_pointers.line;
|
||||||
@@ -547,10 +552,10 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
full_display_rectangle_.draw(0.0f, 0.0f, 0.0f);
|
full_display_rectangle_.draw(0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
stencil_is_valid_ = true;
|
stencil_is_valid_ = true;
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
test_gl(glClear, GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
// Rebind the program for span output.
|
// Rebind the program for span output.
|
||||||
glBindVertexArray(line_vertex_array_);
|
test_gl(glBindVertexArray, line_vertex_array_);
|
||||||
if(!qam_separation_shader_) {
|
if(!qam_separation_shader_) {
|
||||||
output_shader_->bind();
|
output_shader_->bind();
|
||||||
}
|
}
|
||||||
@@ -559,56 +564,57 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
|||||||
// Upload.
|
// Upload.
|
||||||
const auto buffer_size = lines * sizeof(Line);
|
const auto buffer_size = lines * sizeof(Line);
|
||||||
if(!end_line || end_line > start_line) {
|
if(!end_line || end_line > start_line) {
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), &line_buffer_[start_line]);
|
test_gl(glBufferSubData, GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), &line_buffer_[start_line]);
|
||||||
} else {
|
} else {
|
||||||
uint8_t *destination = static_cast<uint8_t *>(
|
uint8_t *destination = static_cast<uint8_t *>(
|
||||||
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
|
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
|
||||||
);
|
);
|
||||||
assert(destination);
|
assert(destination);
|
||||||
|
test_gl_error();
|
||||||
|
|
||||||
const size_t buffer_length = line_buffer_.size() * sizeof(Line);
|
const size_t buffer_length = line_buffer_.size() * sizeof(Line);
|
||||||
const size_t start_position = start_line * sizeof(Line);
|
const size_t start_position = start_line * sizeof(Line);
|
||||||
memcpy(&destination[0], &line_buffer_[start_line], buffer_length - start_position);
|
memcpy(&destination[0], &line_buffer_[start_line], buffer_length - start_position);
|
||||||
memcpy(&destination[buffer_length - start_position], &line_buffer_[0], end_line * sizeof(Line));
|
memcpy(&destination[buffer_length - start_position], &line_buffer_[0], end_line * sizeof(Line));
|
||||||
|
|
||||||
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size));
|
test_gl(glFlushMappedBufferRange, GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size));
|
||||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
test_gl(glUnmapBuffer, GL_ARRAY_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce colour information, if required.
|
// Produce colour information, if required.
|
||||||
if(qam_separation_shader_) {
|
if(qam_separation_shader_) {
|
||||||
qam_separation_shader_->bind();
|
qam_separation_shader_->bind();
|
||||||
qam_chroma_texture_->bind_framebuffer();
|
qam_chroma_texture_->bind_framebuffer();
|
||||||
glClear(GL_COLOR_BUFFER_BIT); // TODO: this is here as a hint that the old framebuffer doesn't need reloading;
|
test_gl(glClear, GL_COLOR_BUFFER_BIT); // TODO: this is here as a hint that the old framebuffer doesn't need reloading;
|
||||||
// test whether that's a valid optimisation on desktop OpenGL.
|
// test whether that's a valid optimisation on desktop OpenGL.
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
test_gl(glDisable, GL_BLEND);
|
||||||
glDisable(GL_STENCIL_TEST);
|
test_gl(glDisable, GL_STENCIL_TEST);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines));
|
test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines));
|
||||||
|
|
||||||
accumulation_texture_->bind_framebuffer();
|
accumulation_texture_->bind_framebuffer();
|
||||||
output_shader_->bind();
|
output_shader_->bind();
|
||||||
glEnable(GL_BLEND);
|
test_gl(glEnable, GL_BLEND);
|
||||||
glEnable(GL_STENCIL_TEST);
|
test_gl(glEnable, GL_STENCIL_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render to the output.
|
// Render to the output.
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines));
|
test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines));
|
||||||
|
|
||||||
start_line = end_line;
|
start_line = end_line;
|
||||||
new_lines -= lines;
|
new_lines -= lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable blending and the stencil test again.
|
// Disable blending and the stencil test again.
|
||||||
glDisable(GL_STENCIL_TEST);
|
test_gl(glDisable, GL_STENCIL_TEST);
|
||||||
glDisable(GL_BLEND);
|
test_gl(glDisable, GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the accumulatiion texture to the target.
|
// Copy the accumulatiion texture to the target.
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, target_framebuffer_);
|
test_gl(glBindFramebuffer, GL_FRAMEBUFFER, target_framebuffer_);
|
||||||
glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height);
|
test_gl(glViewport, 0, 0, (GLsizei)output_width, (GLsizei)output_height);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
test_gl(glClear, GL_COLOR_BUFFER_BIT);
|
||||||
accumulation_texture_->bind_texture();
|
accumulation_texture_->bind_texture();
|
||||||
accumulation_texture_->draw(float(output_width) / float(output_height), 4.0f / 255.0f);
|
accumulation_texture_->draw(float(output_width) / float(output_height), 4.0f / 255.0f);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user