2014-10-14 11:53:15 -04:00
# include "EmberPch.h"
# include "RendererBase.h"
namespace EmberNs
{
/// <summary>
/// Constructor that sets default values.
/// The thread count is set to the number of cores detected on the system.
/// </summary>
RendererBase : : RendererBase ( )
{
ThreadCount ( Timing : : ProcessorCount ( ) ) ;
}
/// <summary>
/// Non-virtual processing functions.
/// </summary>
/// <summary>
/// Abort the render and call a function to do something, most likely change a value.
/// Then update the current process action to the one specified.
/// The current process action will only be set if it makes sense based
/// on the current process state. If the value specified doesn't make sense
/// the next best choice will be made. If nothing makes sense, a complete
/// re-render will be triggered on the next call to Run().
/// </summary>
/// <param name="func">The function to execute</param>
/// <param name="action">The desired process action</param>
void RendererBase : : ChangeVal ( std : : function < void ( void ) > func , eProcessAction action )
{
Abort ( ) ;
EnterRender ( ) ;
func ( ) ;
//If they want a full render, don't bother inspecting process state, just start over.
2015-12-31 19:00:36 -05:00
if ( action = = eProcessAction : : FULL_RENDER )
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : NONE ;
m_ProcessAction = eProcessAction : : FULL_RENDER ;
2014-10-14 11:53:15 -04:00
}
//Keep iterating is when rendering has completed and the user increases the quality.
//Rendering can be started where it left off by adding just the difference between the
//new and old quality values.
2015-12-31 19:00:36 -05:00
else if ( action = = eProcessAction : : KEEP_ITERATING )
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
if ( m_ProcessState = = eProcessState : : ACCUM_DONE & & TemporalSamples ( ) = = 1 )
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : ITER_STARTED ;
m_ProcessAction = eProcessAction : : KEEP_ITERATING ;
2014-10-14 11:53:15 -04:00
}
else //Invaid process state to handle KEEP_ITERATING, so just start over.
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : NONE ;
m_ProcessAction = eProcessAction : : FULL_RENDER ;
2014-10-14 11:53:15 -04:00
}
}
2015-12-31 19:00:36 -05:00
else if ( action = = eProcessAction : : FILTER_AND_ACCUM )
2014-10-14 11:53:15 -04:00
{
//If in the middle of a render, cannot skip to filtering or accum, so just start over.
2015-12-31 19:00:36 -05:00
if ( m_ProcessState = = eProcessState : : NONE | | m_ProcessState = = eProcessState : : ITER_STARTED )
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : NONE ;
m_ProcessAction = eProcessAction : : FULL_RENDER ;
2014-10-14 11:53:15 -04:00
}
2014-11-03 02:16:34 -05:00
//Set the state to ITER_DONE and the next process action to FILTER_AND_ACCUM.
2014-10-14 11:53:15 -04:00
else
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : ITER_DONE ;
m_ProcessAction = eProcessAction : : FILTER_AND_ACCUM ;
2014-10-14 11:53:15 -04:00
}
}
//Run accum only.
2015-12-31 19:00:36 -05:00
else if ( action = = eProcessAction : : ACCUM_ONLY )
2014-10-14 11:53:15 -04:00
{
//Doesn't make sense if in the middle of iterating, so just start over.
2015-12-31 19:00:36 -05:00
if ( m_ProcessState = = eProcessState : : NONE | | m_ProcessState = = eProcessState : : ITER_STARTED )
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessAction = eProcessAction : : FULL_RENDER ;
2014-10-14 11:53:15 -04:00
}
2015-12-31 19:00:36 -05:00
else if ( m_ProcessState = = eProcessState : : ITER_DONE ) //If iterating is done, can start at density filtering and proceed.
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessAction = eProcessAction : : FILTER_AND_ACCUM ;
2014-10-14 11:53:15 -04:00
}
2015-12-31 19:00:36 -05:00
else if ( m_ProcessState = = eProcessState : : FILTER_DONE ) //Density filtering is done, so the process action is assigned as desired.
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessAction = eProcessAction : : ACCUM_ONLY ;
2014-10-14 11:53:15 -04:00
}
2015-12-31 19:00:36 -05:00
else if ( m_ProcessState = = eProcessState : : ACCUM_DONE ) //Final accum is done, so back up and run final accum again.
2014-10-14 11:53:15 -04:00
{
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : FILTER_DONE ;
m_ProcessAction = eProcessAction : : ACCUM_ONLY ;
2014-10-14 11:53:15 -04:00
}
}
LeaveRender ( ) ;
}
/// <summary>
2014-12-09 03:24:28 -05:00
/// Return the amount of memory needed for the histogram.
2014-10-14 11:53:15 -04:00
/// </summary>
2014-12-09 03:24:28 -05:00
/// <returns>The memory required for the histogram to render the current ember</returns>
size_t RendererBase : : HistMemoryRequired ( size_t strips )
2014-10-14 11:53:15 -04:00
{
bool newFilterAlloc = false ;
CreateSpatialFilter ( newFilterAlloc ) ;
CreateTemporalFilter ( newFilterAlloc ) ;
ComputeBounds ( ) ;
//Because ComputeBounds() was called, this includes gutter.
2014-12-09 03:24:28 -05:00
return ( SuperSize ( ) * HistBucketSize ( ) ) / strips ;
}
/// <summary>
/// Return a pair whose first member contains the amount of memory needed for the histogram,
/// and whose second member contains the total the amount of memory needed to render the current ember.
/// Optionally include the memory needed for the final output image in pair.second.
2015-01-19 11:39:50 -05:00
/// Note that the memory required for the final output image will be doubled if threaded writes
/// are used because a copy of the final output is passed to a thread.
2014-12-09 03:24:28 -05:00
/// </summary>
2015-01-19 11:39:50 -05:00
/// <param name="strips">The number of strips being used</param>
2014-12-09 03:24:28 -05:00
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
2015-01-19 11:39:50 -05:00
/// <param name="threadedWrite">Whether the caller will be writing the output in a thread, which doubles the memory required for the final output buffer.</param>
2014-12-09 03:24:28 -05:00
/// <returns>The histogram memory required in first, and the total memory required in second</returns>
2015-01-19 11:39:50 -05:00
pair < size_t , size_t > RendererBase : : MemoryRequired ( size_t strips , bool includeFinal , bool threadedWrite )
2014-12-09 03:24:28 -05:00
{
pair < size_t , size_t > p ;
2015-01-19 11:39:50 -05:00
size_t outSize = includeFinal ? FinalBufferSize ( ) : 0 ;
outSize * = ( threadedWrite ? 2 : 1 ) ;
2014-12-09 03:24:28 -05:00
p . first = HistMemoryRequired ( strips ) ;
2015-01-19 11:39:50 -05:00
p . second = ( p . first * 2 ) + outSize ; //Multiply hist by 2 to account for the density filtering buffer which is the same size as the histogram.
2014-12-09 03:24:28 -05:00
return p ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get a copy of the vector of random contexts.
/// Useful for debugging because the returned vector can be used for future renders to
/// produce the exact same output.
/// </summary>
/// <returns>The vector of random contexts to assign</returns>
vector < QTIsaac < ISAAC_SIZE , ISAAC_INT > > RendererBase : : RandVec ( ) { return m_Rand ; }
/// <summary>
/// Set the vector of random contexts.
/// Assignment will only take place if the size of the vector matches
/// the number of threads used for rendering.
/// Reset the rendering process.
/// </summary>
/// <param name="randVec">The vector of random contexts to assign</param>
/// <returns>True if the size of the vector matched the number of threads used for rendering, else false.</returns>
bool RendererBase : : RandVec ( vector < QTIsaac < ISAAC_SIZE , ISAAC_INT > > & randVec )
{
bool b = false ;
if ( randVec . size ( ) = = ThreadCount ( ) )
{
ChangeVal ( [ & ]
{
m_Rand = randVec ;
b = true ;
2015-12-31 19:00:36 -05:00
} , eProcessAction : : FULL_RENDER ) ;
2014-10-14 11:53:15 -04:00
}
return b ;
}
/// <summary>
/// Resize the passed in vector to be large enough to handle the output image.
/// If m_ReclaimOnResize is true, and the vector is already larger than needed,
/// it will be shrunk to the needed size. However if m_ReclaimOnResize is false,
/// it will be left alone if already large enough.
/// ComputeBounds() must be called before calling this function.
/// </summary>
/// <param name="pixels">The vector to allocate</param>
/// <returns>True if the vector contains enough space to hold the output image</returns>
2014-12-06 00:05:09 -05:00
bool RendererBase : : PrepFinalAccumVector ( vector < byte > & pixels )
2014-10-14 11:53:15 -04:00
{
EnterResize ( ) ;
size_t size = FinalBufferSize ( ) ;
if ( m_ReclaimOnResize )
{
if ( pixels . size ( ) ! = size )
{
pixels . resize ( size ) ;
pixels . shrink_to_fit ( ) ;
}
}
else
{
if ( pixels . size ( ) < size )
pixels . resize ( size ) ;
}
LeaveResize ( ) ;
return pixels . size ( ) > = size ; //Ensure allocation went ok.
}
/// <summary>
/// Virtual processing functions.
/// </summary>
/// <summary>
/// Get a status indicating whether this renderer is ok.
/// Return true for this class, derived classes will inspect GPU hardware
/// to determine if they are ok.
/// </summary>
/// <returns>Always true for this class</returns>
bool RendererBase : : Ok ( ) const
{
return true ;
}
/// <summary>
/// The amount of RAM available to render with.
/// </summary>
/// <returns>An unsigned 64-bit integer specifying how much memory is available</returns>
size_t RendererBase : : MemoryAvailable ( )
{
size_t memAvailable = 0 ;
2016-03-01 20:26:45 -05:00
# ifdef _WIN32
2014-10-14 11:53:15 -04:00
MEMORYSTATUSEX stat ;
stat . dwLength = sizeof ( stat ) ;
GlobalMemoryStatusEx ( & stat ) ;
memAvailable = stat . ullTotalPhys ;
# elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
memAvailable = sysconf ( _SC_PHYS_PAGES ) * sysconf ( _SC_PAGESIZE ) ;
# elif defined __APPLE__
# ifdef __LP64__
long physmem ;
size_t len = sizeof ( physmem ) ;
static int mib [ 2 ] = { CTL_HW , HW_MEMSIZE } ;
# else
size_t physmem ;
size_t len = sizeof ( physmem ) ;
static int mib [ 2 ] = { CTL_HW , HW_PHYSMEM } ;
# endif
if ( sysctl ( mib , 2 , & physmem , & len , nullptr , 0 ) = = 0 & & len = = sizeof ( physmem ) )
{
memAvailable = physmem ;
}
else
{
2016-02-12 00:38:21 -05:00
cout < < " Warning: unable to determine physical memory. \n " ;
2014-10-14 11:53:15 -04:00
memAvailable = 4e9 ;
}
# else
2016-02-12 00:38:21 -05:00
cout < < " Warning: unable to determine physical memory. \n " ;
2014-10-14 11:53:15 -04:00
memAvailable = 4e9 ;
# endif
return memAvailable ;
}
/// <summary>
/// Non-virtual renderer properties, getters only.
/// </summary>
2014-10-18 15:56:37 -04:00
size_t RendererBase : : SuperRasW ( ) const { return m_SuperRasW ; }
size_t RendererBase : : SuperRasH ( ) const { return m_SuperRasH ; }
size_t RendererBase : : SuperSize ( ) const { return m_SuperSize ; }
size_t RendererBase : : FinalRowSize ( ) const { return FinalRasW ( ) * PixelSize ( ) ; }
size_t RendererBase : : FinalDimensions ( ) const { return FinalRasW ( ) * FinalRasH ( ) ; }
size_t RendererBase : : FinalBufferSize ( ) const { return FinalRowSize ( ) * FinalRasH ( ) ; }
size_t RendererBase : : PixelSize ( ) const { return NumChannels ( ) * BytesPerChannel ( ) ; }
size_t RendererBase : : GutterWidth ( ) const { return m_GutterWidth ; }
size_t RendererBase : : DensityFilterOffset ( ) const { return m_DensityFilterOffset ; }
2014-12-07 02:51:44 -05:00
size_t RendererBase : : TotalIterCount ( size_t strips ) const { return size_t ( size_t ( Round ( ScaledQuality ( ) ) ) * FinalRasW ( ) * FinalRasH ( ) * strips ) ; } //Use Round() because there can be some roundoff error when interpolating.
size_t RendererBase : : ItersPerTemporalSample ( ) const { return size_t ( ceil ( double ( TotalIterCount ( 1 ) ) / double ( TemporalSamples ( ) ) ) ) ; } //Temporal samples is used with animation, which doesn't support strips, so pass 1.
2014-10-18 15:56:37 -04:00
eProcessState RendererBase : : ProcessState ( ) const { return m_ProcessState ; }
eProcessAction RendererBase : : ProcessAction ( ) const { return m_ProcessAction ; }
EmberStats RendererBase : : Stats ( ) const { return m_Stats ; }
2014-10-14 11:53:15 -04:00
/// <summary>
/// Non-virtual render properties, getters and setters.
/// </summary>
/// <summary>
/// Get whether the histogram is locked during accumulation.
/// This is to prevent two threads from writing to the same histogram
/// bucket at once.
/// The current implementation matches flam3 and is very innefficient
/// to the point of negating any gains gotten from multi-threading.
/// Future workarounds may be tried in the future.
/// Default: false.
/// </summary>
/// <returns>True if the histogram is locked during accumulation, else false.</returns>
bool RendererBase : : LockAccum ( ) const { return m_LockAccum ; }
/// <summary>
/// Set whether the histogram is locked during accumulation.
/// This is to prevent two threads from writing to the same histogram
/// bucket at once.
/// The current implementation matches flam3 and is very innefficient
/// to the point of negating any gains gotten from multi-threading.
/// Different workarounds may be tried in the future.
/// Reset the rendering process.
/// </summary>
/// <param name="lockAccum">True if the histogram should be locked when accumulating, else false</param>
void RendererBase : : LockAccum ( bool lockAccum )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_LockAccum = lockAccum ; } , eProcessAction : : FULL_RENDER ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get whether color clipping and gamma correction is done before
/// or after spatial filtering.
/// Default: false.
/// </summary>
/// <returns>True if early clip, else false.</returns>
bool RendererBase : : EarlyClip ( ) const { return m_EarlyClip ; }
/// <summary>
/// Set whether color clipping and gamma correction is done before
/// or after spatial filtering.
/// Set the render state to FILTER_AND_ACCUM.
/// </summary>
/// <param name="earlyClip">True if early clip, else false.</param>
void RendererBase : : EarlyClip ( bool earlyClip )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_EarlyClip = earlyClip ; } , eProcessAction : : FILTER_AND_ACCUM ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get whether the positive Y coordinate of the final output image is up.
/// Default: false.
/// </summary>
/// <returns>True if up, else false.</returns>
bool RendererBase : : YAxisUp ( ) const { return m_YAxisUp ; }
/// <summary>
/// Set whether the positive Y axis of the final output image is up.
/// </summary>
/// <param name="yup">True if the positive y axis is up, else false.</param>
void RendererBase : : YAxisUp ( bool yup )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_YAxisUp = yup ; } , eProcessAction : : ACCUM_ONLY ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get whether to insert the palette as a block of colors in the final output image.
/// This is useful for debugging palette issues.
/// Default: 1.
/// </summary>
/// <returns>True if inserting the palette, else false.</returns>
bool RendererBase : : InsertPalette ( ) const { return m_InsertPalette ; }
/// <summary>
/// Set whether to insert the palette as a block of colors in the final output image.
/// This is useful for debugging palette issues.
/// Set the render state to ACCUM_ONLY.
/// </summary>
/// <param name="insertPalette">True if inserting the palette, else false.</param>
void RendererBase : : InsertPalette ( bool insertPalette )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_InsertPalette = insertPalette ; } , eProcessAction : : ACCUM_ONLY ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get whether to reclaim unused memory in the final output buffer
/// when a smaller size is requested than has been previously allocated.
/// Default: false.
/// </summary>
/// <returns>True if reclaim, else false.</returns>
bool RendererBase : : ReclaimOnResize ( ) const { return m_ReclaimOnResize ; }
/// <summary>
/// Set whether to reclaim unused memory in the final output buffer
/// when a smaller size is requested than has been previously allocated.
/// Reset the rendering process.
/// </summary>
/// <param name="reclaimOnResize">True if reclaim, else false.</param>
void RendererBase : : ReclaimOnResize ( bool reclaimOnResize )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_ReclaimOnResize = reclaimOnResize ; } , eProcessAction : : FULL_RENDER ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get whether to use transparency in the alpha channel.
/// This only applies when the number of channels is 4 and the output
/// image is Png.
/// Default: false.
/// </summary>
/// <returns>True if using transparency, else false.</returns>
bool RendererBase : : Transparency ( ) const { return m_Transparency ; }
/// <summary>
/// Set whether to use transparency in the alpha channel.
/// This only applies when the number of channels is 4 and the output
/// image is Png.
/// Set the render state to ACCUM_ONLY.
/// </summary>
/// <param name="transparency">True if using transparency, else false.</param>
void RendererBase : : Transparency ( bool transparency )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_Transparency = transparency ; } , eProcessAction : : ACCUM_ONLY ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Set the callback object.
/// </summary>
/// <param name="callback">The callback object to set</param>
void RendererBase : : Callback ( RenderCallback * callback )
{
m_Callback = callback ;
}
/// <summary>
/// Set the number of threads to use when rendering.
/// This will also reset the vector of random contexts to be the same size
/// as the number of specified threads.
/// Since this is where they get set up, the caller can optionally pass in
/// a seed string, however it's only used if threads is 1.
/// This is useful for debugging since it will run the same point trajectory
/// every time.
/// Reset the rendering process.
/// </summary>
/// <param name="threads">The number of threads to use</param>
/// <param name="seedString">The seed string to use if threads is 1. Default: nullptr.</param>
void RendererBase : : ThreadCount ( size_t threads , const char * seedString )
{
ChangeVal ( [ & ]
{
Timing t ;
size_t i , size ;
const size_t isaacSize = 1 < < ISAAC_SIZE ;
ISAAC_INT seeds [ isaacSize ] ;
m_ThreadsToUse = threads > 0 ? threads : 1 ;
m_Rand . clear ( ) ;
m_SubBatch . clear ( ) ;
m_SubBatch . resize ( m_ThreadsToUse ) ;
m_BadVals . resize ( m_ThreadsToUse ) ;
if ( seedString )
{
memset ( seeds , 0 , isaacSize * sizeof ( ISAAC_INT ) ) ;
2015-03-21 18:27:37 -04:00
memcpy ( reinterpret_cast < char * > ( seeds ) , seedString , std : : min ( strlen ( seedString ) , isaacSize * sizeof ( ISAAC_INT ) ) ) ;
2014-10-14 11:53:15 -04:00
}
//This is critical for multithreading, otherwise the threads all happen
//too close to each other in time, resulting in bad randomization.
while ( m_Rand . size ( ) < m_ThreadsToUse )
{
size = m_Rand . size ( ) ;
if ( seedString )
{
2014-12-07 02:51:44 -05:00
ISAAC_INT newSize = ISAAC_INT ( size + 5 + ( t . Toc ( ) + t . EndTime ( ) ) ) ;
2014-10-14 11:53:15 -04:00
# ifdef ISAAC_FLAM3_DEBUG
QTIsaac < ISAAC_SIZE , ISAAC_INT > isaac ( 0 , 0 , 0 , seeds ) ;
# else
QTIsaac < ISAAC_SIZE , ISAAC_INT > isaac ( newSize , newSize * 2 , newSize * 3 , seeds ) ;
# endif
m_Rand . push_back ( isaac ) ;
for ( i = 0 ; i < ( isaacSize * sizeof ( ISAAC_INT ) ) ; i + + )
2014-12-07 02:51:44 -05:00
reinterpret_cast < byte * > ( seeds ) [ i ] + + ;
2014-10-14 11:53:15 -04:00
}
else
{
for ( i = 0 ; i < isaacSize ; i + + )
{
t . Toc ( ) ;
2014-12-07 02:51:44 -05:00
seeds [ i ] = ISAAC_INT ( ( t . EndTime ( ) * i ) + ( size + 1 ) ) ;
2014-10-14 11:53:15 -04:00
}
t . Toc ( ) ;
2014-12-07 02:51:44 -05:00
ISAAC_INT r = ISAAC_INT ( ( size * i ) + i + t . EndTime ( ) ) ;
2014-10-14 11:53:15 -04:00
QTIsaac < ISAAC_SIZE , ISAAC_INT > isaac ( r , r * 2 , r * 3 , seeds ) ;
m_Rand . push_back ( isaac ) ;
}
}
2015-12-31 19:00:36 -05:00
} , eProcessAction : : FULL_RENDER ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get the bytes per channel of the output image.
/// The only acceptable values are 1 and 2, and 2 is only
/// used when the output is Png.
/// Default: 1.
/// </summary>
/// <returns></returns>
size_t RendererBase : : BytesPerChannel ( ) const { return m_BytesPerChannel ; }
/// <summary>
/// Set the bytes per channel of the output image.
/// The only acceptable values are 1 and 2, and 2 is only
/// used when the output is Png.
/// Set the render state to ACCUM_ONLY.
/// </summary>
/// <param name="bytesPerChannel">The bytes per channel.</param>
void RendererBase : : BytesPerChannel ( size_t bytesPerChannel )
{
ChangeVal ( [ & ]
{
if ( bytesPerChannel = = 0 | | bytesPerChannel > 2 )
m_BytesPerChannel = 1 ;
else
m_BytesPerChannel = bytesPerChannel ;
2015-12-31 19:00:36 -05:00
} , eProcessAction : : ACCUM_ONLY ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get the number of channels per pixel in the output image. 3 for RGB images
/// like Bitmap and Jpeg, 4 for Png.
/// Default is 3.
/// </summary>
/// <returns>The number of channels per pixel in the output image</returns>
size_t RendererBase : : NumChannels ( ) const { return m_NumChannels ; }
2015-05-31 01:14:34 -04:00
/// <summary>
/// Get/set the priority used for the CPU rendering threads.
/// This does not affect OpenCL rendering.
/// </summary>
/// <param name="priority">The priority to use for the CPU rendering threads</param>
eThreadPriority RendererBase : : Priority ( ) const { return m_Priority ; }
void RendererBase : : Priority ( eThreadPriority priority ) { m_Priority = priority ; }
2014-10-14 11:53:15 -04:00
/// <summary>
/// Get the type of filter to use for preview renders during interactive rendering.
/// Using basic log scaling is quicker, but doesn't provide any bluring.
/// Full DE is much slower, but provides a more realistic preview of what the final image
/// will look like.
/// Default: FILTER_LOG.
/// </summary>
/// <returns>The type of filter to use</returns>
eInteractiveFilter RendererBase : : InteractiveFilter ( ) const { return m_InteractiveFilter ; }
/// <summary>
/// Set the type of filter to use for preview renders during interactive rendering.
/// Using basic log scaling is quicker, but doesn't provide any bluring.
/// Full DE is much slower, but provides a more realistic preview of what the final image
/// will look like.
/// Reset the rendering process.
/// </summary>
/// <param name="filter">The filter.</param>
void RendererBase : : InteractiveFilter ( eInteractiveFilter filter )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_InteractiveFilter = filter ; } , eProcessAction : : FULL_RENDER ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Virtual render properties, getters and setters.
/// </summary>
/// <summary>
/// Set the number of channels per pixel in the output image. 3 for RGB images
/// like Bitmap and Jpeg, 4 for Png.
/// Default is 3.
/// Set the render state to ACCUM_ONLY.
/// </summary>
/// <param name="numChannels">The number of channels per pixel in the output image</param>
void RendererBase : : NumChannels ( size_t numChannels )
{
2015-12-31 19:00:36 -05:00
ChangeVal ( [ & ] { m_NumChannels = numChannels ; } , eProcessAction : : ACCUM_ONLY ) ;
2014-10-14 11:53:15 -04:00
}
/// <summary>
/// Get the number of threads used when rendering.
/// Default: use all avaliable cores.
/// </summary>
/// <returns>The number of threads used when rendering</returns>
size_t RendererBase : : ThreadCount ( ) const { return m_ThreadsToUse ; }
/// <summary>
/// Get the renderer type enum.
2016-01-04 19:50:15 -05:00
/// eRendererType::CPU_RENDERER for this class, other values for derived classes.
2014-10-14 11:53:15 -04:00
/// </summary>
2016-01-04 19:50:15 -05:00
/// <returns>eRendererType::CPU_RENDERER</returns>
eRendererType RendererBase : : RendererType ( ) const { return eRendererType : : CPU_RENDERER ; }
2014-10-14 11:53:15 -04:00
/// <summary>
/// //Non-virtual threading control.
/// </summary>
/// <summary>
/// Stop rendering, ensure all locks are exited and reset the rendering state.
/// </summary>
void RendererBase : : Reset ( )
{
Abort ( ) ;
EnterRender ( ) ;
EnterFinalAccum ( ) ;
LeaveFinalAccum ( ) ;
LeaveRender ( ) ;
2015-12-31 19:00:36 -05:00
m_ProcessState = eProcessState : : NONE ;
m_ProcessAction = eProcessAction : : FULL_RENDER ;
2014-10-14 11:53:15 -04:00
}
2016-02-12 00:38:21 -05:00
void RendererBase : : EnterRender ( ) { m_RenderingCs . lock ( ) ; }
void RendererBase : : LeaveRender ( ) { m_RenderingCs . unlock ( ) ; }
2014-10-14 11:53:15 -04:00
2016-02-12 00:38:21 -05:00
void RendererBase : : EnterFinalAccum ( ) { m_FinalAccumCs . lock ( ) ; m_InFinalAccum = true ; }
void RendererBase : : LeaveFinalAccum ( ) { m_FinalAccumCs . unlock ( ) ; m_InFinalAccum = false ; }
2014-10-14 11:53:15 -04:00
2016-02-12 00:38:21 -05:00
void RendererBase : : EnterResize ( ) { m_ResizeCs . lock ( ) ; }
void RendererBase : : LeaveResize ( ) { m_ResizeCs . unlock ( ) ; }
2014-10-14 11:53:15 -04:00
void RendererBase : : Abort ( ) { m_Abort = true ; }
bool RendererBase : : Aborted ( ) { return m_Abort ; }
bool RendererBase : : InRender ( ) { return m_InRender ; }
bool RendererBase : : InFinalAccum ( ) { return m_InFinalAccum ; }
2014-12-07 02:51:44 -05:00
}