1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-07 23:29:06 +00:00

It's broken now, but this is what I now intend the full public interface of the CRT to be.

This commit is contained in:
Thomas Harte 2016-02-02 22:41:33 -05:00
parent 4554abb755
commit 19393390ac

View File

@ -18,67 +18,80 @@
namespace Outputs {
class CRT;
struct CRTFrameBuilder {
CRTFrame frame;
CRTFrameBuilder(uint16_t width, uint16_t height, unsigned int number_of_buffers, va_list buffer_sizes);
~CRTFrameBuilder();
private:
std::vector<uint8_t> _all_runs;
void reset();
void complete();
uint8_t *get_next_run();
friend CRT;
void allocate_write_area(int required_length);
uint8_t *get_write_target_for_buffer(int buffer);
// a pointer to the section of content buffer currently being
// returned and to where the next section will begin
uint16_t _next_write_x_position, _next_write_y_position;
uint16_t _write_x_position, _write_y_position;
size_t _write_target_pointer;
};
static const int kCRTNumberOfFrames = 4;
class CRT {
public:
~CRT();
enum DisplayType {
PAL50,
NTSC60
};
CRT(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...);
CRT(unsigned int cycles_per_line, DisplayType displayType, unsigned int number_of_buffers, ...);
~CRT();
/*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency.
The requested number of buffers, each with the requested number of bytes per pixel,
is created for the machine to write raw pixel data to.
@param cycles_per_line The clock rate at which this CRT will be driven, specified as the number
of cycles expected to take up one whole scanline of the display.
@param height_of_dispaly The number of lines that nominally form one field of the display, rounded
up to the next whole integer.
@param colour_cycle_numerator Specifies the numerator for the per-line frequency of the colour subcarrier.
@param colour_cycle_denominator Specifies the denominator for the per-line frequency of the colour subcarrier.
The colour subcarrier is taken to have colour_cycle_numerator/colour_cycle_denominator cycles per line.
@param number_of_buffers The number of source data buffers to create for this machine. Machines
may provide per-clock-cycle data in any form that they consider convenient, supplying a sampling
function to convert between their data format and either a composite or RGB signal, allowing that
work to be offloaded onto the GPU and allowing the output signal to be sampled at a rate appropriate
to the display size.
@param ... A list of sizes for source data buffers, provided as the number of bytes per sample.
For compatibility with OpenGL ES, samples should be 14 bytes in size. If a machine requires more
than 4 bytes/sample then it should use multiple buffers.
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
*/
CRT(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...);
/*! Constructs the CRT with the specified clock rate, with the display height and colour
subcarrier frequency dictated by a standard display type and with the requested number of
buffers, each with the requested number of bytes per pixel.
Exactly identical to calling the designated constructor with colour subcarrier information
looked up by display type.
*/
CRT(unsigned int cycles_per_line, DisplayType displayType, unsigned int number_of_buffers, ...);
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
been provided at construction. */
void set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator);
/*! Resets the CRT with new timing information derived from a new display type. The CRT then continues
as though the new timing had been provided at construction. */
void set_new_display_type(unsigned int cycles_per_line, DisplayType displayType);
/*! Output at the sync level.
/*! Output at the sync level.
@param number_of_cycles The amount of time to putput sync for.
*/
void output_sync(unsigned int number_of_cycles);
/*! Output at the blanking level.
/*! Output at the blanking level.
@param number_of_cycles The amount of time to putput the blanking level for.
*/
void output_blank(unsigned int number_of_cycles);
/*! Outputs the first written to the most-recently created run of data repeatedly for a prolonged period.
/*! Outputs the first written to the most-recently created run of data repeatedly for a prolonged period.
@param number_of_cycles The number of cycles to repeat the output for.
*/
void output_level(unsigned int number_of_cycles);
/*! Declares that the caller has created a run of data via @c allocate_write_area and @c get_write_target_for_buffer
/*! Declares that the caller has created a run of data via @c allocate_write_area and @c get_write_target_for_buffer
that is at least @c number_of_cycles long, and that the first @c number_of_cycles/source_divider should be spread
over that amount of time.
@ -86,10 +99,12 @@ class CRT {
@param source_divider A divider for source data; if the divider is 1 then one source pixel is output every cycle,
if it is 2 then one source pixel covers two cycles; if it is n then one source pixel covers n cycles.
@see @c allocate_write_area , @c get_write_target_for_buffer
*/
void output_data(unsigned int number_of_cycles, unsigned int source_divider);
/*! Outputs a colour burst.
/*! Outputs a colour burst.
@param number_of_cycles The length of the colour burst.
@ -101,43 +116,101 @@ class CRT {
*/
void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t magnitude);
class Delegate {
public:
virtual void crt_did_end_frame(CRT *crt, CRTFrame *frame, bool did_detect_vsync) = 0;
};
void set_delegate(Delegate *delegate);
void return_frame();
/*! Ensures that the given number of output samples are allocated for writing.
Following this call, the caller should call @c get_write_target_for_buffer for each
buffer they requested to get the location of the allocated memory.
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.
@param required_length The number of samples to allocate.
*/
void allocate_write_area(int required_length);
/*! Gets a pointer for writing to the area created by the most recent call to @c allocate_write_area
for the nominated buffer.
@param buffer The buffer to get a write target for.
*/
uint8_t *get_write_target_for_buffer(int buffer);
/*! Gets the vertex shader for display of vended CRTFrames.
// MARK: Binding
class Delegate {
public:
/*! Notifies the delegate that a new frame is complete, providing an ID for it.
@returns A vertex shader, allocated using a C function. The caller then owns the memory
and is responsible for free'ing it.
The delegate then owns that frame. It can draw it by issuing an @c draw_frame
call to the CRT. It should call @c return_frame to return the oldest frame it
is currently holding.
@param crt The CRT that produced the new frame.
@param frame_id An identifier for the finished frame, used for calls to @c draw_frame.
@param did_detect_vsync @c true if this frame ended due to a vsync signal detected in
the incoming signal; @c false otherwise.
*/
virtual void crt_did_end_frame(CRT *crt, int frame_id, bool did_detect_vsync) = 0;
};
/*! Sets the CRT frame delegate. The delegate will be notified as frames are completed; it is
responsible for requesting that they be drawn and returning them when they are no longer needed.
@param delegate The delegate.
*/
char *get_vertex_shader();
void set_delegate(std::weak_ptr<Delegate> delegate);
/*! Gets a fragment shader for display of vended CRTFrames based on the supplied sampling function.
/*! Causes appropriate OpenGL or OpenGL ES calls to be made in order to draw a frame. The caller
is responsible for ensuring that a valid OpenGL context exists for the duration of this call.
@param sample_function A GLSL fragment including a function with the signature
`float sample(vec2 coordinate, float phase)` that evaluates to the composite signal level
as a function of a source buffer sampling location and the current colour carrier phase.
@returns A complete fragment shader.
@param frame_id The frame to draw.
*/
char *get_fragment_shader(const char *sample_function);
void draw_frame(int frame_id);
/*! Gets a fragment shader for composite display of vended CRTFrames based on a default encoding
of the supplied sampling function.
/*! Indicates that the delegate has no further interest in the oldest frame posted to it. */
void return_frame();
@param sample_function A GLSL fragent including a function with the signature
/*! Tells the CRT that the next call to draw_frame will occur on a different OpenGL context than
the previous.
@param should_delete_resources If @c true then all resources textures, vertex arrays, etc
currently held by the CRT will be deleted now via calls to glDeleteTexture and equivalent. If
@c false then the references are simply marked as invalid.
*/
void set_openGL_context_will_change(bool should_delete_resources);
/*! Sets a function that will map from whatever data the machine provided to a composite signal.
@param shader A GLSL fragment including a function with the signature
`float composite_sample(vec2 coordinate, float phase)` that evaluates to the composite signal
level as a function of a source buffer sampling location and the provided colour carrier phase.
The shader may assume a uniform array of sampler2Ds named `buffers` provides access to all input data.
*/
void set_composite_sampling_function(const char *shader);
/*! Sets a function that will map from whatever data the machine provided to an RGB signal.
If the output mode is composite then a default mapping from RGB to the display's composite
format will be applied.
@param shader A GLSL fragent including a function with the signature
`vec3 rgb_sample(vec2 coordinate)` that evaluates to an RGB colour as a function of
the source buffer sampling location.
@returns A complete fragment shader.
The shader may assume a uniform array of sampler2Ds named `buffers` provides access to all input data.
*/
char *get_rgb_encoding_fragment_shader(const char *sample_function);
void set_rgb_sampling_function(const char *shader);
/*! Optionally sets a function that will map from an input cycle count to a colour carrier phase.
If this function is not supplied then the colour phase is determined from
the input clock rate and the the colour cycle clock rate. Machines whose per-line clock rate
is not intended exactly to match the normal line time may prefer to supply a custom function.
@param A GLSL fragent including a function with the signature
`float phase_for_clock_cycle(int cycle)` that returns the colour phase at the beginning of
the supplied cycle.
*/
void set_phase_function(const char *shader);
private:
CRT();
@ -159,13 +232,6 @@ class CRT {
uint32_t x, y;
} _rasterPosition, _scanSpeed[4], _beamWidth[4];
// the run delegate and the triple buffer
CRTFrameBuilder *_frame_builders[kCRTNumberOfFrames];
CRTFrameBuilder *_current_frame_builder;
int _frames_with_delegate;
int _frame_read_pointer;
Delegate *_delegate;
// outer elements of sync separation
bool _is_receiving_sync; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)
bool _did_detect_hsync; // true if horizontal sync was detected during this scanline (so, this affects flywheel adjustments)
@ -212,6 +278,69 @@ class CRT {
} _scans[2];
int _next_scan;
void output_scan();
// MARK: shader storage and information.
/*! Gets the vertex shader for display of vended CRTFrames.
@returns A vertex shader, allocated using a C function. The caller then owns the memory
and is responsible for free'ing it.
*/
char *get_vertex_shader();
/*! Gets a fragment shader for display of vended CRTFrames based on the supplied sampling function.
@param sample_function A GLSL fragment including a function with the signature
`float sample(vec2 coordinate, float phase)` that evaluates to the composite signal level
as a function of a source buffer sampling location and the current colour carrier phase.
@returns A complete fragment shader.
*/
char *get_fragment_shader(const char *sample_function);
/*! Gets a fragment shader for composite display of vended CRTFrames based on a default encoding
of the supplied sampling function.
@param sample_function A GLSL fragent including a function with the signature
`vec3 rgb_sample(vec2 coordinate)` that evaluates to an RGB colour as a function of
the source buffer sampling location.
@returns A complete fragment shader.
*/
char *get_rgb_encoding_fragment_shader(const char *sample_function);
struct CRTFrameBuilder {
CRTFrame frame;
CRTFrameBuilder(uint16_t width, uint16_t height, unsigned int number_of_buffers, va_list buffer_sizes);
~CRTFrameBuilder();
private:
std::vector<uint8_t> _all_runs;
void reset();
void complete();
uint8_t *get_next_run();
friend CRT;
void allocate_write_area(int required_length);
uint8_t *get_write_target_for_buffer(int buffer);
// a pointer to the section of content buffer currently being
// returned and to where the next section will begin
uint16_t _next_write_x_position, _next_write_y_position;
uint16_t _write_x_position, _write_y_position;
size_t _write_target_pointer;
};
static const int kCRTNumberOfFrames = 4;
// the run delegate and the triple buffer
CRTFrameBuilder *_frame_builders[kCRTNumberOfFrames];
CRTFrameBuilder *_current_frame_builder;
int _frames_with_delegate;
int _frame_read_pointer;
Delegate *_delegate;
};
}