1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +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 "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;

View File

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

View File

@ -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());
}

View File

@ -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_;
};
}