back
OxyScope (swap chain) buffering
OxyScope has 3 modes for collecting SimHub property values:
- grow range
- starts with a capture, based on samples per shot,
then appends samples different from those previously captured,
up to the total buffer limit.
This single buffer is shared for plotting;
capturing may be paused by changing Auto to Hold.
then resumed or restarted.
- one shot
- Captures of length samples per shot can be plotted,
while capture continues. This wants at least ping-pong buffering,
to avoid data changes during plot by subsequent capture.
However, a chain of 3 buffers would enable
plotting another buffer immediately after a plot is dismissed.
Currently, with only two buffers,
the unplotted buffer is likely incomplete when refresh is wanted.
- more range
- OxyScope searches for capture of length samples per shot
with wider range of values for some selected properties.
This wants a chain of at least 3 buffers, allowing
OxyScope to continue searching for a larger range
than one currently held, but not yet displayed,
while reprocessing and replotting a third buffer.
I feel the need
While 3 swap chain buffer benefits were recognized early in OxyScope development,
it did not become so important until VS and rescale options,
which want to manipulate and replot currently buffered data.
Before, capture could resume modifying second swap buffer as soon as its data had been plotted.
Sadly, C# examples for swap-chain buffering are all about display buffering
and tied to specifics of some display rendering architecture
handshaking
Plotting and user interactions are handled on a thread
separate from that used for processing SimHub properties.
- grow range
- Because a single buffer,
DataUpdate() simply does nothing if !AutoPlot
- one shot
- With multiple buffers,
DataUpdate() continues collecting...
Replot() may become !busy at any time.
- if a newer (one shot) or bigger more range buffer is available ,
then call Replot() before the current work buffer completes.
when current work buffer completes,
mark buffer available and switch to other buffer.
- more range
- similar to one shot, except
available wants buffer with larger value range.
available handling
New variables: bool available ; byte VM.plot, other // buffer indices
- Invoke `Replot()` asynchronusly:
if (available && !VM.busy)
{
available = false;
VM.busy = true;
VM.plot = other; // buffer index for Replot()
other = (byte)(3 - (VM.plot + work));
View.Dispatcher.Invoke(() => View.Replot(VM.Slength));
}
- one shot or more range buffer complete
if ((++Sample - VM.start[work]) >= VM.Slength) // filled?
{
// swap chain buffer: buffer setup in Control.xaml.cs Control() and Model.Slength
// https://blekenbleu.github.io/SimHub/swapchain.htm
double work_range = Drange(work, VM.property);
VM.Current = $"{VM.min[work][clf]:#0.000} <= Y <= {VM.max[work][clf]:#0.000}; "
+ ((1 == VM.Refresh) ? $"{VM.min[work][3]:#0.000} <= X <= {VM.max[work][3]:#0.000}"
: $"{VM.PropName[VM.property]} range {work_range}");
// Refresh: 0 = greater range, 1 = snapshot, 2 = grow range (not handled here)
// property: 3 == no curve fitting; 0-2 correspond to Y0-Y2
if (1 == VM.Refresh || Drange(other, VM.property) < work_range)
{
other = work;
work = (byte)(3 - (other + VM.plot));
}
available = 1 == VM.Refresh || Drange(VM.plot, VM.property) < Drange(other, VM.property);
Sample = VM.start[work];
}
|