mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +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:
parent
3684c6404f
commit
87df57195d
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user