From 8ecf885629062087c1e17bede6de6b47e26a98b4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 18 Feb 2019 10:29:40 -0500 Subject: [PATCH] Attempts to put in better OpenGL safety rails. --- Outputs/OpenGL/OpenGL.hpp | 18 +++ Outputs/OpenGL/Primitives/Rectangle.cpp | 22 +-- Outputs/OpenGL/Primitives/Shader.cpp | 46 +++--- Outputs/OpenGL/Primitives/TextureTarget.cpp | 64 ++++---- Outputs/OpenGL/ScanTarget.cpp | 170 ++++++++++---------- 5 files changed, 172 insertions(+), 148 deletions(-) diff --git a/Outputs/OpenGL/OpenGL.hpp b/Outputs/OpenGL/OpenGL.hpp index af83410a0..cc17cc4f5 100644 --- a/Outputs/OpenGL/OpenGL.hpp +++ b/Outputs/OpenGL/OpenGL.hpp @@ -22,4 +22,22 @@ #include #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 */ diff --git a/Outputs/OpenGL/Primitives/Rectangle.cpp b/Outputs/OpenGL/Primitives/Rectangle.cpp index 07e4e1bd6..e72aa3dc6 100644 --- a/Outputs/OpenGL/Primitives/Rectangle.cpp +++ b/Outputs/OpenGL/Primitives/Rectangle.cpp @@ -33,16 +33,16 @@ Rectangle::Rectangle(float x, float y, float width, float height): ){ pixel_shader_.bind(); - glGenVertexArrays(1, &drawing_vertex_array_); - glGenBuffers(1, &drawing_array_buffer_); + test_gl(glGenVertexArrays, 1, &drawing_vertex_array_); + test_gl(glGenBuffers, 1, &drawing_array_buffer_); - glBindVertexArray(drawing_vertex_array_); - glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_); + test_gl(glBindVertexArray, drawing_vertex_array_); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_); GLint position_attribute = pixel_shader_.get_attrib_location("position"); - glEnableVertexAttribArray(static_cast(position_attribute)); + test_gl(glEnableVertexAttribArray, GLuint(position_attribute)); - glVertexAttribPointer( + test_gl(glVertexAttribPointer, (GLuint)position_attribute, 2, GL_FLOAT, @@ -61,14 +61,14 @@ Rectangle::Rectangle(float x, float y, float width, float height): buffer[6] = x + width; buffer[7] = y + height; // Upload buffer. - glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_); - glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_); + test_gl(glBufferData, GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); } void Rectangle::draw(float red, float green, float blue) { 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_); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + test_gl(glBindVertexArray, drawing_vertex_array_); + test_gl(glDrawArrays, GL_TRIANGLE_STRIP, 0, 4); } diff --git a/Outputs/OpenGL/Primitives/Shader.cpp b/Outputs/OpenGL/Primitives/Shader.cpp index 3e141e751..3c07fc236 100644 --- a/Outputs/OpenGL/Primitives/Shader.cpp +++ b/Outputs/OpenGL/Primitives/Shader.cpp @@ -21,18 +21,18 @@ namespace { GLuint Shader::compile_shader(const std::string &source, GLenum type) { GLuint shader = glCreateShader(type); const char *c_str = source.c_str(); - glShaderSource(shader, 1, &c_str, NULL); - glCompileShader(shader); + test_gl(glShaderSource, shader, 1, &c_str, NULL); + test_gl(glCompileShader, shader); #ifndef NDEBUG GLint isCompiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + test_gl(glGetShaderiv, shader, GL_COMPILE_STATUS, &isCompiled); if(isCompiled == GL_FALSE) { GLint logLength; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + test_gl(glGetShaderiv, shader, GL_INFO_LOG_LENGTH, &logLength); if(logLength > 0) { - GLchar *log = new GLchar[static_cast(logLength)]; - glGetShaderInfoLog(shader, logLength, &logLength, log); + GLchar *log = new GLchar[std::size_t(logLength)]; + test_gl(glGetShaderInfoLog, shader, logLength, &logLength, log); LOG("Compile log:\n" << 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 fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER); - glAttachShader(shader_program_, vertex); - glAttachShader(shader_program_, fragment); + test_gl(glAttachShader, shader_program_, vertex); + test_gl(glAttachShader, shader_program_, fragment); 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 const auto error = glGetError(); switch(error) { @@ -85,20 +85,20 @@ void Shader::init(const std::string &vertex_shader, const std::string &fragment_ #endif } - glLinkProgram(shader_program_); + test_gl(glLinkProgram, shader_program_); #ifndef NDEBUG GLint logLength; - glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength); + test_gl(glGetProgramiv, shader_program_, GL_INFO_LOG_LENGTH, &logLength); if(logLength > 0) { - GLchar *log = new GLchar[static_cast(logLength)]; - glGetProgramInfoLog(shader_program_, logLength, &logLength, log); + GLchar *log = new GLchar[std::size_t(logLength)]; + test_gl(glGetProgramInfoLog, shader_program_, logLength, &logLength, log); LOG("Link log:\n" << log); delete[] log; } GLint didLink = 0; - glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink); + test_gl(glGetProgramiv, shader_program_, GL_LINK_STATUS, &didLink); if(didLink == GL_FALSE) { throw ProgramLinkageError; } @@ -112,7 +112,7 @@ Shader::~Shader() { void Shader::bind() const { // if(bound_shader != this) { - glUseProgram(shader_program_); + test_gl(glUseProgram, shader_program_); // bound_shader = this; // } flush_functions(); @@ -120,7 +120,7 @@ void Shader::bind() const { void Shader::unbind() { // bound_shader = nullptr; - glUseProgram(0); + test_gl(glUseProgram, 0); } 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) { GLint location = get_attrib_location(name); if(location >= 0) { - glEnableVertexAttribArray((GLuint)location); - glVertexAttribPointer((GLuint)location, size, type, normalised, stride, pointer); - glVertexAttribDivisor((GLuint)location, divisor); + test_gl(glEnableVertexAttribArray, GLuint(location)); + test_gl(glVertexAttribPointer, GLuint(location), size, type, normalised, stride, pointer); + test_gl(glVertexAttribDivisor, GLuint(location), divisor); } else { 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) { - std::size_t number_of_values = static_cast(count) * static_cast(size); + std::size_t number_of_values = std::size_t(count) * std::size_t(size); std::vector values_copy(values, values + number_of_values); 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) { - std::size_t number_of_values = static_cast(count) * static_cast(size); + std::size_t number_of_values = std::size_t(count) * std::size_t(size); std::vector values_copy(values, values + number_of_values); 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) { - std::size_t number_of_values = static_cast(count) * static_cast(size); + std::size_t number_of_values = std::size_t(count) * std::size_t(size); std::vector values_copy(values, values + number_of_values); 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) { - std::size_t number_of_values = static_cast(count) * static_cast(size) * static_cast(size); + std::size_t number_of_values = std::size_t(count) * std::size_t(size) * std::size_t(size); std::vector values_copy(values, values + number_of_values); enqueue_function([name, size, count, transpose, values_copy, this] { diff --git a/Outputs/OpenGL/Primitives/TextureTarget.cpp b/Outputs/OpenGL/Primitives/TextureTarget.cpp index 93a344ae1..4c492170c 100644 --- a/Outputs/OpenGL/Primitives/TextureTarget.cpp +++ b/Outputs/OpenGL/Primitives/TextureTarget.cpp @@ -18,8 +18,8 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, height_(height), texture_unit_(texture_unit) { // Generate and bind a frame buffer. - glGenFramebuffers(1, &framebuffer_); - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); + test_gl(glGenFramebuffers, 1, &framebuffer_); + test_gl(glBindFramebuffer, GL_FRAMEBUFFER, framebuffer_); // Round the width and height up to the next power of two. expanded_width_ = 1; @@ -28,23 +28,23 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, while(expanded_height_ < height) expanded_height_ <<= 1; // Generate a texture and bind it to the nominated texture unit. - glGenTextures(1, &texture_); + test_gl(glGenTextures, 1, &texture_); bind_texture(); // Set dimensions and set the user-supplied magnification filter. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast(expanded_width_), static_cast(expanded_height_), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + test_gl(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGBA, GLsizei(expanded_width_), GLsizei(expanded_height_), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // 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. if(has_stencil_buffer) { - glGenRenderbuffers(1, &renderbuffer_); - glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX1, expanded_width_, expanded_height_); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_); + test_gl(glGenRenderbuffers, 1, &renderbuffer_); + test_gl(glBindRenderbuffer, GL_RENDERBUFFER, renderbuffer_); + test_gl(glRenderbufferStorage, GL_RENDERBUFFER, GL_STENCIL_INDEX1, expanded_width_, expanded_height_); + test_gl(glFramebufferRenderbuffer, GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_); } // Check for successful construction. @@ -61,13 +61,13 @@ TextureTarget::~TextureTarget() { } void TextureTarget::bind_framebuffer() { - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); - glViewport(0, 0, width_, height_); + test_gl(glBindFramebuffer, GL_FRAMEBUFFER, framebuffer_); + test_gl(glViewport, 0, 0, width_, height_); } void TextureTarget::bind_texture() const { - glActiveTexture(texture_unit_); - glBindTexture(GL_TEXTURE_2D, texture_); + test_gl(glActiveTexture, texture_unit_); + test_gl(glBindTexture, GL_TEXTURE_2D, texture_); } 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_->bind(); - glGenVertexArrays(1, &drawing_vertex_array_); - glGenBuffers(1, &drawing_array_buffer_); + test_gl(glGenVertexArrays, 1, &drawing_vertex_array_); + test_gl(glGenBuffers, 1, &drawing_array_buffer_); - glBindVertexArray(drawing_vertex_array_); - glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_); + test_gl(glBindVertexArray, drawing_vertex_array_); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_); const GLint position_attribute = pixel_shader_->get_attrib_location("position"); const GLint tex_coord_attribute = pixel_shader_->get_attrib_location("texCoord"); - glEnableVertexAttribArray(static_cast(position_attribute)); - glEnableVertexAttribArray(static_cast(tex_coord_attribute)); + test_gl(glEnableVertexAttribArray, GLuint(position_attribute)); + test_gl(glEnableVertexAttribArray, GLuint(tex_coord_attribute)); const GLsizei vertex_stride = 4 * sizeof(GLfloat); - 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(position_attribute), 2, GL_FLOAT, GL_FALSE, vertex_stride, (void *)0); + 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"); - glUniform1i(texIDUniform, static_cast(texture_unit_ - GL_TEXTURE0)); + test_gl(glUniform1i, texIDUniform, GLint(texture_unit_ - GL_TEXTURE0)); 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[3] = 0.0f; buffer[6] = 0.0f; - buffer[7] = static_cast(height_) / static_cast(expanded_height_); - buffer[10] = static_cast(width_) / static_cast(expanded_width_); + buffer[7] = float(height_) / float(expanded_height_); + buffer[10] = float(width_) / float(expanded_width_); buffer[11] = 0.0f; buffer[14] = buffer[10]; buffer[15] = buffer[7]; // determine positions; rule is to keep the same height and centre - float internal_aspect_ratio = static_cast(width_) / static_cast(height_); + float internal_aspect_ratio = float(width_) / float(height_); float aspect_ratio_ratio = internal_aspect_ratio / aspect_ratio; 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; // upload buffer - glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_); - glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, drawing_array_buffer_); + test_gl(glBufferData, GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); } pixel_shader_->bind(); - glUniform1f(threshold_uniform_, colour_threshold); + test_gl(glUniform1f, threshold_uniform_, colour_threshold); - glBindVertexArray(drawing_vertex_array_); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + test_gl(glBindVertexArray, drawing_vertex_array_); + test_gl(glDrawArrays, GL_TRIANGLE_STRIP, 0, 4); } diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index 0b4e51f62..2de6148c7 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -8,6 +8,7 @@ #include "ScanTarget.hpp" +#include "OpenGL.hpp" #include "Primitives/Rectangle.hpp" #include @@ -62,13 +63,13 @@ const GLenum formatForDepth(std::size_t depth) { template void ScanTarget::allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name) { const auto buffer_size = array.size() * sizeof(array[0]); - glGenBuffers(1, &buffer_name); - glBindBuffer(GL_ARRAY_BUFFER, buffer_name); - glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW); + test_gl(glGenBuffers, 1, &buffer_name); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, buffer_name); + test_gl(glBufferData, GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW); - glGenVertexArrays(1, &vertex_array_name); - glBindVertexArray(vertex_array_name); - glBindBuffer(GL_ARRAY_BUFFER, buffer_name); + test_gl(glGenVertexArrays, 1, &vertex_array_name); + test_gl(glBindVertexArray, vertex_array_name); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, buffer_name); } 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 // write straight into it. - glGenTextures(1, &write_area_texture_name_); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + test_gl(glGenTextures, 1, &write_area_texture_name_); + test_gl(glClearColor, 0.0f, 0.0f, 0.0f, 0.0f); - glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR); - glBlendColor(0.4f, 0.4f, 0.4f, 1.0f); + test_gl(glBlendFunc, GL_SRC_ALPHA, GL_CONSTANT_COLOR); + test_gl(glBlendColor, 0.4f, 0.4f, 0.4f, 1.0f); is_drawing_.clear(); } @@ -307,8 +308,8 @@ void ScanTarget::setup_pipeline() { } // Prepare to bind line shaders. - glBindVertexArray(line_vertex_array_); - glBindBuffer(GL_ARRAY_BUFFER, line_buffer_name_); + test_gl(glBindVertexArray, line_vertex_array_); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, line_buffer_name_); // 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); @@ -337,8 +338,8 @@ void ScanTarget::setup_pipeline() { // Establish an input shader. input_shader_ = composition_shader(); - glBindVertexArray(scan_vertex_array_); - glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_); + test_gl(glBindVertexArray, scan_vertex_array_); + test_gl(glBindBuffer, GL_ARRAY_BUFFER, scan_buffer_name_); enable_vertex_attributes(ShaderType::Composition, *input_shader_); set_uniforms(ShaderType::Composition, *input_shader_); 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. size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size(); 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. const size_t new_scans_size = new_scans * sizeof(Scan); uint8_t *const destination = static_cast( 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) { 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. - glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size)); - glUnmapBuffer(GL_ARRAY_BUFFER); + test_gl(glFlushMappedBufferRange, GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size)); + test_gl(glUnmapBuffer, GL_ARRAY_BUFFER); } // Submit texture. if(submit_pointers.write_area != read_pointers.write_area) { - glActiveTexture(SourceDataTextureUnit); - glBindTexture(GL_TEXTURE_2D, write_area_texture_name_); + test_gl(glActiveTexture, SourceDataTextureUnit); + 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 // because the pixel format wasn't initially known. if(!texture_exists_) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D( + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + test_gl(glTexImage2D, GL_TEXTURE_2D, 0, 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); if(end_y >= start_y) { // Submit the direct region from the submit pointer to the read pointer. - glTexSubImage2D( GL_TEXTURE_2D, 0, - 0, start_y, - WriteAreaWidth, - 1 + end_y - start_y, - formatForDepth(data_type_size_), - GL_UNSIGNED_BYTE, - &write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]); + test_gl(glTexSubImage2D, + GL_TEXTURE_2D, 0, + 0, start_y, + WriteAreaWidth, + 1 + end_y - start_y, + formatForDepth(data_type_size_), + GL_UNSIGNED_BYTE, + &write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]); } else { // 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. - glTexSubImage2D( GL_TEXTURE_2D, 0, - 0, 0, - WriteAreaWidth, - 1 + end_y, - formatForDepth(data_type_size_), - GL_UNSIGNED_BYTE, - &write_area_texture_[0]); - glTexSubImage2D( GL_TEXTURE_2D, 0, - 0, start_y, - WriteAreaWidth, - WriteAreaHeight - start_y, - formatForDepth(data_type_size_), - GL_UNSIGNED_BYTE, - &write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]); + test_gl(glTexSubImage2D, + GL_TEXTURE_2D, 0, + 0, 0, + WriteAreaWidth, + 1 + end_y, + formatForDepth(data_type_size_), + GL_UNSIGNED_BYTE, + &write_area_texture_[0]); + test_gl(glTexSubImage2D, + GL_TEXTURE_2D, 0, + 0, start_y, + WriteAreaWidth, + WriteAreaHeight - start_y, + 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 final_line_to_clear = submit_pointers.line; 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) { - 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(glScissor, 0, first_line_to_clear, unprocessed_line_texture_.get_width(), final_line_to_clear - first_line_to_clear); + test_gl(glClear, GL_COLOR_BUFFER_BIT); } else { - glScissor(0, 0, unprocessed_line_texture_.get_width(), final_line_to_clear); - 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); - glClear(GL_COLOR_BUFFER_BIT); + test_gl(glScissor, 0, 0, unprocessed_line_texture_.get_width(), final_line_to_clear); + test_gl(glClear, GL_COLOR_BUFFER_BIT); + test_gl(glScissor, 0, first_line_to_clear, unprocessed_line_texture_.get_width(), unprocessed_line_texture_.get_height() - first_line_to_clear); + 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. - glBindVertexArray(scan_vertex_array_); + test_gl(glBindVertexArray, scan_vertex_array_); 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. @@ -488,13 +493,13 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) { true)); if(accumulation_texture_) { 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_->draw(float(output_width) / float(output_height)); - glClear(GL_STENCIL_BUFFER_BIT); + test_gl(glClear, GL_STENCIL_BUFFER_BIT); 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; if(new_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. 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(); // Enable blending and stenciling. - glEnable(GL_BLEND); - glEnable(GL_STENCIL_TEST); + test_gl(glEnable, GL_BLEND); + test_gl(glEnable, GL_STENCIL_TEST); } // Set the proper stencil function regardless. - glStencilFunc(GL_EQUAL, 0, GLuint(~0)); - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + test_gl(glStencilFunc, GL_EQUAL, 0, GLuint(~0)); + test_gl(glStencilOp, GL_KEEP, GL_KEEP, GL_INCR); // 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. 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); } stencil_is_valid_ = true; - glClear(GL_STENCIL_BUFFER_BIT); + test_gl(glClear, GL_STENCIL_BUFFER_BIT); // Rebind the program for span output. - glBindVertexArray(line_vertex_array_); + test_gl(glBindVertexArray, line_vertex_array_); if(!qam_separation_shader_) { output_shader_->bind(); } @@ -559,56 +564,57 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) { // Upload. const auto buffer_size = lines * sizeof(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 { uint8_t *destination = static_cast( glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT) ); assert(destination); + test_gl_error(); const size_t buffer_length = line_buffer_.size() * sizeof(Line); const size_t start_position = start_line * sizeof(Line); memcpy(&destination[0], &line_buffer_[start_line], buffer_length - start_position); memcpy(&destination[buffer_length - start_position], &line_buffer_[0], end_line * sizeof(Line)); - glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size)); - glUnmapBuffer(GL_ARRAY_BUFFER); + test_gl(glFlushMappedBufferRange, GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size)); + test_gl(glUnmapBuffer, GL_ARRAY_BUFFER); } // Produce colour information, if required. if(qam_separation_shader_) { qam_separation_shader_->bind(); 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 whether that's a valid optimisation on desktop OpenGL. + 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. - glDisable(GL_BLEND); - glDisable(GL_STENCIL_TEST); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines)); + test_gl(glDisable, GL_BLEND); + test_gl(glDisable, GL_STENCIL_TEST); + test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(lines)); accumulation_texture_->bind_framebuffer(); output_shader_->bind(); - glEnable(GL_BLEND); - glEnable(GL_STENCIL_TEST); + test_gl(glEnable, GL_BLEND); + test_gl(glEnable, GL_STENCIL_TEST); } // 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; new_lines -= lines; } // Disable blending and the stencil test again. - glDisable(GL_STENCIL_TEST); - glDisable(GL_BLEND); + test_gl(glDisable, GL_STENCIL_TEST); + test_gl(glDisable, GL_BLEND); } // Copy the accumulatiion texture to the target. - glBindFramebuffer(GL_FRAMEBUFFER, target_framebuffer_); - glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height); + test_gl(glBindFramebuffer, GL_FRAMEBUFFER, target_framebuffer_); + 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_->draw(float(output_width) / float(output_height), 4.0f / 255.0f);