1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-02 20:30:00 +00:00

Experimental: let's try accumulating history directly in the framebuffer.

This commit is contained in:
Thomas Harte 2016-04-26 21:41:39 -04:00
parent 3af97d4069
commit 416c944f02
6 changed files with 38 additions and 153 deletions

View File

@ -305,7 +305,6 @@
4BB73EC21B587A5100552FC2 /* Clock_SignalUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EC11B587A5100552FC2 /* Clock_SignalUITests.swift */; };
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99081C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp */; };
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */; };
4BBF99161C8FBA6F0075DAFB /* CRTRunBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF990C1C8FBA6F0075DAFB /* CRTRunBuilder.cpp */; };
4BBF99171C8FBA6F0075DAFB /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99101C8FBA6F0075DAFB /* Shader.cpp */; };
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99121C8FBA6F0075DAFB /* TextureTarget.cpp */; };
4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; };
@ -660,8 +659,6 @@
4BBF99091C8FBA6F0075DAFB /* CRTInputBufferBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTInputBufferBuilder.hpp; sourceTree = "<group>"; };
4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = "<group>"; };
4BBF990B1C8FBA6F0075DAFB /* CRTOpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTOpenGL.hpp; sourceTree = "<group>"; };
4BBF990C1C8FBA6F0075DAFB /* CRTRunBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTRunBuilder.cpp; sourceTree = "<group>"; };
4BBF990D1C8FBA6F0075DAFB /* CRTRunBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTRunBuilder.hpp; sourceTree = "<group>"; };
4BBF990E1C8FBA6F0075DAFB /* Flywheel.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Flywheel.hpp; sourceTree = "<group>"; };
4BBF990F1C8FBA6F0075DAFB /* OpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenGL.hpp; sourceTree = "<group>"; };
4BBF99101C8FBA6F0075DAFB /* Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shader.cpp; sourceTree = "<group>"; };
@ -1210,8 +1207,6 @@
4BBF99091C8FBA6F0075DAFB /* CRTInputBufferBuilder.hpp */,
4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */,
4BBF990B1C8FBA6F0075DAFB /* CRTOpenGL.hpp */,
4BBF990C1C8FBA6F0075DAFB /* CRTRunBuilder.cpp */,
4BBF990D1C8FBA6F0075DAFB /* CRTRunBuilder.hpp */,
4BBF990E1C8FBA6F0075DAFB /* Flywheel.hpp */,
4BBF990F1C8FBA6F0075DAFB /* OpenGL.hpp */,
4BBF99101C8FBA6F0075DAFB /* Shader.cpp */,
@ -1653,7 +1648,6 @@
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */,
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */,
4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */,
4BBF99161C8FBA6F0075DAFB /* CRTRunBuilder.cpp in Sources */,
4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */,
4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */,
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,

View File

