1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-28 22:29:36 +00:00

Removes some migrated work.

This commit is contained in:
Thomas Harte 2018-11-11 16:22:14 -05:00
parent 0ba3ae53ab
commit d5af1f3948
6 changed files with 23 additions and 442 deletions

View File

@ -1363,8 +1363,6 @@
4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Oric.cpp; path = Oric/Oric.cpp; sourceTree = "<group>"; };
4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Oric/Oric.hpp; sourceTree = "<group>"; };
4BD060A51FE49D3C006E14BE /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = "<group>"; };
4BD191D6219113B80042E144 /* ArrayBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBuilder.cpp; sourceTree = "<group>"; };
4BD191D7219113B80042E144 /* CRTOpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTOpenGL.hpp; sourceTree = "<group>"; };
4BD191D8219113B80042E144 /* TextureBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureBuilder.cpp; sourceTree = "<group>"; };
4BD191D9219113B80042E144 /* OpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenGL.hpp; sourceTree = "<group>"; };
4BD191DC219113B80042E144 /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = "<group>"; };
@ -1373,7 +1371,6 @@
4BD191E1219113B80042E144 /* OutputShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputShader.cpp; sourceTree = "<group>"; };
4BD191E3219113B80042E144 /* IntermediateShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermediateShader.cpp; sourceTree = "<group>"; };
4BD191E4219113B80042E144 /* OutputShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OutputShader.hpp; sourceTree = "<group>"; };
4BD191E7219113B90042E144 /* ArrayBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ArrayBuilder.hpp; sourceTree = "<group>"; };
4BD191F22191180E0042E144 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
4BD191F32191180E0042E144 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = "<group>"; };
4BD388411FE34E010042B588 /* 9918Base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 9918Base.hpp; path = 9918/Implementation/9918Base.hpp; sourceTree = "<group>"; };
@ -3025,12 +3022,9 @@
4BD191D5219113B80042E144 /* OpenGL */ = {
isa = PBXGroup;
children = (
4BD191D6219113B80042E144 /* ArrayBuilder.cpp */,
4BD191DC219113B80042E144 /* CRTOpenGL.cpp */,
4BD191F22191180E0042E144 /* ScanTarget.cpp */,
4BD191D8219113B80042E144 /* TextureBuilder.cpp */,
4BD191E7219113B90042E144 /* ArrayBuilder.hpp */,
4BD191D7219113B80042E144 /* CRTOpenGL.hpp */,
4BD191D9219113B80042E144 /* OpenGL.hpp */,
4BD191F32191180E0042E144 /* ScanTarget.hpp */,
4BD191DD219113B80042E144 /* TextureBuilder.hpp */,

View File

@ -1,149 +0,0 @@
//
// ArrayBuilder.cpp
// Clock Signal
//
// Created by Thomas Harte on 17/11/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#include "ArrayBuilder.hpp"
#include <cstring>
using namespace Outputs::CRT;
ArrayBuilder::ArrayBuilder(std::size_t input_size, std::size_t output_size) :
output_(output_size, nullptr),
input_(input_size, nullptr) {}
ArrayBuilder::ArrayBuilder(std::size_t input_size, std::size_t output_size, std::function<void(bool is_input, uint8_t *, std::size_t)> submission_function) :
output_(output_size, submission_function),
input_(input_size, submission_function) {}
bool ArrayBuilder::is_full() {
bool was_full;
was_full = is_full_;
return was_full;
}
uint8_t *ArrayBuilder::get_input_storage(std::size_t size) {
return get_storage(size, input_);
}
uint8_t *ArrayBuilder::get_output_storage(std::size_t size) {
return get_storage(size, output_);
}
void ArrayBuilder::flush(const std::function<void(uint8_t *input, std::size_t input_size, uint8_t *output, std::size_t output_size)> &function) {
if(!is_full_) {
std::size_t input_size = 0, output_size = 0;
uint8_t *input = input_.get_unflushed(input_size);
uint8_t *output = output_.get_unflushed(output_size);
function(input, input_size, output, output_size);
input_.flush();
output_.flush();
}
}
void ArrayBuilder::bind_input() {
input_.bind();
}
void ArrayBuilder::bind_output() {
output_.bind();
}
ArrayBuilder::Submission ArrayBuilder::submit() {
ArrayBuilder::Submission submission;
submission.input_size = input_.submit(true);
submission.output_size = output_.submit(false);
if(is_full_) {
is_full_ = false;
input_.reset();
output_.reset();
}
return submission;
}
ArrayBuilder::Buffer::Buffer(std::size_t size, std::function<void(bool is_input, uint8_t *, std::size_t)> submission_function) :
submission_function_(submission_function) {
if(!submission_function_) {
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, NULL, GL_STREAM_DRAW);
}
data.resize(size);
}
ArrayBuilder::Buffer::~Buffer() {
if(!submission_function_)
glDeleteBuffers(1, &buffer);
}
uint8_t *ArrayBuilder::get_storage(std::size_t size, Buffer &buffer) {
uint8_t *pointer = buffer.get_storage(size);
if(!pointer) is_full_ = true;
return pointer;
}
uint8_t *ArrayBuilder::Buffer::get_storage(std::size_t size) {
if(is_full || allocated_data + size > data.size()) {
is_full = true;
return nullptr;
}
uint8_t *pointer = &data[allocated_data];
allocated_data += size;
return pointer;
}
uint8_t *ArrayBuilder::Buffer::get_unflushed(std::size_t &size) {
if(is_full) {
return nullptr;
}
size = allocated_data - flushed_data;
return &data[flushed_data];
}
void ArrayBuilder::Buffer::flush() {
if(submitted_data) {
memmove(data.data(), &data[submitted_data], allocated_data - submitted_data);
allocated_data -= submitted_data;
flushed_data -= submitted_data;
submitted_data = 0;
}
flushed_data = allocated_data;
}
std::size_t ArrayBuilder::Buffer::submit(bool is_input) {
std::size_t length = flushed_data;
if(submission_function_) {
submission_function_(is_input, data.data(), length);
} else {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
uint8_t *destination = static_cast<uint8_t *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
if(!glGetError() && destination) {
std::memcpy(destination, data.data(), length);
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length);
glUnmapBuffer(GL_ARRAY_BUFFER);
} else {
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)length, data.data(), GL_STREAM_DRAW);
}
}
submitted_data = flushed_data;
return length;
}
void ArrayBuilder::Buffer::bind() {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
}
void ArrayBuilder::Buffer::reset() {
is_full = false;
allocated_data = 0;
flushed_data = 0;
submitted_data = 0;
}

