1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Breaks all output.

... by switching out NSOpenGLView for MKLView with no drawing infrastructure yet in place.
This commit is contained in:
Thomas Harte 2020-08-04 18:22:14 -04:00
parent d20c11e401
commit e235a45abb
12 changed files with 272 additions and 210 deletions

View File

@ -120,11 +120,11 @@ class ConcreteMachine:
if(!target.media.cartridges.empty()) {
cartridge_ = target.media.cartridges[0]->get_segments()[0].data;
}
if(cartridge_.size() < 48*1024) {
std::size_t new_space = 48*1024 - cartridge_.size();
cartridge_.resize(48*1024);
memset(&cartridge_[48*1024 - new_space], 0xff, new_space);
}
// if(cartridge_.size() < 48*1024) {
// std::size_t new_space = 48*1024 - cartridge_.size();
// cartridge_.resize(48*1024);
// memset(&cartridge_[48*1024 - new_space], 0xff, new_space);
// }
if(paging_scheme_ == Target::PagingScheme::Codemasters) {
// The Codemasters cartridges start with pages 0, 1 and 0 again initially visible.

View File

@ -155,6 +155,8 @@
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D08051E0F7A1100763741 /* TimeTests.mm */; };
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85801D176468001EF87D /* 6532Tests.swift */; };
4B1EDB451E39A0AC009D6819 /* chip.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B1EDB431E39A0AC009D6819 /* chip.png */; };
4B228CD524D773B40077EF25 /* CSScanTarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B228CD424D773B30077EF25 /* CSScanTarget.mm */; };
4B228CD924DA12C60077EF25 /* CSScanTargetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B228CD824DA12C60077EF25 /* CSScanTargetView.m */; };
4B2530F4244E6774007980BF /* fm.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B2530F3244E6773007980BF /* fm.json */; };
4B2A332D1DB86821002876E3 /* OricOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2A332B1DB86821002876E3 /* OricOptions.xib */; };
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
@ -215,7 +217,6 @@
4B54C0C51F8D91D90050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C41F8D91D90050900F /* Keyboard.cpp */; };
4B54C0C81F8D91E50050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C61F8D91E50050900F /* Keyboard.cpp */; };
4B54C0CB1F8D92590050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0CA1F8D92580050900F /* Keyboard.cpp */; };
4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */; };
4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */; };
4B55DD8320DF06680043F2E5 /* MachinePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55DD8020DF06680043F2E5 /* MachinePicker.swift */; };
4B55DD8420DF06680043F2E5 /* MachinePicker.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B55DD8120DF06680043F2E5 /* MachinePicker.xib */; };
@ -1004,6 +1005,10 @@
4B1E857B1D174DEC001EF87D /* 6532.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6532.hpp; sourceTree = "<group>"; };
4B1E85801D176468001EF87D /* 6532Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6532Tests.swift; sourceTree = "<group>"; };
4B1EDB431E39A0AC009D6819 /* chip.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chip.png; sourceTree = "<group>"; };
4B228CD424D773B30077EF25 /* CSScanTarget.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSScanTarget.mm; sourceTree = "<group>"; };
4B228CD624D773CA0077EF25 /* CSScanTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSScanTarget.h; sourceTree = "<group>"; };
4B228CD724DA12C50077EF25 /* CSScanTargetView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSScanTargetView.h; sourceTree = "<group>"; };
4B228CD824DA12C60077EF25 /* CSScanTargetView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSScanTargetView.m; sourceTree = "<group>"; };
4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = "<group>"; };
4B2530F3244E6773007980BF /* fm.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = fm.json; sourceTree = "<group>"; };
4B2A332C1DB86821002876E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/OricOptions.xib"; sourceTree = SOURCE_ROOT; };
@ -1129,8 +1134,6 @@
4B54C0C71F8D91E50050900F /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hpp; path = Electron/Keyboard.hpp; sourceTree = "<group>"; };
4B54C0C91F8D92580050900F /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hpp; path = ZX8081/Keyboard.hpp; sourceTree = "<group>"; };
4B54C0CA1F8D92580050900F /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cpp; path = ZX8081/Keyboard.cpp; sourceTree = "<group>"; };
4B55CE5B1C3B7D6F0093A61B /* CSOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSOpenGLView.h; sourceTree = "<group>"; };
4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSOpenGLView.m; sourceTree = "<group>"; };
4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachineDocument.swift; sourceTree = "<group>"; };
4B55DD8020DF06680043F2E5 /* MachinePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachinePicker.swift; sourceTree = "<group>"; };
4B55DD8220DF06680043F2E5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MachinePicker.xib; sourceTree = "<group>"; };
@ -2060,6 +2063,15 @@
path = Icons;
sourceTree = "<group>";
};
4B228CD324D773B30077EF25 /* ScanTarget */ = {
isa = PBXGroup;
children = (
4B228CD424D773B30077EF25 /* CSScanTarget.mm */,
4B228CD624D773CA0077EF25 /* CSScanTarget.h */,
);
path = ScanTarget;
sourceTree = "<group>";
};
4B2409591C45DF85004DA684 /* SignalProcessing */ = {
isa = PBXGroup;
children = (
@ -2471,8 +2483,8 @@
4B55CE5A1C3B7D6F0093A61B /* Views */ = {
isa = PBXGroup;
children = (
4B55CE5B1C3B7D6F0093A61B /* CSOpenGLView.h */,
4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */,
4B228CD724DA12C50077EF25 /* CSScanTargetView.h */,
4B228CD824DA12C60077EF25 /* CSScanTargetView.m */,
);
path = Views;
sourceTree = "<group>";
@ -3371,6 +3383,7 @@
4BB73EAA1B587A5100552FC2 /* MainMenu.xib */,
4BE5F85A1C3E1C2500C43F01 /* Resources */,
4BDA00DB22E60EE900AC3CD0 /* ROMRequester */,
4B228CD324D773B30077EF25 /* ScanTarget */,
4B55CE5A1C3B7D6F0093A61B /* Views */,
);
path = "Clock Signal";
@ -4574,6 +4587,7 @@
4B0E04EA1FC9E5DA00F43484 /* CAS.cpp in Sources */,
4B7A90ED20410A85008514A2 /* StaticAnalyser.cpp in Sources */,
4B58601E1F806AB200AEE2E3 /* MFMSectorDump.cpp in Sources */,
4B228CD924DA12C60077EF25 /* CSScanTargetView.m in Sources */,
4B6AAEAD230E40250078E864 /* Target.cpp in Sources */,
4B448E841F1C4C480009ABD6 /* PulseQueuedTape.cpp in Sources */,
4B0E61071FF34737002A9DBD /* MSX.cpp in Sources */,
@ -4673,6 +4687,7 @@
4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */,
4BDA00E022E644AF00AC3CD0 /* CSROMReceiverView.m in Sources */,
4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */,
4B228CD524D773B40077EF25 /* CSScanTarget.mm in Sources */,
4BCD634922D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */,
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */,
4B89452A201967B4007DE474 /* File.cpp in Sources */,
@ -4699,7 +4714,6 @@
4B0E04FA1FC9FA3100F43484 /* 9918.cpp in Sources */,
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */,
4B4518841F75E91A00926311 /* UnformattedTrack.cpp in Sources */,
4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */,
4B65086022F4CF8D009C1100 /* Keyboard.cpp in Sources */,
4B894528201967B4007DE474 /* Disk.cpp in Sources */,
4BBB70A4202011C2002FE009 /* MultiMediaTarget.cpp in Sources */,

View File

@ -67,7 +67,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableASanStackUseAfterReturn = "YES"

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16097.2"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MachineDocument" customModule="Clock_Signal" customModuleProvider="target">
<connections>
<outlet property="openGLView" destination="DEG-fq-cjd" id="Gxs-2u-n7B"/>
<outlet property="scanTargetView" destination="DEG-fq-cjd" id="5aX-3R-eXQ"/>
<outlet property="volumeSlider" destination="zaz-lB-Iyt" id="flY-Th-oG4"/>
<outlet property="volumeView" destination="4ap-Gi-2AO" id="v4e-k6-Fqf"/>
<outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/>
@ -27,7 +27,7 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="450"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<openGLView hidden="YES" wantsLayer="YES" useAuxiliaryDepthBufferStencil="NO" allowOffline="YES" wantsBestResolutionOpenGLSurface="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DEG-fq-cjd" customClass="CSOpenGLView">
<openGLView hidden="YES" wantsLayer="YES" useAuxiliaryDepthBufferStencil="NO" allowOffline="YES" wantsBestResolutionOpenGLSurface="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DEG-fq-cjd" customClass="CSScanTargetView">
<rect key="frame" x="0.0" y="0.0" width="600" height="450"/>
</openGLView>
<box hidden="YES" boxType="custom" cornerRadius="4" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="4ap-Gi-2AO">

View File

@ -10,7 +10,7 @@
#import "CSStaticAnalyser.h"
#import "CSAudioQueue.h"
#import "CSOpenGLView.h"
#import "CSScanTargetView.h"
#import "CSROMReceiverView.h"
#import "CSJoystickManager.h"

View File

@ -14,8 +14,8 @@ class MachineDocument:
NSDocument,
NSWindowDelegate,
CSMachineDelegate,
CSOpenGLViewDelegate,
CSOpenGLViewResponderDelegate,
// CSOpenGLViewDelegate,
CSScanTargetViewResponderDelegate,
CSAudioQueueDelegate,
CSROMReciverViewDelegate
{
@ -45,7 +45,7 @@ class MachineDocument:
// MARK: - Main NIB connections.
/// The OpenGL view to receive this machine's display.
@IBOutlet weak var openGLView: CSOpenGLView!
@IBOutlet weak var scanTargetView: CSScanTargetView!
/// The options panel, if any.
@IBOutlet var optionsPanel: MachinePanel!
@ -100,8 +100,9 @@ class MachineDocument:
actionLock.lock()
drawLock.lock()
machine = nil
openGLView.delegate = nil
openGLView.invalidate()
// openGLView.delegate = nil
// openGLView.invalidate()
scanTargetView.invalidate()
actionLock.unlock()
drawLock.unlock()
@ -181,10 +182,10 @@ class MachineDocument:
// MARK: - Connections Between Machine and the Outside World
private func setupMachineOutput() {
if let machine = self.machine, let openGLView = self.openGLView, machine.view != openGLView {
if let machine = self.machine, let scanTargetView = self.scanTargetView, machine.view != scanTargetView {
// Establish the output aspect ratio and audio.
let aspectRatio = self.aspectRatio()
machine.setView(openGLView, aspectRatio: Float(aspectRatio.width / aspectRatio.height))
machine.setView(scanTargetView, aspectRatio: Float(aspectRatio.width / aspectRatio.height))
// Attach an options panel if one is available.
if let optionsPanelNibName = self.machineDescription?.optionsPanelNibName {
@ -198,20 +199,20 @@ class MachineDocument:
// Callbacks from the OpenGL may come on a different thread, immediately following the .delegate set;
// hence the full setup of the best-effort updater prior to setting self as a delegate.
openGLView.delegate = self
openGLView.responderDelegate = self
// scanTargetView.delegate = self
scanTargetView.responderDelegate = self
// If this machine has a mouse, enable mouse capture; also indicate whether usurption
// of the command key is desired.
openGLView.shouldCaptureMouse = machine.hasMouse
openGLView.shouldUsurpCommand = machine.shouldUsurpCommand
scanTargetView.shouldCaptureMouse = machine.hasMouse
scanTargetView.shouldUsurpCommand = machine.shouldUsurpCommand
setupAudioQueueClockRate()
// Bring OpenGL view-holding window on top of the options panel and show the content.
openGLView.isHidden = false
openGLView.window!.makeKeyAndOrderFront(self)
openGLView.window!.makeFirstResponder(openGLView)
scanTargetView.isHidden = false
scanTargetView.window!.makeKeyAndOrderFront(self)
scanTargetView.window!.makeFirstResponder(scanTargetView)
// Start forwarding best-effort updates.
machine.start()
@ -254,15 +255,15 @@ class MachineDocument:
/// Responds to the CSOpenGLViewDelegate redraw message by requesting a machine update if this is a timed
/// request, and ordering a redraw regardless of the motivation.
final func openGLViewRedraw(_ view: CSOpenGLView, event redrawEvent: CSOpenGLViewRedrawEvent) {
if drawLock.try() {
if redrawEvent == .timer {
machine.updateView(forPixelSize: view.backingSize)
}
machine.drawView(forPixelSize: view.backingSize)
drawLock.unlock()
}
}
// final func openGLViewRedraw(_ view: CSOpenGLView, event redrawEvent: CSOpenGLViewRedrawEvent) {
// if drawLock.try() {
// if redrawEvent == .timer {
// machine.updateView(forPixelSize: view.backingSize)
// }
// machine.drawView(forPixelSize: view.backingSize)
// drawLock.unlock()
// }
// }
// MARK: - Pasteboard Forwarding.
@ -277,7 +278,7 @@ class MachineDocument:
// MARK: - Runtime Media Insertion.
/// Delegate message to receive drag and drop files.
final func openGLView(_ view: CSOpenGLView, didReceiveFileAt URL: URL) {
final func openGLView(_ view: CSScanTargetView, didReceiveFileAt URL: URL) {
let mediaSet = CSMediaSet(fileAt: URL)
if let mediaSet = mediaSet {
mediaSet.apply(to: self.machine)
@ -310,7 +311,7 @@ class MachineDocument:
machine.clearAllKeys()
machine.joystickManager = nil
}
self.openGLView.releaseMouse()
self.scanTargetView.releaseMouse()
}
/// Upon becoming key, attaches joystick input to the machine.
@ -609,7 +610,7 @@ class MachineDocument:
// Obtain the machine's current display.
var imageRepresentation: NSBitmapImageRep? = nil
self.openGLView.perform {
self.scanTargetView.perform {
imageRepresentation = self.machine.imageRepresentation
}
@ -620,11 +621,11 @@ class MachineDocument:
// MARK: - Window Title Updates.
private var unadornedWindowTitle = ""
func openGLViewDidCaptureMouse(_ view: CSOpenGLView) {
internal func openGLViewDidCaptureMouse(_ view: CSScanTargetView) {
self.windowControllers[0].window?.title = self.unadornedWindowTitle + " (press ⌘+control to release mouse)"
}
func openGLViewDidReleaseMouse(_ view: CSOpenGLView) {
internal func openGLViewDidReleaseMouse(_ view: CSScanTargetView) {
self.windowControllers[0].window?.title = self.unadornedWindowTitle
}
@ -750,7 +751,7 @@ class MachineDocument:
}
fileprivate var animationFader: ViewFader? = nil
func openGLViewDidShowOSMouseCursor(_ view: CSOpenGLView) {
internal func openGLViewDidShowOSMouseCursor(_ view: CSScanTargetView) {
// The OS mouse cursor became visible, so show the volume controls.
animationFader = nil
volumeView.layer?.removeAllAnimations()
@ -758,7 +759,7 @@ class MachineDocument:
volumeView.layer?.opacity = 1.0
}
func openGLViewWillHideOSMouseCursor(_ view: CSOpenGLView) {
internal func openGLViewWillHideOSMouseCursor(_ view: CSScanTargetView) {
// The OS mouse cursor will be hidden, so hide the volume controls.
if !volumeView.isHidden && volumeView.layer?.animation(forKey: "opacity") == nil {
let fadeAnimation = CABasicAnimation(keyPath: "opacity")

View File

@ -9,9 +9,9 @@
#import <Foundation/Foundation.h>
#import "CSAudioQueue.h"
#import "CSOpenGLView.h"
#import "CSStaticAnalyser.h"
#import "CSJoystickManager.h"
#import "CSScanTargetView.h"
#import "CSStaticAnalyser.h"
@class CSMachine;
@protocol CSMachineDelegate
@ -62,7 +62,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
- (BOOL)isStereo;
- (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize stereo:(BOOL)stereo;
- (void)setView:(nullable CSOpenGLView *)view aspectRatio:(float)aspectRatio;
- (void)setView:(nullable CSScanTargetView *)view aspectRatio:(float)aspectRatio;
- (void)start;
- (void)stop;
@ -77,7 +77,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
- (void)addMouseMotionX:(CGFloat)deltaX y:(CGFloat)deltaY;
@property (atomic, strong, nullable) CSAudioQueue *audioQueue;
@property (nonatomic, readonly, nonnull) CSOpenGLView *view;
@property (nonatomic, readonly, nonnull) CSScanTargetView *view;
@property (nonatomic, weak, nullable) id<CSMachineDelegate> delegate;
@property (nonatomic, readonly, nonnull) NSString *userDefaultsPrefix;

View File

@ -9,8 +9,9 @@
#import "CSMachine.h"
#import "CSMachine+Target.h"
#include "CSROMFetcher.hpp"
#import "CSHighPrecisionTimer.h"
#include "CSROMFetcher.hpp"
#import "CSScanTarget.h"
#include "MediaTarget.hpp"
#include "JoystickMachine.hpp"
@ -37,7 +38,7 @@
#include "../../../../Outputs/OpenGL/ScanTarget.hpp"
#include "../../../../Outputs/OpenGL/Screenshot.hpp"
@interface CSMachine() <CSOpenGLViewDisplayLinkDelegate>
@interface CSMachine() <CSScanTargetViewDisplayLinkDelegate>
- (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
- (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker;
- (void)addLED:(NSString *)led;
@ -164,8 +165,6 @@ struct ActivityObserver: public Activity::Observer {
Time::ScanSynchroniser _scanSynchroniser;
NSTimer *_joystickTimer;
std::unique_ptr<Outputs::Display::OpenGL::ScanTarget> _scanTarget;
}
- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result missingROMs:(inout NSMutableArray<CSMissingROM *> *)missingROMs {
@ -245,11 +244,11 @@ struct ActivityObserver: public Activity::Observer {
_speakerDelegate.machine = nil;
[_delegateMachineAccessLock unlock];
[_view performWithGLContext:^{
@synchronized(self) {
self->_scanTarget.reset();
}
}];
// [_view performWithGLContext:^{
// @synchronized(self) {
// self->_scanTarget.reset();
// }
// }];
}
- (float)idealSamplingRateFromRange:(NSRange)range {
@ -351,17 +350,17 @@ struct ActivityObserver: public Activity::Observer {
}
}
- (void)setView:(CSOpenGLView *)view aspectRatio:(float)aspectRatio {
- (void)setView:(CSScanTargetView *)view aspectRatio:(float)aspectRatio {
_view = view;
_view.displayLinkDelegate = self;
[view performWithGLContext:^{
[self setupOutputWithAspectRatio:aspectRatio];
} flushDrawable:NO];
// [view performWithGLContext:^{
// [self setupOutputWithAspectRatio:aspectRatio];
// } flushDrawable:NO];
}
- (void)setupOutputWithAspectRatio:(float)aspectRatio {
_scanTarget = std::make_unique<Outputs::Display::OpenGL::ScanTarget>();
_machine->scan_producer()->set_scan_target(_scanTarget.get());
// _scanTarget = std::make_unique<Outputs::Display::OpenGL::ScanTarget>();
// _machine->scan_producer()->set_scan_target(_scanTarget.get());
}
- (void)updateViewForPixelSize:(CGSize)pixelSize {
@ -374,7 +373,7 @@ struct ActivityObserver: public Activity::Observer {
}
- (void)drawViewForPixelSize:(CGSize)pixelSize {
_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
// _scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
}
- (void)paste:(NSString *)paste {
@ -737,7 +736,7 @@ struct ActivityObserver: public Activity::Observer {
#pragma mark - Timer
- (void)openGLViewDisplayLinkDidFire:(CSOpenGLView *)view now:(const CVTimeStamp *)now outputTime:(const CVTimeStamp *)outputTime {
- (void)openGLViewDisplayLinkDidFire:(CSScanTargetView *)view now:(const CVTimeStamp *)now outputTime:(const CVTimeStamp *)outputTime {
// First order of business: grab a timestamp.
const auto timeNow = Time::nanos_now();
@ -765,9 +764,9 @@ struct ActivityObserver: public Activity::Observer {
// Draw the current output. (TODO: do this within the timer if either raster racing or, at least, sync matching).
if(!isSyncLocking) {
[self.view performWithGLContext:^{
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
} flushDrawable:YES];
// [self.view performWithGLContext:^{
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
// } flushDrawable:YES];
}
}
@ -823,10 +822,10 @@ struct ActivityObserver: public Activity::Observer {
if(!wasUpdating) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
[self.view performWithGLContext:^{
self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
// self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
if(splitAndSync) {
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
}
} flushDrawable:splitAndSync];
self->_isUpdating.clear();

View File

@ -0,0 +1,18 @@
//
// ScanTarget.h
// Clock Signal
//
// Created by Thomas Harte on 02/08/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#import <Foundation/Foundation.h>
/*!
Provides a ScanTarget that uses Metal as its back-end.
*/
@interface CSScanTarget : NSObject
- (nonnull instancetype)init;
@end

View File

@ -0,0 +1,28 @@
//
// ScanTarget.m
// Clock Signal
//
// Created by Thomas Harte on 02/08/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#import "CSScanTarget.h"
#import <Metal/Metal.h>
@implementation CSScanTarget {
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
}
- (nonnull instancetype)init {
self = [super init];
if(self) {
_device = MTLCreateSystemDefaultDevice();
_commandQueue = [_device newCommandQueue];
NSLog(@"%@; %@", _device, _commandQueue);
}
return self;
}
@end

View File

@ -1,5 +1,5 @@
//
// CSOpenGLView.h
// CSScanTargetView.h
// Clock Signal
//
// Created by Thomas Harte on 16/07/2015.
@ -8,63 +8,33 @@
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <MetalKit/MetalKit.h>
@class CSOpenGLView;
@class CSScanTargetView;
typedef NS_ENUM(NSInteger, CSOpenGLViewRedrawEvent) {
typedef NS_ENUM(NSInteger, CSScanTargetViewRedrawEvent) {
/// Indicates that AppKit requested a redraw for some reason (mostly likely, the window is being resized). So,
/// if the delegate doesn't redraw the view, the user is likely to see a graphical flaw.
CSOpenGLViewRedrawEventAppKit,
CSScanTargetViewRedrawEventAppKit,
/// Indicates that the view's display-linked timer has triggered a redraw request. So, if the delegate doesn't
/// redraw the view, the user will just see the previous drawing without interruption.
CSOpenGLViewRedrawEventTimer
CSScanTargetViewRedrawEventTimer
};
@protocol CSOpenGLViewDelegate
/*!
Requests that the delegate produce an image of its current output state. May be called on
any queue or thread.
@param view The view making the request.
@param redrawEvent If @c YES then the delegate may decline to redraw if its output would be
identical to the previous frame. If @c NO then the delegate must draw.
*/
- (void)openGLViewRedraw:(nonnull CSOpenGLView *)view event:(CSOpenGLViewRedrawEvent)redrawEvent;
//@protocol CSScanTargetViewDelegate
///*!
// Requests that the delegate produce an image of its current output state. May be called on
// any queue or thread.
// @param view The view making the request.
// @param redrawEvent If @c YES then the delegate may decline to redraw if its output would be
// identical to the previous frame. If @c NO then the delegate must draw.
//*/
//- (void)openGLViewRedraw:(nonnull CSScanTargetView *)view event:(CSScanTargetViewRedrawEvent)redrawEvent;
//
//
//@end
/*!
Announces receipt of a file by drag and drop to the delegate.
@param view The view making the request.
@param URL The file URL of the received file.
*/
- (void)openGLView:(nonnull CSOpenGLView *)view didReceiveFileAtURL:(nonnull NSURL *)URL;
/*!
Announces 'capture' of the mouse i.e. that the view is now preventing the mouse from exiting
the window, in order to forward continuous mouse motion.
@param view The view making the announcement.
*/
- (void)openGLViewDidCaptureMouse:(nonnull CSOpenGLView *)view;
/*!
Announces that the mouse is no longer captured.
@param view The view making the announcement.
*/
- (void)openGLViewDidReleaseMouse:(nonnull CSOpenGLView *)view;
/*!
Announces that the OS mouse cursor is now being displayed again, after having been invisible.
@param view The view making the announcement.
*/
- (void)openGLViewDidShowOSMouseCursor:(nonnull CSOpenGLView *)view;
/*!
Announces that the OS mouse cursor will now be hidden.
@param view The view making the announcement.
*/
- (void)openGLViewWillHideOSMouseCursor:(nonnull CSOpenGLView *)view;
@end
@protocol CSOpenGLViewResponderDelegate <NSObject>
@protocol CSScanTargetViewResponderDelegate <NSObject>
/*!
Supplies a keyDown event to the delegate.
@param event The @c NSEvent describing the keyDown.
@ -111,22 +81,54 @@ typedef NS_ENUM(NSInteger, CSOpenGLViewRedrawEvent) {
*/
- (void)mouseUp:(nonnull NSEvent *)event;
/*!
Announces 'capture' of the mouse i.e. that the view is now preventing the mouse from exiting
the window, in order to forward continuous mouse motion.
@param view The view making the announcement.
*/
- (void)openGLViewDidCaptureMouse:(nonnull CSScanTargetView *)view;
/*!
Announces that the mouse is no longer captured.
@param view The view making the announcement.
*/
- (void)openGLViewDidReleaseMouse:(nonnull CSScanTargetView *)view;
/*!
Announces that the OS mouse cursor is now being displayed again, after having been invisible.
@param view The view making the announcement.
*/
- (void)openGLViewDidShowOSMouseCursor:(nonnull CSScanTargetView *)view;
/*!
Announces that the OS mouse cursor will now be hidden.
@param view The view making the announcement.
*/
- (void)openGLViewWillHideOSMouseCursor:(nonnull CSScanTargetView *)view;
/*!
Announces receipt of a file by drag and drop to the delegate.
@param view The view making the request.
@param URL The file URL of the received file.
*/
- (void)openGLView:(nonnull CSScanTargetView *)view didReceiveFileAtURL:(nonnull NSURL *)URL;
@end
/*!
Although I'm still on the fence about this as a design decision, CSOpenGLView is itself responsible
Although I'm still on the fence about this as a design decision, CSScanTargetView is itself responsible
for creating and destroying a CVDisplayLink. There's a practical reason for this: you'll get real synchronisation
only if a link is explicitly tied to a particular display, and the CSOpenGLView therefore owns the knowledge
only if a link is explicitly tied to a particular display, and the CSScanTargetView therefore owns the knowledge
necessary to decide when to create and modify them. It doesn't currently just propagate "did change screen"-type
messages because I haven't yet found a way to track that other than polling, in which case I might as well put
that into the display link callback.
*/
@protocol CSOpenGLViewDisplayLinkDelegate
@protocol CSScanTargetViewDisplayLinkDelegate
/*!
Informs the delegate that the display link has fired.
*/
- (void)openGLViewDisplayLinkDidFire:(nonnull CSOpenGLView *)view now:(nonnull const CVTimeStamp *)now outputTime:(nonnull const CVTimeStamp *)outputTime;
- (void)openGLViewDisplayLinkDidFire:(nonnull CSScanTargetView *)view now:(nonnull const CVTimeStamp *)now outputTime:(nonnull const CVTimeStamp *)outputTime;
@end
@ -134,18 +136,18 @@ typedef NS_ENUM(NSInteger, CSOpenGLViewRedrawEvent) {
Provides an OpenGL canvas with a refresh-linked update timer that can forward a subset
of typical first-responder actions.
*/
@interface CSOpenGLView : NSOpenGLView
@interface CSScanTargetView : MTKView
@property (atomic, weak, nullable) id <CSOpenGLViewDelegate> delegate;
@property (nonatomic, weak, nullable) id <CSOpenGLViewResponderDelegate> responderDelegate;
@property (atomic, weak, nullable) id <CSOpenGLViewDisplayLinkDelegate> displayLinkDelegate;
//@property (atomic, weak, nullable) id <CSOpenGLViewDelegate> delegate;
@property (nonatomic, weak, nullable) id <CSScanTargetViewResponderDelegate> responderDelegate;
@property (atomic, weak, nullable) id <CSScanTargetViewDisplayLinkDelegate> displayLinkDelegate;
/// Determines whether the view offers mouse capturing — i.e. if the user clicks on the view then
/// then the system cursor is disabled and the mouse events defined by CSOpenGLViewResponderDelegate
/// then the system cursor is disabled and the mouse events defined by CSScanTargetViewResponderDelegate
/// are forwarded, unless and until the user releases the mouse using the control+command shortcut.
@property (nonatomic, assign) BOOL shouldCaptureMouse;
/// Determines whether the CSOpenGLViewResponderDelegate of this window expects to use the command
/// Determines whether the CSScanTargetViewResponderDelegate of this window expects to use the command
/// key as though it were any other key — i.e. all command combinations should be forwarded to the delegate,
/// not being allowed to trigger regular application shortcuts such as command+q or command+h.
///

View File

@ -1,22 +1,22 @@
//
// CSOpenGLView
// CSScanTargetView
// CLK
//
// Created by Thomas Harte on 16/07/2015.
// Copyright 2015 Thomas Harte. All rights reserved.
//
#import "CSOpenGLView.h"
#import "CSScanTargetView.h"
#import "CSApplication.h"
@import CoreVideo;
@import GLKit;
#include <stdatomic.h>
@interface CSOpenGLView () <NSDraggingDestination, CSApplicationEventDelegate>
@interface CSScanTargetView () <NSDraggingDestination, CSApplicationEventDelegate>
@end
@implementation CSOpenGLView {
@implementation CSScanTargetView {
CVDisplayLinkRef _displayLink;
CGSize _backingSize;
NSNumber *_currentScreenNumber;
@ -29,19 +29,19 @@
BOOL _isInvalid;
}
- (void)prepareOpenGL {
[super prepareOpenGL];
// Prepare the atomic int.
atomic_init(&_isDrawingFlag, 0);
// Set the clear colour.
[self.openGLContext makeCurrentContext];
glClearColor(0.0, 0.0, 0.0, 1.0);
// Setup the [initial] display link.
[self setupDisplayLink];
}
//- (void)prepareOpenGL {
// [super prepareOpenGL];
//
// // Prepare the atomic int.
// atomic_init(&_isDrawingFlag, 0);
//
// // Set the clear colour.
// [self.openGLContext makeCurrentContext];
// glClearColor(0.0, 0.0, 0.0, 1.0);
//
// // Setup the [initial] display link.
// [self setupDisplayLink];
//}
- (void)setupDisplayLink {
// Kill the existing link if there is one.
@ -59,16 +59,16 @@
CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge void * __nullable)(self));
// Set the display link for the current renderer.
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
// CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
// CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
// CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
// Activate the display link.
CVDisplayLinkStart(_displayLink);
}
static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, __unused CVOptionFlags flagsIn, __unused CVOptionFlags *flagsOut, void *displayLinkContext) {
CSOpenGLView *const view = (__bridge CSOpenGLView *)displayLinkContext;
CSScanTargetView *const view = (__bridge CSScanTargetView *)displayLinkContext;
// Schedule an opportunity to check that the display link is still linked to the correct display.
dispatch_async(dispatch_get_main_queue(), ^{
@ -108,7 +108,7 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
if(![_currentScreenNumber isEqual:screenNumber]) {
// Issue a reshape, in case a switch to/from a Retina display has
// happened, changing the results of -convertSizeToBacking:, etc.
[self reshape];
// [self reshape];
// Also switch display links, to make sure synchronisation is with the display
// the window is actually on, and at its rate.
@ -117,16 +117,16 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
}
- (void)drawAtTime:(const CVTimeStamp *)now frequency:(double)frequency {
[self redrawWithEvent:CSOpenGLViewRedrawEventTimer];
[self redrawWithEvent:CSScanTargetViewRedrawEventTimer];
}
- (void)drawRect:(NSRect)dirtyRect {
[self redrawWithEvent:CSOpenGLViewRedrawEventAppKit];
[self redrawWithEvent:CSScanTargetViewRedrawEventAppKit];
}
- (void)redrawWithEvent:(CSOpenGLViewRedrawEvent)event {
- (void)redrawWithEvent:(CSScanTargetViewRedrawEvent)event {
[self performWithGLContext:^{
[self.delegate openGLViewRedraw:self event:event];
// [self.delegate openGLViewRedraw:self event:event];
} flushDrawable:YES];
}
@ -166,59 +166,59 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
}
}
- (void)reshape {
[super reshape];
@synchronized(self) {
_backingSize = [self convertSizeToBacking:self.bounds.size];
}
[self performWithGLContext:^{
CGSize viewSize = [self backingSize];
glViewport(0, 0, (GLsizei)viewSize.width, (GLsizei)viewSize.height);
} flushDrawable:NO];
}
//- (void)reshape {
// [super reshape];
// @synchronized(self) {
// _backingSize = [self convertSizeToBacking:self.bounds.size];
// }
//
// [self performWithGLContext:^{
// CGSize viewSize = [self backingSize];
// glViewport(0, 0, (GLsizei)viewSize.width, (GLsizei)viewSize.height);
// } flushDrawable:NO];
//}
- (void)awakeFromNib {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
// NSOpenGLPFAMultisample,
// NSOpenGLPFASampleBuffers, 1,
// NSOpenGLPFASamples, 2,
0
};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
#ifdef DEBUG
// When we're using a CoreProfile context, crash if we call a legacy OpenGL function
// This will make it much more obvious where and when such a function call is made so
// that we can remove such calls.
// Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions
// but it would be more difficult to see where that function was called.
CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
#endif
self.pixelFormat = pixelFormat;
self.openGLContext = context;
self.wantsBestResolutionOpenGLSurface = YES;
// NSOpenGLPixelFormatAttribute attributes[] = {
// NSOpenGLPFADoubleBuffer,
// NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
//// NSOpenGLPFAMultisample,
//// NSOpenGLPFASampleBuffers, 1,
//// NSOpenGLPFASamples, 2,
// 0
// };
//
// NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
// NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
//
//#ifdef DEBUG
// // When we're using a CoreProfile context, crash if we call a legacy OpenGL function
// // This will make it much more obvious where and when such a function call is made so
// // that we can remove such calls.
// // Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions
// // but it would be more difficult to see where that function was called.
// CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
//#endif
//
// self.pixelFormat = pixelFormat;
// self.openGLContext = context;
// self.wantsBestResolutionOpenGLSurface = YES;
// Register to receive dragged and dropped file URLs.
[self registerForDraggedTypes:@[(__bridge NSString *)kUTTypeFileURL]];
}
- (void)performWithGLContext:(dispatch_block_t)action flushDrawable:(BOOL)flushDrawable {
CGLLockContext([[self openGLContext] CGLContextObj]);
[self.openGLContext makeCurrentContext];
action();
CGLUnlockContext([[self openGLContext] CGLContextObj]);
if(flushDrawable) CGLFlushDrawable([[self openGLContext] CGLContextObj]);
// CGLLockContext([[self openGLContext] CGLContextObj]);
// [self.openGLContext makeCurrentContext];
// action();
// CGLUnlockContext([[self openGLContext] CGLContextObj]);
//
// if(flushDrawable) CGLFlushDrawable([[self openGLContext] CGLContextObj]);
}
- (void)performWithGLContext:(nonnull dispatch_block_t)action {
[self performWithGLContext:action flushDrawable:NO];
// [self performWithGLContext:action flushDrawable:NO];
}
#pragma mark - NSResponder
@ -264,7 +264,7 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
for(NSPasteboardItem *item in [[sender draggingPasteboard] pasteboardItems]) {
NSURL *URL = [NSURL URLWithString:[item stringForType:(__bridge NSString *)kUTTypeFileURL]];
[self.delegate openGLView:self didReceiveFileAtURL:URL];
[self.responderDelegate openGLView:self didReceiveFileAtURL:URL];
}
return YES;
}
@ -300,13 +300,13 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
_mouseHideTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:NO block:^(__unused NSTimer * _Nonnull timer) {
[NSCursor setHiddenUntilMouseMoves:YES];
[self.delegate openGLViewWillHideOSMouseCursor:self];
[self.responderDelegate openGLViewWillHideOSMouseCursor:self];
}];
}
}
- (void)mouseEntered:(NSEvent *)event {
[self.delegate openGLViewDidShowOSMouseCursor:self];
[self.responderDelegate openGLViewDidShowOSMouseCursor:self];
[super mouseEntered:event];
[self scheduleMouseHide];
}
@ -315,7 +315,7 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
[super mouseExited:event];
[_mouseHideTimer invalidate];
_mouseHideTimer = nil;
[self.delegate openGLViewWillHideOSMouseCursor:self];
[self.responderDelegate openGLViewWillHideOSMouseCursor:self];
}
- (void)releaseMouse {
@ -323,8 +323,8 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
_mouseIsCaptured = NO;
CGAssociateMouseAndMouseCursorPosition(true);
[NSCursor unhide];
[self.delegate openGLViewDidReleaseMouse:self];
[self.delegate openGLViewDidShowOSMouseCursor:self];
[self.responderDelegate openGLViewDidReleaseMouse:self];
[self.responderDelegate openGLViewDidShowOSMouseCursor:self];
((CSApplication *)[NSApplication sharedApplication]).eventDelegate = nil;
}
}
@ -336,7 +336,7 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
// Mouse capture is off, so don't play games with the cursor, just schedule it to
// hide in the near future.
[self scheduleMouseHide];
[self.delegate openGLViewDidShowOSMouseCursor:self];
[self.responderDelegate openGLViewDidShowOSMouseCursor:self];
} else {
if(_mouseIsCaptured) {
// Mouse capture is on, so move the cursor back to the middle of the window, and
@ -354,7 +354,7 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
[self.responderDelegate mouseMoved:event];
} else {
[self.delegate openGLViewDidShowOSMouseCursor:self];
[self.responderDelegate openGLViewDidShowOSMouseCursor:self];
}
}
}
@ -387,8 +387,8 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
_mouseIsCaptured = YES;
[NSCursor hide];
CGAssociateMouseAndMouseCursorPosition(false);
[self.delegate openGLViewWillHideOSMouseCursor:self];
[self.delegate openGLViewDidCaptureMouse:self];
[self.responderDelegate openGLViewWillHideOSMouseCursor:self];
[self.responderDelegate openGLViewDidCaptureMouse:self];
if(self.shouldUsurpCommand) {
((CSApplication *)[NSApplication sharedApplication]).eventDelegate = self;
}