mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Started edging towards completing the CPU side of accumulating enough data for composite decoding.
This commit is contained in:
parent
5c8db71c64
commit
23c223e2ed
@ -66,9 +66,9 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
|
||||
_run_builders = new CRTRunBuilder *[kCRTNumberOfFields];
|
||||
for(int builder = 0; builder < kCRTNumberOfFields; builder++)
|
||||
{
|
||||
_run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize);
|
||||
_run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize, 6);
|
||||
}
|
||||
_composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(kCRTInputVertexSize));
|
||||
_composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(kCRTInputVertexSize, 2));
|
||||
|
||||
va_list va;
|
||||
va_copy(va, sizes);
|
||||
@ -77,14 +77,14 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
|
||||
}
|
||||
|
||||
CRT::CRT(unsigned int common_output_divisor) :
|
||||
_next_scan(0),
|
||||
_run_write_pointer(0),
|
||||
_sync_capacitor_charge_level(0),
|
||||
_is_receiving_sync(false),
|
||||
_output_mutex(new std::mutex),
|
||||
_visible_area(Rect(0, 0, 1, 1)),
|
||||
_sync_period(0),
|
||||
_common_output_divisor(common_output_divisor)
|
||||
_common_output_divisor(common_output_divisor),
|
||||
_composite_src_output_y(0)
|
||||
{
|
||||
construct_openGL();
|
||||
}
|
||||
@ -131,6 +131,21 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested,
|
||||
return _horizontal_flywheel->get_next_event_in_period(hsync_is_requested, cycles_to_run_for, cycles_advanced);
|
||||
}
|
||||
|
||||
#define output_position_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 0])
|
||||
#define output_position_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 2])
|
||||
#define output_tex_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 0])
|
||||
#define output_tex_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 2])
|
||||
#define output_lateral(v) next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfLateral]
|
||||
#define output_timestamp(v) (*(uint32_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTimestamp])
|
||||
|
||||
#define input_input_position_x(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfInputPosition + 0])
|
||||
#define input_input_position_y(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfInputPosition + 2])
|
||||
#define input_output_position_x(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfOutputPosition + 0])
|
||||
#define input_output_position_y(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfOutputPosition + 2])
|
||||
#define input_phase(v) next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseAndAmplitude + 0]
|
||||
#define input_amplitude(v) next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseAndAmplitude + 1]
|
||||
#define input_phase_time(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseTime])
|
||||
|
||||
void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divider, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Type type, uint16_t tex_x, uint16_t tex_y)
|
||||
{
|
||||
number_of_cycles *= _time_multiplier;
|
||||
@ -150,33 +165,44 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
|
||||
hsync_requested = false;
|
||||
vsync_requested = false;
|
||||
|
||||
uint8_t *next_run = ((is_output_run && next_run_length) && !_horizontal_flywheel->is_in_retrace() && !_vertical_flywheel->is_in_retrace()) ? _run_builders[_run_write_pointer]->get_next_run() : nullptr;
|
||||
|
||||
#define position_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 0])
|
||||
#define position_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 2])
|
||||
#define tex_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 0])
|
||||
#define tex_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 2])
|
||||
#define lateral(v) next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfLateral]
|
||||
#define timestamp(v) (*(uint32_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTimestamp])
|
||||
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)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
next_run = (_output_device == CRT::Monitor) ? _run_builders[_run_write_pointer]->get_next_run() : _composite_src_runs->get_next_run();
|
||||
}
|
||||
|
||||
// Vertex output is arranged as:
|
||||
//
|
||||
// [0/4] 3
|
||||
//
|
||||
// 1 [2/5]
|
||||
|
||||
if(next_run)
|
||||
{
|
||||
// set the type, initial raster position and type of this run
|
||||
position_x(0) = position_x(1) = position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
position_y(0) = position_y(1) = position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
|
||||
timestamp(0) = timestamp(1) = timestamp(4) = _run_builders[_run_write_pointer]->duration;
|
||||
tex_x(0) = tex_x(1) = tex_x(4) = tex_x;
|
||||
if(_output_device == CRT::Monitor)
|
||||
{
|
||||
// set the type, initial raster position and type of this run
|
||||
output_position_x(0) = output_position_x(1) = output_position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
output_position_y(0) = output_position_y(1) = output_position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
|
||||
output_timestamp(0) = output_timestamp(1) = output_timestamp(4) = _run_builders[_run_write_pointer]->duration;
|
||||
output_tex_x(0) = output_tex_x(1) = output_tex_x(4) = tex_x;
|
||||
|
||||
// these things are constants across the line so just throw them out now
|
||||
tex_y(0) = tex_y(4) = tex_y(1) = tex_y(2) = tex_y(3) = tex_y(5) = tex_y;
|
||||
lateral(0) = lateral(4) = lateral(5) = 0;
|
||||
lateral(1) = lateral(2) = lateral(3) = 1;
|
||||
// these things are constants across the line so just throw them out now
|
||||
output_tex_y(0) = output_tex_y(4) = output_tex_y(1) = output_tex_y(2) = output_tex_y(3) = output_tex_y(5) = tex_y;
|
||||
output_lateral(0) = output_lateral(4) = output_lateral(5) = 0;
|
||||
output_lateral(1) = output_lateral(2) = output_lateral(3) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_input_position_x(0) = tex_x;
|
||||
input_input_position_y(0) = input_input_position_y(1) = tex_y;
|
||||
input_output_position_x(0) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
input_output_position_y(0) = input_output_position_y(1) = _composite_src_output_y;
|
||||
input_phase(0) = input_phase(1) = _colour_burst_phase;
|
||||
input_amplitude(0) = input_amplitude(1) = _colour_burst_amplitude;
|
||||
input_phase_time(0) = input_phase_time(1) = _colour_burst_time;
|
||||
}
|
||||
}
|
||||
|
||||
// decrement the number of cycles left to run for and increment the
|
||||
@ -196,18 +222,39 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
|
||||
|
||||
if(next_run)
|
||||
{
|
||||
// store the final raster position
|
||||
position_x(2) = position_x(3) = position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
position_y(2) = position_y(3) = position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
|
||||
timestamp(2) = timestamp(3) = timestamp(5) = _run_builders[_run_write_pointer]->duration;
|
||||
|
||||
// if this is a data run then advance the buffer pointer
|
||||
if(type == Type::Data && source_divider) tex_x += next_run_length / (_time_multiplier * source_divider);
|
||||
|
||||
// if this is a data or level run then store the end point
|
||||
tex_x(2) = tex_x(3) = tex_x(5) = tex_x;
|
||||
if(_output_device == CRT::Monitor)
|
||||
{
|
||||
// store the final raster position
|
||||
output_position_x(2) = output_position_x(3) = output_position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
output_position_y(2) = output_position_y(3) = output_position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
|
||||
output_timestamp(2) = output_timestamp(3) = output_timestamp(5) = _run_builders[_run_write_pointer]->duration;
|
||||
output_tex_x(2) = output_tex_x(3) = output_tex_x(5) = tex_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_input_position_x(1) = tex_x;
|
||||
input_output_position_x(1) = (uint16_t)_horizontal_flywheel->get_current_output_position();
|
||||
}
|
||||
}
|
||||
|
||||
if(is_output_segment)
|
||||
{
|
||||
_output_mutex->unlock();
|
||||
}
|
||||
|
||||
// if this is horizontal retrace then advance the output line counter and bookend an output run
|
||||
if(_output_device == CRT::Television)
|
||||
{
|
||||
if(next_run_length == time_until_horizontal_sync_event && next_horizontal_sync_event == Flywheel::SyncEvent::EndRetrace)
|
||||
{
|
||||
_composite_src_output_y = (_composite_src_output_y + 1) % CRTIntermediateBufferHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is vertical retrace then adcance a field
|
||||
if(next_run_length == time_until_vertical_sync_event && next_vertical_sync_event == Flywheel::SyncEvent::EndRetrace)
|
||||
{
|
||||
// TODO: how to communicate did_detect_vsync? Bring the delegate back?
|
||||
@ -219,13 +266,25 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
|
||||
}
|
||||
}
|
||||
|
||||
#undef output_position_x
|
||||
#undef output_position_y
|
||||
#undef output_tex_x
|
||||
#undef output_tex_y
|
||||
#undef output_lateral
|
||||
#undef output_timestamp
|
||||
|
||||
#undef input_input_position_x
|
||||
#undef input_input_position_y
|
||||
#undef input_output_position_x
|
||||
#undef input_output_position_y
|
||||
#undef input_phase
|
||||
#undef input_amplitude
|
||||
#undef input_phase_age
|
||||
|
||||
#pragma mark - stream feeding methods
|
||||
|
||||
void CRT::output_scan()
|
||||
void CRT::output_scan(Scan *scan)
|
||||
{
|
||||
// _next_scan ^= 1;
|
||||
Scan *scan = &_scans[_next_scan];
|
||||
|
||||
bool this_is_sync = (scan->type == Type::Sync);
|
||||
bool is_trailing_edge = (_is_receiving_sync && !this_is_sync);
|
||||
bool hsync_requested = is_trailing_edge && (_sync_period < (_horizontal_flywheel->get_scan_period() >> 2));
|
||||
@ -241,57 +300,55 @@ void CRT::output_scan()
|
||||
*/
|
||||
void CRT::output_sync(unsigned int number_of_cycles)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
_scans[_next_scan].type = Type::Sync;
|
||||
_scans[_next_scan].number_of_cycles = number_of_cycles;
|
||||
output_scan();
|
||||
_output_mutex->unlock();
|
||||
Scan scan{
|
||||
.type = Type::Sync,
|
||||
.number_of_cycles = number_of_cycles
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_blank(unsigned int number_of_cycles)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
_scans[_next_scan].type = Type::Blank;
|
||||
_scans[_next_scan].number_of_cycles = number_of_cycles;
|
||||
output_scan();
|
||||
_output_mutex->unlock();
|
||||
Scan scan {
|
||||
.type = Type::Blank,
|
||||
.number_of_cycles = number_of_cycles
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_level(unsigned int number_of_cycles)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
_scans[_next_scan].type = Type::Level;
|
||||
_scans[_next_scan].number_of_cycles = number_of_cycles;
|
||||
_scans[_next_scan].tex_x = _buffer_builder->_write_x_position;
|
||||
_scans[_next_scan].tex_y = _buffer_builder->_write_y_position;
|
||||
output_scan();
|
||||
_output_mutex->unlock();
|
||||
Scan scan {
|
||||
.type = Type::Level,
|
||||
.number_of_cycles = number_of_cycles,
|
||||
.tex_x = _buffer_builder->_write_x_position,
|
||||
.tex_y = _buffer_builder->_write_y_position
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t magnitude)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
_scans[_next_scan].type = Type::ColourBurst;
|
||||
_scans[_next_scan].number_of_cycles = number_of_cycles;
|
||||
_scans[_next_scan].phase = phase;
|
||||
_scans[_next_scan].magnitude = magnitude;
|
||||
output_scan();
|
||||
_output_mutex->unlock();
|
||||
Scan scan {
|
||||
.type = Type::ColourBurst,
|
||||
.number_of_cycles = number_of_cycles,
|
||||
.phase = phase,
|
||||
.magnitude = magnitude
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
|
||||
{
|
||||
_output_mutex->lock();
|
||||
|
||||
_buffer_builder->reduce_previous_allocation_to(number_of_cycles / source_divider);
|
||||
_scans[_next_scan].type = Type::Data;
|
||||
_scans[_next_scan].number_of_cycles = number_of_cycles;
|
||||
_scans[_next_scan].tex_x = _buffer_builder->_write_x_position;
|
||||
_scans[_next_scan].tex_y = _buffer_builder->_write_y_position;
|
||||
_scans[_next_scan].source_divider = source_divider;
|
||||
output_scan();
|
||||
|
||||
_output_mutex->unlock();
|
||||
Scan scan {
|
||||
.type = Type::Data,
|
||||
.number_of_cycles = number_of_cycles,
|
||||
.tex_x = _buffer_builder->_write_x_position,
|
||||
.tex_y = _buffer_builder->_write_y_position,
|
||||
.source_divider = source_divider
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
#pragma mark - Buffer supply
|
||||
|
@ -292,12 +292,11 @@ class CRT {
|
||||
uint8_t phase, magnitude;
|
||||
};
|
||||
};
|
||||
} _scans[2];
|
||||
int _next_scan;
|
||||
void output_scan();
|
||||
};
|
||||
void output_scan(Scan *scan);
|
||||
|
||||
struct CRTRunBuilder {
|
||||
CRTRunBuilder(size_t vertex_size) : _vertex_size(vertex_size) { reset(); }
|
||||
CRTRunBuilder(size_t vertex_size, int vertices_per_run) : _vertex_size(vertex_size), _vertices_per_run(vertices_per_run) { reset(); }
|
||||
|
||||
// Resets the run builder.
|
||||
void reset();
|
||||
@ -319,6 +318,7 @@ class CRT {
|
||||
|
||||
private:
|
||||
size_t _vertex_size;
|
||||
int _vertices_per_run;
|
||||
};
|
||||
|
||||
struct CRTInputBufferBuilder {
|
||||
@ -355,7 +355,9 @@ class CRT {
|
||||
|
||||
// transient buffers indicating composite data not yet decoded
|
||||
std::unique_ptr<CRTRunBuilder> _composite_src_runs;
|
||||
int _composite_src_output_y;
|
||||
uint16_t _composite_src_output_y;
|
||||
uint8_t _colour_burst_phase, _colour_burst_amplitude;
|
||||
uint16_t _colour_burst_time;
|
||||
|
||||
// OpenGL state, kept behind an opaque pointer to avoid inclusion of the GL headers here.
|
||||
struct OpenGLState;
|
||||
|
@ -88,16 +88,14 @@ void CRT::CRTRunBuilder::reset()
|
||||
|
||||
uint8_t *CRT::CRTRunBuilder::get_next_run()
|
||||
{
|
||||
const size_t vertices_per_run = 6;
|
||||
|
||||
// get a run from the allocated list, allocating more if we're about to overrun
|
||||
if((number_of_vertices + vertices_per_run) * _vertex_size >= _runs.size())
|
||||
if((number_of_vertices + (size_t)_vertices_per_run) * _vertex_size >= _runs.size())
|
||||
{
|
||||
_runs.resize(_runs.size() + _vertex_size * vertices_per_run * 100);
|
||||
_runs.resize(_runs.size() + _vertex_size * (size_t)_vertices_per_run * 100);
|
||||
}
|
||||
|
||||
uint8_t *next_run = &_runs[number_of_vertices * _vertex_size];
|
||||
number_of_vertices += vertices_per_run;
|
||||
number_of_vertices += (size_t)_vertices_per_run;
|
||||
|
||||
return next_run;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const size_t kCRTOutputVertexSize = 16;
|
||||
const size_t kCRTInputVertexOffsetOfInputPosition = 0;
|
||||
const size_t kCRTInputVertexOffsetOfOutputPosition = 4;
|
||||
const size_t kCRTInputVertexOffsetOfPhaseAndAmplitude = 8;
|
||||
const size_t kCRTInputVertexOffsetOfPhaseAge = 12;
|
||||
const size_t kCRTInputVertexOffsetOfPhaseTime = 12;
|
||||
|
||||
const size_t kCRTInputVertexSize = 16;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user