1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Started trying to clean up my Outputs namespace by moving stuff related to the CRT underneath a separate subnamespace.

This commit is contained in:
Thomas Harte 2016-03-08 20:49:07 -05:00
parent bb09a5f58c
commit c7976dd657
10 changed files with 166 additions and 150 deletions

View File

@ -24,7 +24,7 @@ Machine::Machine() :
_piaDataValue{0xff, 0xff},
_tiaInputValue{0xff, 0xff}
{
_crt = new Outputs::CRT(228, 1, Outputs::CRT::DisplayType::NTSC60, 1, 2);
_crt = new Outputs::CRT::CRT(228, 1, Outputs::CRT::DisplayType::NTSC60, 1, 2);
_crt->set_composite_sampling_function(
"float composite_sample(vec2 coordinate, float phase)\n"
"{\n"

View File

@ -29,7 +29,7 @@ class Machine: public CPU6502::Processor<Machine> {
void set_digital_input(Atari2600DigitalInput input, bool state);
Outputs::CRT *get_crt() { return _crt; }
Outputs::CRT::CRT *get_crt() { return _crt; }
private:
uint8_t *_rom, *_romPages[4], _ram[128];
@ -90,7 +90,7 @@ class Machine: public CPU6502::Processor<Machine> {
void output_pixels(unsigned int count);
void get_output_pixel(uint8_t *pixel, int offset);
Outputs::CRT *_crt;
Outputs::CRT::CRT *_crt;
// latched output state
unsigned int _lastOutputStateDuration;

View File

@ -32,7 +32,7 @@ Machine::Machine() :
_audioOutputPositionError(0),
_currentOutputLine(0),
_is_odd_field(false),
_crt(std::unique_ptr<Outputs::CRT>(new Outputs::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1, 1)))
_crt(std::unique_ptr<Outputs::CRT::CRT>(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1, 1)))
{
_crt->set_rgb_sampling_function(
"vec4 rgb_sample(vec2 coordinate)"

View File

@ -147,7 +147,7 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
void set_key_state(Key key, bool isPressed);
Outputs::CRT *get_crt() { return _crt.get(); }
Outputs::CRT::CRT *get_crt() { return _crt.get(); }
Outputs::Speaker *get_speaker() { return &_speaker; }
virtual void tape_did_change_interrupt_status(Tape *tape);
@ -201,7 +201,7 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
Tape _tape;
// Outputs.
std::unique_ptr<Outputs::CRT> _crt;
std::unique_ptr<Outputs::CRT::CRT> _crt;
Speaker _speaker;
};

View File

@ -11,7 +11,7 @@
#include <stdarg.h>
#include <math.h>
using namespace Outputs;
using namespace Outputs::CRT;
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator)
{
@ -39,8 +39,8 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
_sync_capacitor_charge_threshold = ((syncCapacityLineChargeThreshold * _cycles_per_line) * 50) >> 7;
// create the two flywheels
_horizontal_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line, (millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6));
_vertical_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * _cycles_per_line));
_horizontal_flywheel = std::unique_ptr<Flywheel>(new Flywheel(_cycles_per_line, (millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6));
_vertical_flywheel = std::unique_ptr<Flywheel>(new Flywheel(_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * _cycles_per_line));
// figure out the divisor necessary to get the horizontal flywheel into a 16-bit range
unsigned int real_clock_scan_period = (_cycles_per_line * height_of_display) / (_time_multiplier * _common_output_divisor);
@ -63,12 +63,12 @@ void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType display
void CRT::allocate_buffers(unsigned int number, va_list sizes)
{
_run_builders = new CRTRunBuilder *[kCRTNumberOfFields];
for(int builder = 0; builder < kCRTNumberOfFields; builder++)
_run_builders = new CRTRunBuilder *[NumberOfFields];
for(int builder = 0; builder < NumberOfFields; builder++)
{
_run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize);
_run_builders[builder] = new CRTRunBuilder(OutputVertexSize);
}
_composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(kCRTInputVertexSize));
_composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(InputVertexSize));
va_list va;
va_copy(va, sizes);
@ -92,7 +92,7 @@ CRT::CRT(unsigned int common_output_divisor) :
CRT::~CRT()
{
for(int builder = 0; builder < kCRTNumberOfFields; builder++)
for(int builder = 0; builder < NumberOfFields; builder++)
{
delete _run_builders[builder];
}
@ -132,20 +132,20 @@ 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 output_position_x(v) (*(uint16_t *)&next_run[OutputVertexSize*v + OutputVertexOffsetOfPosition + 0])
#define output_position_y(v) (*(uint16_t *)&next_run[OutputVertexSize*v + OutputVertexOffsetOfPosition + 2])
#define output_tex_x(v) (*(uint16_t *)&next_run[OutputVertexSize*v + OutputVertexOffsetOfTexCoord + 0])
#define output_tex_y(v) (*(uint16_t *)&next_run[OutputVertexSize*v + OutputVertexOffsetOfTexCoord + 2])
#define output_lateral(v) next_run[OutputVertexSize*v + OutputVertexOffsetOfLateral]
#define output_timestamp(v) (*(uint32_t *)&next_run[OutputVertexSize*v + OutputVertexOffsetOfTimestamp])
#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])
#define input_input_position_x(v) (*(uint16_t *)&next_run[InputVertexSize*v + InputVertexOffsetOfInputPosition + 0])
#define input_input_position_y(v) (*(uint16_t *)&next_run[InputVertexSize*v + InputVertexOffsetOfInputPosition + 2])
#define input_output_position_x(v) (*(uint16_t *)&next_run[InputVertexSize*v + InputVertexOffsetOfOutputPosition + 0])
#define input_output_position_y(v) (*(uint16_t *)&next_run[InputVertexSize*v + InputVertexOffsetOfOutputPosition + 2])
#define input_phase(v) next_run[OutputVertexSize*v + InputVertexOffsetOfPhaseAndAmplitude + 0]
#define input_amplitude(v) next_run[OutputVertexSize*v + InputVertexOffsetOfPhaseAndAmplitude + 1]
#define input_phase_time(v) (*(uint16_t *)&next_run[OutputVertexSize*v + InputVertexOffsetOfPhaseTime])
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)
{
@ -171,7 +171,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
if(is_output_segment)
{
_output_mutex->lock();
next_run = (_output_device == CRT::Monitor) ? _run_builders[_run_write_pointer]->get_next_run(6) : _composite_src_runs->get_next_run(2);
next_run = (_output_device == Monitor) ? _run_builders[_run_write_pointer]->get_next_run(6) : _composite_src_runs->get_next_run(2);
}
// Vertex output is arranged for triangle strips, as:
@ -181,7 +181,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// [0/1] 3
if(next_run)
{
if(_output_device == CRT::Monitor)
if(_output_device == Monitor)
{
// set the type, initial raster position and type of this run
output_position_x(0) = output_position_x(1) = output_position_x(2) = (uint16_t)_horizontal_flywheel->get_current_output_position();
@ -226,7 +226,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// 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(_output_device == CRT::Monitor)
if(_output_device == Monitor)
{
// store the final raster position
output_position_x(3) = output_position_x(4) = output_position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
@ -247,7 +247,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
}
// if this is horizontal retrace then advance the output line counter and bookend an output run
if(_output_device == CRT::Television)
if(_output_device == Television)
{
Flywheel::SyncEvent honoured_event = Flywheel::SyncEvent::None;
if(next_run_length == time_until_vertical_sync_event && next_vertical_sync_event != Flywheel::SyncEvent::None) honoured_event = next_vertical_sync_event;
@ -274,7 +274,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
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;
_composite_src_output_y = (_composite_src_output_y + 1) % IntermediateBufferHeight;
}
}
@ -284,7 +284,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// TODO: how to communicate did_detect_vsync? Bring the delegate back?
// _delegate->crt_did_end_frame(this, &_current_frame_builder->frame, _did_detect_vsync);
_run_write_pointer = (_run_write_pointer + 1)%kCRTNumberOfFields;
_run_write_pointer = (_run_write_pointer + 1)%NumberOfFields;
_run_builders[_run_write_pointer]->reset();
}
}

