From c5e9a74c88111b2c2838004a3e8f83e5d72b56e4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 13 Sep 2020 21:07:59 -0400 Subject: [PATCH] Uses DisplayMetrics to disable supersampling when too slow. --- .../xcschemes/Clock Signal.xcscheme | 2 +- .../Clock Signal/ScanTarget/CSScanTarget.mm | 25 ++++++++++++++++--- Outputs/DisplayMetrics.cpp | 6 ++++- Outputs/DisplayMetrics.hpp | 3 +++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 63be2c037..a99eb0a5d 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -67,7 +67,7 @@ _isUsingSupersampling; // The output view. __weak MTKView *_view; @@ -359,14 +360,22 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; [self setAspectRatio]; @synchronized(self) { + // Always [re]try multisampling upon a resize. + _scanTarget.display_metrics_.announce_did_resize(); + _isUsingSupersampling = true; [self updateSizeBuffersToSize:size]; } } +- (void)updateSizeBuffers { + @synchronized(self) { + [self updateSizeBuffersToSize:_view.drawableSize]; + } +} + - (void)updateSizeBuffersToSize:(CGSize)size { - // TODO: above what size threshold is supersampling no longer desired? - const NSUInteger frameBufferWidth = NSUInteger(size.width * _view.layer.contentsScale) * 2; - const NSUInteger frameBufferHeight = NSUInteger(size.height * _view.layer.contentsScale) * 2; + const NSUInteger frameBufferWidth = NSUInteger(size.width * _view.layer.contentsScale) * (_isUsingSupersampling ? 2 : 1); + const NSUInteger frameBufferHeight = NSUInteger(size.height * _view.layer.contentsScale) * (_isUsingSupersampling ? 2 : 1); // Generate a framebuffer and a stencil. MTLTextureDescriptor *const textureDescriptor = [MTLTextureDescriptor @@ -1075,9 +1084,16 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; */ - (void)drawInMTKView:(nonnull MTKView *)view { if(_isDrawing.test_and_set()) { + _scanTarget.display_metrics_.announce_draw_status(false); return; } + // Disable supersampling if performance requires it. + if(_isUsingSupersampling && _scanTarget.display_metrics_.should_lower_resolution()) { + _isUsingSupersampling = false; + [self updateSizeBuffers]; + } + // Schedule a copy from the current framebuffer to the view; blitting is unavailable as the target is a framebuffer texture. id commandBuffer = [_commandQueue commandBuffer]; @@ -1085,7 +1101,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; view.currentRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare; id encoder = [commandBuffer renderCommandEncoderWithDescriptor:view.currentRenderPassDescriptor]; - [encoder setRenderPipelineState:_supersamplePipeline]; + [encoder setRenderPipelineState:_isUsingSupersampling ? _supersamplePipeline : _copyPipeline]; [encoder setVertexTexture:_frameBuffer atIndex:0]; [encoder setFragmentTexture:_frameBuffer atIndex:0]; @@ -1095,6 +1111,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; [commandBuffer presentDrawable:view.currentDrawable]; [commandBuffer addCompletedHandler:^(id _Nonnull) { self->_isDrawing.clear(); + self->_scanTarget.display_metrics_.announce_draw_status(true); }]; [commandBuffer commit]; } diff --git a/Outputs/DisplayMetrics.cpp b/Outputs/DisplayMetrics.cpp index 05632b4b1..f238f5065 100644 --- a/Outputs/DisplayMetrics.cpp +++ b/Outputs/DisplayMetrics.cpp @@ -50,7 +50,7 @@ void Metrics::announce_did_resize() { frames_missed_ = frames_hit_ = 0; } -void Metrics::announce_draw_status(size_t, std::chrono::high_resolution_clock::duration, bool complete) { +void Metrics::announce_draw_status(bool complete) { if(!complete) { ++frames_missed_; } else { @@ -79,6 +79,10 @@ void Metrics::announce_draw_status(size_t, std::chrono::high_resolution_clock::d } } +void Metrics::announce_draw_status(size_t, std::chrono::high_resolution_clock::duration, bool complete) { + announce_draw_status(complete); +} + bool Metrics::should_lower_resolution() const { // If less than 100 frames are on record, return no opinion; otherwise // suggest a lower resolution if more than 10 frames in the last 100-200 diff --git a/Outputs/DisplayMetrics.hpp b/Outputs/DisplayMetrics.hpp index 9cd4f7889..c8fae3124 100644 --- a/Outputs/DisplayMetrics.hpp +++ b/Outputs/DisplayMetrics.hpp @@ -33,6 +33,9 @@ class Metrics { /// Provides Metrics with a new data point for output speed estimation. void announce_draw_status(size_t lines, std::chrono::high_resolution_clock::duration duration, bool complete); + /// Provides Metrics with a new data point for output speed estimation, albeit without line-specific information. + void announce_draw_status(bool complete); + /// @returns @c true if Metrics thinks a lower output buffer resolution is desirable in the abstract; @c false otherwise. bool should_lower_resolution() const;