View File

@ -1,101 +0,0 @@
//
// ArrayBuilder.hpp
// Clock Signal
//
// Created by Thomas Harte on 17/11/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#ifndef ArrayBuilder_hpp
#define ArrayBuilder_hpp
#include <functional>
#include <memory>
#include <vector>
#include "OpenGL.hpp"
namespace Outputs {
namespace CRT {
/*!
Owns two array buffers, an 'input' and an 'output' and vends pointers to allow an owner to write provisional data into those
plus a flush function to lock provisional data into place. Also supplies a submit method to transfer all currently locked
data to the GPU and bind_input/output methods to bind the internal buffers.
It is safe for one thread to communicate via the get_*_storage and flush inputs asynchronously from another that is making
use of the bind and submit outputs.
*/
class ArrayBuilder {
public:
/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
/// @c input_size bytes of storage for the input buffer.
ArrayBuilder(std::size_t input_size, std::size_t output_size);
/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
/// @c input_size bytes of storage for the input buffer that, rather than using OpenGL, will submit data
/// to the @c submission_function. [Teleological: this is provided as a testing hook.]
ArrayBuilder(std::size_t input_size, std::size_t output_size, std::function<void(bool is_input, uint8_t *, std::size_t)> submission_function);
/// Attempts to add @c size bytes to the input set.
/// @returns a pointer to the allocated area if allocation was possible; @c nullptr otherwise.
uint8_t *get_input_storage(std::size_t size);
/// Attempts to add @c size bytes to the output set.
/// @returns a pointer to the allocated area if allocation was possible; @c nullptr otherwise.
uint8_t *get_output_storage(std::size_t size);
/// @returns @c true if either of the input or output storage areas is currently exhausted; @c false otherwise.
bool is_full();
/// If neither input nor output was exhausted since the last flush, atomically commits both input and output
/// up to the currently allocated size for use upon the next @c submit, giving the supplied function a
/// chance to perform last-minute processing. Otherwise acts as a no-op.
void flush(const std::function<void(uint8_t *input, std::size_t input_size, uint8_t *output, std::size_t output_size)> &);
/// Binds the input array to GL_ARRAY_BUFFER.
void bind_input();
/// Binds the output array to GL_ARRAY_BUFFER.
void bind_output();
struct Submission {
std::size_t input_size, output_size;
};
/// Submits all flushed input and output data to the corresponding arrays.
/// @returns A @c Submission record, indicating how much data of each type was submitted.
Submission submit();
private:
class Buffer {
public:
Buffer(std::size_t size, std::function<void(bool is_input, uint8_t *, std::size_t)> submission_function);
~Buffer();
uint8_t *get_storage(std::size_t size);
uint8_t *get_unflushed(std::size_t &size);
void flush();
std::size_t submit(bool is_input);
void bind();
void reset();
private:
bool is_full = false;
GLuint buffer = 0;
std::function<void(bool is_input, uint8_t *, std::size_t)> submission_function_;
std::vector<uint8_t> data;
std::size_t allocated_data = 0;
std::size_t flushed_data = 0;
std::size_t submitted_data = 0;
} output_, input_;
uint8_t *get_storage(std::size_t size, Buffer &buffer);
bool is_full_ = false;
};
}
}
#endif /* ArrayBuilder_hpp */