View File

@ -18,6 +18,7 @@
#include "Flywheel.hpp"
namespace Outputs {
namespace CRT {
struct Rect {
struct {
@ -33,25 +34,78 @@ struct Rect {
origin({.x = x, .y = y}), size({.width = width, .height =height}) {}
};
enum DisplayType {
PAL50,
NTSC60
};
enum ColourSpace {
YIQ,
YUV
};
enum OutputDevice {
Monitor,
Television
};
struct CRTInputBufferBuilder {
CRTInputBufferBuilder(unsigned int number_of_buffers, va_list buffer_sizes);
~CRTInputBufferBuilder();
void allocate_write_area(size_t required_length);
void reduce_previous_allocation_to(size_t actual_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;
size_t _last_allocation_amount;
struct Buffer {
uint8_t *data;
size_t bytes_per_pixel;
} *buffers;
unsigned int number_of_buffers;
// 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;
};
struct CRTRunBuilder {
CRTRunBuilder(size_t vertex_size) : _vertex_size(vertex_size) { reset(); }
// Resets the run builder.
void reset();
// Getter for new storage plus backing storage; in RGB mode input runs will map directly
// from the input buffer to the screen. In composite mode input runs will map from the
// input buffer to the processing buffer, and output runs will map from the processing
// buffer to the screen.
uint8_t *get_next_run(size_t number_of_vertices);
std::vector<uint8_t> _runs;
// Container for total length in cycles of all contained runs.
uint32_t duration;
// Storage for the length of run data uploaded so far; reset to zero by reset but otherwise
// entrusted to the CRT to update.
size_t uploaded_vertices;
size_t number_of_vertices;
private:
size_t _vertex_size;
};
struct OpenGLState;
class CRT {
public:
~CRT();
enum DisplayType {
PAL50,
NTSC60
};
enum ColourSpace {
YIQ,
YUV
};
enum OutputDevice {
Monitor,
Television
};
/*! 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.
@ -259,7 +313,7 @@ class CRT {
Rect _visible_area;
// the two flywheels regulating scanning
std::unique_ptr<Outputs::Flywheel> _horizontal_flywheel, _vertical_flywheel;
std::unique_ptr<Flywheel> _horizontal_flywheel, _vertical_flywheel;
uint16_t _vertical_flywheel_output_divider;
// elements of sync separation
@ -295,57 +349,6 @@ class CRT {
};
void output_scan(Scan *scan);
struct CRTRunBuilder {
CRTRunBuilder(size_t vertex_size) : _vertex_size(vertex_size) { reset(); }
// Resets the run builder.
void reset();
// Getter for new storage plus backing storage; in RGB mode input runs will map directly
// from the input buffer to the screen. In composite mode input runs will map from the
// input buffer to the processing buffer, and output runs will map from the processing
// buffer to the screen.
uint8_t *get_next_run(size_t number_of_vertices);
std::vector<uint8_t> _runs;
// Container for total length in cycles of all contained runs.
uint32_t duration;
// Storage for the length of run data uploaded so far; reset to zero by reset but otherwise
// entrusted to the CRT to update.
size_t uploaded_vertices;
size_t number_of_vertices;
private:
size_t _vertex_size;
};
struct CRTInputBufferBuilder {
CRTInputBufferBuilder(unsigned int number_of_buffers, va_list buffer_sizes);
~CRTInputBufferBuilder();
void allocate_write_area(size_t required_length);
void reduce_previous_allocation_to(size_t actual_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;
size_t _last_allocation_amount;
struct Buffer {
uint8_t *data;
size_t bytes_per_pixel;
} *buffers;
unsigned int number_of_buffers;
// 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;
};
// the run and input data buffers
std::unique_ptr<CRTInputBufferBuilder> _buffer_builder;
CRTRunBuilder **_run_builders;
@ -360,7 +363,6 @@ class CRT {
bool _is_writing_composite_run;
// OpenGL state, kept behind an opaque pointer to avoid inclusion of the GL headers here.
struct OpenGLState;
OpenGLState *_openGL_state;
// Other things the caller may have provided.
@ -390,6 +392,6 @@ class CRT {
};
}
}
#endif /* CRT_cpp */

View File

@ -23,7 +23,7 @@ CRT::CRTInputBufferBuilder::CRTInputBufferBuilder(unsigned int number_of_buffers
for(int buffer = 0; buffer < number_of_buffers; buffer++)
{
buffers[buffer].bytes_per_pixel = va_arg(buffer_sizes, unsigned int);
buffers[buffer].data = new uint8_t[CRTInputBufferBuilderWidth * CRTInputBufferBuilderHeight * buffers[buffer].bytes_per_pixel];
buffers[buffer].data = new uint8_t[InputBufferBuilderWidth * InputBufferBuilderHeight * buffers[buffer].bytes_per_pixel];
}
_next_write_x_position = _next_write_y_position = 0;
@ -42,15 +42,15 @@ void CRT::CRTInputBufferBuilder::allocate_write_area(size_t required_length)
{
_last_allocation_amount = required_length;
if(_next_write_x_position + required_length + 2 > CRTInputBufferBuilderWidth)
if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
{
_next_write_x_position = 0;
_next_write_y_position = (_next_write_y_position+1)%CRTInputBufferBuilderHeight;
_next_write_y_position = (_next_write_y_position+1)%InputBufferBuilderHeight;
}
_write_x_position = _next_write_x_position + 1;
_write_y_position = _next_write_y_position;
_write_target_pointer = (_write_y_position * CRTInputBufferBuilderWidth) + _write_x_position;
_write_target_pointer = (_write_y_position * InputBufferBuilderWidth) + _write_x_position;
_next_write_x_position += required_length + 2;
}

View File

@ -14,9 +14,10 @@
#include "Shader.hpp"
#include "CRTOpenGL.hpp"
using namespace Outputs;
namespace Outputs {
namespace CRT {
struct CRT::OpenGLState {
struct OpenGLState {
std::unique_ptr<OpenGL::Shader> rgb_shader_program;
std::unique_ptr<OpenGL::Shader> composite_input_shader_program, composite_output_shader_program;
@ -35,6 +36,11 @@ struct CRT::OpenGLState {
std::unique_ptr<OpenGL::TextureTarget> filteredTexture; // receives filtered YIQ or YUV
};
}
}
using namespace Outputs::CRT;
namespace {
static const GLenum first_supplied_buffer_texture_unit = 3;
}
@ -84,7 +90,7 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GLenum format = formatForDepth(_buffer_builder->buffers[buffer].bytes_per_pixel);
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight, 0, format, GL_UNSIGNED_BYTE, _buffer_builder->buffers[buffer].data);
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, InputBufferBuilderWidth, InputBufferBuilderHeight, 0, format, GL_UNSIGNED_BYTE, _buffer_builder->buffers[buffer].data);
}
glGenVertexArrays(1, &_openGL_state->output_vertex_array);
@ -105,11 +111,11 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
// Create intermediate textures and bind to slots 0, 1 and 2
glActiveTexture(GL_TEXTURE0);
_openGL_state->compositeTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight));
_openGL_state->compositeTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight));
glActiveTexture(GL_TEXTURE1);
_openGL_state->filteredYTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight));
_openGL_state->filteredYTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight));
glActiveTexture(GL_TEXTURE2);
_openGL_state->filteredTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight));
_openGL_state->filteredTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight));
}
// glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&_openGL_state->defaultFramebuffer);
@ -129,9 +135,9 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
{
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, (GLint)_buffer_builder->last_uploaded_line,
CRTInputBufferBuilderWidth, (GLint)(CRTInputBufferBuilderHeight - _buffer_builder->last_uploaded_line),
InputBufferBuilderWidth, (GLint)(InputBufferBuilderHeight - _buffer_builder->last_uploaded_line),
format, GL_UNSIGNED_BYTE,
&_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]);
&_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * InputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]);
_buffer_builder->last_uploaded_line = 0;
}
@ -139,9 +145,9 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
{
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, (GLint)_buffer_builder->last_uploaded_line,
CRTInputBufferBuilderWidth, (GLint)(1 + _buffer_builder->_next_write_y_position - _buffer_builder->last_uploaded_line),
InputBufferBuilderWidth, (GLint)(1 + _buffer_builder->_next_write_y_position - _buffer_builder->last_uploaded_line),
format, GL_UNSIGNED_BYTE,
&_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]);
&_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * InputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]);
_buffer_builder->last_uploaded_line = _buffer_builder->_next_write_y_position;
}
}
@ -163,19 +169,19 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
// ensure array buffer is up to date
glBindBuffer(GL_ARRAY_BUFFER, _openGL_state->output_array_buffer);
size_t max_number_of_vertices = 0;
for(int c = 0; c < kCRTNumberOfFields; c++)
for(int c = 0; c < NumberOfFields; c++)
{
max_number_of_vertices = std::max(max_number_of_vertices, _run_builders[c]->number_of_vertices);
}
if(_openGL_state->output_vertices_per_slice < max_number_of_vertices)
{
_openGL_state->output_vertices_per_slice = max_number_of_vertices;
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(max_number_of_vertices * kCRTOutputVertexSize * kCRTOutputVertexSize), NULL, GL_STREAM_DRAW);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(max_number_of_vertices * OutputVertexSize * OutputVertexSize), NULL, GL_STREAM_DRAW);
for(unsigned int c = 0; c < kCRTNumberOfFields; c++)
for(unsigned int c = 0; c < NumberOfFields; c++)
{
uint8_t *data = &_run_builders[c]->_runs[0];
glBufferSubData(GL_ARRAY_BUFFER, (GLsizeiptr)(c * _openGL_state->output_vertices_per_slice * kCRTOutputVertexSize), (GLsizeiptr)(_run_builders[c]->number_of_vertices * kCRTOutputVertexSize), data);
glBufferSubData(GL_ARRAY_BUFFER, (GLsizeiptr)(c * _openGL_state->output_vertices_per_slice * OutputVertexSize), (GLsizeiptr)(_run_builders[c]->number_of_vertices * OutputVertexSize), data);
_run_builders[c]->uploaded_vertices = _run_builders[c]->number_of_vertices;
}
}
@ -198,7 +204,7 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
unsigned int run = (unsigned int)_run_write_pointer;
// printf("%d: %zu v %zu\n", run, _run_builders[run]->uploaded_vertices, _run_builders[run]->number_of_vertices);
GLint total_age = 0;
for(int c = 0; c < kCRTNumberOfFields; c++)
for(int c = 0; c < NumberOfFields; c++)
{
// update the total age at the start of this set of runs
total_age += _run_builders[run]->duration;
@ -209,10 +215,10 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
if(_run_builders[run]->uploaded_vertices != _run_builders[run]->number_of_vertices)
{
uint8_t *data = &_run_builders[run]->_runs[_run_builders[run]->uploaded_vertices * kCRTOutputVertexSize];
uint8_t *data = &_run_builders[run]->_runs[_run_builders[run]->uploaded_vertices * OutputVertexSize];
glBufferSubData(GL_ARRAY_BUFFER,
(GLsizeiptr)(((run * _openGL_state->output_vertices_per_slice) + _run_builders[run]->uploaded_vertices) * kCRTOutputVertexSize),
(GLsizeiptr)((_run_builders[run]->number_of_vertices - _run_builders[run]->uploaded_vertices) * kCRTOutputVertexSize), data);
(GLsizeiptr)(((run * _openGL_state->output_vertices_per_slice) + _run_builders[run]->uploaded_vertices) * OutputVertexSize),
(GLsizeiptr)((_run_builders[run]->number_of_vertices - _run_builders[run]->uploaded_vertices) * OutputVertexSize), data);
_run_builders[run]->uploaded_vertices = _run_builders[run]->number_of_vertices;
}
@ -221,7 +227,7 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool
}
// advance back in time
run = (run - 1 + kCRTNumberOfFields) % kCRTNumberOfFields;
run = (run - 1 + NumberOfFields) % NumberOfFields;
}
}
@ -437,8 +443,8 @@ void CRT::prepare_composite_input_shader()
GLint phaseCyclesPerTickUniform = _openGL_state->composite_input_shader_program->get_uniform_location("phaseCyclesPerTick");
glUniform1i(texIDUniform, first_supplied_buffer_texture_unit);
glUniform2f(outputTextureSizeUniform, CRTIntermediateBufferWidth, CRTIntermediateBufferHeight);
glUniform2f(inputTextureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight);
glUniform2f(outputTextureSizeUniform, IntermediateBufferWidth, IntermediateBufferHeight);
glUniform2f(inputTextureSizeUniform, InputBufferBuilderWidth, InputBufferBuilderHeight);
glUniform1f(phaseCyclesPerTickUniform, (float)_colour_cycle_numerator / (float)(_colour_cycle_denominator * _cycles_per_line));
}
free(vertex_shader);
@ -509,7 +515,7 @@ void CRT::prepare_rgb_output_shader()
glUniform1i(texIDUniform, first_supplied_buffer_texture_unit);
glUniform1i(shadowMaskTexIDUniform, 1);
glUniform2f(textureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight);
glUniform2f(textureSizeUniform, InputBufferBuilderWidth, InputBufferBuilderHeight);
glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display));
glUniform2f(positionConversionUniform, _horizontal_flywheel->get_scan_period(), _vertical_flywheel->get_scan_period() / (unsigned int)_vertical_flywheel_output_divider);
@ -539,23 +545,23 @@ void CRT::prepare_output_vertex_array()
glEnableVertexAttribArray((GLuint)lateralAttribute);
glEnableVertexAttribArray((GLuint)timestampAttribute);
const GLsizei vertexStride = kCRTOutputVertexSize;
glVertexAttribPointer((GLuint)positionAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfPosition);
glVertexAttribPointer((GLuint)textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfTexCoord);
glVertexAttribPointer((GLuint)timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfTimestamp);
glVertexAttribPointer((GLuint)lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfLateral);
const GLsizei vertexStride = OutputVertexSize;
glVertexAttribPointer((GLuint)positionAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)OutputVertexOffsetOfPosition);
glVertexAttribPointer((GLuint)textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)OutputVertexOffsetOfTexCoord);
glVertexAttribPointer((GLuint)timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)OutputVertexOffsetOfTimestamp);
glVertexAttribPointer((GLuint)lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)OutputVertexOffsetOfLateral);
}
}
#pragma mark - Configuration
void CRT::set_output_device(CRT::OutputDevice output_device)
void CRT::set_output_device(OutputDevice output_device)
{
if (_output_device != output_device)
{
_output_device = output_device;
for(int builder = 0; builder < kCRTNumberOfFields; builder++)
for(int builder = 0; builder < NumberOfFields; builder++)
{
_run_builders[builder]->reset();
}

View File

@ -9,35 +9,41 @@
#ifndef CRTOpenGL_h
#define CRTOpenGL_h
namespace Outputs {
namespace CRT {
// Output vertices are those used to copy from an input buffer — whether it describes data that maps directly to RGB
// or is one of the intermediate buffers that we've used to convert from composite towards RGB.
const size_t kCRTOutputVertexOffsetOfPosition = 0;
const size_t kCRTOutputVertexOffsetOfTexCoord = 4;
const size_t kCRTOutputVertexOffsetOfTimestamp = 8;
const size_t kCRTOutputVertexOffsetOfLateral = 12;
const size_t OutputVertexOffsetOfPosition = 0;
const size_t OutputVertexOffsetOfTexCoord = 4;
const size_t OutputVertexOffsetOfTimestamp = 8;
const size_t OutputVertexOffsetOfLateral = 12;
const size_t kCRTOutputVertexSize = 16;
const size_t OutputVertexSize = 16;
// Input vertices, used only in composite mode, map from the input buffer to temporary buffer locations; such
// remapping occurs to ensure a continous stream of data for each scan, giving correct out-of-bounds behaviour
const size_t kCRTInputVertexOffsetOfInputPosition = 0;
const size_t kCRTInputVertexOffsetOfOutputPosition = 4;
const size_t kCRTInputVertexOffsetOfPhaseAndAmplitude = 8;
const size_t kCRTInputVertexOffsetOfPhaseTime = 12;
const size_t InputVertexOffsetOfInputPosition = 0;
const size_t InputVertexOffsetOfOutputPosition = 4;
const size_t InputVertexOffsetOfPhaseAndAmplitude = 8;
const size_t InputVertexOffsetOfPhaseTime = 12;
const size_t kCRTInputVertexSize = 16;
const size_t InputVertexSize = 16;
// These constants hold the size of the rolling buffer to which the CPU writes
const int CRTInputBufferBuilderWidth = 2048;
const int CRTInputBufferBuilderHeight = 1024;
const int InputBufferBuilderWidth = 2048;
const int InputBufferBuilderHeight = 1024;
// This is the size of the intermediate buffers used during composite to RGB conversion
const int CRTIntermediateBufferWidth = 2048;
const int CRTIntermediateBufferHeight = 2048;
const int IntermediateBufferWidth = 2048;
const int IntermediateBufferHeight = 2048;
// Runs are divided discretely by vertical syncs in order to put a usable bounds on the uniform used to track
// run age; that therefore creates a discrete number of fields that are stored. This number should be the
// number of historic fields that are required fully to
const int kCRTNumberOfFields = 3;
const int NumberOfFields = 3;
}
}
#endif /* CRTOpenGL_h */

View File

@ -10,6 +10,7 @@
#define Flywheel_hpp
namespace Outputs {
namespace CRT {
/*!
Provides timing for a two-phase signal consisting of a retrace phase followed by a scan phase,
@ -211,6 +212,7 @@ struct Flywheel
*/
};
}
}
#endif /* Flywheel_hpp */