Skip to content
Snippets Groups Projects
Commit 7f6cbba6 authored by Tobias Pietzsch's avatar Tobias Pietzsch
Browse files

Minor refactoring and javadoc

parent 1ce9aea3
Branches
No related tags found
No related merge requests found
......@@ -44,6 +44,7 @@ import net.imglib2.ui.PainterThread;
import net.imglib2.ui.RenderTarget;
import net.imglib2.util.Intervals;
/**
* A renderer that uses a coarse-to-fine rendering scheme. First, a small target
* image at a fraction of the canvas resolution is rendered. Then, increasingly
......@@ -67,13 +68,10 @@ import net.imglib2.util.Intervals;
* scale is currently rendering, {@link #requestRepaint() repaint request} will
* cancel rendering, such that display remains interactive.
* <p>
* The renderer tries to maintain a per-frame rendering time close to a desired
* number of {@code targetRenderNanos} nanoseconds. If the rendering time (in
* nanoseconds) for the (currently) highest scaled screen image is above this
* threshold, a coarser screen scale is chosen as the highest screen scale to
* use. Similarly, if the rendering time for the (currently) second-highest
* scaled screen image is below this threshold, this finer screen scale chosen
* as the highest screen scale to use.
* The renderer tries to maintain a per-frame rendering time close to
* {@code targetRenderNanos} nanoseconds. The current highest screen scale is
* chosen to match this time based on per-output-pixel time measured in previous
* frames.
* <p>
* The renderer uses multiple threads (if desired).
* <p>
......@@ -103,10 +101,18 @@ public class MultiResolutionRenderer
private final PainterThread painterThread;
/**
* Currently active projector, used to re-paint the display. It maps the
* source data to {@code ©screenImages}.
* Creates projectors for rendering current {@code ViewerState} to a
* {@code screenImage}.
*/
private VolatileProjector projector;
private final ProjectorFactory projectorFactory;
/**
* Controls IO budgeting and fetcher queue.
*/
private final CacheControl cacheControl;
// TODO: should be settable
private final long[] iobudget = new long[] { 100l * 1000000l, 10l * 1000000l };
/**
* Scale factors from the {@link #display viewer canvas} to the
......@@ -153,6 +159,9 @@ public class MultiResolutionRenderer
private int screenH;
/**
* Maintains arrays for intermediate per-source render images and masks.
*/
private final RenderStorage renderStorage;
/**
......@@ -170,26 +179,28 @@ public class MultiResolutionRenderer
private final MovingAverage renderNanosPerPixelAndSource;
/**
* The index of the screen scale of the {@link #projector current
* projector}.
* Currently active projector, used to re-paint the display. It maps the
* source data to {@code ©screenImages}.
*/
private int currentScreenScaleIndex;
private VolatileProjector projector;
/**
* The index of the screen scale which should be rendered next.
* Screen scale of the last successful (not cancelled) rendering pass in
* full-frame mode.
*/
private int requestedScreenScaleIndex;
private int currentScreenScaleIndex;
/**
* The index of the coarsest screen scale currently used.
* Rendering at finer screen scales may be cancelled.
* The index of the screen scale which should be rendered next in full-frame
* mode.
*/
private int maxScreenScaleIndex;
private int requestedScreenScaleIndex;
/**
* Whether the current rendering operation may be cancelled (to start a new
* one). Rendering may be cancelled unless we are rendering at the
* {@link #maxScreenScaleIndex coarsest screen scale}.
* (estimated) coarsest screen scale meeting the rendering time
* {@link #targetRenderNanos threshold}.
*/
private boolean renderingMayBeCancelled;
......@@ -204,24 +215,31 @@ public class MultiResolutionRenderer
private int currentNumVisibleSources;
/**
* Creates projectors for rendering current {@code ViewerState} to a
* {@code screenImage}.
* Whether a full repaint was {@link #requestRepaint() requested}. This will
* cause {@link CacheControl#prepareNextFrame()}.
*/
private final ProjectorFactory projectorFactory;
private boolean newFrameRequest;
/**
* Controls IO budgeting and fetcher queue.
* If {@code true}, then we are painting intervals currently.
* If {@code false}, then we are painting full frames.
*/
private final CacheControl cacheControl;
private boolean intervalMode;
/**
* Whether a repaint was {@link #requestRepaint() requested}. This will
* cause {@link CacheControl#prepareNextFrame()}.
* Screen scale of the last successful (not cancelled) rendering pass in
* interval mode.
*/
private boolean newFrameRequest;
private int currentIntervalScaleIndex;
// TODO: should be settable
private final long[] iobudget = new long[] { 100l * 1000000l, 10l * 1000000l };
private int requestedIntervalScaleIndex;
/**
* Whether repainting of an interval was {@link #requestRepaint(Interval)
* requested}. This will cause {@link CacheControl#prepareNextFrame()}.
* Pending interval requests are obsoleted by full repaint requests.
*/
private boolean newIntervalRequest;
/**
* @param display
......@@ -276,8 +294,7 @@ public class MultiResolutionRenderer
renderNanosPerPixelAndSource = new MovingAverage( 3 );
renderNanosPerPixelAndSource.init( 500 );
maxScreenScaleIndex = screenScales.length - 1;
requestedScreenScaleIndex = maxScreenScaleIndex;
requestedScreenScaleIndex = screenScales.length - 1;
renderingMayBeCancelled = false;
this.cacheControl = cacheControl;
newFrameRequest = false;
......@@ -334,9 +351,15 @@ public class MultiResolutionRenderer
newFrameRequest = false;
intervalMode = false;
}
paintInterval = intervalMode;
newInterval = newIntervalRequest;
newIntervalRequest = false;
if ( newInterval )
{
newIntervalRequest = false;
intervalMode = true;
}
paintInterval = intervalMode;
}
if ( paintInterval )
......@@ -347,8 +370,7 @@ public class MultiResolutionRenderer
cacheControl.prepareNextFrame();
currentViewerState = viewerState.snapshot();
currentNumVisibleSources = currentViewerState.getVisibleAndPresentSources().size();
maxScreenScaleIndex = suggestScreenScale( new FinalDimensions( screenW, screenH ), currentNumVisibleSources );
requestedScreenScaleIndex = maxScreenScaleIndex;
requestedScreenScaleIndex = suggestScreenScale( new FinalDimensions( screenW, screenH ), currentNumVisibleSources );
}
final boolean createProjector = newFrame || ( requestedScreenScaleIndex != currentScreenScaleIndex );
......@@ -375,7 +397,7 @@ public class MultiResolutionRenderer
renderStorage.checkRenewData( screenScales[ 0 ].w, screenScales[ 0 ].h, currentNumVisibleSources );
projector = createProjector( currentViewerState, requestedScreenScaleIndex, renderResult.getScreenImage(), 0, 0 );
requestNewFrameIfIncomplete = projectorFactory.requestNewFrameIfIncomplete();
renderingMayBeCancelled = ( requestedScreenScaleIndex < maxScreenScaleIndex );
renderingMayBeCancelled = !newFrame;
}
p = projector;
}
......@@ -406,7 +428,7 @@ public class MultiResolutionRenderer
// TODO else renderResult.setUpdated();
if ( currentScreenScaleIndex > 0 )
requestRepaint( currentScreenScaleIndex - 1 );
iterateRepaint( currentScreenScaleIndex - 1 );
else if ( p.isValid() )
{
// indicate that rendering is complete
......@@ -426,7 +448,7 @@ public class MultiResolutionRenderer
if( requestNewFrameIfIncomplete )
requestRepaint();
else
requestRepaint( currentScreenScaleIndex );
iterateRepaint( currentScreenScaleIndex );
}
}
}
......@@ -434,6 +456,20 @@ public class MultiResolutionRenderer
return success;
}
/**
* Request a repaint of the display from the painter thread, setting
* {@code requestedScreenScaleIndex} to the specified
* {@code screenScaleIndex}. This is used to repaint the
* {@code currentViewerState} in a loop, until everything is painted at
* highest resolution from valid data (or painting is interrupted by a new
* "real" {@link #requestRepaint()}.
*/
private void iterateRepaint( final int screenScaleIndex )
{
requestedScreenScaleIndex = screenScaleIndex;
painterThread.requestRepaint();
}
/**
* Request a repaint of the display from the painter thread. The painter
* thread will trigger a {@link #paint} as soon as possible (that is,
......@@ -449,20 +485,6 @@ public class MultiResolutionRenderer
painterThread.requestRepaint();
}
/**
* Request a repaint of the display from the painter thread, setting
* {@code requestedScreenScaleIndex} to the specified
* {@code screenScaleIndex}. This is used to repaint the
* {@code currentViewerState} in a loop, until everything is painted at
* highest resolution from valid data (or painting is interrupted by a new
* "real" {@link #requestRepaint()}.
*/
private void requestRepaint( final int screenScaleIndex )
{
requestedScreenScaleIndex = screenScaleIndex;
painterThread.requestRepaint();
}
private int suggestScreenScale( final Dimensions screenSize, final int numSources )
{
final double intervalRenderNanos = renderNanosPerPixelAndSource.getAverage() * Intervals.numElements( screenSize ) * numSources;
......@@ -526,12 +548,7 @@ public class MultiResolutionRenderer
// =========== intervals =============
private Interval requestedScreenInterval;
private boolean intervalMode;
private boolean newIntervalRequest;
private RenderResult currentRenderResult;
private int requestedIntervalScaleIndex;
private int currentIntervalScaleIndex;
private int maxIntervalScaleIndex;
public static class IntervalRenderData
{
......@@ -560,8 +577,7 @@ public class MultiResolutionRenderer
if ( newInterval )
{
cacheControl.prepareNextFrame();
maxIntervalScaleIndex = Math.max( currentScreenScaleIndex, suggestScreenScale( requestedScreenInterval, currentNumVisibleSources ) );
requestedIntervalScaleIndex = maxIntervalScaleIndex;
requestedIntervalScaleIndex = Math.max( currentScreenScaleIndex, suggestScreenScale( requestedScreenInterval, currentNumVisibleSources ) );
}
final boolean createProjector = newInterval || ( requestedIntervalScaleIndex != currentIntervalScaleIndex );
......@@ -588,7 +604,7 @@ public class MultiResolutionRenderer
final double ty = interval.min( 1 ) * relativeScale;
intervalRenderData = new IntervalRenderData( targetInterval, tx, ty );
renderingMayBeCancelled = ( requestedIntervalScaleIndex < maxIntervalScaleIndex );
renderingMayBeCancelled = !newInterval;
}
p = projector;
}
......@@ -605,13 +621,14 @@ public class MultiResolutionRenderer
currentRenderResult.patch( intervalResult, intervalRenderData.targetInterval, intervalRenderData.tx, intervalRenderData.ty );
if ( currentIntervalScaleIndex > currentScreenScaleIndex )
requestRepaintInterval( currentIntervalScaleIndex - 1 );
iterateRepaintInterval( currentIntervalScaleIndex - 1 );
else if ( p.isValid() )
{
if ( requestedScreenScaleIndex >= 0 )
{
// go back to "normal" rendering
intervalMode = false;
renderingMayBeCancelled = false;
if ( requestedScreenScaleIndex == currentScreenScaleIndex )
++currentScreenScaleIndex;
painterThread.requestRepaint();
......@@ -628,7 +645,7 @@ public class MultiResolutionRenderer
// restore interrupted state
Thread.currentThread().interrupt();
}
requestRepaintInterval( currentIntervalScaleIndex );
iterateRepaintInterval( currentIntervalScaleIndex );
}
}
}
......@@ -636,6 +653,12 @@ public class MultiResolutionRenderer
return success;
}
private void iterateRepaintInterval( final int intervalScaleIndex )
{
requestedIntervalScaleIndex = intervalScaleIndex;
painterThread.requestRepaint();
}
private Interval scaleScreenInterval( final Interval requestedScreenInterval, final int intervalScaleIndex )
{
final int clipW = screenScales[ intervalScaleIndex ].w;
......@@ -651,15 +674,9 @@ public class MultiResolutionRenderer
);
}
private void requestRepaintInterval( final int intervalScaleIndex )
{
requestedIntervalScaleIndex = intervalScaleIndex;
painterThread.requestRepaint();
}
public synchronized void requestRepaint( final Interval screenInterval )
{
if ( renderingMayBeCancelled )
if ( renderingMayBeCancelled || intervalMode )
{
if ( projector != null )
projector.cancel();
......@@ -669,8 +686,6 @@ public class MultiResolutionRenderer
painterThread.requestRepaint();
}
else
{
requestRepaint();
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment