mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-20 06:25:01 +00:00
Merge pull request #605 from TomHarte/DisplayMetrics
UNREADY! Introduces dynamic output quality selection.
This commit is contained in:
commit
d03a7911b5
@ -215,6 +215,7 @@
|
|||||||
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B595FAC2086DFBA0083CAA8 /* AudioToggle.cpp */; };
|
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B595FAC2086DFBA0083CAA8 /* AudioToggle.cpp */; };
|
||||||
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; };
|
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; };
|
||||||
4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */; };
|
4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */; };
|
||||||
|
4B622AE5222E0AD5008B59F2 /* DisplayMetrics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */; };
|
||||||
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */; };
|
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */; };
|
||||||
4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; };
|
4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; };
|
||||||
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; };
|
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; };
|
||||||
@ -897,6 +898,8 @@
|
|||||||
4B5FADB91DE3151600AEC565 /* FileHolder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileHolder.hpp; sourceTree = "<group>"; };
|
4B5FADB91DE3151600AEC565 /* FileHolder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileHolder.hpp; sourceTree = "<group>"; };
|
||||||
4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Microdisc.cpp; path = Oric/Microdisc.cpp; sourceTree = "<group>"; };
|
4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Microdisc.cpp; path = Oric/Microdisc.cpp; sourceTree = "<group>"; };
|
||||||
4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Microdisc.hpp; path = Oric/Microdisc.hpp; sourceTree = "<group>"; };
|
4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Microdisc.hpp; path = Oric/Microdisc.hpp; sourceTree = "<group>"; };
|
||||||
|
4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DisplayMetrics.cpp; path = ../../Outputs/DisplayMetrics.cpp; sourceTree = "<group>"; };
|
||||||
|
4B622AE4222E0AD5008B59F2 /* DisplayMetrics.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DisplayMetrics.hpp; path = ../../Outputs/DisplayMetrics.hpp; sourceTree = "<group>"; };
|
||||||
4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = "<group>"; };
|
4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = "<group>"; };
|
||||||
4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSStaticAnalyser.mm; path = StaticAnalyser/CSStaticAnalyser.mm; sourceTree = "<group>"; };
|
4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSStaticAnalyser.mm; path = StaticAnalyser/CSStaticAnalyser.mm; sourceTree = "<group>"; };
|
||||||
4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Target.h"; sourceTree = "<group>"; };
|
4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Target.h"; sourceTree = "<group>"; };
|
||||||
@ -1780,7 +1783,9 @@
|
|||||||
4B366DFD1B5C165F0026627B /* Outputs */ = {
|
4B366DFD1B5C165F0026627B /* Outputs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */,
|
||||||
4B05401D219D1618001BF69C /* ScanTarget.cpp */,
|
4B05401D219D1618001BF69C /* ScanTarget.cpp */,
|
||||||
|
4B622AE4222E0AD5008B59F2 /* DisplayMetrics.hpp */,
|
||||||
4BD601A920D89F2A00CBCE57 /* Log.hpp */,
|
4BD601A920D89F2A00CBCE57 /* Log.hpp */,
|
||||||
4BF52672218E752E00313227 /* ScanTarget.hpp */,
|
4BF52672218E752E00313227 /* ScanTarget.hpp */,
|
||||||
4B0CCC411C62D0B3001CAC5F /* CRT */,
|
4B0CCC411C62D0B3001CAC5F /* CRT */,
|
||||||
@ -3025,8 +3030,8 @@
|
|||||||
4BD5D2672199148100DDF17D /* ScanTargetGLSLFragments.cpp */,
|
4BD5D2672199148100DDF17D /* ScanTargetGLSLFragments.cpp */,
|
||||||
4BD191D9219113B80042E144 /* OpenGL.hpp */,
|
4BD191D9219113B80042E144 /* OpenGL.hpp */,
|
||||||
4BD191F32191180E0042E144 /* ScanTarget.hpp */,
|
4BD191F32191180E0042E144 /* ScanTarget.hpp */,
|
||||||
4BD424DC2193B5340097291A /* Primitives */,
|
|
||||||
4B961408222760E0001A7BF2 /* Screenshot.hpp */,
|
4B961408222760E0001A7BF2 /* Screenshot.hpp */,
|
||||||
|
4BD424DC2193B5340097291A /* Primitives */,
|
||||||
);
|
);
|
||||||
name = OpenGL;
|
name = OpenGL;
|
||||||
path = ../../Outputs/OpenGL;
|
path = ../../Outputs/OpenGL;
|
||||||
@ -3895,6 +3900,7 @@
|
|||||||
4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */,
|
4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */,
|
||||||
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */,
|
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */,
|
||||||
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */,
|
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */,
|
||||||
|
4B622AE5222E0AD5008B59F2 /* DisplayMetrics.cpp in Sources */,
|
||||||
4B1497881EE4A1DA00CE2596 /* ZX80O81P.cpp in Sources */,
|
4B1497881EE4A1DA00CE2596 /* ZX80O81P.cpp in Sources */,
|
||||||
4B894520201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
4B894520201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||||
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */,
|
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */,
|
||||||
|
88
Outputs/DisplayMetrics.cpp
Normal file
88
Outputs/DisplayMetrics.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// DisplayMetrics.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 04/03/2019.
|
||||||
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DisplayMetrics.hpp"
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
using namespace Outputs::Display;
|
||||||
|
|
||||||
|
// MARK: Frame size estimation.
|
||||||
|
|
||||||
|
void Metrics::announce_event(ScanTarget::Event event) {
|
||||||
|
switch(event) {
|
||||||
|
case ScanTarget::Event::EndHorizontalRetrace:
|
||||||
|
++lines_this_frame_;
|
||||||
|
break;
|
||||||
|
case ScanTarget::Event::BeginVerticalRetrace:
|
||||||
|
add_line_total(lines_this_frame_);
|
||||||
|
break;
|
||||||
|
case ScanTarget::Event::EndVerticalRetrace:
|
||||||
|
lines_this_frame_ = 0;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metrics::add_line_total(int total) {
|
||||||
|
line_total_history_[line_total_history_pointer_] = total;
|
||||||
|
line_total_history_pointer_ = (line_total_history_pointer_ + 1) % line_total_history_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Metrics::visible_lines_per_frame_estimate() {
|
||||||
|
// Just average the number of records contained in line_total_history_ to provide this estimate;
|
||||||
|
// that array should be an even number, to allow for potential interlaced sources.
|
||||||
|
return float(std::accumulate(line_total_history_.begin(), line_total_history_.end(), 0)) / float(line_total_history_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int Metrics::current_line() {
|
||||||
|
return lines_this_frame_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: GPU processing speed decisions.
|
||||||
|
|
||||||
|
void Metrics::announce_did_resize() {
|
||||||
|
frames_missed_ = frames_hit_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metrics::announce_draw_status(size_t lines, std::chrono::high_resolution_clock::duration duration, bool complete) {
|
||||||
|
if(!complete) {
|
||||||
|
++frames_missed_;
|
||||||
|
} else {
|
||||||
|
++frames_hit_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't allow the record of history to extend too far into the past.
|
||||||
|
if(frames_hit_ + frames_missed_ > 200) {
|
||||||
|
// Subtract from whichever wasn't just incremented, to ensure the
|
||||||
|
// most recent information is more important than the historic stuff.
|
||||||
|
if(!complete) {
|
||||||
|
--frames_hit_;
|
||||||
|
} else {
|
||||||
|
--frames_missed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebalance if either thing has gone negative.
|
||||||
|
if(frames_hit_ < 0) {
|
||||||
|
frames_missed_ += frames_hit_;
|
||||||
|
frames_hit_ = 0;
|
||||||
|
}
|
||||||
|
if(frames_missed_ < 0) {
|
||||||
|
frames_hit_ += frames_missed_;
|
||||||
|
frames_missed_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metrics::should_lower_resolution() {
|
||||||
|
// 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
|
||||||
|
// took too long to produce.
|
||||||
|
if(frames_hit_ + frames_missed_ < 100) return false;
|
||||||
|
return frames_missed_ > 10;
|
||||||
|
}
|
57
Outputs/DisplayMetrics.hpp
Normal file
57
Outputs/DisplayMetrics.hpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// DisplayMetrics.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 04/03/2019.
|
||||||
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DisplayMetrics_hpp
|
||||||
|
#define DisplayMetrics_hpp
|
||||||
|
|
||||||
|
#include "ScanTarget.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace Outputs {
|
||||||
|
namespace Display {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A class to derive various metrics about the input to a ScanTarget,
|
||||||
|
based purely on empirical observation. In particular it is intended
|
||||||
|
to allow for host-client frame synchronisation.
|
||||||
|
*/
|
||||||
|
class Metrics {
|
||||||
|
public:
|
||||||
|
/// Notifies Metrics of a beam event.
|
||||||
|
void announce_event(ScanTarget::Event event);
|
||||||
|
|
||||||
|
/// Notifies Metrics that the size of the output buffer has changed.
|
||||||
|
void announce_did_resize();
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
/// @returns @c true if Metrics thinks a lower output buffer resolution is desirable in the abstract; @c false otherwise.
|
||||||
|
bool should_lower_resolution();
|
||||||
|
|
||||||
|
/// @returns An estimate of the number of lines being produced per frame, excluding vertical sync.
|
||||||
|
float visible_lines_per_frame_estimate();
|
||||||
|
|
||||||
|
/// @returns The number of lines since vertical retrace ended.
|
||||||
|
int current_line();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int lines_this_frame_ = 0;
|
||||||
|
std::array<int, 20> line_total_history_;
|
||||||
|
size_t line_total_history_pointer_ = 0;
|
||||||
|
void add_line_total(int);
|
||||||
|
|
||||||
|
int frames_hit_ = 0;
|
||||||
|
int frames_missed_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DisplayMetrics_hpp */
|
@ -33,7 +33,7 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit,
|
|||||||
bind_texture();
|
bind_texture();
|
||||||
|
|
||||||
// Set dimensions and set the user-supplied magnification filter.
|
// Set dimensions and set the user-supplied magnification filter.
|
||||||
test_gl(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGBA, GLsizei(expanded_width_), GLsizei(expanded_height_), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
test_gl(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGB, GLsizei(expanded_width_), GLsizei(expanded_height_), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
||||||
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||||
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
test_gl(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
using namespace Outputs::Display::OpenGL;
|
using namespace Outputs::Display::OpenGL;
|
||||||
|
|
||||||
@ -254,6 +255,9 @@ void ScanTarget::submit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScanTarget::announce(Event event, bool is_visible, const Outputs::Display::ScanTarget::Scan::EndPoint &location, uint8_t composite_amplitude) {
|
void ScanTarget::announce(Event event, bool is_visible, const Outputs::Display::ScanTarget::Scan::EndPoint &location, uint8_t composite_amplitude) {
|
||||||
|
// Forward the event to the display metrics tracker.
|
||||||
|
display_metrics_.announce_event(event);
|
||||||
|
|
||||||
if(event == ScanTarget::Event::EndVerticalRetrace) {
|
if(event == ScanTarget::Event::EndVerticalRetrace) {
|
||||||
// The previous-frame-is-complete flag is subject to a two-slot queue because
|
// The previous-frame-is-complete flag is subject to a two-slot queue because
|
||||||
// measurement for *this* frame needs to begin now, meaning that the previous
|
// measurement for *this* frame needs to begin now, meaning that the previous
|
||||||
@ -383,14 +387,26 @@ void ScanTarget::setup_pipeline() {
|
|||||||
input_shader_->set_uniform("textureName", GLint(SourceDataTextureUnit - GL_TEXTURE0));
|
input_shader_->set_uniform("textureName", GLint(SourceDataTextureUnit - GL_TEXTURE0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Outputs::Display::Metrics &ScanTarget::display_metrics() {
|
||||||
|
return display_metrics_;
|
||||||
|
}
|
||||||
|
|
||||||
void ScanTarget::update(int output_width, int output_height) {
|
void ScanTarget::update(int output_width, int output_height) {
|
||||||
if(fence_ != nullptr) {
|
if(fence_ != nullptr) {
|
||||||
// if the GPU is still busy, don't wait; we'll catch it next time
|
// if the GPU is still busy, don't wait; we'll catch it next time
|
||||||
if(glClientWaitSync(fence_, GL_SYNC_FLUSH_COMMANDS_BIT, 0) == GL_TIMEOUT_EXPIRED) {
|
if(glClientWaitSync(fence_, GL_SYNC_FLUSH_COMMANDS_BIT, 0) == GL_TIMEOUT_EXPIRED) {
|
||||||
|
display_metrics_.announce_draw_status(
|
||||||
|
lines_submitted_,
|
||||||
|
std::chrono::high_resolution_clock::now() - line_submission_begin_time_,
|
||||||
|
false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fence_ = nullptr;
|
fence_ = nullptr;
|
||||||
}
|
}
|
||||||
|
display_metrics_.announce_draw_status(
|
||||||
|
lines_submitted_,
|
||||||
|
std::chrono::high_resolution_clock::now() - line_submission_begin_time_,
|
||||||
|
true);
|
||||||
|
|
||||||
// Spin until the is-drawing flag is reset; the wait sync above will deal
|
// Spin until the is-drawing flag is reset; the wait sync above will deal
|
||||||
// with instances where waiting is inappropriate.
|
// with instances where waiting is inappropriate.
|
||||||
@ -403,10 +419,16 @@ void ScanTarget::update(int output_width, int output_height) {
|
|||||||
modals_are_dirty_ = false;
|
modals_are_dirty_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the start time of this submission group.
|
||||||
|
line_submission_begin_time_ = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// Grab the current read and submit pointers.
|
// Grab the current read and submit pointers.
|
||||||
const auto submit_pointers = submit_pointers_.load();
|
const auto submit_pointers = submit_pointers_.load();
|
||||||
const auto read_pointers = read_pointers_.load();
|
const auto read_pointers = read_pointers_.load();
|
||||||
|
|
||||||
|
// Determine how many lines are about to be submitted.
|
||||||
|
lines_submitted_ = (read_pointers.line + line_buffer_.size() - submit_pointers.line) % line_buffer_.size();
|
||||||
|
|
||||||
// Submit scans; only the new ones need to be communicated.
|
// Submit scans; only the new ones need to be communicated.
|
||||||
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
||||||
if(new_scans) {
|
if(new_scans) {
|
||||||
@ -529,13 +551,26 @@ void ScanTarget::update(int output_width, int output_height) {
|
|||||||
test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(new_scans));
|
test_gl(glDrawArraysInstanced, GL_TRIANGLE_STRIP, 0, 4, GLsizei(new_scans));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the accumulation buffer is properly sized.
|
// Logic for reducing resolution: start doing so if the metrics object reports that
|
||||||
// TODO: based on a decision about host speed, potentially switch to the std::min fragment as shown below,
|
// it's a good idea. Go up to a quarter of the requested resolution, subject to
|
||||||
// which would limit total output buffer size to 1440x1080.
|
// clamping at each stage. If the output resolution changes, or anything else about
|
||||||
const int framebuffer_height = output_height;//std::min(output_height, 1080);
|
// the output pipeline, just start trying the highest size again.
|
||||||
|
if(display_metrics_.should_lower_resolution()) {
|
||||||
|
resolution_reduction_level_ = std::min(resolution_reduction_level_+1, 4);
|
||||||
|
}
|
||||||
|
if(output_height_ != output_height || did_setup_pipeline) {
|
||||||
|
resolution_reduction_level_ = 1;
|
||||||
|
output_height_ = output_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the accumulation buffer is properly sized, allowing for the metrics object's
|
||||||
|
// feelings about whether too high a resolution is being used.
|
||||||
|
const int framebuffer_height = std::max(output_height / resolution_reduction_level_, std::min(540, output_height));
|
||||||
const int proportional_width = (framebuffer_height * 4) / 3;
|
const int proportional_width = (framebuffer_height * 4) / 3;
|
||||||
const bool did_create_accumulation_texture = !accumulation_texture_ || ( /* !synchronous && */ (accumulation_texture_->get_width() != proportional_width || accumulation_texture_->get_height() != framebuffer_height));
|
const bool did_create_accumulation_texture = !accumulation_texture_ || ( (accumulation_texture_->get_width() != proportional_width || accumulation_texture_->get_height() != framebuffer_height));
|
||||||
if(did_create_accumulation_texture) {
|
if(did_create_accumulation_texture) {
|
||||||
|
LOG("Changed output resolution to " << proportional_width << " by " << framebuffer_height);
|
||||||
|
display_metrics_.announce_did_resize();
|
||||||
std::unique_ptr<OpenGL::TextureTarget> new_framebuffer(
|
std::unique_ptr<OpenGL::TextureTarget> new_framebuffer(
|
||||||
new TextureTarget(
|
new TextureTarget(
|
||||||
GLsizei(proportional_width),
|
GLsizei(proportional_width),
|
||||||
@ -549,7 +584,7 @@ void ScanTarget::update(int output_width, int output_height) {
|
|||||||
|
|
||||||
test_gl(glActiveTexture, AccumulationTextureUnit);
|
test_gl(glActiveTexture, AccumulationTextureUnit);
|
||||||
accumulation_texture_->bind_texture();
|
accumulation_texture_->bind_texture();
|
||||||
accumulation_texture_->draw(float(output_width) / float(output_height));
|
accumulation_texture_->draw(4.0f / 3.0f);
|
||||||
|
|
||||||
test_gl(glClear, GL_STENCIL_BUFFER_BIT);
|
test_gl(glClear, GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
@ -9,8 +9,9 @@
|
|||||||
#ifndef ScanTarget_hpp
|
#ifndef ScanTarget_hpp
|
||||||
#define ScanTarget_hpp
|
#define ScanTarget_hpp
|
||||||
|
|
||||||
#include "../ScanTarget.hpp"
|
|
||||||
#include "../Log.hpp"
|
#include "../Log.hpp"
|
||||||
|
#include "../DisplayMetrics.hpp"
|
||||||
|
#include "../ScanTarget.hpp"
|
||||||
|
|
||||||
#include "OpenGL.hpp"
|
#include "OpenGL.hpp"
|
||||||
#include "Primitives/TextureTarget.hpp"
|
#include "Primitives/TextureTarget.hpp"
|
||||||
@ -21,6 +22,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <chrono>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -47,6 +49,9 @@ class ScanTarget: public Outputs::Display::ScanTarget {
|
|||||||
/*! Processes all the latest input, at a resolution suitable for later output to a framebuffer of the specified size. */
|
/*! Processes all the latest input, at a resolution suitable for later output to a framebuffer of the specified size. */
|
||||||
void update(int output_width, int output_height);
|
void update(int output_width, int output_height);
|
||||||
|
|
||||||
|
/*! @returns The DisplayMetrics object that this ScanTarget has been providing with announcements and draw overages. */
|
||||||
|
Metrics &display_metrics();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
struct OpenGLVersionDumper {
|
struct OpenGLVersionDumper {
|
||||||
@ -78,6 +83,13 @@ class ScanTarget: public Outputs::Display::ScanTarget {
|
|||||||
|
|
||||||
bool output_is_visible_ = false;
|
bool output_is_visible_ = false;
|
||||||
|
|
||||||
|
Metrics display_metrics_;
|
||||||
|
int resolution_reduction_level_ = 1;
|
||||||
|
int output_height_ = 0;
|
||||||
|
|
||||||
|
size_t lines_submitted_ = 0;
|
||||||
|
std::chrono::high_resolution_clock::time_point line_submission_begin_time_;
|
||||||
|
|
||||||
// Extends the definition of a Scan to include two extra fields,
|
// Extends the definition of a Scan to include two extra fields,
|
||||||
// relevant to the way that this scan target processes video.
|
// relevant to the way that this scan target processes video.
|
||||||
struct Scan {
|
struct Scan {
|
||||||
|
Loading…
Reference in New Issue
Block a user