// // ArrayBuilder.cpp // Clock Signal // // Created by Thomas Harte on 17/11/2016. // Copyright © 2016 Thomas Harte. All rights reserved. // #include "ArrayBuilder.hpp" using namespace Outputs::CRT; ArrayBuilder::ArrayBuilder(size_t input_size, size_t output_size) : output_(output_size, nullptr), input_(input_size, nullptr) {} ArrayBuilder::ArrayBuilder(size_t input_size, size_t output_size, std::function submission_function) : output_(output_size, submission_function), input_(input_size, submission_function) {} bool ArrayBuilder::is_full() { bool was_full; was_full = is_full_; return was_full; } uint8_t *ArrayBuilder::get_input_storage(size_t size) { return get_storage(size, input_); } uint8_t *ArrayBuilder::get_output_storage(size_t size) { return get_storage(size, output_); } void ArrayBuilder::flush(const std::function &function) { if(!is_full_) { size_t input_size = 0, output_size = 0; uint8_t *input = input_.get_unflushed(input_size); uint8_t *output = output_.get_unflushed(output_size); function(input, input_size, output, output_size); input_.flush(); output_.flush(); } } void ArrayBuilder::bind_input() { input_.bind(); } void ArrayBuilder::bind_output() { output_.bind(); } ArrayBuilder::Submission ArrayBuilder::submit() { ArrayBuilder::Submission submission; submission.input_size = input_.submit(true); submission.output_size = output_.submit(false); if(is_full_) { is_full_ = false; input_.reset(); output_.reset(); } return submission; } ArrayBuilder::Buffer::Buffer(size_t size, std::function submission_function) : is_full(false), submission_function_(submission_function), allocated_data(0), flushed_data(0), submitted_data(0) { if(!submission_function_) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, NULL, GL_STREAM_DRAW); } data.resize(size); } ArrayBuilder::Buffer::~Buffer() { if(!submission_function_) glDeleteBuffers(1, &buffer); } uint8_t *ArrayBuilder::get_storage(size_t size, Buffer &buffer) { uint8_t *pointer = buffer.get_storage(size); if(!pointer) is_full_ = true; return pointer; } uint8_t *ArrayBuilder::Buffer::get_storage(size_t size) { if(is_full || allocated_data + size > data.size()) { is_full = true; return nullptr; } uint8_t *pointer = &data[allocated_data]; allocated_data += size; return pointer; } uint8_t *ArrayBuilder::Buffer::get_unflushed(size_t &size) { if(is_full) { return nullptr; } size = allocated_data - flushed_data; return &data[flushed_data]; } void ArrayBuilder::Buffer::flush() { if(submitted_data) { memmove(data.data(), &data[submitted_data], allocated_data - submitted_data); allocated_data -= submitted_data; flushed_data -= submitted_data; submitted_data = 0; } flushed_data = allocated_data; } size_t ArrayBuilder::Buffer::submit(bool is_input) { size_t length = flushed_data; if(submission_function_) { submission_function_(is_input, data.data(), length); } else { 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); memcpy(destination, data.data(), length); glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length); glUnmapBuffer(GL_ARRAY_BUFFER); } submitted_data = flushed_data; return length; } void ArrayBuilder::Buffer::bind() { glBindBuffer(GL_ARRAY_BUFFER, buffer); } void ArrayBuilder::Buffer::reset() { is_full = false; allocated_data = 0; flushed_data = 0; submitted_data = 0; }