View File

@ -1,181 +0,0 @@
//
// CRTOpenGL.hpp
// Clock Signal
//
// Created by Thomas Harte on 13/02/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#ifndef CRTOpenGL_h
#define CRTOpenGL_h
#include "CRTConstants.hpp"
#include "OpenGL.hpp"
#include "TextureTarget.hpp"
#include "Shaders/Shader.hpp"
#include "ArrayBuilder.hpp"
#include "TextureBuilder.hpp"
#include "Shaders/OutputShader.hpp"
#include "Shaders/IntermediateShader.hpp"
#include "Rectangle.hpp"
#include "../ScanTarget.hpp"
#include <mutex>
#include <vector>
namespace Outputs {
namespace CRT {
class OpenGLOutputBuilder {
private:
// colour information
ColourSpace colour_space_;
unsigned int colour_cycle_numerator_;
unsigned int colour_cycle_denominator_;
VideoSignal video_signal_;
float gamma_;
// timing information to allow reasoning about input information
unsigned int input_frequency_;
unsigned int cycles_per_line_;
unsigned int height_of_display_;
unsigned int horizontal_scan_period_;
unsigned int vertical_scan_period_;
unsigned int vertical_period_divider_;
// The user-supplied visible area
Rect visible_area_;
// Other things the caller may have provided.
std::string composite_shader_;
std::string svideo_shader_;
std::string rgb_shader_;
GLint target_framebuffer_ = 0;
// Methods used by the OpenGL code
void prepare_output_shader();
void prepare_rgb_input_shaders();
void prepare_svideo_input_shaders();
void prepare_composite_input_shaders();
void prepare_output_vertex_array();
void prepare_source_vertex_array();
// the run and input data buffers
std::mutex output_mutex_;
std::mutex draw_mutex_;
// transient buffers indicating composite data not yet decoded
GLsizei composite_src_output_y_;
std::unique_ptr<OpenGL::OutputShader> output_shader_program_;
std::unique_ptr<OpenGL::IntermediateShader> composite_input_shader_program_;
std::unique_ptr<OpenGL::IntermediateShader> composite_separation_filter_program_;
std::unique_ptr<OpenGL::IntermediateShader> composite_chrominance_filter_shader_program_;
std::unique_ptr<OpenGL::IntermediateShader> svideo_input_shader_program_;
std::unique_ptr<OpenGL::IntermediateShader> rgb_input_shader_program_;
std::unique_ptr<OpenGL::IntermediateShader> rgb_filter_shader_program_;
std::unique_ptr<OpenGL::TextureTarget> composite_texture_; // receives raw composite levels
std::unique_ptr<OpenGL::TextureTarget> separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B
std::unique_ptr<OpenGL::TextureTarget> filtered_texture_; // receives filtered YIQ or YUV
std::unique_ptr<OpenGL::TextureTarget> work_texture_; // used for all intermediate rendering if texture fences are supported
std::unique_ptr<OpenGL::TextureTarget> framebuffer_; // the current pixel output
GLuint output_vertex_array_;
GLuint source_vertex_array_;
unsigned int last_output_width_, last_output_height_;
void set_timing_uniforms();
void set_colour_space_uniforms();
void set_gamma();
void establish_OpenGL_state();
void reset_all_OpenGL_state();
GLsync fence_;
float get_composite_output_width() const;
void set_output_shader_width();
// Maintain a couple of rectangles for masking off the extreme edge of the display;
// this is a bit of a cheat: there's some tolerance in when a sync pulse will be
// generated. So it might be slightly later than expected. Which might cause a scan
// that is slightly longer than expected. Which means that from then on, those scans
// might have touched parts of the extreme edge of the display which are not rescanned.
// Which because I've implemented persistence-of-vision as an in-buffer effect will
// cause perpetual persistence.
//
// The fix: just always treat that area as invisible. This is acceptable thanks to
// the concept of overscan. One is allowed not to display extreme ends of the image.
std::unique_ptr<OpenGL::Rectangle> right_overlay_;
std::unique_ptr<OpenGL::Rectangle> left_overlay_;
public:
// These two are protected by output_mutex_.
TextureBuilder texture_builder;
ArrayBuilder array_builder;
OpenGLOutputBuilder(std::size_t bytes_per_pixel);
~OpenGLOutputBuilder();
inline void set_colour_format(ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator) {
std::lock_guard<std::mutex> output_guard(output_mutex_);
colour_space_ = colour_space;
colour_cycle_numerator_ = colour_cycle_numerator;
colour_cycle_denominator_ = colour_cycle_denominator;
set_colour_space_uniforms();
}
inline void set_visible_area(Rect visible_area) {
visible_area_ = visible_area;
}
inline void set_gamma(float gamma) {
gamma_ = gamma;
set_gamma();
}
inline std::unique_lock<std::mutex> get_output_lock() {
return std::unique_lock<std::mutex>(output_mutex_);
}
inline VideoSignal get_output_device() {
return video_signal_;
}
inline uint16_t get_composite_output_y() {
return static_cast<uint16_t>(composite_src_output_y_);
}
inline bool composite_output_buffer_is_full() {
return composite_src_output_y_ == IntermediateBufferHeight;
}
inline void increment_composite_output_y() {
if(!composite_output_buffer_is_full())
composite_src_output_y_++;
}
void set_target_framebuffer(GLint);
void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty);
void set_openGL_context_will_change(bool should_delete_resources);
void set_composite_sampling_function(const std::string &);
void set_svideo_sampling_function(const std::string &);
void set_rgb_sampling_function(const std::string &);
void set_video_signal(VideoSignal);
void set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider);
};
}
}
#endif /* CRTOpenGL_h */

