Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a software-based scan target. #1059

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -1113,6 +1114,8 @@
4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; };
4B04B65622A58CB40006AB58 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
4B04C898285E3DC800AA8FD6 /* 65816ComparativeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 65816ComparativeTests.mm; sourceTree = "<group>"; };
4B04C89D2870BDDD00AA8FD6 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = "<group>"; };
4B04C89E2870BDDD00AA8FD6 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ROMCatalogue.cpp; sourceTree = "<group>"; };
4B051C5926670A9300CA44E8 /* ROMCatalogue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMCatalogue.hpp; sourceTree = "<group>"; };
4B051C94266EF50200CA44E8 /* AppleIIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleIIController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2263,6 +2266,15 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
4B04C89C2870BDDD00AA8FD6 /* SoftwareRendering */ = {
isa = PBXGroup;
children = (
4B04C89D2870BDDD00AA8FD6 /* ScanTarget.hpp */,
4B04C89E2870BDDD00AA8FD6 /* ScanTarget.cpp */,
);
path = SoftwareRendering;
sourceTree = "<group>";
};
4B051C9F2676F52200CA44E8 /* Enterprise */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2731,6 +2743,7 @@
4B0CCC411C62D0B3001CAC5F /* CRT */,
4BD191D5219113B80042E144 /* OpenGL */,
4BB8616B24E22DC500A00E03 /* ScanTargets */,
4B04C89C2870BDDD00AA8FD6 /* SoftwareRendering */,
4BD060A41FE49D3C006E14BE /* Speaker */,
);
name = Outputs;
Expand Down Expand Up @@ -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 */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,19 @@
</CommandLineArgument>
<CommandLineArgument
argument = "--volume=0.001"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--new=enterprise"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--basic-version=any"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/ColecoVision/Galaxian (1983)(Atari).col&quot;"
isEnabled = "NO">
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/Master System/R-Type (NTSC).sms&quot;"
Expand Down
3 changes: 3 additions & 0 deletions OSBindings/SDL/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down
18 changes: 11 additions & 7 deletions OSBindings/SDL/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#include "../../Machines/MachineTypes.hpp"

#include "../../Activity/Observer.hpp"

#include "../../Outputs/SoftwareRendering/ScanTarget.hpp"

#include "../../Outputs/OpenGL/Primitives/Rectangle.hpp"
#include "../../Outputs/OpenGL/ScanTarget.hpp"
#include "../../Outputs/OpenGL/Screenshot.hpp"
Expand Down Expand Up @@ -897,17 +900,18 @@ int main(int argc, char *argv[]) {
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &target_framebuffer);

// Setup output, assuming a CRT machine for now, and prepare a best-effort updater.
Outputs::Display::OpenGL::ScanTarget scan_target(target_framebuffer);
Outputs::Display::OpenGL::ScanTarget opengl_scan_target(target_framebuffer);
Outputs::Display::Software::ScanTarget software_scan_target;
std::unique_ptr<ActivityObserver> activity_observer;
bool uses_mouse;
std::vector<SDLJoystick> 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();
Expand Down Expand Up @@ -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();

Expand All @@ -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;
Expand All @@ -1039,7 +1043,7 @@ int main(int argc, char *argv[]) {
if(error != Machine::Error::None) break;

machine = std::move(new_machine);
static_cast<Outputs::Display::ScanTarget *>(&scan_target)->will_change_owner();
static_cast<Outputs::Display::ScanTarget *>(&opengl_scan_target)->will_change_owner();
setup_machine_input_output();
window_titler.set_file_name(final_path_component(event.drop.file));
} break;
Expand Down
6 changes: 3 additions & 3 deletions Outputs/OpenGL/ScanTarget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -160,4 +160,4 @@ class ScanTarget: public Outputs::Display::BufferingScanTarget { // TODO: use pr
}
}

#endif /* ScanTarget_hpp */
#endif /* Outputs_OpenGL_ScanTarget_hpp */
2 changes: 1 addition & 1 deletion Outputs/ScanTarget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions Outputs/SoftwareRendering/ScanTarget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// SoftwareScanTarget.cpp
// Clock Signal
//
// Created by Thomas Harte on 02/07/2022.
// Copyright © 2022 Thomas Harte. All rights reserved.
//

#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() {
scan_buffer_pointer_ = sample_buffer_pointer_ = 0;
has_failed_ = false;
}
82 changes: 82 additions & 0 deletions Outputs/SoftwareRendering/ScanTarget.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// 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"

#include <array>

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 {
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.
sample_buffer_pointer_ += (required_alignment - sample_buffer_pointer_) & (required_alignment - 1);

// Return target.
return &sample_buffer_[sample_buffer_pointer_];

// TODO: nullptr case.
}
void end_data(size_t actual_length) override {
sample_buffer_pointer_ += actual_length;
}

//
void submit() final;

template <InputDataType, DisplayType, ColourSpace> void process();

// 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.
std::array<Scan, 8> scan_buffer_;
Scan *vended_buffer_ = nullptr;
size_t scan_buffer_pointer_ = 0;

std::array<uint8_t, 2048> sample_buffer_;
size_t sample_buffer_pointer_ = 0;

bool has_failed_ = false;

};

}
}
}

#endif /* SoftwareScanTarget_hpp */