mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-07 23:25:00 +00:00
Adds an intermediate buffer to correct inter-frame smoothing.
Also goes someway back to the old scan output scheduling, albeit presently with limited thread safety.
This commit is contained in:
@@ -5259,6 +5259,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MTL_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
OTHER_CPLUSPLUSFLAGS = (
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
"$(OTHER_CFLAGS)",
|
"$(OTHER_CFLAGS)",
|
||||||
"-Wreorder",
|
"-Wreorder",
|
||||||
@@ -5306,6 +5307,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MTL_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
OTHER_CPLUSPLUSFLAGS = (
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
"$(OTHER_CFLAGS)",
|
"$(OTHER_CFLAGS)",
|
||||||
"-Wreorder",
|
"-Wreorder",
|
||||||
|
@@ -609,13 +609,10 @@ class MachineDocument:
|
|||||||
let url = pictursURL.appendingPathComponent(filename)
|
let url = pictursURL.appendingPathComponent(filename)
|
||||||
|
|
||||||
// Obtain the machine's current display.
|
// Obtain the machine's current display.
|
||||||
var imageRepresentation: NSBitmapImageRep? = nil
|
let imageRepresentation = self.machine.imageRepresentation
|
||||||
self.scanTargetView.perform {
|
|
||||||
imageRepresentation = self.machine.imageRepresentation
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode as a PNG and save.
|
// Encode as a PNG and save.
|
||||||
let pngData = imageRepresentation!.representation(using: .png, properties: [:])
|
let pngData = imageRepresentation.representation(using: .png, properties: [:])
|
||||||
try! pngData?.write(to: url)
|
try! pngData?.write(to: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -67,9 +67,6 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
|
|||||||
- (void)start;
|
- (void)start;
|
||||||
- (void)stop;
|
- (void)stop;
|
||||||
|
|
||||||
- (void)updateViewForPixelSize:(CGSize)pixelSize;
|
|
||||||
- (void)drawViewForPixelSize:(CGSize)pixelSize;
|
|
||||||
|
|
||||||
- (void)setKey:(uint16_t)key characters:(nullable NSString *)characters isPressed:(BOOL)isPressed;
|
- (void)setKey:(uint16_t)key characters:(nullable NSString *)characters isPressed:(BOOL)isPressed;
|
||||||
- (void)clearAllKeys;
|
- (void)clearAllKeys;
|
||||||
|
|
||||||
|
@@ -358,19 +358,6 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
_machine->scan_producer()->set_scan_target(_view.scanTarget.scanTarget);
|
_machine->scan_producer()->set_scan_target(_view.scanTarget.scanTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateViewForPixelSize:(CGSize)pixelSize {
|
|
||||||
// _pixelSize = pixelSize;
|
|
||||||
|
|
||||||
// @synchronized(self) {
|
|
||||||
// const auto scan_status = _machine->crt_machine()->get_scan_status();
|
|
||||||
// NSLog(@"FPS (hopefully): %0.2f [retrace: %0.4f]", 1.0f / scan_status.field_duration, scan_status.retrace_duration);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawViewForPixelSize:(CGSize)pixelSize {
|
|
||||||
// _scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)paste:(NSString *)paste {
|
- (void)paste:(NSString *)paste {
|
||||||
auto keyboardMachine = _machine->keyboard_machine();
|
auto keyboardMachine = _machine->keyboard_machine();
|
||||||
if(keyboardMachine)
|
if(keyboardMachine)
|
||||||
@@ -831,13 +818,14 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
}
|
}
|
||||||
if(!wasUpdating) {
|
if(!wasUpdating) {
|
||||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
[self.view performWithGLContext:^{
|
[self.view updateBacking];
|
||||||
|
// [self.view performWithGLContext:^{
|
||||||
// self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
|
// self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
|
||||||
|
|
||||||
if(splitAndSync) {
|
// if(splitAndSync) {
|
||||||
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
||||||
}
|
// }
|
||||||
} flushDrawable:splitAndSync];
|
// } flushDrawable:splitAndSync];
|
||||||
self->_isUpdating.clear();
|
self->_isUpdating.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -16,4 +16,8 @@
|
|||||||
|
|
||||||
- (nonnull instancetype)initWithView:(nonnull MTKView *)view;
|
- (nonnull instancetype)initWithView:(nonnull MTKView *)view;
|
||||||
|
|
||||||
|
// Draws all scans currently residing at the scan target to the backing store,
|
||||||
|
// ready for output when next requested.
|
||||||
|
- (void)updateFrameBuffer;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -42,7 +42,9 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
|
|
||||||
id<MTLFunction> _vertexShader;
|
id<MTLFunction> _vertexShader;
|
||||||
id<MTLFunction> _fragmentShader;
|
id<MTLFunction> _fragmentShader;
|
||||||
|
|
||||||
id<MTLRenderPipelineState> _scanPipeline;
|
id<MTLRenderPipelineState> _scanPipeline;
|
||||||
|
id<MTLRenderPipelineState> _copyPipeline;
|
||||||
|
|
||||||
// Buffers.
|
// Buffers.
|
||||||
id<MTLBuffer> _uniformsBuffer;
|
id<MTLBuffer> _uniformsBuffer;
|
||||||
@@ -56,10 +58,16 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
size_t _bytesPerInputPixel;
|
size_t _bytesPerInputPixel;
|
||||||
size_t _totalTextureBytes;
|
size_t _totalTextureBytes;
|
||||||
|
|
||||||
|
id<MTLTexture> _frameBuffer;
|
||||||
|
MTLRenderPassDescriptor *_frameBufferRenderPass;
|
||||||
|
|
||||||
// The scan target in C++-world terms and the non-GPU storage for it.
|
// The scan target in C++-world terms and the non-GPU storage for it.
|
||||||
BufferingScanTarget _scanTarget;
|
BufferingScanTarget _scanTarget;
|
||||||
BufferingScanTarget::LineMetadata _lineMetadataBuffer[NumBufferedLines];
|
BufferingScanTarget::LineMetadata _lineMetadataBuffer[NumBufferedLines];
|
||||||
std::atomic_bool _isDrawing;
|
std::atomic_bool _isDrawing;
|
||||||
|
|
||||||
|
// The output view's aspect ratio.
|
||||||
|
__weak MTKView *_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nonnull instancetype)initWithView:(nonnull MTKView *)view {
|
- (nonnull instancetype)initWithView:(nonnull MTKView *)view {
|
||||||
@@ -89,6 +97,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
_scanTarget.set_scan_buffer(reinterpret_cast<BufferingScanTarget::Scan *>(_scansBuffer.contents), NumBufferedScans);
|
_scanTarget.set_scan_buffer(reinterpret_cast<BufferingScanTarget::Scan *>(_scansBuffer.contents), NumBufferedScans);
|
||||||
|
|
||||||
// Set initial aspect-ratio multiplier.
|
// Set initial aspect-ratio multiplier.
|
||||||
|
_view = view;
|
||||||
[self mtkView:view drawableSizeWillChange:view.drawableSize];
|
[self mtkView:view drawableSizeWillChange:view.drawableSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,17 +112,41 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
@param size New drawable size in pixels
|
@param size New drawable size in pixels
|
||||||
*/
|
*/
|
||||||
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
|
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
|
||||||
uniforms()->aspectRatioMultiplier = float(_scanTarget.modals().aspect_ratio / (size.width / size.height));
|
[self setAspectRatio];
|
||||||
|
|
||||||
|
// TODO: consider multisampling here? But it seems like you'd need another level of indirection
|
||||||
|
// in order to maintain an ongoing buffer that supersamples only at the end.
|
||||||
|
|
||||||
|
// TODO: attach a stencil buffer.
|
||||||
|
|
||||||
|
// Generate a framebuffer and a pipeline that targets it.
|
||||||
|
MTLTextureDescriptor *const textureDescriptor = [MTLTextureDescriptor
|
||||||
|
texture2DDescriptorWithPixelFormat:view.colorPixelFormat
|
||||||
|
width:NSUInteger(size.width * view.layer.contentsScale)
|
||||||
|
height:NSUInteger(size.height * view.layer.contentsScale)
|
||||||
|
mipmapped:NO];
|
||||||
|
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||||
|
textureDescriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||||
|
_frameBuffer = [view.device newTextureWithDescriptor:textureDescriptor];
|
||||||
|
|
||||||
|
_frameBufferRenderPass = [[MTLRenderPassDescriptor alloc] init];
|
||||||
|
_frameBufferRenderPass.colorAttachments[0].texture = _frameBuffer;
|
||||||
|
_frameBufferRenderPass.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||||
|
_frameBufferRenderPass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setModals:(const Outputs::Display::ScanTarget::Modals &)modals view:(nonnull MTKView *)view {
|
- (void)setAspectRatio {
|
||||||
|
uniforms()->aspectRatioMultiplier = float(_scanTarget.modals().aspect_ratio / (_view.bounds.size.width / _view.bounds.size.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setModals:(const Outputs::Display::ScanTarget::Modals &)modals {
|
||||||
//
|
//
|
||||||
// Populate uniforms.
|
// Populate uniforms.
|
||||||
//
|
//
|
||||||
uniforms()->scale[0] = modals.output_scale.x;
|
uniforms()->scale[0] = modals.output_scale.x;
|
||||||
uniforms()->scale[1] = modals.output_scale.y;
|
uniforms()->scale[1] = modals.output_scale.y;
|
||||||
uniforms()->lineWidth = 0.75f / modals.expected_vertical_lines; // TODO: return to 1.0 (or slightly more), once happy.
|
uniforms()->lineWidth = 1.05f / modals.expected_vertical_lines; // TODO: return to 1.0 (or slightly more), once happy.
|
||||||
uniforms()->aspectRatioMultiplier = float(modals.aspect_ratio / (view.bounds.size.width / view.bounds.size.height));
|
[self setAspectRatio];
|
||||||
|
|
||||||
const auto toRGB = to_rgb_matrix(modals.composite_colour_space);
|
const auto toRGB = to_rgb_matrix(modals.composite_colour_space);
|
||||||
uniforms()->toRGB = simd::float3x3(
|
uniforms()->toRGB = simd::float3x3(
|
||||||
@@ -172,11 +205,11 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Generate pipeline.
|
// Generate scan pipeline.
|
||||||
//
|
//
|
||||||
id<MTLLibrary> library = [view.device newDefaultLibrary];
|
id<MTLLibrary> library = [_view.device newDefaultLibrary];
|
||||||
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
pipelineDescriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat;
|
pipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
|
||||||
|
|
||||||
// TODO: logic somewhat more complicated than this, probably
|
// TODO: logic somewhat more complicated than this, probably
|
||||||
pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"scanToDisplay"];
|
pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"scanToDisplay"];
|
||||||
@@ -214,30 +247,40 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
|
||||||
_scanPipeline = [view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
_scanPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate copy pipeline.
|
||||||
|
//
|
||||||
|
pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
|
||||||
|
pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"copyVertex"];
|
||||||
|
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"];
|
||||||
|
_copyPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)checkModals {
|
||||||
@method drawInMTKView:
|
// TODO: rethink BufferingScanTarget::perform. Is it now really just for guarding the modals?
|
||||||
@abstract Called on the delegate when it is asked to render into the view
|
_scanTarget.perform([=] {
|
||||||
@discussion Called on the delegate when it is asked to render into the view
|
const Outputs::Display::ScanTarget::Modals *const newModals = _scanTarget.new_modals();
|
||||||
*/
|
if(newModals) {
|
||||||
- (void)drawInMTKView:(nonnull MTKView *)view {
|
[self setModals:*newModals];
|
||||||
const Outputs::Display::ScanTarget::Modals *const newModals = _scanTarget.new_modals();
|
}
|
||||||
if(newModals) {
|
});
|
||||||
[self setModals:*newModals view:view];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Buy into framebuffer preservation.
|
//- (void)updateFrameBuffer {
|
||||||
// TODO: do I really need to do this on every draw?
|
//}
|
||||||
MTLRenderPassDescriptor *const descriptor = view.currentRenderPassDescriptor;
|
|
||||||
descriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
- (void)updateFrameBuffer {
|
||||||
descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
[self checkModals];
|
||||||
descriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 1.0, 0.0, 1.0);
|
if(!_frameBufferRenderPass) return;
|
||||||
|
|
||||||
// Generate a command encoder for the view.
|
// Generate a command encoder for the view.
|
||||||
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
||||||
id <MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor];
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:_frameBufferRenderPass];
|
||||||
|
|
||||||
// Drawing. Just scans.
|
// Drawing. Just scans.
|
||||||
[encoder setRenderPipelineState:_scanPipeline];
|
[encoder setRenderPipelineState:_scanPipeline];
|
||||||
@@ -284,7 +327,30 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
self->_scanTarget.complete_output_area(outputArea);
|
self->_scanTarget.complete_output_area(outputArea);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Register the drawable's presentation, finalise and commit.
|
// Commit the drawing.
|
||||||
|
[commandBuffer commit];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method drawInMTKView:
|
||||||
|
@abstract Called on the delegate when it is asked to render into the view
|
||||||
|
@discussion Called on the delegate when it is asked to render into the view
|
||||||
|
*/
|
||||||
|
- (void)drawInMTKView:(nonnull MTKView *)view {
|
||||||
|
[self checkModals];
|
||||||
|
// [self updateFrameBuffer];
|
||||||
|
|
||||||
|
// Schedule a copy from the current framebuffer to the view; blitting is unavailable as the target is a framebuffer texture.
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
||||||
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:view.currentRenderPassDescriptor];
|
||||||
|
|
||||||
|
[encoder setRenderPipelineState:_copyPipeline];
|
||||||
|
[encoder setVertexTexture:_frameBuffer atIndex:0];
|
||||||
|
[encoder setFragmentTexture:_frameBuffer atIndex:0];
|
||||||
|
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
[encoder endEncoding];
|
||||||
|
|
||||||
[commandBuffer presentDrawable:view.currentDrawable];
|
[commandBuffer presentDrawable:view.currentDrawable];
|
||||||
[commandBuffer commit];
|
[commandBuffer commit];
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,6 @@ struct Line {
|
|||||||
|
|
||||||
// MARK: - Intermediate structs.
|
// MARK: - Intermediate structs.
|
||||||
|
|
||||||
// This is an intermediate struct, which is TEMPORARY.
|
|
||||||
struct SourceInterpolator {
|
struct SourceInterpolator {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
float2 textureCoordinates;
|
float2 textureCoordinates;
|
||||||
@@ -201,3 +200,34 @@ DeclareShaders(Red8Green8Blue8, float)
|
|||||||
DeclareShaders(Red4Green4Blue4, ushort)
|
DeclareShaders(Red4Green4Blue4, ushort)
|
||||||
DeclareShaders(Red2Green2Blue2, ushort)
|
DeclareShaders(Red2Green2Blue2, ushort)
|
||||||
DeclareShaders(Red1Green1Blue1, ushort)
|
DeclareShaders(Red1Green1Blue1, ushort)
|
||||||
|
|
||||||
|
// MARK: - Shaders for copying from a same-sized texture to an MTKView's frame buffer.
|
||||||
|
|
||||||
|
struct CopyInterpolator {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 textureCoordinates;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex CopyInterpolator copyVertex(uint vertexID [[vertex_id]], texture2d<float> texture [[texture(0)]]) {
|
||||||
|
CopyInterpolator vert;
|
||||||
|
|
||||||
|
const uint x = vertexID & 1;
|
||||||
|
const uint y = (vertexID >> 1) & 1;
|
||||||
|
|
||||||
|
vert.textureCoordinates = float2(
|
||||||
|
x * texture.get_width(),
|
||||||
|
y * texture.get_height()
|
||||||
|
);
|
||||||
|
vert.position = float4(
|
||||||
|
float(x) * 2.0 - 1.0,
|
||||||
|
1.0 - float(y) * 2.0,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
return vert;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 copyFragment(CopyInterpolator vert [[stage_in]], texture2d<float> texture [[texture(0)]]) {
|
||||||
|
return texture.sample(standardSampler, vert.textureCoordinates);
|
||||||
|
}
|
||||||
|
@@ -168,12 +168,8 @@ typedef NS_ENUM(NSInteger, CSScanTargetViewRedrawEvent) {
|
|||||||
/// The size in pixels of the OpenGL canvas, factoring in screen pixel density and view size in points.
|
/// The size in pixels of the OpenGL canvas, factoring in screen pixel density and view size in points.
|
||||||
@property (nonatomic, readonly) CGSize backingSize;
|
@property (nonatomic, readonly) CGSize backingSize;
|
||||||
|
|
||||||
/*!
|
- (void)updateBacking;
|
||||||
Locks this view's OpenGL context and makes it current, performs @c action and then unlocks
|
//- (void)performWithGLContext:(nonnull dispatch_block_t)action;
|
||||||
the context. @c action is performed on the calling queue.
|
|
||||||
*/
|
|
||||||
- (void)performWithGLContext:(nonnull dispatch_block_t)action flushDrawable:(BOOL)flushDrawable;
|
|
||||||
- (void)performWithGLContext:(nonnull dispatch_block_t)action;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Instructs that the mouse cursor, if currently captured, should be released.
|
Instructs that the mouse cursor, if currently captured, should be released.
|
||||||
|
@@ -119,20 +119,20 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawAtTime:(const CVTimeStamp *)now frequency:(double)frequency {
|
//- (void)drawAtTime:(const CVTimeStamp *)now frequency:(double)frequency {
|
||||||
[self redrawWithEvent:CSScanTargetViewRedrawEventTimer];
|
// [self redrawWithEvent:CSScanTargetViewRedrawEventTimer];
|
||||||
}
|
//}
|
||||||
|
|
||||||
//- (void)drawRect:(NSRect)dirtyRect {
|
//- (void)drawRect:(NSRect)dirtyRect {
|
||||||
// [self redrawWithEvent:CSScanTargetViewRedrawEventAppKit];
|
// [self redrawWithEvent:CSScanTargetViewRedrawEventAppKit];
|
||||||
// NSLog(@"...");
|
// NSLog(@"...");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
- (void)redrawWithEvent:(CSScanTargetViewRedrawEvent)event {
|
//- (void)redrawWithEvent:(CSScanTargetViewRedrawEvent)event {
|
||||||
[self performWithGLContext:^{
|
// [self performWithGLContext:^{
|
||||||
// [self.delegate openGLViewRedraw:self event:event];
|
//// [self.delegate openGLViewRedraw:self event:event];
|
||||||
} flushDrawable:YES];
|
// } flushDrawable:YES];
|
||||||
}
|
//}
|
||||||
|
|
||||||
- (void)invalidate {
|
- (void)invalidate {
|
||||||
_isInvalid = YES;
|
_isInvalid = YES;
|
||||||
@@ -174,17 +174,9 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- (void)reshape {
|
- (void)updateBacking {
|
||||||
// [super reshape];
|
[_scanTarget updateFrameBuffer];
|
||||||
// @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 {
|
- (void)awakeFromNib {
|
||||||
// Use the preferred device if available.
|
// Use the preferred device if available.
|
||||||
@@ -202,19 +194,6 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
|
|||||||
[self registerForDraggedTypes:@[(__bridge NSString *)kUTTypeFileURL]];
|
[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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)performWithGLContext:(nonnull dispatch_block_t)action {
|
|
||||||
// [self performWithGLContext:action flushDrawable:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSResponder
|
#pragma mark - NSResponder
|
||||||
|
|
||||||
- (BOOL)acceptsFirstResponder {
|
- (BOOL)acceptsFirstResponder {
|
||||||
|
Reference in New Issue
Block a user