@ -10,6 +10,7 @@
#include "CRTOpenGL.hpp"
#include <stdarg.h>
#include <math.h>
#include <algorithm>
using namespace Outputs::CRT;
@ -149,14 +150,14 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// 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();
output_position_y(0) = output_position_y(1) = output_position_y(2) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
output_timestamp(0) = output_timestamp(1) = output_timestamp(2) = _openGL_output_builder->get_current_field_time();
// output_timestamp(0) = output_timestamp(1) = output_timestamp(2) = _openGL_output_builder->get_current_field_time();
output_tex_x(0) = output_tex_x(1) = output_tex_x(2) = tex_x;
// these things are constants across the line so just throw them out now
output_tex_y(0) = output_tex_y(1) = output_tex_y(2) = output_tex_y(3) = output_tex_y(4) = output_tex_y(5) = tex_y;
output_lateral(0) = output_lateral(1) = output_lateral(3) = 0;
output_lateral(2) = output_lateral(4) = output_lateral(5) = 1;
output_frame_id(0) = output_frame_id(1) = output_frame_id(2) = output_frame_id(3) = output_frame_id(4) = output_frame_id(5) = (uint8_t)_openGL_output_builder->get_current_field();
// output_frame_id(0) = output_frame_id(1) = output_frame_id(2) = output_frame_id(3) = output_frame_id(4) = output_frame_id(5) = (uint8_t)_openGL_output_builder->get_current_field();
}
else
{
@ -175,7 +176,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// decrement the number of cycles left to run for and increment the
// horizontal counter appropriately
number_of_cycles -= next_run_length;
_openGL_output_builder->add_to_field_time(next_run_length);
// _openGL_output_builder->add_to_field_time(next_run_length);
// either charge or deplete the vertical retrace capacitor (making sure it stops at 0)
if(vsync_charging)
@ -197,7 +198,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
// 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();
output_position_y(3) = output_position_y(4) = output_position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
output_timestamp(3) = output_timestamp(4) = output_timestamp(5) = _openGL_output_builder->get_current_field_time();
// output_timestamp(3) = output_timestamp(4) = output_timestamp(5) = _openGL_output_builder->get_current_field_time();
output_tex_x(3) = output_tex_x(4) = output_tex_x(5) = tex_x;
_openGL_output_builder->complete_output_run(6);
@ -227,13 +228,13 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
output_position_x(0) = output_position_x(1) = output_position_x(2) = (uint16_t)_horizontal_flywheel->get_current_output_position();
output_position_y(0) = output_position_y(1) = output_position_y(2) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
output_timestamp(0) = output_timestamp(1) = output_timestamp(2) = _openGL_output_builder->get_current_field_time();
// output_timestamp(0) = output_timestamp(1) = output_timestamp(2) = _openGL_output_builder->get_current_field_time();
output_tex_x(0) = output_tex_x(1) = output_tex_x(2) = (uint16_t)_horizontal_flywheel->get_current_output_position();
output_tex_y(0) = output_tex_y(1) = output_tex_y(2) = _openGL_output_builder->get_composite_output_y();
output_lateral(0) = 0;
output_lateral(1) = _is_writing_composite_run ? 1 : 0;
output_lateral(2) = 1;
output_frame_id(0) = output_frame_id(1) = output_frame_id(2) = (uint8_t)_openGL_output_builder->get_current_field();
// output_frame_id(0) = output_frame_id(1) = output_frame_id(2) = (uint8_t)_openGL_output_builder->get_current_field();
_openGL_output_builder->complete_output_run(3);
_is_writing_composite_run ^= true;
@ -258,7 +259,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
}
}
_openGL_output_builder->increment_field();
// _openGL_output_builder->increment_field();
}
}
}

View File