View File

@ -18,7 +18,26 @@ constexpr int WriteAreaHeight = 2048;
constexpr int CompositeLineBufferWidth = 2048;
constexpr int CompositeLineBufferHeight = 2048;
constexpr int CompositeLineBufferTextureUnit = 0;
/// The texture unit from which to source 1bpp input data.
constexpr GLenum SourceData1BppTextureUnit = GL_TEXTURE0;
/// The texture unit from which to source 2bpp input data.
constexpr GLenum SourceData2BppTextureUnit = GL_TEXTURE1;
/// The texture unit from which to source 4bpp input data.
constexpr GLenum SourceData4BppTextureUnit = GL_TEXTURE2;
/// The texture unit which contains raw line-by-line composite or RGB data.
constexpr GLenum UnprocessedLineBufferTextureUnit = GL_TEXTURE3;
/// The texture unit which contains line-by-line records of luminance and amplitude-modulated chrominance.
constexpr GLenum CompositeSeparatedTextureUnit = GL_TEXTURE4;
/// The texture unit which contains line-by-line records of luminance and demodulated chrominance.
constexpr GLenum DemodulatedCompositeTextureUnit = GL_TEXTURE5;
/// The texture unit which contains line-by-line RGB.
constexpr GLenum LineBufferTextureUnit = GL_TEXTURE6;
/// The texture unit that contains the current display.
constexpr GLenum AccumulationTextureUnit = GL_TEXTURE7;
#define TextureAddress(x, y) (((y) << 11) | (x))
#define TextureAddressGetY(v) uint16_t((v) >> 11)
@ -48,13 +67,12 @@ const GLenum formatForDepth(std::size_t depth) {
}
ScanTarget::ScanTarget() :
composite_line_texture_(CompositeLineBufferWidth, CompositeLineBufferHeight, CompositeLineBufferTextureUnit, GL_LINEAR) {
unprocessed_line_texture_(CompositeLineBufferWidth, CompositeLineBufferHeight, UnprocessedLineBufferTextureUnit, GL_LINEAR) {
// Allocate space for the scans.
const auto buffer_size = scan_buffer_.size() * sizeof(Scan);
glGenBuffers(1, &scan_buffer_name_);
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
const auto buffer_size = scan_buffer_.size() * sizeof(Scan);
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW);
// TODO: if this is OpenGL 4.4 or newer, use glBufferStorage rather than glBufferData

View File

@ -78,7 +78,7 @@ class ScanTarget: public Outputs::Display::ScanTarget {
uint16_t composite_y;
};
std::array<CompositeLine, 2048> composite_line_buffer_;
TextureTarget composite_line_texture_;
TextureTarget unprocessed_line_texture_;
GLuint composite_line_vertex_array_ = 0;
CompositeLine *active_composite_line_ = nullptr;