1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Started on an attempt not to treat the various buffers as free to loop within, starting with the input texture.

This commit is contained in:
Thomas Harte 2016-05-04 07:39:45 -04:00
parent 3684c6404f
commit 87df57195d
7 changed files with 151 additions and 118 deletions

View File

@ -156,8 +156,8 @@ void Machine::get_output_pixel(uint8_t *pixel, int offset)
if(playerPixels[0] || missilePixels[0]) outputColour = _playerColour[0]; if(playerPixels[0] || missilePixels[0]) outputColour = _playerColour[0];
} }
// store colour // store colour, if possible
pixel[0] = outputColour; if(pixel) *pixel = outputColour;
} }
// in imputing the knowledge that all we're dealing with is the rollover from 159 to 0, // in imputing the knowledge that all we're dealing with is the rollover from 159 to 0,
@ -237,8 +237,7 @@ void Machine::output_pixels(unsigned int count)
} }
if(_horizontalTimer < (_vBlankExtend ? 152 : 160)) { if(_horizontalTimer < (_vBlankExtend ? 152 : 160)) {
if(_outputBuffer) get_output_pixel(_outputBuffer ? &_outputBuffer[_lastOutputStateDuration] : nullptr, 159 - _horizontalTimer);
get_output_pixel(&_outputBuffer[_lastOutputStateDuration], 159 - _horizontalTimer);
// increment all graphics counters // increment all graphics counters
increment_object_counter(0); increment_object_counter(0);

View File

@ -539,7 +539,7 @@ inline void Machine::start_pixel_line()
} }
_currentScreenAddress = _startLineAddress; _currentScreenAddress = _startLineAddress;
_current_pixel_column = 0; _current_pixel_column = 0;
_current_output_target = nullptr; _initial_output_target = _current_output_target = nullptr;
} }
inline void Machine::end_pixel_line() inline void Machine::end_pixel_line()
@ -566,7 +566,7 @@ inline void Machine::output_pixels(unsigned int number_of_cycles)
case 2: case 5: divider = 8; break; case 2: case 5: divider = 8; break;
} }
if(!_current_output_target || divider != _current_output_divider) if(!_initial_output_target || divider != _current_output_divider)
{ {
if(_current_output_target) _crt->output_data((unsigned int)((_current_output_target - _initial_output_target) * _current_output_divider), _current_output_divider); if(_current_output_target) _crt->output_data((unsigned int)((_current_output_target - _initial_output_target) * _current_output_divider), _current_output_divider);
_current_output_divider = divider; _current_output_divider = divider;
@ -584,97 +584,112 @@ inline void Machine::output_pixels(unsigned int number_of_cycles)
switch(_screen_mode) switch(_screen_mode)
{ {
case 0: case 3: case 0: case 3:
while(number_of_cycles--) if(_initial_output_target)
{ {
get_pixel(); while(number_of_cycles--)
*(uint32_t *)_current_output_target = _paletteTables.eighty1bpp[_last_pixel_byte]; {
_current_output_target += 4; get_pixel();
_current_pixel_column++; *(uint32_t *)_current_output_target = _paletteTables.eighty1bpp[_last_pixel_byte];
} _current_output_target += 4;
_current_pixel_column++;
}
} else _current_output_target += 4*number_of_cycles;
break; break;
case 1: case 1:
while(number_of_cycles--) if(_initial_output_target)
{ {
get_pixel(); while(number_of_cycles--)
*(uint16_t *)_current_output_target = _paletteTables.eighty2bpp[_last_pixel_byte]; {
_current_output_target += 2; get_pixel();
_current_pixel_column++; *(uint16_t *)_current_output_target = _paletteTables.eighty2bpp[_last_pixel_byte];
} _current_output_target += 2;
_current_pixel_column++;
}
} else _current_output_target += 2*number_of_cycles;
break; break;
case 2: case 2:
while(number_of_cycles--) if(_initial_output_target)
{ {
get_pixel(); while(number_of_cycles--)
*_current_output_target = _paletteTables.eighty4bpp[_last_pixel_byte]; {
_current_output_target += 1; get_pixel();
_current_pixel_column++; *_current_output_target = _paletteTables.eighty4bpp[_last_pixel_byte];
} _current_output_target += 1;
_current_pixel_column++;
}
} else _current_output_target += number_of_cycles;
break; break;
case 4: case 6: case 4: case 6:
if(_current_pixel_column&1) if(_initial_output_target)
{ {
_last_pixel_byte <<= 4; if(_current_pixel_column&1)
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte]; {
_current_output_target += 2; _last_pixel_byte <<= 4;
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
number_of_cycles--; number_of_cycles--;
_current_pixel_column++; _current_pixel_column++;
} }
while(number_of_cycles > 1) while(number_of_cycles > 1)
{ {
get_pixel(); get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte]; *(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2; _current_output_target += 2;
_last_pixel_byte <<= 4; _last_pixel_byte <<= 4;
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte]; *(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2; _current_output_target += 2;
number_of_cycles -= 2; number_of_cycles -= 2;
_current_pixel_column+=2; _current_pixel_column+=2;
} }
if(number_of_cycles) if(number_of_cycles)
{ {
get_pixel(); get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte]; *(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2; _current_output_target += 2;
_current_pixel_column++; _current_pixel_column++;
} }
} else _current_output_target += 2 * number_of_cycles;
break; break;
case 5: case 5:
if(_current_pixel_column&1) if(_initial_output_target)
{ {
_last_pixel_byte <<= 2; if(_current_pixel_column&1)
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte]; {
_current_output_target += 1; _last_pixel_byte <<= 2;
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
number_of_cycles--; number_of_cycles--;
_current_pixel_column++; _current_pixel_column++;
} }
while(number_of_cycles > 1) while(number_of_cycles > 1)
{ {
get_pixel(); get_pixel();
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte]; *_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1; _current_output_target += 1;
_last_pixel_byte <<= 2; _last_pixel_byte <<= 2;
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte]; *_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1; _current_output_target += 1;
number_of_cycles -= 2; number_of_cycles -= 2;
_current_pixel_column+=2; _current_pixel_column+=2;
} }
if(number_of_cycles) if(number_of_cycles)
{ {
get_pixel(); get_pixel();
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte]; *_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1; _current_output_target += 1;
_current_pixel_column++; _current_pixel_column++;
} }
} else _current_output_target += number_of_cycles;
break; break;
} }

