1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-11 04:28:58 +00:00

Progressed to usage of an array builder and a texture builder up to the point of a successful build.

This commit is contained in:
Thomas Harte 2016-11-17 12:26:04 +08:00
parent 0f3b02edb7
commit 1f91d29434
8 changed files with 134 additions and 184 deletions

View File

@ -67,9 +67,7 @@ CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
is_writing_composite_run_(false), is_writing_composite_run_(false),
delegate_(nullptr), delegate_(nullptr),
frames_since_last_delegate_call_(0), frames_since_last_delegate_call_(0),
openGL_output_builder_(buffer_depth), openGL_output_builder_(buffer_depth) {}
array_builder_(SourceVertexBufferDataSize, OutputVertexBufferDataSize),
texture_builder_(buffer_depth) {}
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int buffer_depth) : CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int buffer_depth) :
CRT(common_output_divisor, buffer_depth) CRT(common_output_divisor, buffer_depth)
@ -133,7 +131,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
uint8_t *next_run = nullptr; uint8_t *next_run = nullptr;
if(is_output_segment && !openGL_output_builder_.composite_output_buffer_is_full()) if(is_output_segment && !openGL_output_builder_.composite_output_buffer_is_full())
{ {
next_run = openGL_output_builder_.get_next_source_run(); next_run = openGL_output_builder_.array_builder.get_input_storage(SourceVertexSize);
} }
if(next_run) if(next_run)
@ -169,8 +167,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
source_input_position_x2() = tex_x; source_input_position_x2() = tex_x;
source_output_position_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position(); source_output_position_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position();
openGL_output_builder_.complete_source_run();
} }
// if this is horizontal retrace then advance the output line counter and bookend an output run // if this is horizontal retrace then advance the output line counter and bookend an output run
@ -184,7 +180,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
if(needs_endpoint) if(needs_endpoint)
{ {
if( if(
openGL_output_builder_.composite_output_run_has_room_for_vertex() && !openGL_output_builder_.array_builder.is_full() &&
!openGL_output_builder_.composite_output_buffer_is_full()) !openGL_output_builder_.composite_output_buffer_is_full())
{ {
if(!is_writing_composite_run_) if(!is_writing_composite_run_)
@ -199,19 +195,19 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// Get and write all those previously unwritten output ys // Get and write all those previously unwritten output ys
uint16_t output_y = openGL_output_builder_.get_composite_output_y(); uint16_t output_y = openGL_output_builder_.get_composite_output_y();
size_t size; size_t size;
uint8_t *buffered_lines = openGL_output_builder_.get_buffered_source_runs(size); uint8_t *buffered_lines = openGL_output_builder_.array_builder.reget_input_storage(size);
for(size_t position = 0; position < size; position += SourceVertexSize) for(size_t position = 0; position < size; position += SourceVertexSize)
{ {
(*(uint16_t *)&buffered_lines[position + SourceVertexOffsetOfOutputStart + 2]) = output_y; (*(uint16_t *)&buffered_lines[position + SourceVertexOffsetOfOutputStart + 2]) = output_y;
} }
// Construct the output run // Construct the output run
uint8_t *next_run = openGL_output_builder_.get_next_output_run(); uint8_t *next_run = openGL_output_builder_.array_builder.get_output_storage(OutputVertexSize);
output_x1() = output_run_.x1; output_x1() = output_run_.x1;
output_position_y() = output_run_.y; output_position_y() = output_run_.y;
output_tex_y() = output_y; output_tex_y() = output_y;
output_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position(); output_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position();
openGL_output_builder_.complete_output_run(); openGL_output_builder_.array_builder.flush();
openGL_output_builder_.unlock_output(); openGL_output_builder_.unlock_output();
} }
@ -311,13 +307,13 @@ void CRT::output_blank(unsigned int number_of_cycles)
void CRT::output_level(unsigned int number_of_cycles) void CRT::output_level(unsigned int number_of_cycles)
{ {
if(!openGL_output_builder_.input_buffer_is_full()) if(!openGL_output_builder_.array_builder.is_full())
{ {
Scan scan { Scan scan {
.type = Scan::Type::Level, .type = Scan::Type::Level,
.number_of_cycles = number_of_cycles, .number_of_cycles = number_of_cycles,
.tex_x = openGL_output_builder_.get_last_write_x_posititon(), .tex_x = openGL_output_builder_.texture_builder.get_last_write_x_position(),
.tex_y = openGL_output_builder_.get_last_write_y_posititon() .tex_y = openGL_output_builder_.texture_builder.get_last_write_y_position()
}; };
output_scan(&scan); output_scan(&scan);
} }
@ -344,14 +340,14 @@ void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider) void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
{ {
if(!openGL_output_builder_.input_buffer_is_full()) if(!openGL_output_builder_.array_builder.is_full())
{ {
openGL_output_builder_.reduce_previous_allocation_to(number_of_cycles / source_divider); openGL_output_builder_.texture_builder.reduce_previous_allocation_to(number_of_cycles / source_divider);
Scan scan { Scan scan {
.type = Scan::Type::Data, .type = Scan::Type::Data,
.number_of_cycles = number_of_cycles, .number_of_cycles = number_of_cycles,
.tex_x = openGL_output_builder_.get_last_write_x_posititon(), .tex_x = openGL_output_builder_.texture_builder.get_last_write_x_position(),
.tex_y = openGL_output_builder_.get_last_write_y_posititon(), .tex_y = openGL_output_builder_.texture_builder.get_last_write_y_position(),
.source_divider = source_divider .source_divider = source_divider
}; };
output_scan(&scan); output_scan(&scan);

View File

@ -78,8 +78,6 @@ class CRT {
// OpenGL state // OpenGL state
OpenGLOutputBuilder openGL_output_builder_; OpenGLOutputBuilder openGL_output_builder_;
ArrayBuilder array_builder_;
TextureBuilder texture_builder_;
// temporary storage used during the construction of output runs // temporary storage used during the construction of output runs
struct { struct {
@ -194,7 +192,7 @@ class CRT {
*/ */
inline uint8_t *allocate_write_area(size_t required_length) inline uint8_t *allocate_write_area(size_t required_length)
{ {
return openGL_output_builder_.allocate_write_area(required_length); return openGL_output_builder_.texture_builder.allocate_write_area(required_length);
} }
/*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state. /*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state.

View File

@ -15,36 +15,43 @@ ArrayBuilder::ArrayBuilder(size_t input_size, size_t output_size) :
input_(input_size) input_(input_size)
{} {}
ArrayBuilder::Buffer::Buffer(size_t size) : bool ArrayBuilder::is_full()
allocated_data(0), completed_data(0)
{ {
glGenBuffers(1, &buffer); bool was_full;
glBindBuffer(GL_ARRAY_BUFFER, buffer); buffer_mutex_.lock();
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, NULL, GL_STREAM_DRAW); was_full = is_full_;
data.resize(size); buffer_mutex_.unlock();
} return was_full;
ArrayBuilder::Buffer::~Buffer()
{
glDeleteBuffers(1, &buffer);
} }
uint8_t *ArrayBuilder::get_input_storage(size_t size) uint8_t *ArrayBuilder::get_input_storage(size_t size)
{ {
return input_.get_storage(size); return get_storage(size, input_);
}
uint8_t *ArrayBuilder::reget_input_storage(size_t &size)
{
return input_.reget_storage(size);
} }
uint8_t *ArrayBuilder::get_output_storage(size_t size) uint8_t *ArrayBuilder::get_output_storage(size_t size)
{ {
return output_.get_storage(size); return get_storage(size, output_);
}
uint8_t *ArrayBuilder::reget_output_storage(size_t &size)
{
return output_.reget_storage(size);
} }
void ArrayBuilder::flush() void ArrayBuilder::flush()
{ {
// TODO: don't flush anything if either buffer was exhausted
buffer_mutex_.lock(); buffer_mutex_.lock();
input_.flush(); if(!is_full_)
output_.flush(); {
input_.flush();
output_.flush();
}
buffer_mutex_.unlock(); buffer_mutex_.unlock();
} }
@ -65,41 +72,82 @@ ArrayBuilder::Submission ArrayBuilder::submit()
buffer_mutex_.lock(); buffer_mutex_.lock();
submission.input_size = input_.submit(); submission.input_size = input_.submit();
submission.output_size = output_.submit(); submission.output_size = output_.submit();
if(is_full_)
{
is_full_ = false;
input_.reset();
output_.reset();
}
buffer_mutex_.unlock(); buffer_mutex_.unlock();
// TODO: if either buffer was exhausted, reset both
return submission; return submission;
} }
ArrayBuilder::Buffer::Buffer(size_t size) :
allocated_data(0), flushed_data(0), submitted_data(0), is_full(false)
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, NULL, GL_STREAM_DRAW);
data.resize(size);
}
ArrayBuilder::Buffer::~Buffer()
{
glDeleteBuffers(1, &buffer);
}
uint8_t *ArrayBuilder::get_storage(size_t size, Buffer &buffer)
{
buffer_mutex_.lock();
uint8_t *pointer = buffer.get_storage(size);
if(!pointer) is_full_ = true;
buffer_mutex_.unlock();
return pointer;
}
uint8_t *ArrayBuilder::Buffer::get_storage(size_t size) uint8_t *ArrayBuilder::Buffer::get_storage(size_t size)
{ {
if(allocated_data + size > data.size()) return nullptr; if(is_full || allocated_data + size > data.size())
{
is_full = true;
return nullptr;
}
uint8_t *pointer = &data[allocated_data]; uint8_t *pointer = &data[allocated_data];
vended_pointer = allocated_data;
allocated_data += size; allocated_data += size;
return pointer; return pointer;
} }
uint8_t *ArrayBuilder::Buffer::reget_storage(size_t &size)
{
if(is_full)
{
return nullptr;
}
size = allocated_data - flushed_data;
return &data[flushed_data];
}
void ArrayBuilder::Buffer::flush() void ArrayBuilder::Buffer::flush()
{ {
// Ordinarily this just requires the completed data count to be bumped up if(submitted_data && !is_full && allocated_data > submitted_data)
// to the current allocated data value. However if the amount of allocated {
// data is now less than the completed data then that implies a submission memcpy(data.data(), &data[flushed_data], allocated_data - flushed_data);
// occurred while the pointer previously vended by get_storage was in use. allocated_data -= flushed_data;
// So copy whatever is danging back to the start and make amends. flushed_data = allocated_data;
if(completed_data < allocated_data) submitted_data = 0;
completed_data = allocated_data; }
else else
{ {
completed_data = allocated_data - vended_pointer; allocated_data = 0;
allocated_data = completed_data; flushed_data = 0;
memcpy(data.data(), &data[vended_pointer], completed_data); submitted_data = 0;
} }
} }
size_t ArrayBuilder::Buffer::submit() size_t ArrayBuilder::Buffer::submit()
{ {
size_t length = completed_data; size_t length = flushed_data;
glBindBuffer(GL_ARRAY_BUFFER, buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer);
uint8_t *destination = (uint8_t *)glMapBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); uint8_t *destination = (uint8_t *)glMapBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
@ -107,7 +155,7 @@ size_t ArrayBuilder::Buffer::submit()
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length); glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length);
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
completed_data = 0; submitted_data = flushed_data;
return length; return length;
} }
@ -118,5 +166,8 @@ void ArrayBuilder::Buffer::bind()
void ArrayBuilder::Buffer::reset() void ArrayBuilder::Buffer::reset()
{ {
completed_data = allocated_data = 0; allocated_data = 0;
flushed_data = 0;
submitted_data = 0;
is_full = false;
} }

View File

@ -34,7 +34,12 @@ class ArrayBuilder {
/// Attempts to add @c size bytes /// Attempts to add @c size bytes
uint8_t *get_input_storage(size_t size); uint8_t *get_input_storage(size_t size);
uint8_t *reget_input_storage(size_t &size);
uint8_t *get_output_storage(size_t size); uint8_t *get_output_storage(size_t size);
uint8_t *reget_output_storage(size_t &size);
bool is_full();
void flush(); void flush();
void bind_input(); void bind_input();
@ -51,17 +56,24 @@ class ArrayBuilder {
~Buffer(); ~Buffer();
std::vector<uint8_t> data; std::vector<uint8_t> data;
size_t allocated_data, completed_data, vended_pointer; size_t allocated_data;
size_t flushed_data;
size_t submitted_data;
bool is_full;
GLuint buffer; GLuint buffer;
uint8_t *get_storage(size_t size); uint8_t *get_storage(size_t size);
uint8_t *reget_storage(size_t &size);
void flush(); void flush();
size_t submit(); size_t submit();
void bind(); void bind();
void reset(); void reset();
} output_, input_; } output_, input_;
uint8_t *get_storage(size_t size, Buffer &buffer);
std::mutex buffer_mutex_; std::mutex buffer_mutex_;
bool is_exhausted_; bool is_full_;
}; };
} }

View File

@ -13,27 +13,6 @@
#include "../../../SignalProcessing/FIRFilter.hpp" #include "../../../SignalProcessing/FIRFilter.hpp"
#include "Shaders/OutputShader.hpp" #include "Shaders/OutputShader.hpp"
struct Range {
GLsizei location, length;
};
static GLsizei submitArrayData(GLuint buffer, uint8_t *source, size_t *length_pointer)
{
GLsizei length = (GLsizei)*length_pointer;
// The development machine is a Mac; Apple seemingly having given up on OpenGL (?), GL_MAP_PERSISTENT_BIT is not
// available. Which possibly means I'm doing no better here than a traditional buffer submit, but there it is.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
uint8_t *data = (uint8_t *)glMapBufferRange(GL_ARRAY_BUFFER, 0, length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
memcpy(data, source, (size_t)length);
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, length);
glUnmapBuffer(GL_ARRAY_BUFFER);
*length_pointer = 0;
return length;
}
using namespace Outputs::CRT; using namespace Outputs::CRT;
namespace { namespace {
@ -45,7 +24,7 @@ namespace {
static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE5; static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE5;
} }
OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) : OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) :
_output_mutex(new std::mutex), _output_mutex(new std::mutex),
_draw_mutex(new std::mutex), _draw_mutex(new std::mutex),
_visible_area(Rect(0, 0, 1, 1)), _visible_area(Rect(0, 0, 1, 1)),
@ -54,11 +33,10 @@ 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(bytes_per_pixel, source_data_texture_unit),
array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize)
{ {
_output_buffer.data.resize(OutputVertexBufferDataSize);
_source_buffer.data.resize(SourceVertexBufferDataSize);
glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR); glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR);
glBlendColor(0.6f, 0.6f, 0.6f, 1.0f); glBlendColor(0.6f, 0.6f, 0.6f, 1.0f);
@ -68,31 +46,15 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
filteredYTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_y_texture_unit)); filteredYTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_y_texture_unit));
filteredTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)); filteredTexture.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit));
// create the surce texture
glActiveTexture(source_data_texture_unit);
_texture_builder.reset(new TextureBuilder(buffer_depth));
// create the output vertex array // create the output vertex array
glGenVertexArrays(1, &output_vertex_array); glGenVertexArrays(1, &output_vertex_array);
// create a buffer for output vertex attributes
glGenBuffers(1, &output_array_buffer);
glBindBuffer(GL_ARRAY_BUFFER, output_array_buffer);
glBufferData(GL_ARRAY_BUFFER, OutputVertexBufferDataSize, NULL, GL_STREAM_DRAW);
// create the source vertex array // create the source vertex array
glGenVertexArrays(1, &source_vertex_array); glGenVertexArrays(1, &source_vertex_array);
// create a buffer for source vertex attributes
glGenBuffers(1, &source_array_buffer);
glBindBuffer(GL_ARRAY_BUFFER, source_array_buffer);
glBufferData(GL_ARRAY_BUFFER, SourceVertexBufferDataSize, NULL, GL_STREAM_DRAW);
} }
OpenGLOutputBuilder::~OpenGLOutputBuilder() OpenGLOutputBuilder::~OpenGLOutputBuilder()
{ {
glDeleteBuffers(1, &output_array_buffer);
glDeleteBuffers(1, &source_array_buffer);
glDeleteVertexArrays(1, &output_vertex_array); glDeleteVertexArrays(1, &output_vertex_array);
free(_composite_shader); free(_composite_shader);
@ -152,14 +114,11 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
_output_mutex->lock(); _output_mutex->lock();
// release the mapping, giving up on trying to draw if data has been lost // release the mapping, giving up on trying to draw if data has been lost
GLsizei submitted_output_data = submitArrayData(output_array_buffer, _output_buffer.data.data(), &_output_buffer.pointer); ArrayBuilder::Submission array_submission = array_builder.submit();
// bind and flush the source array buffer
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
glActiveTexture(source_data_texture_unit); glActiveTexture(source_data_texture_unit);
_texture_builder->submit(); texture_builder.submit();
// 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;
@ -192,7 +151,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
RenderStage *active_pipeline = (_output_device == Television || !rgb_input_shader_program) ? composite_render_stages : rgb_render_stages; RenderStage *active_pipeline = (_output_device == Television || !rgb_input_shader_program) ? composite_render_stages : rgb_render_stages;
// for television, update intermediate buffers and then draw; for a monitor, just draw // for television, update intermediate buffers and then draw; for a monitor, just draw
if(submitted_source_data) if(array_submission.input_size || array_submission.output_size)
{ {
// all drawing will be from the source vertex array and without blending // all drawing will be from the source vertex array and without blending
glBindVertexArray(source_vertex_array); glBindVertexArray(source_vertex_array);
@ -206,7 +165,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
active_pipeline->shader->bind(); active_pipeline->shader->bind();
// draw as desired // draw as desired
glDrawArraysInstanced(GL_LINES, 0, 2, submitted_source_data / SourceVertexSize); glDrawArraysInstanced(GL_LINES, 0, 2, (GLsizei)array_submission.input_size / SourceVertexSize);
active_pipeline++; active_pipeline++;
} }
@ -229,7 +188,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
output_shader_program->bind(); output_shader_program->bind();
// draw // draw
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, submitted_output_data / OutputVertexSize); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize);
} }
// copy framebuffer to the intended place // copy framebuffer to the intended place
@ -325,7 +284,7 @@ void OpenGLOutputBuilder::prepare_source_vertex_array()
if(composite_input_shader_program) if(composite_input_shader_program)
{ {
glBindVertexArray(source_vertex_array); glBindVertexArray(source_vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, source_array_buffer); array_builder.bind_input();
composite_input_shader_program->enable_vertex_attribute_with_pointer("inputStart", 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, (void *)SourceVertexOffsetOfInputStart, 1); composite_input_shader_program->enable_vertex_attribute_with_pointer("inputStart", 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, (void *)SourceVertexOffsetOfInputStart, 1);
composite_input_shader_program->enable_vertex_attribute_with_pointer("outputStart", 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, (void *)SourceVertexOffsetOfOutputStart, 1); composite_input_shader_program->enable_vertex_attribute_with_pointer("outputStart", 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, (void *)SourceVertexOffsetOfOutputStart, 1);
@ -345,7 +304,7 @@ void OpenGLOutputBuilder::prepare_output_vertex_array()
if(output_shader_program) if(output_shader_program)
{ {
glBindVertexArray(output_vertex_array); glBindVertexArray(output_vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, output_array_buffer); array_builder.bind_output();
output_shader_program->enable_vertex_attribute_with_pointer("horizontal", 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, (void *)OutputVertexOffsetOfHorizontal, 1); output_shader_program->enable_vertex_attribute_with_pointer("horizontal", 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, (void *)OutputVertexOffsetOfHorizontal, 1);
output_shader_program->enable_vertex_attribute_with_pointer("vertical", 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, (void *)OutputVertexOffsetOfVertical, 1); output_shader_program->enable_vertex_attribute_with_pointer("vertical", 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, (void *)OutputVertexOffsetOfVertical, 1);
} }

View File

@ -14,6 +14,8 @@
#include "OpenGL.hpp" #include "OpenGL.hpp"
#include "TextureTarget.hpp" #include "TextureTarget.hpp"
#include "Shader.hpp" #include "Shader.hpp"
#include "ArrayBuilder.hpp"
#include "TextureBuilder.hpp" #include "TextureBuilder.hpp"
#include "Shaders/OutputShader.hpp" #include "Shaders/OutputShader.hpp"
@ -57,7 +59,6 @@ class OpenGLOutputBuilder {
void prepare_source_vertex_array(); void prepare_source_vertex_array();
// the run and input data buffers // the run and input data buffers
std::unique_ptr<TextureBuilder> _texture_builder;
std::unique_ptr<std::mutex> _output_mutex; std::unique_ptr<std::mutex> _output_mutex;
std::unique_ptr<std::mutex> _draw_mutex; std::unique_ptr<std::mutex> _draw_mutex;
@ -75,8 +76,8 @@ class OpenGLOutputBuilder {
std::unique_ptr<OpenGL::TextureTarget> framebuffer; // the current pixel output std::unique_ptr<OpenGL::TextureTarget> framebuffer; // the current pixel output
GLuint output_array_buffer, output_vertex_array; GLuint output_vertex_array;
GLuint source_array_buffer, source_vertex_array; GLuint source_vertex_array;
unsigned int _last_output_width, _last_output_height; unsigned int _last_output_width, _last_output_height;
@ -91,45 +92,12 @@ class OpenGLOutputBuilder {
void reset_all_OpenGL_state(); void reset_all_OpenGL_state();
public: public:
OpenGLOutputBuilder(unsigned int buffer_depth); TextureBuilder texture_builder;
ArrayBuilder array_builder;
OpenGLOutputBuilder(size_t bytes_per_pixel);
~OpenGLOutputBuilder(); ~OpenGLOutputBuilder();
inline uint8_t *get_next_source_run()
{
if(_line_buffer.data.size() < _line_buffer.pointer + SourceVertexSize)
_line_buffer.data.resize(_line_buffer.pointer + SourceVertexSize);
return &_line_buffer.data[_line_buffer.pointer];
}
inline void complete_source_run()
{
_line_buffer.pointer += SourceVertexSize;
}
inline uint8_t *get_buffered_source_runs(size_t &size)
{
size = _line_buffer.pointer;
return _line_buffer.data.data();
}
inline uint8_t *get_next_output_run()
{
if(_output_buffer.pointer == OutputVertexBufferDataSize) return nullptr;
return &_output_buffer.data[_output_buffer.pointer];
}
inline void complete_output_run()
{
size_t line_buffer_size = _line_buffer.data.size();
if(_source_buffer.pointer + line_buffer_size < SourceVertexBufferDataSize)
{
_output_buffer.pointer += OutputVertexSize;
memcpy(&_source_buffer.data[_source_buffer.pointer], _line_buffer.data.data(), _line_buffer.data.size());
_source_buffer.pointer += _line_buffer.data.size();
_line_buffer.pointer = 0;
}
}
inline void set_colour_format(ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator) inline void set_colour_format(ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator)
{ {
_output_mutex->lock(); _output_mutex->lock();
@ -145,11 +113,6 @@ class OpenGLOutputBuilder {
_visible_area = visible_area; _visible_area = visible_area;
} }
inline bool composite_output_run_has_room_for_vertex()
{
return _output_buffer.pointer < OutputVertexBufferDataSize;
}
inline void lock_output() inline void lock_output()
{ {
_output_mutex->lock(); _output_mutex->lock();
@ -181,31 +144,6 @@ class OpenGLOutputBuilder {
_composite_src_output_y++; _composite_src_output_y++;
} }
inline uint8_t *allocate_write_area(size_t required_length)
{
return _texture_builder->allocate_write_area(required_length);
}
inline void reduce_previous_allocation_to(size_t actual_length)
{
_texture_builder->reduce_previous_allocation_to(actual_length);
}
inline bool input_buffer_is_full()
{
return _texture_builder->is_full();
}
inline uint16_t get_last_write_x_posititon()
{
return _texture_builder->get_last_write_x_position();
}
inline uint16_t get_last_write_y_posititon()
{
return _texture_builder->get_last_write_y_position();
}
void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty); void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty);
void set_openGL_context_will_change(bool should_delete_resources); void set_openGL_context_will_change(bool should_delete_resources);
void set_composite_sampling_function(const char *shader); void set_composite_sampling_function(const char *shader);
@ -213,12 +151,6 @@ class OpenGLOutputBuilder {
void set_output_device(OutputDevice output_device); void set_output_device(OutputDevice output_device);
void set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider); void set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider);
struct Buffer {
std::vector<uint8_t> data;
size_t pointer;
Buffer() : pointer(0) {}
} _line_buffer, _source_buffer, _output_buffer;
GLsync _fence; GLsync _fence;
}; };

View File

@ -37,13 +37,15 @@ static const GLenum formatForDepth(size_t depth)
} }
} }
TextureBuilder::TextureBuilder(size_t bytes_per_pixel) : TextureBuilder::TextureBuilder(size_t bytes_per_pixel, GLenum texture_unit) :
bytes_per_pixel_(bytes_per_pixel), bytes_per_pixel_(bytes_per_pixel),
next_write_x_position_(0), next_write_x_position_(0),
next_write_y_position_(0) next_write_y_position_(0)
{ {
image_.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight); image_.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight);
glGenTextures(1, &texture_name_); glGenTextures(1, &texture_name_);
glActiveTexture(texture_unit);
glBindTexture(GL_TEXTURE_2D, 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_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

View File

@ -28,7 +28,7 @@ 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. /// 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, GLenum texture_unit);
virtual ~TextureBuilder(); 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