mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 00:37:27 +00:00
Made an attempt further to tie geometry and texture generation fully together, removing the assumption that the caller will achieve one-to-one calling.
This commit is contained in:
parent
7476c64a66
commit
bfbe12b94b
@ -140,6 +140,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
bool is_output_segment = ((is_output_run && next_run_length) && !horizontal_flywheel_->is_in_retrace() && !vertical_flywheel_->is_in_retrace());
|
||||
uint8_t *next_run = nullptr;
|
||||
if(is_output_segment && !openGL_output_builder_.composite_output_buffer_is_full()) {
|
||||
openGL_output_builder_.texture_builder.retain_latest();
|
||||
next_run = openGL_output_builder_.array_builder.get_input_storage(SourceVertexSize);
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
[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(
|
||||
[=] (const std::vector<TextureBuilder::WriteArea> &write_areas, size_t number_of_write_areas) {
|
||||
assert(number_of_write_areas == input_size * SourceVertexSize);
|
||||
assert(number_of_write_areas * SourceVertexSize == input_size);
|
||||
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;
|
||||
@ -313,6 +314,7 @@ void CRT::output_blank(unsigned int number_of_cycles) {
|
||||
}
|
||||
|
||||
void CRT::output_level(unsigned int number_of_cycles) {
|
||||
openGL_output_builder_.texture_builder.reduce_previous_allocation_to(1);
|
||||
Scan scan {
|
||||
.type = Scan::Type::Level,
|
||||
.number_of_cycles = number_of_cycles,
|
||||
|
@ -74,7 +74,6 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) {
|
||||
starting_y = write_areas_[number_of_write_areas_ - 1].y;
|
||||
}
|
||||
|
||||
WriteArea next_write_area;
|
||||
if(starting_x + required_length + 2 > InputBufferBuilderWidth) {
|
||||
starting_x = 0;
|
||||
starting_y++;
|
||||
@ -85,33 +84,36 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) {
|
||||
}
|
||||
}
|
||||
|
||||
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_++;
|
||||
write_area_.x = starting_x + 1;
|
||||
write_area_.y = starting_y;
|
||||
write_area_.length = (uint16_t)required_length;
|
||||
has_write_area_ = true;
|
||||
|
||||
return pointer_to_location(next_write_area.x, next_write_area.y);
|
||||
return pointer_to_location(write_area_.x, write_area_.y);
|
||||
}
|
||||
|
||||
bool TextureBuilder::is_full() {
|
||||
return is_full_;
|
||||
}
|
||||
|
||||
void TextureBuilder::retain_latest() {
|
||||
if(is_full_ || !has_write_area_) return;
|
||||
if(number_of_write_areas_ < write_areas_.size())
|
||||
write_areas_[number_of_write_areas_] = write_area_;
|
||||
else
|
||||
write_areas_.push_back(write_area_);
|
||||
number_of_write_areas_++;
|
||||
has_write_area_ = false;
|
||||
}
|
||||
|
||||
void TextureBuilder::reduce_previous_allocation_to(size_t actual_length) {
|
||||
if(is_full_ || !has_write_area_) return;
|
||||
|
||||
has_write_area_ = false;
|
||||
WriteArea &write_area = write_areas_[number_of_write_areas_-1];
|
||||
write_area.length = (uint16_t)actual_length;
|
||||
write_area_.length = (uint16_t)actual_length;
|
||||
|
||||
// book end the allocation with duplicates of the first and last pixel, to protect
|
||||
// against rounding errors when this run is drawn
|
||||
uint8_t *start_pointer = pointer_to_location(write_area.x, write_area.y);
|
||||
uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y);
|
||||
memcpy( &start_pointer[-bytes_per_pixel_],
|
||||
start_pointer,
|
||||
bytes_per_pixel_);
|
||||
|
@ -24,6 +24,32 @@ namespace CRT {
|
||||
Owns an OpenGL texture resource and provides mechanisms to fill it from bottom left to top right
|
||||
with runs of data, ensuring each run is neighboured immediately to the left and right by copies of its
|
||||
first and last pixels.
|
||||
|
||||
Intended usage:
|
||||
|
||||
(i) allocate a write area with allocate_write_area, supplying a maximum size.
|
||||
(ii) call reduce_previous_allocation_to to announce the actual size written.
|
||||
|
||||
This will cause you to have added source data to the target texture. You can then either use that data
|
||||
or allow it to expire.
|
||||
|
||||
(iii) call retain_latest to add the most recently written write area to the flush queue.
|
||||
|
||||
The flush queue contains provisional data, that can sit in the CPU's memory space indefinitely. This facility
|
||||
is provided because it is expected that a texture will be built alontside some other collection of data —
|
||||
that data in the flush queue is expected to become useful in coordination with something else but should
|
||||
be retained at least until then.
|
||||
|
||||
(iv) call flush to move data to the submit queue.
|
||||
|
||||
When you flush, you'll receive a record of the bounds of all newly-flushed areas of source data. That gives
|
||||
an opportunity to correlate the data with whatever else it is being tied to. It will continue to sit in
|
||||
the CPU's memory space but has now passed beyond any further modification or reporting.
|
||||
|
||||
(v) call submit to move data to the GPU and free up its CPU-side resources.
|
||||
|
||||
The data is now on the GPU, for whatever use the caller desires.
|
||||
|
||||
*/
|
||||
class TextureBuilder {
|
||||
public:
|
||||
@ -41,6 +67,9 @@ class TextureBuilder {
|
||||
/// and indicates that its actual final size was @c actual_length.
|
||||
void reduce_previous_allocation_to(size_t actual_length);
|
||||
|
||||
/// Allocated runs are provisional; they will not appear in the next flush queue unless retained.
|
||||
void retain_latest();
|
||||
|
||||
/// @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();
|
||||
@ -64,7 +93,10 @@ class TextureBuilder {
|
||||
std::vector<uint8_t> image_;
|
||||
GLuint texture_name_;
|
||||
|
||||
// the current list of write areas
|
||||
// the current write area
|
||||
WriteArea write_area_;
|
||||
|
||||
// the list of write areas that have ascended to the flush queue
|
||||
std::vector<WriteArea> write_areas_;
|
||||
size_t number_of_write_areas_;
|
||||
bool is_full_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user