diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index aab5669dc..58d69b723 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -624,6 +624,8 @@ 4BD424E82193B5830097291A /* Rectangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD424E22193B5820097291A /* Rectangle.cpp */; }; 4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD468F51D8DF41D0084958B /* 1770.cpp */; }; 4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */; }; + 4BD5D2682199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5D2672199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp */; }; + 4BD5D2692199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5D2672199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp */; }; 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.mm */; }; 4BD61664206B2AC800236112 /* QuickLoadOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BD61662206B2AC700236112 /* QuickLoadOptions.xib */; }; 4BD67DCB209BE4D700AB2146 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD67DCA209BE4D600AB2146 /* StaticAnalyser.cpp */; }; @@ -1385,6 +1387,7 @@ 4BD468F51D8DF41D0084958B /* 1770.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = 1770.cpp; path = 1770/1770.cpp; sourceTree = ""; }; 4BD468F61D8DF41D0084958B /* 1770.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 1770.hpp; path = 1770/1770.hpp; sourceTree = ""; }; 4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMTrackTests.mm; sourceTree = ""; }; + 4BD5D2672199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTargetVertexArrayAttributs.cpp; sourceTree = ""; }; 4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = ""; }; 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSBestEffortUpdater.mm; path = Updater/CSBestEffortUpdater.mm; sourceTree = ""; }; 4BD601A920D89F2A00CBCE57 /* Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Log.hpp; path = ../../Outputs/Log.hpp; sourceTree = ""; }; @@ -3024,6 +3027,7 @@ children = ( 4BD191DC219113B80042E144 /* CRTOpenGL.cpp */, 4BD191F22191180E0042E144 /* ScanTarget.cpp */, + 4BD5D2672199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp */, 4BD191D8219113B80042E144 /* TextureBuilder.cpp */, 4BD191D9219113B80042E144 /* OpenGL.hpp */, 4BD191F32191180E0042E144 /* ScanTarget.hpp */, @@ -3668,6 +3672,7 @@ 4B894521201967B4007DE474 /* StaticAnalyser.cpp in Sources */, 4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */, 4B055AA51FAE85EF0060FFFF /* Encoder.cpp in Sources */, + 4BD5D2692199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp in Sources */, 4B894529201967B4007DE474 /* Disk.cpp in Sources */, 4B055AEA1FAE9B990060FFFF /* 6502Storage.cpp in Sources */, 4B055AA71FAE85EF0060FFFF /* SegmentParser.cpp in Sources */, @@ -3857,6 +3862,7 @@ 4B0333AF2094081A0050B93D /* AppleDSK.cpp in Sources */, 4B894518201967B4007DE474 /* ConfidenceCounter.cpp in Sources */, 4B89452E201967B4007DE474 /* StaticAnalyser.cpp in Sources */, + 4BD5D2682199148100DDF17D /* ScanTargetVertexArrayAttributs.cpp in Sources */, 4B38F3481F2EC11D00D9235D /* AmstradCPC.cpp in Sources */, 4B8FE2221DA19FB20090D3CE /* MachinePanel.swift in Sources */, 4B4518A41F75FD1C00926311 /* OricMFMDSK.cpp in Sources */, diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index be1f6cec8..291efcddf 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -16,8 +16,8 @@ namespace { constexpr int WriteAreaWidth = 2048; constexpr int WriteAreaHeight = 2048; -constexpr int CompositeLineBufferWidth = 2048; -constexpr int CompositeLineBufferHeight = 2048; +constexpr int LineBufferWidth = 2048; +constexpr int LineBufferHeight = 2048; /// The texture unit from which to source 1bpp input data. constexpr GLenum SourceData1BppTextureUnit = GL_TEXTURE0; @@ -67,7 +67,7 @@ const GLenum formatForDepth(std::size_t depth) { } ScanTarget::ScanTarget() : - unprocessed_line_texture_(CompositeLineBufferWidth, CompositeLineBufferHeight, UnprocessedLineBufferTextureUnit, GL_LINEAR) { + unprocessed_line_texture_(LineBufferWidth, LineBufferHeight, UnprocessedLineBufferTextureUnit, GL_LINEAR) { // Allocate space for the scans. const auto buffer_size = scan_buffer_.size() * sizeof(Scan); @@ -123,17 +123,17 @@ Outputs::Display::ScanTarget::Scan *ScanTarget::begin_scan() { write_pointers_.scan_buffer = next_write_pointer; // Fill in extra OpenGL-specific details. - result->composite_y = write_pointers_.composite_y; + result->line = write_pointers_.line; vended_scan_ = result; - return static_cast(result); + return &result->scan; } void ScanTarget::end_scan() { if(vended_scan_) { vended_scan_->data_y = TextureAddressGetY(vended_write_area_pointer_); - vended_scan_->end_points[0].data_offset += TextureAddressGetX(vended_write_area_pointer_); - vended_scan_->end_points[1].data_offset += TextureAddressGetX(vended_write_area_pointer_); + vended_scan_->scan.end_points[0].data_offset += TextureAddressGetX(vended_write_area_pointer_); + vended_scan_->scan.end_points[1].data_offset += TextureAddressGetX(vended_write_area_pointer_); } vended_scan_ = nullptr; } @@ -201,27 +201,27 @@ void ScanTarget::announce(Event event, uint16_t x, uint16_t y) { switch(event) { default: break; case ScanTarget::Event::BeginHorizontalRetrace: - if(active_composite_line_) { - active_composite_line_->end_points[1].x = x; - active_composite_line_->end_points[1].y = y; - active_composite_line_ = nullptr; + if(active_line_) { + active_line_->end_points[1].x = x; + active_line_->end_points[1].y = y; + active_line_ = nullptr; } break; case ScanTarget::Event::EndHorizontalRetrace: { const auto read_pointers = read_pointers_.load(); // Attempt to allocate a new line; note allocation failure if necessary. - const auto next_composite_y = uint16_t((write_pointers_.composite_y + 1) % CompositeLineBufferHeight); + const auto next_line = uint16_t((write_pointers_.line + 1) % LineBufferHeight); // Check whether that's too many. - if(next_composite_y == read_pointers.composite_y) { + if(next_line == read_pointers.line) { allocation_has_failed_ = true; } else { - write_pointers_.composite_y = next_composite_y; - active_composite_line_ = &composite_line_buffer_[size_t(write_pointers_.composite_y)]; - active_composite_line_->end_points[0].x = x; - active_composite_line_->end_points[0].y = y; - active_composite_line_->composite_y = write_pointers_.composite_y; + write_pointers_.line = next_line; + active_line_ = &line_buffer_[size_t(write_pointers_.line)]; + active_line_->end_points[0].x = x; + active_line_->end_points[0].y = y; + active_line_->line = write_pointers_.line; } } break; } diff --git a/Outputs/OpenGL/ScanTarget.hpp b/Outputs/OpenGL/ScanTarget.hpp index bceee1bac..8b0b521cf 100644 --- a/Outputs/OpenGL/ScanTarget.hpp +++ b/Outputs/OpenGL/ScanTarget.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace Outputs { @@ -40,11 +41,13 @@ class ScanTarget: public Outputs::Display::ScanTarget { // Extends the definition of a Scan to include two extra fields, // relevant to the way that this scan target processes video. - struct Scan: public Outputs::Display::ScanTarget::Scan { + struct Scan { + Outputs::Display::ScanTarget::Scan scan; + /// Stores the y coordinate that this scan's data is at, within the write area texture. uint16_t data_y; - /// Stores the y coordinate of this continuous composite segment within the conversion buffer. - uint16_t composite_y; + /// Stores the y coordinate of this scan within the line buffer. + uint16_t line; }; struct PointerSet { @@ -53,7 +56,7 @@ class ScanTarget: public Outputs::Display::ScanTarget { // to be lock free; they are under LLVM x86-64. int write_area = 0; uint16_t scan_buffer = 0; - uint16_t composite_y = 0; + uint16_t line = 0; }; /// A pointer to the next thing that should be provided to the caller for data. @@ -71,16 +74,16 @@ class ScanTarget: public Outputs::Display::ScanTarget { GLuint scan_vertex_array_ = 0; // Maintains a list of composite scan buffer coordinates. - struct CompositeLine { + struct Line { struct EndPoint { uint16_t x, y; } end_points[2]; - uint16_t composite_y; + uint16_t line; }; - std::array composite_line_buffer_; + std::array line_buffer_; TextureTarget unprocessed_line_texture_; - GLuint composite_line_vertex_array_ = 0; - CompositeLine *active_composite_line_ = nullptr; + GLuint line_vertex_array_ = 0; + Line *active_line_ = nullptr; // Uses a texture to vend write areas. std::vector write_area_texture_; @@ -98,6 +101,24 @@ class ScanTarget: public Outputs::Display::ScanTarget { // Receives scan target modals. Modals modals_; + + enum class ShaderType { + Scan, + Line + }; + + /*! + @returns A string containing GLSL code describing the standard set of + @c in and @c uniform variables to bind to the relevant struct + from [...]OpenGL::ScanTarget. + */ + std::string globals(ShaderType type); + + /*! + Calls @c taret.enable_vertex_attribute_with_pointer to attach all + globals for shaders of @c type to @c target. + */ + void enable_vertex_attributes(ShaderType type, Shader &target); }; } diff --git a/Outputs/OpenGL/ScanTargetVertexArrayAttributs.cpp b/Outputs/OpenGL/ScanTargetVertexArrayAttributs.cpp new file mode 100644 index 000000000..41aa86324 --- /dev/null +++ b/Outputs/OpenGL/ScanTargetVertexArrayAttributs.cpp @@ -0,0 +1,93 @@ +// +// ScanTargetVertexArrayAttributs.cpp +// Clock Signal +// +// Created by Thomas Harte on 11/11/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#include "ScanTarget.hpp" + +using namespace Outputs::Display::OpenGL; + +std::string ScanTarget::globals(ShaderType type) { + switch(type) { + case ShaderType::Scan: + return + "uniform vec2 scale;" + "uniform float rowHeight;" + "uniform mat3 lumaChromaToRGB;" + "uniform mat3 rgbToLumaChroma;" + + "in vec2 startPoint;" + "in float startDataX;" + "in float startCompositeAngle;" + + "in vec2 endPoint;" + "in float endDataX;" + "in float endCompositeAngle;" + + "in float dataY;" + "in float lineY;"; + + case ShaderType::Line: + return + "in vec2 startPoint;" + "in vec2 endPoint;"; + } +} + +void ScanTarget::enable_vertex_attributes(ShaderType type, Shader &target) { + switch(type) { + case ShaderType::Scan: + for(int c = 0; c < 2; ++c) { + const std::string prefix = c ? "end" : "start"; + + target.enable_vertex_attribute_with_pointer( + prefix + "Point", + 2, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Scan), + reinterpret_cast(offsetof(Scan, scan.end_points[c].x)), + 1); + target.enable_vertex_attribute_with_pointer( + prefix + "DataX", + 1, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Scan), + reinterpret_cast(offsetof(Scan, scan.end_points[c].data_offset)), + 1); + target.enable_vertex_attribute_with_pointer( + prefix + "CompositeAngle", + 1, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Scan), + reinterpret_cast(offsetof(Scan, scan.end_points[c].composite_angle)), + 1); + } + + target.enable_vertex_attribute_with_pointer( + "dataY", + 1, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Scan), + reinterpret_cast(offsetof(Scan, data_y)), + 1); + target.enable_vertex_attribute_with_pointer( + "lineY", + 1, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Scan), + reinterpret_cast(offsetof(Scan, line)), + 1); + break; + + case ShaderType::Line: + for(int c = 0; c < 2; ++c) { + const std::string prefix = c ? "end" : "start"; + + target.enable_vertex_attribute_with_pointer( + prefix + "Point", + 2, GL_UNSIGNED_SHORT, GL_FALSE, + sizeof(Line), + reinterpret_cast(offsetof(Line, end_points[c].x)), + 1); + } + break; + } +}