View File

@ -312,15 +312,21 @@ 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)
{ {
_openGL_output_builder->reduce_previous_allocation_to(number_of_cycles / source_divider); if(_openGL_output_builder->reduce_previous_allocation_to(number_of_cycles / source_divider))
Scan scan { {
.type = Scan::Type::Data, Scan scan {
.number_of_cycles = number_of_cycles, .type = Scan::Type::Data,
.tex_x = _openGL_output_builder->get_last_write_x_posititon(), .number_of_cycles = number_of_cycles,
.tex_y = _openGL_output_builder->get_last_write_y_posititon(), .tex_x = _openGL_output_builder->get_last_write_x_posititon(),
.source_divider = source_divider .tex_y = _openGL_output_builder->get_last_write_y_posititon(),
}; .source_divider = source_divider
output_scan(&scan); };
output_scan(&scan);
}
else
{
output_blank(number_of_cycles);
}
} }
Outputs::CRT::Rect CRT::get_rect_for_area(int first_line_after_sync, int number_of_lines, int first_cycle_after_sync, int number_of_cycles, float aspect_ratio) Outputs::CRT::Rect CRT::get_rect_for_area(int first_line_after_sync, int number_of_lines, int first_cycle_after_sync, int number_of_cycles, float aspect_ratio)

View File

