mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Made an attempt to shuffle the texture builder to a similar flush/submit pattern as the input builder. Don't care about thread safety yet, as it's obvious I'm going to need to move that back up to the CRT.
This commit is contained in:
parent
0edc043378
commit
0fee8096c1
@ -136,8 +136,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
|
|||||||
|
|
||||||
if(next_run)
|
if(next_run)
|
||||||
{
|
{
|
||||||
source_input_position_x1() = tex_x;
|
// source_input_position_x1() = tex_x;
|
||||||
source_input_position_y() = tex_y;
|
// source_input_position_y() = tex_y;
|
||||||
source_output_position_x1() = (uint16_t)horizontal_flywheel_->get_current_output_position();
|
source_output_position_x1() = (uint16_t)horizontal_flywheel_->get_current_output_position();
|
||||||
// Don't write output_y now, write it later; we won't necessarily know what it is outside of the locked region
|
// Don't write output_y now, write it later; we won't necessarily know what it is outside of the locked region
|
||||||
source_phase() = colour_burst_phase_;
|
source_phase() = colour_burst_phase_;
|
||||||
@ -204,8 +204,18 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
|
|||||||
output_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position();
|
output_x2() = (uint16_t)horizontal_flywheel_->get_current_output_position();
|
||||||
}
|
}
|
||||||
openGL_output_builder_.array_builder.flush(
|
openGL_output_builder_.array_builder.flush(
|
||||||
[output_y] (uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size)
|
[output_y, this] (uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size)
|
||||||
{
|
{
|
||||||
|
openGL_output_builder_.texture_builder.flush(
|
||||||
|
[output_y, input_buffer] (const std::vector<TextureBuilder::WriteArea> &write_areas, size_t number_of_write_areas)
|
||||||
|
{
|
||||||
|
for(size_t run = 0; run < number_of_write_areas; run++)
|
||||||
|
{
|
||||||
|
*(uint16_t *)&input_buffer[run * SourceVertexSize + SourceVertexOffsetOfInputStart + 0] = write_areas[run].x;
|
||||||
|
*(uint16_t *)&input_buffer[run * SourceVertexSize + SourceVertexOffsetOfInputStart + 2] = write_areas[run].y;
|
||||||
|
*(uint16_t *)&input_buffer[run * SourceVertexSize + SourceVertexOffsetOfEnds + 0] = write_areas[run].x + write_areas[run].length;
|
||||||
|
}
|
||||||
|
});
|
||||||
for(size_t position = 0; position < input_size; position += SourceVertexSize)
|
for(size_t position = 0; position < input_size; position += SourceVertexSize)
|
||||||
{
|
{
|
||||||
(*(uint16_t *)&input_buffer[position + SourceVertexOffsetOfOutputStart + 2]) = output_y;
|
(*(uint16_t *)&input_buffer[position + SourceVertexOffsetOfOutputStart + 2]) = output_y;
|
||||||
|
@ -39,8 +39,10 @@ static const GLenum formatForDepth(size_t depth)
|
|||||||
|
|
||||||
TextureBuilder::TextureBuilder(size_t bytes_per_pixel, GLenum texture_unit) :
|
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),
|
write_areas_start_x_(0),
|
||||||
next_write_y_position_(0)
|
write_areas_start_y_(0),
|
||||||
|
is_full_(false),
|
||||||
|
did_submit_(false)
|
||||||
{
|
{
|
||||||
image_.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight);
|
image_.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight);
|
||||||
glGenTextures(1, &texture_name_);
|
glGenTextures(1, &texture_name_);
|
||||||
@ -59,81 +61,81 @@ TextureBuilder::~TextureBuilder()
|
|||||||
glDeleteTextures(1, &texture_name_);
|
glDeleteTextures(1, &texture_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t *TextureBuilder::pointer_to_location(uint16_t x, uint16_t y)
|
||||||
|
{
|
||||||
|
return &image_[((y * InputBufferBuilderWidth) + x) * bytes_per_pixel_];
|
||||||
|
}
|
||||||
|
|
||||||
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(is_full_) return nullptr;
|
||||||
|
|
||||||
|
uint16_t starting_x, starting_y;
|
||||||
|
|
||||||
|
if(!number_of_write_areas_)
|
||||||
{
|
{
|
||||||
last_allocation_amount_ = required_length;
|
starting_x = write_areas_start_x_;
|
||||||
|
starting_y = write_areas_start_y_;
|
||||||
if(next_write_x_position_ + required_length + 2 > InputBufferBuilderWidth)
|
}
|
||||||
{
|
else
|
||||||
next_write_x_position_ = 0;
|
{
|
||||||
next_write_y_position_++;
|
starting_x = write_areas_[number_of_write_areas_ - 1].x + write_areas_[number_of_write_areas_ - 1].length + 1;
|
||||||
|
starting_y = write_areas_[number_of_write_areas_ - 1].y;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else return nullptr;
|
|
||||||
|
|
||||||
return &image_[write_target_pointer_ * bytes_per_pixel_];
|
WriteArea next_write_area;
|
||||||
|
if(starting_x + required_length + 2 > InputBufferBuilderWidth)
|
||||||
|
{
|
||||||
|
starting_x = 0;
|
||||||
|
starting_y++;
|
||||||
|
|
||||||
|
if(starting_y == InputBufferBuilderHeight)
|
||||||
|
{
|
||||||
|
is_full_ = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_write_area.x = starting_x + 1;
|
||||||
|
next_write_area.y = starting_y;
|
||||||
|
next_write_area.length = (uint16_t)required_length;
|
||||||
|
if(number_of_write_areas_ < write_areas_.size())
|
||||||
|
write_areas_[number_of_write_areas_] = next_write_area;
|
||||||
|
else
|
||||||
|
write_areas_.push_back(next_write_area);
|
||||||
|
number_of_write_areas_++;
|
||||||
|
|
||||||
|
return pointer_to_location(next_write_area.x, next_write_area.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureBuilder::is_full()
|
bool TextureBuilder::is_full()
|
||||||
{
|
{
|
||||||
return (next_write_y_position_ == InputBufferBuilderHeight);
|
return is_full_;
|
||||||
}
|
}
|
||||||
|
|
||||||
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(is_full_) return;
|
||||||
|
|
||||||
uint8_t *const image_pointer = image_.data();
|
WriteArea &write_area = write_areas_[number_of_write_areas_-1];
|
||||||
|
write_area.length = (uint16_t)actual_length;
|
||||||
// correct if the writing cursor was reset while a client was writing
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_],
|
uint8_t *start_pointer = pointer_to_location(write_area.x, write_area.y);
|
||||||
&image_pointer[write_target_pointer_ * bytes_per_pixel_],
|
memcpy( &start_pointer[-bytes_per_pixel_],
|
||||||
|
start_pointer,
|
||||||
bytes_per_pixel_);
|
bytes_per_pixel_);
|
||||||
|
|
||||||
memcpy( &image_pointer[(write_target_pointer_ + actual_length) * bytes_per_pixel_],
|
memcpy( &start_pointer[actual_length * bytes_per_pixel_],
|
||||||
&image_pointer[(write_target_pointer_ + actual_length - 1) * bytes_per_pixel_],
|
&start_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
|
|
||||||
next_write_x_position_ -= (last_allocation_amount_ - actual_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TextureBuilder::get_last_write_x_position()
|
|
||||||
{
|
|
||||||
return write_x_position_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TextureBuilder::get_last_write_y_position()
|
|
||||||
{
|
|
||||||
return write_y_position_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureBuilder::submit()
|
void TextureBuilder::submit()
|
||||||
{
|
{
|
||||||
uint16_t height = write_y_position_ + (next_write_x_position_ ? 1 : 0);
|
uint16_t height = write_areas_start_y_ + (write_areas_start_x_ ? 1 : 0);
|
||||||
next_write_x_position_ = next_write_y_position_ = 0;
|
did_submit_ = true;
|
||||||
|
|
||||||
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
glTexSubImage2D( GL_TEXTURE_2D, 0,
|
||||||
0, 0,
|
0, 0,
|
||||||
@ -141,3 +143,47 @@ void TextureBuilder::submit()
|
|||||||
formatForDepth(bytes_per_pixel_), GL_UNSIGNED_BYTE,
|
formatForDepth(bytes_per_pixel_), GL_UNSIGNED_BYTE,
|
||||||
image_.data());
|
image_.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureBuilder::flush(const std::function<void(const std::vector<WriteArea> &write_areas, size_t count)> &function)
|
||||||
|
{
|
||||||
|
bool was_full = is_full_;
|
||||||
|
if(did_submit_)
|
||||||
|
{
|
||||||
|
write_areas_start_y_ = write_areas_start_x_ = 0;
|
||||||
|
is_full_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(number_of_write_areas_ && !was_full)
|
||||||
|
{
|
||||||
|
if(write_areas_[0].x != write_areas_start_x_ || write_areas_[0].y != write_areas_start_y_)
|
||||||
|
{
|
||||||
|
for(auto write_area : write_areas_)
|
||||||
|
{
|
||||||
|
if(write_areas_start_x_ + write_area.length + 2 > InputBufferBuilderWidth)
|
||||||
|
{
|
||||||
|
write_areas_start_x_ = 0;
|
||||||
|
write_areas_start_y_ ++;
|
||||||
|
|
||||||
|
if(write_areas_start_y_ == InputBufferBuilderHeight)
|
||||||
|
{
|
||||||
|
is_full_ = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(
|
||||||
|
pointer_to_location(write_areas_start_x_, write_areas_start_y_),
|
||||||
|
pointer_to_location(write_area.x - 1, write_area.y),
|
||||||
|
(write_area.length + 2) * bytes_per_pixel_);
|
||||||
|
write_area.x = write_areas_start_x_ + 1;
|
||||||
|
write_area.y = write_areas_start_y_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_full_)
|
||||||
|
function(write_areas_, number_of_write_areas_);
|
||||||
|
}
|
||||||
|
|
||||||
|
did_submit_ = false;
|
||||||
|
number_of_write_areas_ = 0;
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define Outputs_CRT_Internals_TextureBuilder_hpp
|
#define Outputs_CRT_Internals_TextureBuilder_hpp
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -48,16 +49,11 @@ class TextureBuilder {
|
|||||||
void submit();
|
void submit();
|
||||||
|
|
||||||
struct WriteArea {
|
struct WriteArea {
|
||||||
uint16_t x, y;
|
uint16_t x, y, length;
|
||||||
size_t length;
|
|
||||||
};
|
};
|
||||||
void flush(std::function<void(const std::vector<WriteArea> &write_areas, size_t count)>);
|
void flush(const std::function<void(const std::vector<WriteArea> &write_areas, size_t count)> &);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// details of the most recent allocation
|
|
||||||
size_t write_target_pointer_;
|
|
||||||
size_t last_allocation_amount_;
|
|
||||||
|
|
||||||
// the buffer size
|
// the buffer size
|
||||||
size_t bytes_per_pixel_;
|
size_t bytes_per_pixel_;
|
||||||
|
|
||||||
@ -65,8 +61,16 @@ class TextureBuilder {
|
|||||||
std::vector<uint8_t> image_;
|
std::vector<uint8_t> image_;
|
||||||
GLuint texture_name_;
|
GLuint texture_name_;
|
||||||
|
|
||||||
|
// the current list of write areas
|
||||||
std::vector<WriteArea> write_areas_;
|
std::vector<WriteArea> write_areas_;
|
||||||
size_t number_of_write_areas_;
|
size_t number_of_write_areas_;
|
||||||
|
bool is_full_;
|
||||||
|
bool did_submit_;
|
||||||
|
inline uint8_t *pointer_to_location(uint16_t x, uint16_t y);
|
||||||
|
|
||||||
|
// Usually: the start position for the current batch of write areas.
|
||||||
|
// Caveat: reset to the origin upon a submit. So used in comparison by flush to
|
||||||
|
// determine whether the current batch of write areas needs to be relocated.
|
||||||
uint16_t write_areas_start_x_, write_areas_start_y_;
|
uint16_t write_areas_start_x_, write_areas_start_y_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user