1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +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];
}
// store colour
pixel[0] = outputColour;
// store colour, if possible
if(pixel) *pixel = outputColour;
}
// 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(_outputBuffer)
get_output_pixel(&_outputBuffer[_lastOutputStateDuration], 159 - _horizontalTimer);
get_output_pixel(_outputBuffer ? &_outputBuffer[_lastOutputStateDuration] : nullptr, 159 - _horizontalTimer);
// increment all graphics counters
increment_object_counter(0);

View File

@ -539,7 +539,7 @@ inline void Machine::start_pixel_line()
}
_currentScreenAddress = _startLineAddress;
_current_pixel_column = 0;
_current_output_target = nullptr;
_initial_output_target = _current_output_target = nullptr;
}
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;
}
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);
_current_output_divider = divider;
@ -584,97 +584,112 @@ inline void Machine::output_pixels(unsigned int number_of_cycles)
switch(_screen_mode)
{
case 0: case 3:
while(number_of_cycles--)
if(_initial_output_target)
{
get_pixel();
*(uint32_t *)_current_output_target = _paletteTables.eighty1bpp[_last_pixel_byte];
_current_output_target += 4;
_current_pixel_column++;
}
while(number_of_cycles--)
{
get_pixel();
*(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;
case 1:
while(number_of_cycles--)
if(_initial_output_target)
{
get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.eighty2bpp[_last_pixel_byte];
_current_output_target += 2;
_current_pixel_column++;
}
while(number_of_cycles--)
{
get_pixel();
*(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;
case 2:
while(number_of_cycles--)
if(_initial_output_target)
{
get_pixel();
*_current_output_target = _paletteTables.eighty4bpp[_last_pixel_byte];
_current_output_target += 1;
_current_pixel_column++;
}
while(number_of_cycles--)
{
get_pixel();
*_current_output_target = _paletteTables.eighty4bpp[_last_pixel_byte];
_current_output_target += 1;
_current_pixel_column++;
}
} else _current_output_target += number_of_cycles;
break;
case 4: case 6:
if(_current_pixel_column&1)
if(_initial_output_target)
{
_last_pixel_byte <<= 4;
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
if(_current_pixel_column&1)
{
_last_pixel_byte <<= 4;
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
number_of_cycles--;
_current_pixel_column++;
}
while(number_of_cycles > 1)
{
get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
number_of_cycles--;
_current_pixel_column++;
}
while(number_of_cycles > 1)
{
get_pixel();
*(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;
_last_pixel_byte <<= 4;
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
number_of_cycles -= 2;
_current_pixel_column+=2;
}
if(number_of_cycles)
{
get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
_current_pixel_column++;
}
number_of_cycles -= 2;
_current_pixel_column+=2;
}
if(number_of_cycles)
{
get_pixel();
*(uint16_t *)_current_output_target = _paletteTables.forty1bpp[_last_pixel_byte];
_current_output_target += 2;
_current_pixel_column++;
}
} else _current_output_target += 2 * number_of_cycles;
break;
case 5:
if(_current_pixel_column&1)
if(_initial_output_target)
{
_last_pixel_byte <<= 2;
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
if(_current_pixel_column&1)
{
_last_pixel_byte <<= 2;
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
number_of_cycles--;
_current_pixel_column++;
}
while(number_of_cycles > 1)
{
get_pixel();
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
number_of_cycles--;
_current_pixel_column++;
}
while(number_of_cycles > 1)
{
get_pixel();
*_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;
_last_pixel_byte <<= 2;
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
number_of_cycles -= 2;
_current_pixel_column+=2;
}
if(number_of_cycles)
{
get_pixel();
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
_current_pixel_column++;
}
number_of_cycles -= 2;
_current_pixel_column+=2;
}
if(number_of_cycles)
{
get_pixel();
*_current_output_target = _paletteTables.forty2bpp[_last_pixel_byte];
_current_output_target += 1;
_current_pixel_column++;
}
} else _current_output_target += number_of_cycles;
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)
{
_openGL_output_builder->reduce_previous_allocation_to(number_of_cycles / source_divider);
Scan scan {
.type = Scan::Type::Data,
.number_of_cycles = number_of_cycles,
.tex_x = _openGL_output_builder->get_last_write_x_posititon(),
.tex_y = _openGL_output_builder->get_last_write_y_posititon(),
.source_divider = source_divider
};
output_scan(&scan);
if(_openGL_output_builder->reduce_previous_allocation_to(number_of_cycles / source_divider))
{
Scan scan {
.type = Scan::Type::Data,
.number_of_cycles = number_of_cycles,
.tex_x = _openGL_output_builder->get_last_write_x_posititon(),
.tex_y = _openGL_output_builder->get_last_write_y_posititon(),
.source_divider = source_divider
};
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)

View File

@ -176,14 +176,16 @@ class CRT {
*/
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
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.
Allocation should fail only if emulation is running significantly below real speed.
@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)
{

View File

@ -13,44 +13,51 @@
using namespace Outputs::CRT;
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_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)
{
_last_allocation_amount = required_length;
if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
if (!_is_full)
{
_next_write_x_position = 0;
_next_write_y_position++;
}
_last_allocation_amount = required_length;
_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;
if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
{
_next_write_x_position = 0;
_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
// against rounding errors when this run is drawn
memcpy( &buffer[(_write_target_pointer - 1) * bytes_per_pixel],
&buffer[_write_target_pointer * bytes_per_pixel],
bytes_per_pixel);
memcpy( &buffer[(_write_target_pointer - 1) * _bytes_per_pixel],
&buffer[_write_target_pointer * _bytes_per_pixel],
_bytes_per_pixel);
memcpy( &buffer[(_write_target_pointer + actual_length) * bytes_per_pixel],
&buffer[(_write_target_pointer + actual_length - 1) * bytes_per_pixel],
bytes_per_pixel);
memcpy( &buffer[(_write_target_pointer + actual_length) * _bytes_per_pixel],
&buffer[(_write_target_pointer + actual_length - 1) * _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);
return true;
}

View File

@ -20,23 +20,26 @@ namespace CRT {
struct CRTInputBufferBuilder {
CRTInputBufferBuilder(size_t bytes_per_pixel);
~CRTInputBufferBuilder();
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()
{
uint16_t result = _write_y_position;
_next_write_x_position = 0;
_next_write_y_position++;
if(!_is_full)
{
_next_write_x_position = 0;
_next_write_y_position++;
}
_next_write_y_position %= InputBufferBuilderHeight;
_is_full = false;
return result;
}
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()
@ -51,7 +54,7 @@ struct CRTInputBufferBuilder {
inline size_t get_bytes_per_pixel()
{
return bytes_per_pixel;
return _bytes_per_pixel;
}
private:
@ -66,11 +69,12 @@ struct CRTInputBufferBuilder {
size_t _last_allocation_amount;
// 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
// 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;
}
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()