1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 16:31:31 +00:00

Pushed responsibility for submitting texture contents up to the texture builder, simplifying the interface.

This commit is contained in:
Thomas Harte 2016-11-16 23:13:06 +08:00
parent 5c5e44874f
commit 6ac20e0066
4 changed files with 99 additions and 111 deletions

View File

@ -13,30 +13,6 @@
#include "../../../SignalProcessing/FIRFilter.hpp" #include "../../../SignalProcessing/FIRFilter.hpp"
#include "Shaders/OutputShader.hpp" #include "Shaders/OutputShader.hpp"
static const GLint internalFormatForDepth(size_t depth)
{
switch(depth)
{
default: return GL_FALSE;
case 1: return GL_R8UI;
case 2: return GL_RG8UI;
case 3: return GL_RGB8UI;
case 4: return GL_RGBA8UI;
}
}
static const GLenum formatForDepth(size_t depth)
{
switch(depth)
{
default: return GL_FALSE;
case 1: return GL_RED_INTEGER;
case 2: return GL_RG_INTEGER;
case 3: return GL_RGB_INTEGER;
case 4: return GL_RGBA_INTEGER;
}
}
struct Range { struct Range {
GLsizei location, length; GLsizei location, length;
}; };
@ -78,8 +54,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
_rgb_shader(nullptr), _rgb_shader(nullptr),
_last_output_width(0), _last_output_width(0),
_last_output_height(0), _last_output_height(0),
_fence(nullptr), _fence(nullptr)
_texture_builder(new TextureBuilder(buffer_depth))
{ {
_output_buffer.data.resize(OutputVertexBufferDataSize); _output_buffer.data.resize(OutputVertexBufferDataSize);
_source_buffer.data.resize(SourceVertexBufferDataSize); _source_buffer.data.resize(SourceVertexBufferDataSize);
@ -94,14 +69,8 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
filteredTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)); filteredTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit));
// create the surce texture // create the surce texture
glGenTextures(1, &textureName);
glActiveTexture(source_data_texture_unit); glActiveTexture(source_data_texture_unit);
glBindTexture(GL_TEXTURE_2D, textureName); _texture_builder.reset(new TextureBuilder(buffer_depth));
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(GL_TEXTURE_2D, 0, internalFormatForDepth(_texture_builder->get_bytes_per_pixel()), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(_texture_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE, nullptr);
// create the output vertex array // create the output vertex array
glGenVertexArrays(1, &output_vertex_array); glGenVertexArrays(1, &output_vertex_array);
@ -122,7 +91,6 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
OpenGLOutputBuilder::~OpenGLOutputBuilder() OpenGLOutputBuilder::~OpenGLOutputBuilder()
{ {
glDeleteTextures(1, &textureName);
glDeleteBuffers(1, &output_array_buffer); glDeleteBuffers(1, &output_array_buffer);
glDeleteBuffers(1, &source_array_buffer); glDeleteBuffers(1, &source_array_buffer);
glDeleteVertexArrays(1, &output_vertex_array); glDeleteVertexArrays(1, &output_vertex_array);
@ -190,16 +158,8 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
GLsizei submitted_source_data = submitArrayData(source_array_buffer, _source_buffer.data.data(), &_source_buffer.pointer); GLsizei submitted_source_data = submitArrayData(source_array_buffer, _source_buffer.data.data(), &_source_buffer.pointer);
// upload new source pixels, if any // upload new source pixels, if any
uint16_t completed_texture_y = _texture_builder->get_and_finalise_current_line();
if(completed_texture_y)
{
glActiveTexture(source_data_texture_unit); glActiveTexture(source_data_texture_unit);
glTexSubImage2D( GL_TEXTURE_2D, 0, _texture_builder->submit();
0, 0,
InputBufferBuilderWidth, completed_texture_y,
formatForDepth(_texture_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE,
_texture_builder->get_image_pointer());
}
// buffer usage restart from 0 for the next time around // buffer usage restart from 0 for the next time around
_composite_src_output_y = 0; _composite_src_output_y = 0;

View File

@ -80,7 +80,7 @@ class OpenGLOutputBuilder {
unsigned int _last_output_width, _last_output_height; unsigned int _last_output_width, _last_output_height;
GLuint textureName, shadowMaskTextureName; GLuint shadowMaskTextureName;
GLuint defaultFramebuffer; GLuint defaultFramebuffer;

View File

@ -8,102 +8,134 @@
#include "TextureBuilder.hpp" #include "TextureBuilder.hpp"
#include "CRTOpenGL.hpp" #include "CRTOpenGL.hpp"
#include "OpenGL.hpp"
#include <string.h> #include <string.h>
using namespace Outputs::CRT; using namespace Outputs::CRT;
TextureBuilder::TextureBuilder(size_t bytes_per_pixel) : static const GLint internalFormatForDepth(size_t depth)
_bytes_per_pixel(bytes_per_pixel),
_next_write_x_position(0),
_next_write_y_position(0)
{ {
_image.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight); switch(depth)
{
default: return GL_FALSE;
case 1: return GL_R8UI;
case 2: return GL_RG8UI;
case 3: return GL_RGB8UI;
case 4: return GL_RGBA8UI;
}
}
static const GLenum formatForDepth(size_t depth)
{
switch(depth)
{
default: return GL_FALSE;
case 1: return GL_RED_INTEGER;
case 2: return GL_RG_INTEGER;
case 3: return GL_RGB_INTEGER;
case 4: return GL_RGBA_INTEGER;
}
}
TextureBuilder::TextureBuilder(size_t bytes_per_pixel) :
bytes_per_pixel_(bytes_per_pixel),
next_write_x_position_(0),
next_write_y_position_(0)
{
image_.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight);
glGenTextures(1, &texture_name_);
glBindTexture(GL_TEXTURE_2D, texture_name_);
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(GL_TEXTURE_2D, 0, internalFormatForDepth(bytes_per_pixel), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(bytes_per_pixel), GL_UNSIGNED_BYTE, nullptr);
}
TextureBuilder::~TextureBuilder()
{
glDeleteTextures(1, &texture_name_);
} }
uint8_t *TextureBuilder::allocate_write_area(size_t required_length) uint8_t *TextureBuilder::allocate_write_area(size_t required_length)
{ {
if(_next_write_y_position != InputBufferBuilderHeight) if(next_write_y_position_ != InputBufferBuilderHeight)
{ {
_last_allocation_amount = required_length; last_allocation_amount_ = required_length;
if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth) if(next_write_x_position_ + required_length + 2 > InputBufferBuilderWidth)
{ {
_next_write_x_position = 0; next_write_x_position_ = 0;
_next_write_y_position++; next_write_y_position_++;
if(_next_write_y_position == InputBufferBuilderHeight) if(next_write_y_position_ == InputBufferBuilderHeight)
return nullptr; return nullptr;
} }
_write_x_position = _next_write_x_position + 1; write_x_position_ = next_write_x_position_ + 1;
_write_y_position = _next_write_y_position; write_y_position_ = next_write_y_position_;
_write_target_pointer = (_write_y_position * InputBufferBuilderWidth) + _write_x_position; write_target_pointer_ = (write_y_position_ * InputBufferBuilderWidth) + write_x_position_;
_next_write_x_position += required_length + 2; next_write_x_position_ += required_length + 2;
} }
else return nullptr; else return nullptr;
return &_image[_write_target_pointer * _bytes_per_pixel]; return &image_[write_target_pointer_ * bytes_per_pixel_];
} }
bool TextureBuilder::is_full() bool TextureBuilder::is_full()
{ {
return (_next_write_y_position == InputBufferBuilderHeight); return (next_write_y_position_ == InputBufferBuilderHeight);
} }
void TextureBuilder::reduce_previous_allocation_to(size_t actual_length) void TextureBuilder::reduce_previous_allocation_to(size_t actual_length)
{ {
if(_next_write_y_position == InputBufferBuilderHeight) return; if(next_write_y_position_ == InputBufferBuilderHeight) return;
uint8_t *const image_pointer = _image.data(); uint8_t *const image_pointer = image_.data();
// correct if the writing cursor was reset while a client was writing // correct if the writing cursor was reset while a client was writing
if(_next_write_x_position == 0 && _next_write_y_position == 0) if(next_write_x_position_ == 0 && next_write_y_position_ == 0)
{ {
memmove(&image_pointer[_bytes_per_pixel], &image_pointer[_write_target_pointer * _bytes_per_pixel], actual_length * _bytes_per_pixel); memmove(&image_pointer[bytes_per_pixel_], &image_pointer[write_target_pointer_ * bytes_per_pixel_], actual_length * bytes_per_pixel_);
_write_target_pointer = 1; write_target_pointer_ = 1;
_last_allocation_amount = actual_length; last_allocation_amount_ = actual_length;
_next_write_x_position = (uint16_t)(actual_length + 2); next_write_x_position_ = (uint16_t)(actual_length + 2);
_write_x_position = 1; write_x_position_ = 1;
_write_y_position = 0; write_y_position_ = 0;
} }
// book end the allocation with duplicates of the first and last pixel, to protect // book end the allocation with duplicates of the first and last pixel, to protect
// against rounding errors when this run is drawn // against rounding errors when this run is drawn
memcpy( &image_pointer[(_write_target_pointer - 1) * _bytes_per_pixel], memcpy( &image_pointer[(write_target_pointer_ - 1) * bytes_per_pixel_],
&image_pointer[_write_target_pointer * _bytes_per_pixel], &image_pointer[write_target_pointer_ * bytes_per_pixel_],
_bytes_per_pixel); bytes_per_pixel_);
memcpy( &image_pointer[(_write_target_pointer + actual_length) * _bytes_per_pixel], memcpy( &image_pointer[(write_target_pointer_ + actual_length) * bytes_per_pixel_],
&image_pointer[(_write_target_pointer + actual_length - 1) * _bytes_per_pixel], &image_pointer[(write_target_pointer_ + actual_length - 1) * bytes_per_pixel_],
_bytes_per_pixel); bytes_per_pixel_);
// return any allocated length that wasn't actually used to the available pool // return any allocated length that wasn't actually used to the available pool
_next_write_x_position -= (_last_allocation_amount - actual_length); next_write_x_position_ -= (last_allocation_amount_ - actual_length);
}
uint8_t *TextureBuilder::get_image_pointer()
{
return _image.data();
}
uint16_t TextureBuilder::get_and_finalise_current_line()
{
uint16_t result = _write_y_position + (_next_write_x_position ? 1 : 0);
_next_write_x_position = _next_write_y_position = 0;
return result;
} }
uint16_t TextureBuilder::get_last_write_x_position() uint16_t TextureBuilder::get_last_write_x_position()
{ {
return _write_x_position; return write_x_position_;
} }
uint16_t TextureBuilder::get_last_write_y_position() uint16_t TextureBuilder::get_last_write_y_position()
{ {
return _write_y_position; return write_y_position_;
} }
size_t TextureBuilder::get_bytes_per_pixel() void TextureBuilder::submit()
{ {
return _bytes_per_pixel; uint16_t height = write_y_position_ + (next_write_x_position_ ? 1 : 0);
next_write_x_position_ = next_write_y_position_ = 0;
glTexSubImage2D( GL_TEXTURE_2D, 0,
0, 0,
InputBufferBuilderWidth, height,
formatForDepth(bytes_per_pixel_), GL_UNSIGNED_BYTE,
image_.data());
} }

View File

@ -26,8 +26,10 @@ namespace CRT {
*/ */
class TextureBuilder { class TextureBuilder {
public: public:
/// Constructs an instance of InputTextureBuilder that contains a texture of colour depth @c bytes_per_pixel. /// Constructs an instance of InputTextureBuilder that contains a texture of colour depth @c bytes_per_pixel;
/// this creates a new texture and binds it to the current active texture unit.
TextureBuilder(size_t bytes_per_pixel); TextureBuilder(size_t bytes_per_pixel);
virtual ~TextureBuilder();
/// Finds the first available space of at least @c required_length pixels in size. Calls must be paired off /// Finds the first available space of at least @c required_length pixels in size. Calls must be paired off
/// with calls to @c reduce_previous_allocation_to. /// with calls to @c reduce_previous_allocation_to.
@ -38,42 +40,36 @@ class TextureBuilder {
/// and indicates that its actual final size was @c actual_length. /// and indicates that its actual final size was @c actual_length.
void reduce_previous_allocation_to(size_t actual_length); void reduce_previous_allocation_to(size_t actual_length);
/// @returns the row that was the final one to receive data; also resets the builder to restart filling of
/// the texture from row 0.
uint16_t get_and_finalise_current_line();
/// @returns a pointer to the image data for this texture.
uint8_t *get_image_pointer();
/// @returns the start column for the most recent allocated write area. /// @returns the start column for the most recent allocated write area.
uint16_t get_last_write_x_position(); uint16_t get_last_write_x_position();
/// @returns the row of the most recent allocated write area. /// @returns the row of the most recent allocated write area.
uint16_t get_last_write_y_position(); uint16_t get_last_write_y_position();
/// @returns the number of bytes per pixel as supplied to the constructor.
size_t get_bytes_per_pixel();
/// @returns @c true if all future calls to @c allocate_write_area will fail on account of the input texture /// @returns @c true if all future calls to @c allocate_write_area will fail on account of the input texture
/// being full; @c false if calls may succeed. /// being full; @c false if calls may succeed.
bool is_full(); bool is_full();
/// Updates the currently-bound texture with all new data provided since the last @c submit.
void submit();
private: private:
// where pixel data will be put to the next time a write is requested // where pixel data will be put to the next time a write is requested
uint16_t _next_write_x_position, _next_write_y_position; uint16_t next_write_x_position_, next_write_y_position_;
// the most recent position returned for pixel data writing // the most recent position returned for pixel data writing
uint16_t _write_x_position, _write_y_position; uint16_t write_x_position_, write_y_position_;
// details of the most recent allocation // details of the most recent allocation
size_t _write_target_pointer; size_t write_target_pointer_;
size_t _last_allocation_amount; size_t last_allocation_amount_;
// the buffer size // the buffer size
size_t _bytes_per_pixel; size_t bytes_per_pixel_;
// the buffer // the buffer
std::vector<uint8_t> _image; std::vector<uint8_t> image_;
GLuint texture_name_;
}; };
} }