From f04e4faae29f50cc9bc6bad061fc2bb0914a9d84 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Jul 2022 13:54:16 -0400 Subject: [PATCH 1/6] Avoid potential ScanTarget include-guard collisions. --- Outputs/OpenGL/ScanTarget.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Outputs/OpenGL/ScanTarget.hpp b/Outputs/OpenGL/ScanTarget.hpp index fb7a75db54..4d2e4ef742 100644 --- a/Outputs/OpenGL/ScanTarget.hpp +++ b/Outputs/OpenGL/ScanTarget.hpp @@ -6,8 +6,8 @@ // Copyright © 2018 Thomas Harte. All rights reserved. // -#ifndef ScanTarget_hpp -#define ScanTarget_hpp +#ifndef Outputs_OpenGL_ScanTarget_hpp +#define Outputs_OpenGL_ScanTarget_hpp #include "../Log.hpp" #include "../DisplayMetrics.hpp" @@ -160,4 +160,4 @@ class ScanTarget: public Outputs::Display::BufferingScanTarget { // TODO: use pr } } -#endif /* ScanTarget_hpp */ +#endif /* Outputs_OpenGL_ScanTarget_hpp */ From f4004baff895335e919856a18086edd7703bab77 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Jul 2022 16:31:38 -0400 Subject: [PATCH 2/6] Set out a stall. --- .../Clock Signal.xcodeproj/project.pbxproj | 14 ++++++ Outputs/ScanTarget.hpp | 2 +- Outputs/SoftwareRendering/ScanTarget.cpp | 9 ++++ Outputs/SoftwareRendering/ScanTarget.hpp | 44 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Outputs/SoftwareRendering/ScanTarget.cpp create mode 100644 Outputs/SoftwareRendering/ScanTarget.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3311a4686b..6a2f9155b8 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 4B0333B02094081A0050B93D /* AppleDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0333AD2094081A0050B93D /* AppleDSK.cpp */; }; 4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; }; 4B04C899285E3DC800AA8FD6 /* 65816ComparativeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B04C898285E3DC800AA8FD6 /* 65816ComparativeTests.mm */; }; + 4B04C89F2870BDEC00AA8FD6 /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B04C89E2870BDDD00AA8FD6 /* ScanTarget.cpp */; }; 4B051C912669C90B00CA44E8 /* ROMCatalogue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */; }; 4B051C922669C90B00CA44E8 /* ROMCatalogue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */; }; 4B051C93266D9D6900CA44E8 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; @@ -1113,6 +1114,8 @@ 4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = ""; }; 4B04B65622A58CB40006AB58 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4B04C898285E3DC800AA8FD6 /* 65816ComparativeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 65816ComparativeTests.mm; sourceTree = ""; }; + 4B04C89D2870BDDD00AA8FD6 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = ""; }; + 4B04C89E2870BDDD00AA8FD6 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = ""; }; 4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ROMCatalogue.cpp; sourceTree = ""; }; 4B051C5926670A9300CA44E8 /* ROMCatalogue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMCatalogue.hpp; sourceTree = ""; }; 4B051C94266EF50200CA44E8 /* AppleIIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleIIController.swift; sourceTree = ""; }; @@ -2263,6 +2266,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4B04C89C2870BDDD00AA8FD6 /* SoftwareRendering */ = { + isa = PBXGroup; + children = ( + 4B04C89D2870BDDD00AA8FD6 /* ScanTarget.hpp */, + 4B04C89E2870BDDD00AA8FD6 /* ScanTarget.cpp */, + ); + path = SoftwareRendering; + sourceTree = ""; + }; 4B051C9F2676F52200CA44E8 /* Enterprise */ = { isa = PBXGroup; children = ( @@ -2731,6 +2743,7 @@ 4B0CCC411C62D0B3001CAC5F /* CRT */, 4BD191D5219113B80042E144 /* OpenGL */, 4BB8616B24E22DC500A00E03 /* ScanTargets */, + 4B04C89C2870BDDD00AA8FD6 /* SoftwareRendering */, 4BD060A41FE49D3C006E14BE /* Speaker */, ); name = Outputs; @@ -5643,6 +5656,7 @@ 4BBB70A5202011C2002FE009 /* MultiMediaTarget.cpp in Sources */, 4B8318BC22D3E588006DB630 /* DisplayMetrics.cpp in Sources */, 4BEDA40E25B2844B000C2DBD /* Decoder.cpp in Sources */, + 4B04C89F2870BDEC00AA8FD6 /* ScanTarget.cpp in Sources */, 4B1B88BD202E3D3D00B67DFF /* MultiMachine.cpp in Sources */, 4BE0A3EF237BB170002AB46F /* ST.cpp in Sources */, 4B055A971FAE85BB0060FFFF /* ZX8081.cpp in Sources */, diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index dc4074d95a..54a347477f 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -312,7 +312,7 @@ struct ScanTarget { /// @return A valid pointer, or @c nullptr if insufficient further storage is available. virtual Scan *begin_scan() = 0; - /// Requests a new scan to populate. + /// Confirms that the scan returned by @c begin_scan (if any) is now fully populated. virtual void end_scan() {} /// Finds the first available storage of at least @c required_length pixels in size which is diff --git a/Outputs/SoftwareRendering/ScanTarget.cpp b/Outputs/SoftwareRendering/ScanTarget.cpp new file mode 100644 index 0000000000..cfccde587b --- /dev/null +++ b/Outputs/SoftwareRendering/ScanTarget.cpp @@ -0,0 +1,9 @@ +// +// SoftwareScanTarget.cpp +// Clock Signal +// +// Created by Thomas Harte on 02/07/2022. +// Copyright © 2022 Thomas Harte. All rights reserved. +// + +#include "SoftwareScanTarget.hpp" diff --git a/Outputs/SoftwareRendering/ScanTarget.hpp b/Outputs/SoftwareRendering/ScanTarget.hpp new file mode 100644 index 0000000000..21d4e2d911 --- /dev/null +++ b/Outputs/SoftwareRendering/ScanTarget.hpp @@ -0,0 +1,44 @@ +// +// SoftwareScanTarget.hpp +// Clock Signal +// +// Created by Thomas Harte on 02/07/2022. +// Copyright © 2022 Thomas Harte. All rights reserved. +// + +#ifndef SoftwareScanTarget_hpp +#define SoftwareScanTarget_hpp + +#include "../ScanTarget.hpp" + +namespace Outputs { +namespace Display { +namespace Software { + +/*! + Provides a ScanTarget that does all intermediate processing on the CPU, + and uses the FrameProducer interface to output results. +*/ +class ScanTarget: public Outputs::Display::ScanTarget { + + private: + // The following are all overridden from Outputs::Display::ScanTarget; + // some notes on their meaning to this specific scan target are given below. + + void set_modals(Modals) override {} + Scan *begin_scan() override { return *current_scan_; } + uint8_t *begin_data(size_t, size_t) override { return nullptr; } + + // + void submit() final; + + + Scan current_scan_; + +}; + +} +} +} + +#endif /* SoftwareScanTarget_hpp */ From 678e1a38fa594fc59b49287fef5e4bc085204aa6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Jul 2022 21:29:59 -0400 Subject: [PATCH 3/6] Ensure some basic traffic reaches the putative software scan target. --- .../xcschemes/Clock Signal Kiosk.xcscheme | 8 ++++---- OSBindings/SDL/main.cpp | 18 ++++++++++------- Outputs/SoftwareRendering/ScanTarget.cpp | 20 ++++++++++++++++++- Outputs/SoftwareRendering/ScanTarget.hpp | 5 +++-- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme index 04eb4197fd..575580d92d 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme @@ -82,19 +82,19 @@ + isEnabled = "NO"> + isEnabled = "NO"> + isEnabled = "NO"> + isEnabled = "YES"> activity_observer; bool uses_mouse; std::vector joysticks; machine_runner.machine_mutex = &machine_mutex; - const auto setup_machine_input_output = [&scan_target, &machine, &speaker_delegate, &activity_observer, &joysticks, &uses_mouse, &machine_runner] { + const auto setup_machine_input_output = [&software_scan_target, &machine, &speaker_delegate, &activity_observer, &joysticks, &uses_mouse, &machine_runner] { // Wire up the best-effort updater, its delegate, and the speaker delegate. machine_runner.machine = machine.get(); - machine->scan_producer()->set_scan_target(&scan_target); + machine->scan_producer()->set_scan_target(&software_scan_target); // For now, lie about audio output intentions. const auto audio_producer = machine->audio_producer(); @@ -986,8 +990,8 @@ int main(int argc, char *argv[]) { machine_runner.start(); while(!should_quit) { // Draw a new frame, indicating completion of the draw to the machine runner. - scan_target.update(int(window_width), int(window_height)); - scan_target.draw(int(window_width), int(window_height)); +// opengl_scan_target.update(int(window_width), int(window_height)); +// opengl_scan_target.draw(int(window_width), int(window_height)); if(activity_observer) activity_observer->draw(); machine_runner.signal_did_draw(); @@ -1012,7 +1016,7 @@ int main(int argc, char *argv[]) { case SDL_WINDOWEVENT_RESIZED: { GLint target_framebuffer = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &target_framebuffer); - scan_target.set_target_framebuffer(target_framebuffer); + opengl_scan_target.set_target_framebuffer(target_framebuffer); SDL_GetWindowSize(window, &window_width, &window_height); if(activity_observer) activity_observer->set_aspect_ratio(float(window_width) / float(window_height)); } break; @@ -1039,7 +1043,7 @@ int main(int argc, char *argv[]) { if(error != Machine::Error::None) break; machine = std::move(new_machine); - static_cast(&scan_target)->will_change_owner(); + static_cast(&opengl_scan_target)->will_change_owner(); setup_machine_input_output(); window_titler.set_file_name(final_path_component(event.drop.file)); } break; diff --git a/Outputs/SoftwareRendering/ScanTarget.cpp b/Outputs/SoftwareRendering/ScanTarget.cpp index cfccde587b..613fc2346c 100644 --- a/Outputs/SoftwareRendering/ScanTarget.cpp +++ b/Outputs/SoftwareRendering/ScanTarget.cpp @@ -6,4 +6,22 @@ // Copyright © 2022 Thomas Harte. All rights reserved. // -#include "SoftwareScanTarget.hpp" +#include "ScanTarget.hpp" + +using namespace Outputs::Display::Software; + +template < + Outputs::Display::InputDataType input_type, + Outputs::Display::DisplayType display_type, + Outputs::Display::ColourSpace colour_space +> void ScanTarget::process() { + // TODO. +} + +void ScanTarget::set_modals(Modals m) { + printf(""); +} + +void ScanTarget::submit() { + printf(""); +} diff --git a/Outputs/SoftwareRendering/ScanTarget.hpp b/Outputs/SoftwareRendering/ScanTarget.hpp index 21d4e2d911..dc7b7c5c22 100644 --- a/Outputs/SoftwareRendering/ScanTarget.hpp +++ b/Outputs/SoftwareRendering/ScanTarget.hpp @@ -25,13 +25,14 @@ class ScanTarget: public Outputs::Display::ScanTarget { // The following are all overridden from Outputs::Display::ScanTarget; // some notes on their meaning to this specific scan target are given below. - void set_modals(Modals) override {} - Scan *begin_scan() override { return *current_scan_; } + void set_modals(Modals) override; + Scan *begin_scan() override { return ¤t_scan_; } uint8_t *begin_data(size_t, size_t) override { return nullptr; } // void submit() final; + template void process(); Scan current_scan_; From 6a8c792c634432b99aa1b2332ffeee7964acd2ad Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Jul 2022 21:57:48 -0400 Subject: [PATCH 4/6] Add new scan target to SDL build. --- OSBindings/SDL/SConstruct | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OSBindings/SDL/SConstruct b/OSBindings/SDL/SConstruct index 3c46930cd7..ce8fdae5be 100644 --- a/OSBindings/SDL/SConstruct +++ b/OSBindings/SDL/SConstruct @@ -95,6 +95,9 @@ SOURCES += glob.glob('../../Machines/Sinclair/ZXSpectrum/*.cpp') SOURCES += glob.glob('../../Outputs/*.cpp') SOURCES += glob.glob('../../Outputs/CRT/*.cpp') SOURCES += glob.glob('../../Outputs/ScanTargets/*.cpp') + +SOURCES += glob.glob('../../Outputs/SoftwareRendering/*.cpp') + SOURCES += glob.glob('../../Outputs/OpenGL/*.cpp') SOURCES += glob.glob('../../Outputs/OpenGL/Primitives/*.cpp') From 3179d0d963e8d44a57d13bcf93f1c093f9de2a2f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Jul 2022 21:58:23 -0400 Subject: [PATCH 5/6] Vend data pointers. --- Outputs/SoftwareRendering/ScanTarget.hpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Outputs/SoftwareRendering/ScanTarget.hpp b/Outputs/SoftwareRendering/ScanTarget.hpp index dc7b7c5c22..adb4396577 100644 --- a/Outputs/SoftwareRendering/ScanTarget.hpp +++ b/Outputs/SoftwareRendering/ScanTarget.hpp @@ -11,6 +11,8 @@ #include "../ScanTarget.hpp" +#include + namespace Outputs { namespace Display { namespace Software { @@ -27,14 +29,29 @@ class ScanTarget: public Outputs::Display::ScanTarget { void set_modals(Modals) override; Scan *begin_scan() override { return ¤t_scan_; } - uint8_t *begin_data(size_t, size_t) override { return nullptr; } + + uint8_t *begin_data(size_t, size_t required_alignment) override { + // Achieve required alignment. + sample_buffer_pointer_ += (required_alignment - sample_buffer_pointer_) & (required_alignment - 1); + + // Return target. + return &sample_buffer_[sample_buffer_pointer_]; + } + void end_data(size_t actual_length) override { + sample_buffer_pointer_ += actual_length; + } // void submit() final; template void process(); + // Temporaries; each scan is rasterised synchronously and upon + // completion, so the storage here is a lot simpler than for + // the GPU-powered scan targets. Scan current_scan_; + std::array sample_buffer_; + size_t sample_buffer_pointer_ = 0; }; From 4078baa42475930d256403d70243bf702cc2c7b1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 3 Jul 2022 21:54:28 -0400 Subject: [PATCH 6/6] Capture up to eight scans per submission group. --- Outputs/SoftwareRendering/ScanTarget.cpp | 3 ++- Outputs/SoftwareRendering/ScanTarget.hpp | 28 ++++++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Outputs/SoftwareRendering/ScanTarget.cpp b/Outputs/SoftwareRendering/ScanTarget.cpp index 613fc2346c..6ed6ab477c 100644 --- a/Outputs/SoftwareRendering/ScanTarget.cpp +++ b/Outputs/SoftwareRendering/ScanTarget.cpp @@ -23,5 +23,6 @@ void ScanTarget::set_modals(Modals m) { } void ScanTarget::submit() { - printf(""); + scan_buffer_pointer_ = sample_buffer_pointer_ = 0; + has_failed_ = false; } diff --git a/Outputs/SoftwareRendering/ScanTarget.hpp b/Outputs/SoftwareRendering/ScanTarget.hpp index adb4396577..1d88392721 100644 --- a/Outputs/SoftwareRendering/ScanTarget.hpp +++ b/Outputs/SoftwareRendering/ScanTarget.hpp @@ -28,7 +28,20 @@ class ScanTarget: public Outputs::Display::ScanTarget { // some notes on their meaning to this specific scan target are given below. void set_modals(Modals) override; - Scan *begin_scan() override { return ¤t_scan_; } + + Scan *begin_scan() override { + if(has_failed_ || scan_buffer_pointer_ == 8) { + has_failed_ = true; + return nullptr; + } + + vended_buffer_ = &scan_buffer_[scan_buffer_pointer_]; + ++scan_buffer_pointer_; + return vended_buffer_; + } + void end_scan() override { + // TODO: adjust sample buffer locations. + } uint8_t *begin_data(size_t, size_t required_alignment) override { // Achieve required alignment. @@ -36,6 +49,8 @@ class ScanTarget: public Outputs::Display::ScanTarget { // Return target. return &sample_buffer_[sample_buffer_pointer_]; + + // TODO: nullptr case. } void end_data(size_t actual_length) override { sample_buffer_pointer_ += actual_length; @@ -46,13 +61,18 @@ class ScanTarget: public Outputs::Display::ScanTarget { template void process(); - // Temporaries; each scan is rasterised synchronously and upon - // completion, so the storage here is a lot simpler than for + // Temporaries; each set of scans is rasterised synchronously upon + // its submit, so the storage here is a lot simpler than for // the GPU-powered scan targets. - Scan current_scan_; + std::array scan_buffer_; + Scan *vended_buffer_ = nullptr; + size_t scan_buffer_pointer_ = 0; + std::array sample_buffer_; size_t sample_buffer_pointer_ = 0; + bool has_failed_ = false; + }; }