From 70b6d5145172df7af0687fdd83ebb4069e82621b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 5 Mar 2016 14:36:12 -0500 Subject: [PATCH] Ever more baby steps back towards composite decoding. --- Outputs/CRT/CRT.cpp | 23 ++++++++++---------- Outputs/CRT/CRT.hpp | 4 ++++ Outputs/CRT/CRTOpenGL.cpp | 44 +++++++++++++++++++++++++-------------- Outputs/CRT/CRTOpenGL.hpp | 26 +++++++++++++++++------ 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 4e96929a5..cfd1a4720 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -63,11 +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 *[kCRTNumberOfFrames]; - for(int builder = 0; builder < kCRTNumberOfFrames; builder++) + _run_builders = new CRTRunBuilder *[kCRTNumberOfFields]; + for(int builder = 0; builder < kCRTNumberOfFields; builder++) { - _run_builders[builder] = new CRTRunBuilder(kCRTSizeOfVertex); + _run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize); } + _composite_src_runs = std::unique_ptr(new CRTRunBuilder(23)); va_list va; va_copy(va, sizes); @@ -90,7 +91,7 @@ CRT::CRT(unsigned int common_output_divisor) : CRT::~CRT() { - for(int builder = 0; builder < kCRTNumberOfFrames; builder++) + for(int builder = 0; builder < kCRTNumberOfFields; builder++) { delete _run_builders[builder]; } @@ -151,12 +152,12 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi 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[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 0]) -#define position_y(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 2]) -#define tex_x(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTexCoord + 0]) -#define tex_y(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTexCoord + 2]) -#define lateral(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfLateral] -#define timestamp(v) (*(uint32_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTimestamp]) +#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]) // Vertex output is arranged as: // @@ -212,7 +213,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)%kCRTNumberOfFrames; + _run_write_pointer = (_run_write_pointer + 1)%kCRTNumberOfFields; _run_builders[_run_write_pointer]->reset(); } } diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 8e993bc79..38d5fa2f7 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -353,6 +353,10 @@ class CRT { int _run_write_pointer; std::shared_ptr _output_mutex; + // transient buffers indicating composite data not yet decoded + std::unique_ptr _composite_src_runs; + int _composite_src_output_y; + // OpenGL state, kept behind an opaque pointer to avoid inclusion of the GL headers here. struct OpenGLState; OpenGLState *_openGL_state; diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp index 70afeff00..2b7026231 100644 --- a/Outputs/CRT/CRTOpenGL.cpp +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -132,19 +132,19 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool // ensure array buffer is up to date size_t max_number_of_vertices = 0; - for(int c = 0; c < kCRTNumberOfFrames; c++) + for(int c = 0; c < kCRTNumberOfFields; c++) { max_number_of_vertices = std::max(max_number_of_vertices, _run_builders[c]->number_of_vertices); } if(_openGL_state->verticesPerSlice < max_number_of_vertices) { _openGL_state->verticesPerSlice = max_number_of_vertices; - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(max_number_of_vertices * kCRTSizeOfVertex * kCRTNumberOfFrames), NULL, GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(max_number_of_vertices * kCRTOutputVertexSize * kCRTOutputVertexSize), NULL, GL_STREAM_DRAW); - for(unsigned int c = 0; c < kCRTNumberOfFrames; c++) + for(unsigned int c = 0; c < kCRTNumberOfFields; c++) { uint8_t *data = &_run_builders[c]->_runs[0]; - glBufferSubData(GL_ARRAY_BUFFER, (GLsizeiptr)(c * _openGL_state->verticesPerSlice * kCRTSizeOfVertex), (GLsizeiptr)(_run_builders[c]->number_of_vertices * kCRTSizeOfVertex), data); + glBufferSubData(GL_ARRAY_BUFFER, (GLsizeiptr)(c * _openGL_state->verticesPerSlice * kCRTOutputVertexSize), (GLsizeiptr)(_run_builders[c]->number_of_vertices * kCRTOutputVertexSize), data); _run_builders[c]->uploaded_vertices = _run_builders[c]->number_of_vertices; } } @@ -153,7 +153,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 < kCRTNumberOfFrames; c++) + for(int c = 0; c < kCRTNumberOfFields; c++) { // update the total age at the start of this set of runs total_age += _run_builders[run]->duration; @@ -164,10 +164,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 * kCRTSizeOfVertex]; + uint8_t *data = &_run_builders[run]->_runs[_run_builders[run]->uploaded_vertices * kCRTOutputVertexSize]; glBufferSubData(GL_ARRAY_BUFFER, - (GLsizeiptr)(((run * _openGL_state->verticesPerSlice) + _run_builders[run]->uploaded_vertices) * kCRTSizeOfVertex), - (GLsizeiptr)((_run_builders[run]->number_of_vertices - _run_builders[run]->uploaded_vertices) * kCRTSizeOfVertex), data); + (GLsizeiptr)(((run * _openGL_state->verticesPerSlice) + _run_builders[run]->uploaded_vertices) * kCRTOutputVertexSize), + (GLsizeiptr)((_run_builders[run]->number_of_vertices - _run_builders[run]->uploaded_vertices) * kCRTOutputVertexSize), data); _run_builders[run]->uploaded_vertices = _run_builders[run]->number_of_vertices; } @@ -176,7 +176,7 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool } // advance back in time - run = (run - 1 + kCRTNumberOfFrames) % kCRTNumberOfFrames; + run = (run - 1 + kCRTNumberOfFields) % kCRTNumberOfFields; } _output_mutex->unlock(); @@ -389,14 +389,26 @@ void CRT::prepare_vertex_array() glEnableVertexAttribArray((GLuint)_openGL_state->lateralAttribute); glEnableVertexAttribArray((GLuint)_openGL_state->timestampAttribute); - const GLsizei vertexStride = kCRTSizeOfVertex; - glVertexAttribPointer((GLuint)_openGL_state->positionAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfPosition); - glVertexAttribPointer((GLuint)_openGL_state->textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTexCoord); - glVertexAttribPointer((GLuint)_openGL_state->timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTimestamp); - glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral); + const GLsizei vertexStride = kCRTOutputVertexSize; + glVertexAttribPointer((GLuint)_openGL_state->positionAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfPosition); + glVertexAttribPointer((GLuint)_openGL_state->textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfTexCoord); + glVertexAttribPointer((GLuint)_openGL_state->timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfTimestamp); + glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTOutputVertexOffsetOfLateral); } -void CRT::set_output_device(OutputDevice output_device) +#pragma mark - Configuration + +void CRT::set_output_device(CRT::OutputDevice output_device) { - _output_device = output_device; + if (_output_device != output_device) + { + _output_device = output_device; + + for(int builder = 0; builder < kCRTNumberOfFields; builder++) + { + _run_builders[builder]->reset(); + } + _composite_src_runs->reset(); + _composite_src_output_y = 0; + } } diff --git a/Outputs/CRT/CRTOpenGL.hpp b/Outputs/CRT/CRTOpenGL.hpp index bbf6f3df1..6fd3e516c 100644 --- a/Outputs/CRT/CRTOpenGL.hpp +++ b/Outputs/CRT/CRTOpenGL.hpp @@ -9,19 +9,33 @@ #ifndef CRTOpenGL_h #define CRTOpenGL_h -const size_t kCRTVertexOffsetOfPosition = 0; -const size_t kCRTVertexOffsetOfTexCoord = 4; -const size_t kCRTVertexOffsetOfTimestamp = 8; -const size_t kCRTVertexOffsetOfLateral = 12; +// 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 kCRTSizeOfVertex = 16; +const size_t kCRTOutputVertexSize = 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 kCRTInputVertexSize = 8; + +// These constants hold the size of the rolling buffer to which the CPU writes const int CRTInputBufferBuilderWidth = 2048; const int CRTInputBufferBuilderHeight = 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 kCRTNumberOfFrames = 3; +// 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; #endif /* CRTOpenGL_h */