@ -176,14 +176,16 @@ class CRT {
*/ */
void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t amplitude); void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t amplitude);
/*! Ensures that the given number of output samples are allocated for writing. /*! Attempts to allocate the given number of output samples for writing.
The beginning of the most recently allocated area is used as the start The beginning of the most recently allocated area is used as the start
of data written by a call to @c output_data; it is acceptable to write and to of data written by a call to @c output_data; it is acceptable to write and to
output less data than the amount requested but that may be less efficient. output less data than the amount requested but that may be less efficient.
Allocation should fail only if emulation is running significantly below real speed.
@param required_length The number of samples to allocate. @param required_length The number of samples to allocate.
@returns A pointer to the allocated area. @returns A pointer to the allocated area if room is available; @c nullptr otherwise.
*/ */
inline uint8_t *allocate_write_area(size_t required_length) inline uint8_t *allocate_write_area(size_t required_length)
{ {

View File

@ -13,44 +13,51 @@
using namespace Outputs::CRT; using namespace Outputs::CRT;
CRTInputBufferBuilder::CRTInputBufferBuilder(size_t bytes_per_pixel) : CRTInputBufferBuilder::CRTInputBufferBuilder(size_t bytes_per_pixel) :
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),
last_uploaded_line(0) _last_uploaded_line(0),
_is_full(false)
{} {}
CRTInputBufferBuilder::~CRTInputBufferBuilder()
{
}
void CRTInputBufferBuilder::allocate_write_area(size_t required_length) void CRTInputBufferBuilder::allocate_write_area(size_t required_length)
{ {
_last_allocation_amount = required_length; if (!_is_full)
if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
{ {
_next_write_x_position = 0; _last_allocation_amount = required_length;
_next_write_y_position++;
}
_write_x_position = _next_write_x_position + 1; if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
_write_y_position = _next_write_y_position; {
_write_target_pointer = ((_write_y_position % InputBufferBuilderHeight) * InputBufferBuilderWidth) + _write_x_position; _next_write_x_position = 0;
_next_write_x_position += required_length + 2; _next_write_y_position++;
_is_full = (_next_write_y_position == _last_uploaded_line + InputBufferBuilderHeight);
if(_is_full) return;
}
_write_x_position = _next_write_x_position + 1;
_write_y_position = _next_write_y_position;
_write_target_pointer = ((_write_y_position % InputBufferBuilderHeight) * InputBufferBuilderWidth) + _write_x_position;
_next_write_x_position += required_length + 2;
}
} }
void CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length, uint8_t *buffer) bool CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length, uint8_t *buffer)
{ {
if(_is_full) return false;
// 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( &buffer[(_write_target_pointer - 1) * bytes_per_pixel], memcpy( &buffer[(_write_target_pointer - 1) * _bytes_per_pixel],
&buffer[_write_target_pointer * bytes_per_pixel], &buffer[_write_target_pointer * _bytes_per_pixel],
bytes_per_pixel); _bytes_per_pixel);
memcpy( &buffer[(_write_target_pointer + actual_length) * bytes_per_pixel], memcpy( &buffer[(_write_target_pointer + actual_length) * _bytes_per_pixel],
&buffer[(_write_target_pointer + actual_length - 1) * bytes_per_pixel], &buffer[(_write_target_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 // return any allocated length that wasn't actually used to the available pool
_next_write_x_position -= (_last_allocation_amount - actual_length); _next_write_x_position -= (_last_allocation_amount - actual_length);
return true;
} }

View File

@ -20,23 +20,26 @@ namespace CRT {
struct CRTInputBufferBuilder { struct CRTInputBufferBuilder {
CRTInputBufferBuilder(size_t bytes_per_pixel); CRTInputBufferBuilder(size_t bytes_per_pixel);
~CRTInputBufferBuilder();
void allocate_write_area(size_t required_length); void allocate_write_area(size_t required_length);
void reduce_previous_allocation_to(size_t actual_length, uint8_t *buffer); bool reduce_previous_allocation_to(size_t actual_length, uint8_t *buffer);
inline uint16_t get_and_finalise_current_line() inline uint16_t get_and_finalise_current_line()
{ {
uint16_t result = _write_y_position; uint16_t result = _write_y_position;
_next_write_x_position = 0; if(!_is_full)
_next_write_y_position++; {
_next_write_x_position = 0;
_next_write_y_position++;
}
_next_write_y_position %= InputBufferBuilderHeight; _next_write_y_position %= InputBufferBuilderHeight;
_is_full = false;
return result; return result;
} }
inline uint8_t *get_write_target(uint8_t *buffer) inline uint8_t *get_write_target(uint8_t *buffer)
{ {
return &buffer[_write_target_pointer * bytes_per_pixel]; return _is_full ? nullptr : &buffer[_write_target_pointer * _bytes_per_pixel];
} }
inline uint16_t get_last_write_x_position() inline uint16_t get_last_write_x_position()
@ -51,7 +54,7 @@ struct CRTInputBufferBuilder {
inline size_t get_bytes_per_pixel() inline size_t get_bytes_per_pixel()
{ {
return bytes_per_pixel; return _bytes_per_pixel;
} }
private: private:
@ -66,11 +69,12 @@ struct CRTInputBufferBuilder {
size_t _last_allocation_amount; size_t _last_allocation_amount;
// the buffer size // the buffer size
size_t bytes_per_pixel; size_t _bytes_per_pixel;
// Storage for the amount of buffer uploaded so far; initialised correctly by the buffer // Storage for the amount of buffer uploaded so far; initialised correctly by the buffer
// builder but otherwise entrusted to the CRT to update. // builder but otherwise entrusted to the CRT to update.
unsigned int last_uploaded_line; unsigned int _last_uploaded_line;
bool _is_full;
}; };
} }

View File

@ -152,9 +152,9 @@ class OpenGLOutputBuilder {
return output; return output;
} }
inline void reduce_previous_allocation_to(size_t actual_length) inline bool reduce_previous_allocation_to(size_t actual_length)
{ {
_buffer_builder->reduce_previous_allocation_to(actual_length, _input_texture_data); return _buffer_builder->reduce_previous_allocation_to(actual_length, _input_texture_data);
} }
inline uint16_t get_last_write_x_posititon() inline uint16_t get_last_write_x_posititon()