diff --git a/Machines/Atari2600.cpp b/Machines/Atari2600.cpp index 502e456dc..af28d628d 100644 --- a/Machines/Atari2600.cpp +++ b/Machines/Atari2600.cpp @@ -81,17 +81,7 @@ void Machine::output_state(OutputState state, uint8_t *pixel) { switch(_lastOutputState) { - case OutputState::Blank: { - _crt->allocate_write_area(1); - _outputBuffer = _crt->get_write_target_for_buffer(0); - - if(_outputBuffer) - { - _outputBuffer[0] = _outputBuffer[1] = _outputBuffer[2] = 0; - _outputBuffer[3] = 0xff; - } - _crt->output_level(_lastOutputStateDuration, atari2600DataType); - } break; + case OutputState::Blank: _crt->output_blank(_lastOutputStateDuration); break; case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break; case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, atari2600DataType); break; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 17c6e3c0a..5fad4447b 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -322,6 +322,7 @@ 4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502AllRAM.hpp; sourceTree = ""; }; 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WolfgangLorenzTests.swift; sourceTree = ""; }; 4B1414611B58888700E04248 /* KlausDormannTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KlausDormannTests.swift; sourceTree = ""; }; + 4B2632551B631A510082A461 /* CRTFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CRTFrame.h; path = ../../Outputs/CRTFrame.h; sourceTree = ""; }; 4B366DFA1B5C165A0026627B /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRT.cpp; path = ../../Outputs/CRT.cpp; sourceTree = ""; }; 4B366DFB1B5C165A0026627B /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRT.hpp; path = ../../Outputs/CRT.hpp; sourceTree = ""; }; 4B6D7F921B58822000787C9A /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = ""; }; @@ -663,6 +664,7 @@ children = ( 4B366DFA1B5C165A0026627B /* CRT.cpp */, 4B366DFB1B5C165A0026627B /* CRT.hpp */, + 4B2632551B631A510082A461 /* CRTFrame.h */, ); name = Outputs; sourceTree = ""; diff --git a/OSBindings/Mac/Clock Signal/Atari2600.mm b/OSBindings/Mac/Clock Signal/Atari2600.mm index 0c15866e9..b768eac5a 100644 --- a/OSBindings/Mac/Clock Signal/Atari2600.mm +++ b/OSBindings/Mac/Clock Signal/Atari2600.mm @@ -19,8 +19,8 @@ const char *vertexShader = "\n" "void main (void)\n" "{\n" - "colour = vec4(position, 0.0, 1.0);\n" - "gl_Position = vec4(position, 0.0, 1.0);\n" + "colour = vec4(1.0, 1.0, 1.0, 1.0);\n" + "gl_Position = vec4(position.x * 2.0 - 1.0, 1.0 - position.y * 2.0, 0.0, 1.0);\n" "}\n"; const char *fragmentShader = @@ -35,12 +35,12 @@ const char *fragmentShader = "}\n"; @interface CSAtari2600 (Callbacks) -- (void)crtDidEndFrame:(Outputs::CRTFrame *)frame; +- (void)crtDidEndFrame:(CRTFrame *)frame; @end struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { CSAtari2600 *atari; - void crt_did_end_frame(Outputs::CRT *crt, Outputs::CRTFrame *frame) { [atari crtDidEndFrame:frame]; } + void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame) { [atari crtDidEndFrame:frame]; } }; @implementation CSAtari2600 { @@ -48,7 +48,7 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { Atari2600CRTDelegate _crtDelegate; dispatch_queue_t _serialDispatchQueue; - Outputs::CRTFrame *_queuedFrame; + CRTFrame *_queuedFrame; GLuint _vertexShader, _fragmentShader; GLuint _shaderProgram; @@ -56,7 +56,7 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { GLuint _arrayBuffer, _vertexArray; } -- (void)crtDidEndFrame:(Outputs::CRTFrame *)frame { +- (void)crtDidEndFrame:(CRTFrame *)frame { dispatch_async(dispatch_get_main_queue(), ^{ if(_queuedFrame) { @@ -95,14 +95,12 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { glGenBuffers(1, &_arrayBuffer); glBindBuffer(GL_ARRAY_BUFFER, _arrayBuffer); - GLfloat vertices[] = { - 0.0f, 0.0f, - 0.5f, 0.0f, - 0.5f, 0.6f, - 0.0f, 0.5f + GLushort vertices[] = { + 0, 0, + 32767, 32767, }; - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); } if(_queuedFrame) @@ -114,40 +112,12 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { GLint position = glGetAttribLocation(_shaderProgram, "position"); + glBufferData(GL_ARRAY_BUFFER, _queuedFrame->number_of_runs * sizeof(GLushort) * 8, _queuedFrame->runs, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(position); - glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); + glVertexAttribPointer(position, 2, GL_UNSIGNED_SHORT, GL_TRUE, 4 * sizeof(GLushort), (void *)0); - glDrawArrays(GL_LINES, 0, 4); - -/* printf("\n\n===\n\n"); - int c = 0; - for(int run = 0; run < _queuedFrame->number_of_runs; run++) - { - char character = ' '; - switch(_queuedFrame->runs[run].type) - { - case Outputs::CRTRun::Type::Sync: character = '<'; break; - case Outputs::CRTRun::Type::Level: character = '_'; break; - case Outputs::CRTRun::Type::Data: character = '-'; break; - case Outputs::CRTRun::Type::Blank: character = ' '; break; - } - - if(_queuedFrame->runs[run].start_point.dst_x < 1.0 / 224.0) - { - printf("\n[%0.2f]: ", _queuedFrame->runs[run].start_point.dst_y); - c++; - } - - printf("(%0.2f): ", _queuedFrame->runs[run].start_point.dst_x); - float length = fabsf(_queuedFrame->runs[run].end_point.dst_x - _queuedFrame->runs[run].start_point.dst_x); - int iLength = (int)(length * 64.0); - for(int c = 0; c < iLength; c++) - { - putc(character, stdout); - } - } - - printf("\n\n[%d]\n\n", c);*/ + glDrawArrays(GL_LINES, 0, _queuedFrame->number_of_runs*2); } } diff --git a/Outputs/CRT.cpp b/Outputs/CRT.cpp index 47f3b45ce..42c120663 100644 --- a/Outputs/CRT.cpp +++ b/Outputs/CRT.cpp @@ -29,10 +29,10 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...) _horizontal_retrace_time = (millisecondsHorizontalRetraceTime * cycles_per_line) >> 6; _vertical_retrace_time = scanlinesVerticalRetraceTime * cycles_per_line; - _scanSpeed.x = 1.0f / (float)cycles_per_line; - _scanSpeed.y = 1.0f / (float)(height_of_display * cycles_per_line); - _retraceSpeed.x = 1.0f / (float)_horizontal_retrace_time; - _retraceSpeed.y = 1.0f / (float)_vertical_retrace_time; + _scanSpeed.x = UINT32_MAX / cycles_per_line; + _scanSpeed.y = UINT32_MAX / (height_of_display * cycles_per_line); + _retraceSpeed.x = UINT32_MAX / _horizontal_retrace_time; + _retraceSpeed.y = UINT32_MAX / _vertical_retrace_time; // generate buffers for signal storage as requested — format is // number of buffers, size of buffer 1, size of buffer 2... @@ -42,15 +42,15 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...) { va_list va; va_start(va, number_of_buffers); - _frames[frame] = new CRTFrame(bufferWidth, bufferHeight, number_of_buffers, va); + _frame_builders[frame] = new CRTFrameBuilder(bufferWidth, bufferHeight, number_of_buffers, va); va_end(va); } _frames_with_delegate = 0; _frame_read_pointer = 0; - _current_frame = _frames[0]; + _current_frame_builder = _frame_builders[0]; // reset raster position - _rasterPosition.x = _rasterPosition.y = 0.0f; + _rasterPosition.x = _rasterPosition.y = 0; // reset flywheel sync _expected_next_hsync = cycles_per_line; @@ -69,7 +69,7 @@ CRT::~CRT() { for(int frame = 0; frame < 3; frame++) { - delete _frames[frame]; + delete _frame_builders[frame]; } } @@ -81,14 +81,14 @@ CRT::SyncEvent CRT::next_vertical_sync_event(bool vsync_is_charging, int cycles_ int proposedSyncTime = cycles_to_run_for; // have we overrun the maximum permitted number of horizontal syncs for this frame? - if (!_vretrace_counter) - { - float raster_distance = _scanSpeed.y * (float)proposedSyncTime; - if(_rasterPosition.y < 1.02f && _rasterPosition.y + raster_distance >= 1.02f) { - proposedSyncTime = (int)(1.02f - _rasterPosition.y) / _scanSpeed.y; - proposedEvent = SyncEvent::StartVSync; - } - } +// if (!_vretrace_counter) +// { +// float raster_distance = _scanSpeed.y * (float)proposedSyncTime; +// if(_rasterPosition.y < 1.02f && _rasterPosition.y + raster_distance >= 1.02f) { +// proposedSyncTime = (int)(1.02f - _rasterPosition.y) / _scanSpeed.y; +// proposedEvent = SyncEvent::StartVSync; +// } +// } // will an acceptable vertical sync be triggered? if (vsync_is_charging && !_vretrace_counter) { @@ -141,10 +141,16 @@ CRT::SyncEvent CRT::next_horizontal_sync_event(bool hsync_is_requested, int cycl return proposedEvent; } -void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool vsync_charging, const CRTRun::Type type, const char *data_type) +void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool vsync_charging, const Type type, const char *data_type) { - // this is safe to keep locally because it accumulates over this run of cycles only - int buffer_offset = 0; + const bool is_output_run = ((type == Type::Level) || (type == Type::Data)); + uint16_t tex_x = 0; + uint16_t tex_y = 0; + + if(is_output_run && _current_frame_builder) { + tex_x = _current_frame_builder->_write_x_position; + tex_y = _current_frame_builder->_write_y_position; + } while(number_of_cycles) { @@ -157,50 +163,40 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool // set it to false for the next run through this loop (if any) int next_run_length = std::min(time_until_vertical_sync_event, time_until_horizontal_sync_event); - CRTRun *nextRun = (_current_frame && next_run_length) ? _current_frame->get_next_run() : nullptr; + uint16_t *next_run = (is_output_run && _current_frame_builder && next_run_length) ? _current_frame_builder->get_next_run() : nullptr; - if(nextRun) + if(next_run) { // set the type, initial raster position and type of this run - nextRun->type = type; - nextRun->start_point.dst_x = _rasterPosition.x; - nextRun->start_point.dst_y = _rasterPosition.y; - nextRun->data_type = data_type; + next_run[0] = _rasterPosition.x >> 16; + next_run[1] = _rasterPosition.y >> 16; + next_run[2] = tex_x; + next_run[3] = tex_y; + } - // if this is a data or level run then store a starting data position - if(type == CRTRun::Type::Data || type == CRTRun::Type::Level) - { - nextRun->start_point.src_x = (_current_frame->_write_target_pointer + buffer_offset) & (_current_frame->size.width - 1); - nextRun->start_point.src_y = (_current_frame->_write_target_pointer + buffer_offset) / _current_frame->size.width; - } + // advance the raster position as dictated by current sync status + if (_is_in_hsync) + _rasterPosition.x = (uint32_t)std::max((int64_t)0, (int64_t)_rasterPosition.x - number_of_cycles * (int64_t)_retraceSpeed.x); + else + _rasterPosition.x = (uint32_t)std::min((int64_t)UINT32_MAX, (int64_t)_rasterPosition.x + number_of_cycles * (int64_t)_scanSpeed.x); - // advance the raster position as dictated by current sync status - if (_is_in_hsync) - _rasterPosition.x = std::max(0.0f, _rasterPosition.x - (float)number_of_cycles * _retraceSpeed.x); - else - _rasterPosition.x = std::min(1.0f, _rasterPosition.x + (float)number_of_cycles * _scanSpeed.x); - - if (_vretrace_counter > 0) - _rasterPosition.y = std::max(0.0f, _rasterPosition.y - (float)number_of_cycles * _retraceSpeed.y); - else - _rasterPosition.y = std::min(1.0f, _rasterPosition.y + (float)number_of_cycles * _scanSpeed.y); + if (_vretrace_counter > 0) + _rasterPosition.y = (uint32_t)std::max((int64_t)0, (int64_t)_rasterPosition.y - number_of_cycles * (int64_t)_retraceSpeed.y); + else + _rasterPosition.y = (uint32_t)std::min((int64_t)UINT32_MAX, (int64_t)_rasterPosition.y + number_of_cycles * (int64_t)_scanSpeed.y); + if(next_run) + { // store the final raster position - nextRun->end_point.dst_x = _rasterPosition.x; - nextRun->end_point.dst_y = _rasterPosition.y; + next_run[4] = _rasterPosition.x >> 16; + next_run[5] = _rasterPosition.y >> 16; // if this is a data run then advance the buffer pointer - if(type == CRTRun::Type::Data) - { - buffer_offset += next_run_length; - } + if(type == Type::Data) tex_x += next_run_length; // if this is a data or level run then store the end point - if(type == CRTRun::Type::Data || type == CRTRun::Type::Level) - { - nextRun->end_point.src_x = (_current_frame->_write_target_pointer + buffer_offset) & (_current_frame->size.width - 1); - nextRun->end_point.src_y = (_current_frame->_write_target_pointer + buffer_offset) / _current_frame->size.width; - } + next_run[6] = tex_x; + next_run[7] = tex_y; } // decrement the number of cycles left to run for and increment the @@ -256,21 +252,21 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool // end of vertical sync: tell the delegate that we finished vertical sync, // releasing all runs back into the common pool case SyncEvent::EndVSync: - if(_delegate && _current_frame) + if(_delegate && _current_frame_builder) { - _current_frame->complete(); + _current_frame_builder->complete(); _frames_with_delegate++; - _delegate->crt_did_end_frame(this, _current_frame); + _delegate->crt_did_end_frame(this, &_current_frame_builder->frame); } if(_frames_with_delegate < kCRTNumberOfFrames) { _frame_read_pointer = (_frame_read_pointer + 1)%kCRTNumberOfFrames; - _current_frame = _frames[_frame_read_pointer]; - _current_frame->reset(); + _current_frame_builder = _frame_builders[_frame_read_pointer]; + _current_frame_builder->reset(); } else - _current_frame = nullptr; + _current_frame_builder = nullptr; break; default: break; @@ -300,104 +296,106 @@ void CRT::output_sync(int number_of_cycles) { bool _hsync_requested = !_is_receiving_sync; // ensure this really is edge triggered; someone calling output_sync twice in succession shouldn't trigger it twice _is_receiving_sync = true; - advance_cycles(number_of_cycles, _hsync_requested, true, CRTRun::Type::Sync, nullptr); + advance_cycles(number_of_cycles, _hsync_requested, true, Type::Sync, nullptr); } void CRT::output_blank(int number_of_cycles) { _is_receiving_sync = false; - advance_cycles(number_of_cycles, false, false, CRTRun::Type::Blank, nullptr); + advance_cycles(number_of_cycles, false, false, Type::Blank, nullptr); } void CRT::output_level(int number_of_cycles, const char *type) { _is_receiving_sync = false; - advance_cycles(number_of_cycles, false, false, CRTRun::Type::Level, type); + advance_cycles(number_of_cycles, false, false, Type::Level, type); } void CRT::output_data(int number_of_cycles, const char *type) { _is_receiving_sync = false; - advance_cycles(number_of_cycles, false, false, CRTRun::Type::Data, type); + advance_cycles(number_of_cycles, false, false, Type::Data, type); } #pragma mark - Buffer supply void CRT::allocate_write_area(int required_length) { - if(_current_frame) _current_frame->allocate_write_area(required_length); + if(_current_frame_builder) _current_frame_builder->allocate_write_area(required_length); } uint8_t *CRT::get_write_target_for_buffer(int buffer) { - if (!_current_frame) return nullptr; - return _current_frame->get_write_target_for_buffer(buffer); + if (!_current_frame_builder) return nullptr; + return _current_frame_builder->get_write_target_for_buffer(buffer); } #pragma mark - CRTFrame -CRTFrame::CRTFrame(int width, int height, int number_of_buffers, va_list buffer_sizes) +CRTFrameBuilder::CRTFrameBuilder(int width, int height, int number_of_buffers, va_list buffer_sizes) { - size.width = width; - size.height = height; - this->number_of_buffers = number_of_buffers; - buffers = new CRTBuffer[number_of_buffers]; + frame.size.width = width; + frame.size.height = height; + frame.number_of_buffers = number_of_buffers; + frame.buffers = new CRTBuffer[number_of_buffers]; for(int buffer = 0; buffer < number_of_buffers; buffer++) { - buffers[buffer].depth = va_arg(buffer_sizes, int); - buffers[buffer].data = new uint8_t[width * height * buffers[buffer].depth]; + frame.buffers[buffer].depth = va_arg(buffer_sizes, int); + frame.buffers[buffer].data = new uint8_t[width * height * frame.buffers[buffer].depth]; } reset(); } -CRTFrame::~CRTFrame() +CRTFrameBuilder::~CRTFrameBuilder() { - for(int buffer = 0; buffer < number_of_buffers; buffer++) - delete[] buffers[buffer].data; - delete buffers; + for(int buffer = 0; buffer < frame.number_of_buffers; buffer++) + delete[] frame.buffers[buffer].data; + delete frame.buffers; } -void CRTFrame::reset() +void CRTFrameBuilder::reset() { - number_of_runs = 0; - _write_allocation_pointer = _write_target_pointer = 0; + frame.number_of_runs = 0; + _write_x_position = _write_y_position = 0; + frame.dirty_size.width = frame.dirty_size.height = 0; } -void CRTFrame::complete() +void CRTFrameBuilder::complete() { - runs = &_all_runs[0]; + frame.runs = &_all_runs[0]; } -CRTRun *CRTFrame::get_next_run() +uint16_t *CRTFrameBuilder::get_next_run() { // get a run from the allocated list, allocating more if we're about to overrun - if(number_of_runs >= _all_runs.size()) + if(frame.number_of_runs * 8 >= _all_runs.size()) { - _all_runs.resize((_all_runs.size() * 2)+1); + _all_runs.resize(_all_runs.size() + 4096); } - CRTRun *nextRun = &_all_runs[number_of_runs]; - number_of_runs++; + uint16_t *next_run = &_all_runs[frame.number_of_runs * 8]; + frame.number_of_runs++; - return nextRun; + return next_run; } -void CRTFrame::allocate_write_area(int required_length) +void CRTFrameBuilder::allocate_write_area(int required_length) { - int xPos = _write_allocation_pointer & (size.width - 1); - if (xPos + required_length > size.width) + if (_write_x_position + required_length > frame.size.width) { - _write_allocation_pointer &= ~(size.width - 1); - _write_allocation_pointer = (_write_allocation_pointer + size.width) & ((size.height-1) * size.width); + _write_x_position = 0; + _write_y_position++; + frame.dirty_size.height++; } - _write_target_pointer = _write_allocation_pointer; - _write_allocation_pointer += required_length; + _write_target_pointer = (_write_y_position * frame.size.width) + _write_x_position; + _write_x_position += required_length; + frame.dirty_size.width = std::max(frame.dirty_size.width, _write_x_position); } -uint8_t *CRTFrame::get_write_target_for_buffer(int buffer) +uint8_t *CRTFrameBuilder::get_write_target_for_buffer(int buffer) { - return &buffers[buffer].data[_write_target_pointer * buffers[buffer].depth]; + return &frame.buffers[buffer].data[_write_target_pointer * frame.buffers[buffer].depth]; } diff --git a/Outputs/CRT.hpp b/Outputs/CRT.hpp index 7dd980411..244777a57 100644 --- a/Outputs/CRT.hpp +++ b/Outputs/CRT.hpp @@ -14,48 +14,24 @@ #include #include +#include "CRTFrame.h" + namespace Outputs { -struct CRTBuffer { - uint8_t *data; - int depth; -}; - -struct CRTRun { - struct Point { - float dst_x, dst_y; - int src_x, src_y; - } start_point, end_point; - - enum Type { - Sync, Level, Data, Blank - } type; - - const char *data_type; -}; - class CRT; -struct CRTFrame { - struct { - int width, height; - } size; +struct CRTFrameBuilder { + CRTFrame frame; - int number_of_buffers; - CRTBuffer *buffers; - - int number_of_runs; - CRTRun *runs; - - CRTFrame(int width, int height, int number_of_buffers, va_list buffer_sizes); - ~CRTFrame(); + CRTFrameBuilder(int width, int height, int number_of_buffers, va_list buffer_sizes); + ~CRTFrameBuilder(); private: - std::vector _all_runs; + std::vector _all_runs; void reset(); void complete(); - CRTRun *get_next_run(); + uint16_t *get_next_run(); friend CRT; void allocate_write_area(int required_length); @@ -63,7 +39,8 @@ struct CRTFrame { // a pointer to the section of content buffer currently being // returned and to where the next section will begin - int _write_allocation_pointer, _write_target_pointer; + int _write_x_position, _write_y_position; + int _write_target_pointer; }; static const int kCRTNumberOfFrames = 3; @@ -98,12 +75,12 @@ class CRT { // the current scanning position struct Vector { - float x, y; + uint32_t x, y; } _rasterPosition, _scanSpeed, _retraceSpeed; // the run delegate and the triple buffer - CRTFrame *_frames[kCRTNumberOfFrames]; - CRTFrame *_current_frame; + CRTFrameBuilder *_frame_builders[kCRTNumberOfFrames]; + CRTFrameBuilder *_current_frame_builder; int _frames_with_delegate; int _frame_read_pointer; CRTDelegate *_delegate; @@ -123,7 +100,10 @@ class CRT { bool _is_in_hsync; // true for the duration of a horizontal sync — used to determine beam running direction and speed // the outer entry point for dispatching output_sync, output_blank, output_level and output_data - void advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_charging, CRTRun::Type type, const char *data_type); + enum Type { + Sync, Level, Data, Blank + } type; + void advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_charging, Type type, const char *data_type); // the inner entry point that determines whether and when the next sync event will occur within // the current output window diff --git a/Outputs/CRTFrame.h b/Outputs/CRTFrame.h new file mode 100644 index 000000000..0e4fa8176 --- /dev/null +++ b/Outputs/CRTFrame.h @@ -0,0 +1,39 @@ +// +// CRTFrame.h +// Clock Signal +// +// Created by Thomas Harte on 24/07/2015. +// Copyright © 2015 Thomas Harte. All rights reserved. +// + +#ifndef CRTFrame_h +#define CRTFrame_h + +#ifdef __cplusplus +extern "C" { +#endif + +struct CRTBuffer { + uint8_t *data; + int depth; +}; + +typedef struct { + int width, height; +} CRTSize; + +struct CRTFrame { + CRTSize size, dirty_size; + + int number_of_buffers; + CRTBuffer *buffers; + + int number_of_runs; + uint16_t *runs; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* CRTFrame_h */