@ -36,8 +36,14 @@ static const GLenum formatForDepth(size_t depth)
}
}
static int getCircularRanges(GLsizei start, GLsizei end, GLsizei buffer_length, GLsizei *ranges)
static int getCircularRanges(GLsizei start, GLsizei end, GLsizei buffer_length, GLsizei granularity, GLsizei *ranges)
{
GLsizei startOffset = start%granularity;
if(startOffset)
{
start -= startOffset;
}
GLsizei length = end - start;
if(!length) return 0;
if(length > buffer_length)
@ -74,7 +80,6 @@ namespace {
}
OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
_run_write_pointer(0),
_output_mutex(new std::mutex),
_visible_area(Rect(0, 0, 1, 1)),
_composite_src_output_y(0),
@ -85,18 +90,14 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
_source_buffer_data(nullptr),
_input_texture_data(nullptr),
_output_buffer_data_pointer(0),
_drawn_output_buffer_data_pointer(0),
_source_buffer_data_pointer(0),
_drawn_source_buffer_data_pointer(0)
{
_run_builders = new CRTRunBuilder *[NumberOfFields];
for(int builder = 0; builder < NumberOfFields; builder++)
{
_run_builders[builder] = new CRTRunBuilder();
}
_buffer_builder = std::unique_ptr<CRTInputBufferBuilder>(new CRTInputBufferBuilder(buffer_depth));
glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_ALPHA);
glBlendColor(1.0f, 1.0f, 1.0f, 0.33f);
glBlendColor(1.0f, 1.0f, 1.0f, 0.5f);
// Create intermediate textures and bind to slots 0, 1 and 2
glActiveTexture(composite_texture_unit);
@ -156,12 +157,6 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) :
OpenGLOutputBuilder::~OpenGLOutputBuilder()
{
for(int builder = 0; builder < NumberOfFields; builder++)
{
delete _run_builders[builder];
}
delete[] _run_builders;
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glDeleteTextures(1, &textureName);
@ -203,11 +198,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
// release the mapping, giving up on trying to draw if data has been lost
glBindBuffer(GL_ARRAY_BUFFER, output_array_buffer);
if(glUnmapBuffer(GL_ARRAY_BUFFER) == GL_FALSE)
{
for(int c = 0; c < NumberOfFields; c++)
_run_builders[c]->reset();
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, source_array_buffer);
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
@ -242,8 +233,8 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
{
// determine how many lines are newly reclaimed; they'll need to be cleared
GLsizei clearing_zones[4], drawing_zones[4];
int number_of_clearing_zones = getCircularRanges(_cleared_composite_output_y+1, _composite_src_output_y+1, IntermediateBufferHeight, clearing_zones);
int number_of_drawing_zones = getCircularRanges(_drawn_source_buffer_data_pointer, _source_buffer_data_pointer, SourceVertexBufferDataSize, drawing_zones);
int number_of_clearing_zones = getCircularRanges(_cleared_composite_output_y+1, _composite_src_output_y+1, IntermediateBufferHeight, 1, clearing_zones);
int number_of_drawing_zones = getCircularRanges(_drawn_source_buffer_data_pointer, _source_buffer_data_pointer, SourceVertexBufferDataSize, 2*SourceVertexSize, drawing_zones);
_composite_src_output_y %= IntermediateBufferHeight;
_cleared_composite_output_y = _composite_src_output_y;
@ -324,23 +315,17 @@ void OpenGLOutputBuilder::perform_output_stage(unsigned int output_width, unsign
if(shader)
{
// clear the buffer
glClear(GL_COLOR_BUFFER_BIT);
// glClear(GL_COLOR_BUFFER_BIT);
// draw all sitting frames
unsigned int run = (unsigned int)_run_write_pointer;
GLint total_age = 0;
float timestampBases[4];
size_t start = 0, count = 0;
for(int c = 0; c < NumberOfFields; c++)
{
total_age += _run_builders[run]->duration;
timestampBases[run] = (float)total_age;
count += _run_builders[run]->amount_of_data;
start = _run_builders[run]->start;
run = (run - 1 + NumberOfFields) % NumberOfFields;
}
// draw all pending lines
GLsizei drawing_zones[4];
int number_of_drawing_zones = getCircularRanges(_drawn_output_buffer_data_pointer, _output_buffer_data_pointer, OutputVertexBufferDataSize, 6*OutputVertexSize, drawing_zones);
if(count > 0)
_output_buffer_data_pointer %= SourceVertexBufferDataSize;
_output_buffer_data_pointer -= (_output_buffer_data_pointer%(6*OutputVertexSize));
_drawn_output_buffer_data_pointer = _output_buffer_data_pointer;
if(number_of_drawing_zones > 0)
{
glEnable(GL_BLEND);
@ -352,18 +337,9 @@ void OpenGLOutputBuilder::perform_output_stage(unsigned int output_width, unsign
push_size_uniforms(output_width, output_height);
// draw
glUniform4fv(timestampBaseUniform, 1, timestampBases);
GLsizei primitive_count = (GLsizei)(count / OutputVertexSize);
GLsizei max_count = (GLsizei)((OutputVertexBufferDataSize - start) / OutputVertexSize);
if(primitive_count < max_count)
for(int c = 0; c < number_of_drawing_zones; c++)
{
glDrawArrays(GL_TRIANGLE_STRIP, (GLint)(start / OutputVertexSize), primitive_count);
}
else
{
glDrawArrays(GL_TRIANGLE_STRIP, (GLint)(start / OutputVertexSize), max_count);
glDrawArrays(GL_TRIANGLE_STRIP, 0, primitive_count - max_count);
glDrawArrays(GL_TRIANGLE_STRIP, drawing_zones[c*2] / OutputVertexSize, drawing_zones[c*2 + 1] / OutputVertexSize);
}
}
}
@ -673,7 +649,7 @@ char *OpenGLOutputBuilder::get_output_vertex_shader(const char *header)
"iSrcCoordinatesVarying = srcCoordinates;"
"srcCoordinatesVarying = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);"
"float age = (timestampBase[int(lateralAndTimestampBaseOffset.y)] - timestamp) / ticksPerFrame;"
"alpha = 1.0;"//15.0*exp(-age*3.0);"
"alpha = 0.5;"//15.0*exp(-age*3.0);"
"vec2 floatingPosition = (position / positionConversion) + lateralAndTimestampBaseOffset.x * scanNormal;"
"vec2 mappedPosition = (floatingPosition - boundsOrigin) / boundsSize;"
@ -884,12 +860,6 @@ void OpenGLOutputBuilder::set_output_device(OutputDevice output_device)
if(_output_device != output_device)
{
_output_device = output_device;
for(int builder = 0; builder < NumberOfFields; builder++)
{
_run_builders[builder]->reset();
}
_composite_src_output_y = 0;
}
}

View File

@ -15,7 +15,6 @@
#include "TextureTarget.hpp"
#include "Shader.hpp"
#include "CRTInputBufferBuilder.hpp"
#include "CRTRunBuilder.hpp"
#include <mutex>
@ -58,8 +57,6 @@ class OpenGLOutputBuilder {
// the run and input data buffers
std::unique_ptr<CRTInputBufferBuilder> _buffer_builder;
CRTRunBuilder **_run_builders;
int _run_write_pointer;
std::shared_ptr<std::mutex> _output_mutex;
// transient buffers indicating composite data not yet decoded
@ -132,13 +129,12 @@ class OpenGLOutputBuilder {
inline uint8_t *get_next_output_run()
{
_output_mutex->lock();
return &_output_buffer_data[_output_buffer_data_pointer];
return &_output_buffer_data[_output_buffer_data_pointer % OutputVertexBufferDataSize];
}
inline void complete_output_run(GLsizei vertices_written)
{
_run_builders[_run_write_pointer]->amount_of_data += (size_t)(vertices_written * OutputVertexSize);
_output_buffer_data_pointer = (_output_buffer_data_pointer + vertices_written * OutputVertexSize) % OutputVertexBufferDataSize;
_output_buffer_data_pointer += vertices_written * OutputVertexSize;
_output_mutex->unlock();
}
@ -147,16 +143,6 @@ class OpenGLOutputBuilder {
return _output_device;
}
inline uint32_t get_current_field_time()
{
return _run_builders[_run_write_pointer]->duration;
}
inline void add_to_field_time(uint32_t amount)
{
_run_builders[_run_write_pointer]->duration += amount;
}
inline uint16_t get_composite_output_y()
{
return _composite_src_output_y % IntermediateBufferHeight;
@ -167,20 +153,6 @@ class OpenGLOutputBuilder {
_composite_src_output_y++;
}
inline void increment_field()
{
_output_mutex->lock();
_run_write_pointer = (_run_write_pointer + 1)%NumberOfFields;
_run_builders[_run_write_pointer]->start = (size_t)_output_buffer_data_pointer;
_run_builders[_run_write_pointer]->reset();
_output_mutex->unlock();
}
inline int get_current_field()
{
return _run_write_pointer;
}
inline uint8_t *allocate_write_area(size_t required_length)
{
_output_mutex->lock();
@ -217,12 +189,13 @@ class OpenGLOutputBuilder {
GLsync _input_texture_sync;
GLsizeiptr _input_texture_array_size;
uint8_t *_output_buffer_data;
GLsizei _output_buffer_data_pointer;
uint8_t *_source_buffer_data;
GLsizei _source_buffer_data_pointer;
GLsizei _drawn_source_buffer_data_pointer;
uint8_t *_output_buffer_data;
GLsizei _output_buffer_data_pointer;
GLsizei _drawn_output_buffer_data_pointer;
};
}

View File

@ -1,12 +0,0 @@
//
// CRTFrameBuilder.cpp
// Clock Signal
//
// Created by Thomas Harte on 04/02/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "CRT.hpp"
#include "CRTOpenGL.hpp"
using namespace Outputs::CRT;

View File

@ -1,41 +0,0 @@
//
// CRTRunBuilder.h
// Clock Signal
//
// Created by Thomas Harte on 08/03/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef CRTRunBuilder_h
#define CRTRunBuilder_h
#import <vector>
namespace Outputs {
namespace CRT {
struct CRTRunBuilder {
CRTRunBuilder() : start(0) { reset(); }
// Resets the run builder.
inline void reset()
{
duration = 0;
amount_of_uploaded_data = 0;
amount_of_data = 0;
}
// Container for total length in cycles of all contained runs.
uint32_t duration;
size_t start;
// 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 amount_of_uploaded_data;
size_t amount_of_data;
};
}
}
#endif /* CRTRunBuilder_h */