diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index f7941d5bc..fd3a1442f 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -352,7 +352,7 @@ 4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */; }; 4BB73EC21B587A5100552FC2 /* Clock_SignalUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EC11B587A5100552FC2 /* Clock_SignalUITests.swift */; }; 4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB142F1CD2CECE00BDB55C /* IntermediateShader.cpp */; }; - 4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99081C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp */; }; + 4BBF99141C8FBA6F0075DAFB /* InputTextureBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99081C8FBA6F0075DAFB /* InputTextureBuilder.cpp */; }; 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */; }; 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99121C8FBA6F0075DAFB /* TextureTarget.cpp */; }; 4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B74D1CD194CC00F86E85 /* Shader.cpp */; }; @@ -828,8 +828,8 @@ 4BBB142F1CD2CECE00BDB55C /* IntermediateShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermediateShader.cpp; sourceTree = ""; }; 4BBB14301CD2CECE00BDB55C /* IntermediateShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IntermediateShader.hpp; sourceTree = ""; }; 4BBC34241D2208B100FFC9DF /* CSFastLoading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSFastLoading.h; sourceTree = ""; }; - 4BBF99081C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTInputBufferBuilder.cpp; sourceTree = ""; }; - 4BBF99091C8FBA6F0075DAFB /* CRTInputBufferBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTInputBufferBuilder.hpp; sourceTree = ""; }; + 4BBF99081C8FBA6F0075DAFB /* InputTextureBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InputTextureBuilder.cpp; sourceTree = ""; }; + 4BBF99091C8FBA6F0075DAFB /* InputTextureBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = InputTextureBuilder.hpp; sourceTree = ""; }; 4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = ""; }; 4BBF990B1C8FBA6F0075DAFB /* CRTOpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTOpenGL.hpp; sourceTree = ""; }; 4BBF990E1C8FBA6F0075DAFB /* Flywheel.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Flywheel.hpp; sourceTree = ""; }; @@ -1688,8 +1688,8 @@ isa = PBXGroup; children = ( 4BC3B74C1CD194CC00F86E85 /* Shaders */, - 4BBF99081C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp */, - 4BBF99091C8FBA6F0075DAFB /* CRTInputBufferBuilder.hpp */, + 4BBF99081C8FBA6F0075DAFB /* InputTextureBuilder.cpp */, + 4BBF99091C8FBA6F0075DAFB /* InputTextureBuilder.hpp */, 4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */, 4BBF990B1C8FBA6F0075DAFB /* CRTOpenGL.hpp */, 4BBF990E1C8FBA6F0075DAFB /* Flywheel.hpp */, @@ -2320,7 +2320,7 @@ 4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */, 4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */, 4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */, - 4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */, + 4BBF99141C8FBA6F0075DAFB /* InputTextureBuilder.cpp in Sources */, 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */, 4BCF1FA81DADC5250039D2E7 /* CSOric.mm in Sources */, 4B6C73BD1D387AE500AFCFCA /* DiskController.cpp in Sources */, diff --git a/Outputs/CRT/Internals/CRTInputBufferBuilder.hpp b/Outputs/CRT/Internals/CRTInputBufferBuilder.hpp deleted file mode 100644 index 39afba9d0..000000000 --- a/Outputs/CRT/Internals/CRTInputBufferBuilder.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// CRTInputBufferBuilder.hpp -// Clock Signal -// -// Created by Thomas Harte on 08/03/2016. -// Copyright © 2016 Thomas Harte. All rights reserved. -// - -#ifndef CRTInputBufferBuilder_hpp -#define CRTInputBufferBuilder_hpp - -#include -#include -#include -#include "CRTConstants.hpp" -#include "OpenGL.hpp" -#include - -namespace Outputs { -namespace CRT { - -struct CRTInputBufferBuilder { - CRTInputBufferBuilder(size_t bytes_per_pixel); - - void allocate_write_area(size_t required_length); - void reduce_previous_allocation_to(size_t actual_length); - - uint16_t get_and_finalise_current_line(); - uint8_t *get_image_pointer(); - - uint8_t *get_write_target(); - - uint16_t get_last_write_x_position(); - - uint16_t get_last_write_y_position(); - - size_t get_bytes_per_pixel(); - - bool is_full(); - - private: - // where pixel data will be put to the next time a write is requested - uint16_t _next_write_x_position, _next_write_y_position; - - // the most recent position returned for pixel data writing - uint16_t _write_x_position, _write_y_position; - - // details of the most recent allocation - size_t _write_target_pointer; - size_t _last_allocation_amount; - - // the buffer size - size_t _bytes_per_pixel; - - // the buffer - std::unique_ptr _image; -}; - -} -} - -#endif /* CRTInputBufferBuilder_hpp */ diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 065f588f8..ec772821e 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -45,6 +45,8 @@ static GLsizei submitArrayData(GLuint buffer, uint8_t *source, size_t *length_po { GLsizei length = (GLsizei)*length_pointer; + // The development machine is a Mac; Apple seemingly having given up on OpenGL (?), GL_MAP_PERSISTENT_BIT is not + // available. Which possibly means I'm doing no better here than a traditional buffer submit, but there it is. glBindBuffer(GL_ARRAY_BUFFER, buffer); uint8_t *data = (uint8_t *)glMapBufferRange(GL_ARRAY_BUFFER, 0, length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); memcpy(data, source, (size_t)length); @@ -78,7 +80,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) : _last_output_height(0), _fence(nullptr) { - _buffer_builder.reset(new CRTInputBufferBuilder(buffer_depth)); + _texture_builder.reset(new InputTextureBuilder(buffer_depth)); _output_buffer.data.resize(OutputVertexBufferDataSize); _source_buffer.data.resize(SourceVertexBufferDataSize); @@ -100,7 +102,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, internalFormatForDepth(_buffer_builder->get_bytes_per_pixel()), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(_buffer_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormatForDepth(_texture_builder->get_bytes_per_pixel()), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(_texture_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE, nullptr); // create the output vertex array glGenVertexArrays(1, &output_vertex_array); @@ -189,15 +191,15 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out GLsizei submitted_source_data = submitArrayData(source_array_buffer, _source_buffer.data.data(), &_source_buffer.pointer); // upload new source pixels, if any - uint16_t completed_texture_y = _buffer_builder->get_and_finalise_current_line(); + uint16_t completed_texture_y = _texture_builder->get_and_finalise_current_line(); if(completed_texture_y) { glActiveTexture(source_data_texture_unit); glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, InputBufferBuilderWidth, completed_texture_y, - formatForDepth(_buffer_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE, - _buffer_builder->get_image_pointer()); + formatForDepth(_texture_builder->get_bytes_per_pixel()), GL_UNSIGNED_BYTE, + _texture_builder->get_image_pointer()); } // buffer usage restart from 0 for the next time around diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index baab3a33e..b7a8b86e7 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -14,7 +14,7 @@ #include "OpenGL.hpp" #include "TextureTarget.hpp" #include "Shader.hpp" -#include "CRTInputBufferBuilder.hpp" +#include "InputTextureBuilder.hpp" #include "Shaders/OutputShader.hpp" #include "Shaders/IntermediateShader.hpp" @@ -57,7 +57,7 @@ class OpenGLOutputBuilder { void prepare_source_vertex_array(); // the run and input data buffers - std::unique_ptr _buffer_builder; + std::unique_ptr _texture_builder; std::unique_ptr _output_mutex; std::unique_ptr _draw_mutex; @@ -183,28 +183,28 @@ class OpenGLOutputBuilder { inline uint8_t *allocate_write_area(size_t required_length) { - _buffer_builder->allocate_write_area(required_length); - return _buffer_builder->get_write_target(); + _texture_builder->allocate_write_area(required_length); + return _texture_builder->get_write_target(); } inline void reduce_previous_allocation_to(size_t actual_length) { - _buffer_builder->reduce_previous_allocation_to(actual_length); + _texture_builder->reduce_previous_allocation_to(actual_length); } inline bool input_buffer_is_full() { - return _buffer_builder->is_full(); + return _texture_builder->is_full(); } inline uint16_t get_last_write_x_posititon() { - return _buffer_builder->get_last_write_x_position(); + return _texture_builder->get_last_write_x_position(); } inline uint16_t get_last_write_y_posititon() { - return _buffer_builder->get_last_write_y_position(); + return _texture_builder->get_last_write_y_position(); } void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty); diff --git a/Outputs/CRT/Internals/CRTInputBufferBuilder.cpp b/Outputs/CRT/Internals/InputTextureBuilder.cpp similarity index 72% rename from Outputs/CRT/Internals/CRTInputBufferBuilder.cpp rename to Outputs/CRT/Internals/InputTextureBuilder.cpp index 983b1f1ee..8b3d6103b 100644 --- a/Outputs/CRT/Internals/CRTInputBufferBuilder.cpp +++ b/Outputs/CRT/Internals/InputTextureBuilder.cpp @@ -1,25 +1,26 @@ // -// CRTInputBufferBuilder.cpp +// InputTextureBuilder.cpp // Clock Signal // // Created by Thomas Harte on 08/03/2016. // Copyright © 2016 Thomas Harte. All rights reserved. // -#include "CRTInputBufferBuilder.hpp" +#include "InputTextureBuilder.hpp" #include "CRTOpenGL.hpp" #include using namespace Outputs::CRT; -CRTInputBufferBuilder::CRTInputBufferBuilder(size_t bytes_per_pixel) : +InputTextureBuilder::InputTextureBuilder(size_t bytes_per_pixel) : _bytes_per_pixel(bytes_per_pixel), _next_write_x_position(0), - _next_write_y_position(0), - _image(new uint8_t[bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight]) -{} + _next_write_y_position(0) +{ + _image.resize(bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight); +} -void CRTInputBufferBuilder::allocate_write_area(size_t required_length) +void InputTextureBuilder::allocate_write_area(size_t required_length) { if(_next_write_y_position != InputBufferBuilderHeight) { @@ -41,16 +42,16 @@ void CRTInputBufferBuilder::allocate_write_area(size_t required_length) } } -bool CRTInputBufferBuilder::is_full() +bool InputTextureBuilder::is_full() { return (_next_write_y_position == InputBufferBuilderHeight); } -void CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length) +void InputTextureBuilder::reduce_previous_allocation_to(size_t actual_length) { if(_next_write_y_position == InputBufferBuilderHeight) return; - uint8_t *const image_pointer = _image.get(); + uint8_t *const image_pointer = _image.data(); // correct if the writing cursor was reset while a client was writing if(_next_write_x_position == 0 && _next_write_y_position == 0) @@ -77,34 +78,34 @@ void CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length) _next_write_x_position -= (_last_allocation_amount - actual_length); } -uint8_t *CRTInputBufferBuilder::get_image_pointer() +uint8_t *InputTextureBuilder::get_image_pointer() { - return _image.get(); + return _image.data(); } -uint16_t CRTInputBufferBuilder::get_and_finalise_current_line() +uint16_t InputTextureBuilder::get_and_finalise_current_line() { uint16_t result = _write_y_position + (_next_write_x_position ? 1 : 0); _next_write_x_position = _next_write_y_position = 0; return result; } -uint8_t *CRTInputBufferBuilder::get_write_target() +uint8_t *InputTextureBuilder::get_write_target() { - return (_next_write_y_position == InputBufferBuilderHeight) ? nullptr : &_image.get()[_write_target_pointer * _bytes_per_pixel]; + return (_next_write_y_position == InputBufferBuilderHeight) ? nullptr : &_image[_write_target_pointer * _bytes_per_pixel]; } -uint16_t CRTInputBufferBuilder::get_last_write_x_position() +uint16_t InputTextureBuilder::get_last_write_x_position() { return _write_x_position; } -uint16_t CRTInputBufferBuilder::get_last_write_y_position() +uint16_t InputTextureBuilder::get_last_write_y_position() { return _write_y_position; } -size_t CRTInputBufferBuilder::get_bytes_per_pixel() +size_t InputTextureBuilder::get_bytes_per_pixel() { return _bytes_per_pixel; } diff --git a/Outputs/CRT/Internals/InputTextureBuilder.hpp b/Outputs/CRT/Internals/InputTextureBuilder.hpp new file mode 100644 index 000000000..a42081b9a --- /dev/null +++ b/Outputs/CRT/Internals/InputTextureBuilder.hpp @@ -0,0 +1,78 @@ +// +// InputTextureBuilder.hpp +// Clock Signal +// +// Created by Thomas Harte on 08/03/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Outputs_CRT_Internals_InputBufferBuilder_hpp +#define Outputs_CRT_Internals_InputBufferBuilder_hpp + +#include +#include +#include + +#include "OpenGL.hpp" +#include "CRTConstants.hpp" + +namespace Outputs { +namespace CRT { + +/*! + Owns an OpenGL texture resource and provides mechanisms to fill it from top left to bottom right + with runs of data, ensuring each run is neighboured immediately to the left and right by copies of its + first and last pixels. +*/ +class InputTextureBuilder { + public: + /// Constructs an instance of InputTextureBuilder that contains a texture of colour depth @c bytes_per_pixel. + InputTextureBuilder(size_t bytes_per_pixel); + + /// Finds the first available space of at least @c required_length pixels in size. Calls must be paired off + /// with calls to @c reduce_previous_allocation_to. + void allocate_write_area(size_t required_length); + + /// Announces that the owner is finished with the region created by the most recent @c allocate_write_area + /// and indicates that its actual final size was @c actual_length. + void reduce_previous_allocation_to(size_t actual_length); + + /// @returns the row that was the final one to receive data; also resets the builder to restart filling of + /// the texture from row 0. + uint16_t get_and_finalise_current_line(); + + /// @returns a pointer to the image data for this texture. + uint8_t *get_image_pointer(); + + uint8_t *get_write_target(); + + uint16_t get_last_write_x_position(); + + uint16_t get_last_write_y_position(); + + size_t get_bytes_per_pixel(); + + bool is_full(); + + private: + // where pixel data will be put to the next time a write is requested + uint16_t _next_write_x_position, _next_write_y_position; + + // the most recent position returned for pixel data writing + uint16_t _write_x_position, _write_y_position; + + // details of the most recent allocation + size_t _write_target_pointer; + size_t _last_allocation_amount; + + // the buffer size + size_t _bytes_per_pixel; + + // the buffer + std::vector _image; +}; + +} +} + +#endif /* CRTInputBufferBuilder_hpp */