mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Pushed responsibility for submitting texture contents up to the texture builder, simplifying the interface.
This commit is contained in:
parent
5c5e44874f
commit
6ac20e0066
@ -13,30 +13,6 @@
|
||||
#include "../../../SignalProcessing/FIRFilter.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 {
|
||||
GLsizei location, length;
|
||||
};
|
||||
@ -78,8 +54,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
|
||||
_rgb_shader(nullptr),
|
||||
_last_output_width(0),
|
||||
_last_output_height(0),
|
||||
_fence(nullptr),
|
||||
_texture_builder(new TextureBuilder(buffer_depth))
|
||||
_fence(nullptr)
|
||||
{
|
||||
_output_buffer.data.resize(OutputVertexBufferDataSize);
|
||||
_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));
|
||||
|
||||
// create the surce texture
|
||||
glGenTextures(1, &textureName);
|
||||
glActiveTexture(source_data_texture_unit);
|
||||
glBindTexture(GL_TEXTURE_2D, textureName);
|
||||
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);
|
||||
_texture_builder.reset(new TextureBuilder(buffer_depth));
|
||||
|
||||
// create the output vertex array
|
||||
glGenVertexArrays(1, &output_vertex_array);
|
||||
@ -122,7 +91,6 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
|
||||
|
||||
OpenGLOutputBuilder::~OpenGLOutputBuilder()
|
||||
{
|
||||
glDeleteTextures(1, &textureName);
|
||||
glDeleteBuffers(1, &output_array_buffer);
|
||||
glDeleteBuffers(1, &source_array_buffer);
|
||||
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);
|
||||
|
||||
// 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);
|
||||
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
||||
0, 0,
|
||||
InputBufferBuilderWidth, completed_texture_y,
|
||||
formatForDepth(_texture_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE,
|
||||
_texture_builder->get_image_pointer());
|
||||
}
|
||||
glActiveTexture(source_data_texture_unit);
|
||||
_texture_builder->submit();
|
||||
|
||||
// buffer usage restart from 0 for the next time around
|
||||
_composite_src_output_y = 0;
|
||||
|
@ -80,7 +80,7 @@ class OpenGLOutputBuilder {
|
||||
|
||||
unsigned int _last_output_width, _last_output_height;
|
||||
|
||||
GLuint textureName, shadowMaskTextureName;
|
||||
GLuint shadowMaskTextureName;
|
||||
|
||||
GLuint defaultFramebuffer;
|
||||
|
||||
|
@ -8,102 +8,134 @@
|
||||
|
||||
#include "TextureBuilder.hpp"
|
||||
#include "CRTOpenGL.hpp"
|
||||
#include "OpenGL.hpp"
|
||||
#include <string.h>
|
||||
|
||||
using namespace Outputs::CRT;
|
||||
|
||||
TextureBuilder::TextureBuilder(size_t bytes_per_pixel) :
|
||||
_bytes_per_pixel(bytes_per_pixel),
|
||||
_next_write_x_position(0),
|
||||
_next_write_y_position(0)
|
||||
static const GLint internalFormatForDepth(size_t depth)
|
||||
{
|
||||
_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)
|
||||
{
|
||||
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_y_position++;
|
||||
next_write_x_position_ = 0;
|
||||
next_write_y_position_++;
|
||||
|
||||
if(_next_write_y_position == InputBufferBuilderHeight)
|
||||
if(next_write_y_position_ == InputBufferBuilderHeight)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_write_x_position = _next_write_x_position + 1;
|
||||
_write_y_position = _next_write_y_position;
|
||||
_write_target_pointer = (_write_y_position * InputBufferBuilderWidth) + _write_x_position;
|
||||
_next_write_x_position += required_length + 2;
|
||||
write_x_position_ = next_write_x_position_ + 1;
|
||||
write_y_position_ = next_write_y_position_;
|
||||
write_target_pointer_ = (write_y_position_ * InputBufferBuilderWidth) + write_x_position_;
|
||||
next_write_x_position_ += required_length + 2;
|
||||
}
|
||||
else return nullptr;
|
||||
|
||||
return &_image[_write_target_pointer * _bytes_per_pixel];
|
||||
return &image_[write_target_pointer_ * bytes_per_pixel_];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
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);
|
||||
_write_target_pointer = 1;
|
||||
_last_allocation_amount = actual_length;
|
||||
_next_write_x_position = (uint16_t)(actual_length + 2);
|
||||
_write_x_position = 1;
|
||||
_write_y_position = 0;
|
||||
memmove(&image_pointer[bytes_per_pixel_], &image_pointer[write_target_pointer_ * bytes_per_pixel_], actual_length * bytes_per_pixel_);
|
||||
write_target_pointer_ = 1;
|
||||
last_allocation_amount_ = actual_length;
|
||||
next_write_x_position_ = (uint16_t)(actual_length + 2);
|
||||
write_x_position_ = 1;
|
||||
write_y_position_ = 0;
|
||||
}
|
||||
|
||||
// book end the allocation with duplicates of the first and last pixel, to protect
|
||||
// against rounding errors when this run is drawn
|
||||
memcpy( &image_pointer[(_write_target_pointer - 1) * _bytes_per_pixel],
|
||||
&image_pointer[_write_target_pointer * _bytes_per_pixel],
|
||||
_bytes_per_pixel);
|
||||
memcpy( &image_pointer[(write_target_pointer_ - 1) * bytes_per_pixel_],
|
||||
&image_pointer[write_target_pointer_ * bytes_per_pixel_],
|
||||
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],
|
||||
_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_],
|
||||
bytes_per_pixel_);
|
||||
|
||||
// return any allocated length that wasn't actually used to the available pool
|
||||
_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;
|
||||
next_write_x_position_ -= (last_allocation_amount_ - actual_length);
|
||||
}
|
||||
|
||||
uint16_t TextureBuilder::get_last_write_x_position()
|
||||
{
|
||||
return _write_x_position;
|
||||
return write_x_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());
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ namespace CRT {
|
||||
*/
|
||||
class TextureBuilder {
|
||||
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);
|
||||
virtual ~TextureBuilder();
|
||||
|
||||
/// 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.
|
||||
@ -38,42 +40,36 @@ class TextureBuilder {
|
||||
/// and indicates that its actual final size was @c 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.
|
||||
uint16_t get_last_write_x_position();
|
||||
|
||||
/// @returns the row of the most recent allocated write area.
|
||||
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
|
||||
/// being full; @c false if calls may succeed.
|
||||
bool is_full();
|
||||
|
||||
/// Updates the currently-bound texture with all new data provided since the last @c submit.
|
||||
void submit();
|
||||
|
||||
private:
|
||||
// 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
|
||||
uint16_t _write_x_position, _write_y_position;
|
||||
uint16_t write_x_position_, write_y_position_;
|
||||
|
||||
// details of the most recent allocation
|
||||
size_t _write_target_pointer;
|
||||
size_t _last_allocation_amount;
|
||||
size_t write_target_pointer_;
|
||||
size_t last_allocation_amount_;
|
||||
|
||||
// the buffer size
|
||||
size_t _bytes_per_pixel;
|
||||
size_t bytes_per_pixel_;
|
||||
|
||||
// the buffer
|
||||
std::vector<uint8_t> _image;
|
||||
std::vector<uint8_t> image_;
|
||||
GLuint texture_name_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user