fractorium/Source/Ember/RendererBase.h
2024-01-30 14:24:56 -07:00

238 lines
8.4 KiB
C++

#pragma once
#include "Utils.h"
#include "Ember.h"
#include "DensityFilter.h"
/// <summary>
/// RendererBase, RenderCallback and EmberStats classes.
/// </summary>
namespace EmberNs
{
/// <summary>
/// Function pointers present a major restriction when dealing
/// with member functions, and that is they can only point to
/// static ones. So instead of a straight function pointer, use
/// a callback class with a single virtual callback
/// member function.
/// Template argument expected to be float or double.
/// </summary>
class EMBER_API RenderCallback
{
public:
RenderCallback() = default;
RenderCallback(RenderCallback& callback) = delete;
/// <summary>
/// Virtual destructor to ensure anything declared in derived classes gets cleaned up.
/// </summary>
virtual ~RenderCallback() = default;
/// <summary>
/// Empty progress function to be implemented in derived classes to take action on progress updates.
/// </summary>
/// <param name="ember">The ember currently being rendered</param>
/// <param name="foo">An extra dummy parameter</param>
/// <param name="fraction">The progress fraction from 0-100</param>
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
/// <returns>Override should return 0 if an abort is requested, else 1 to continue rendering</returns>
virtual int ProgressFunc(Ember<float>& ember, void* foo, double fraction, int stage, double etaMs) { return 0; }
virtual int ProgressFunc(Ember<double>& ember, void* foo, double fraction, int stage, double etaMs) { return 0; }
};
/// <summary>
/// Render statistics for the number of iterations ran,
/// number of bad values calculated during iteration, and
/// the total time for the entire render from the start of
/// iteration to the end of final accumulation.
/// </summary>
class EMBER_API EmberStats
{
public:
/// <summary>
/// Constructor which sets all values to 0.
/// </summary>
EmberStats() noexcept
{
Clear();
}
void Clear() noexcept
{
m_Success = true;
m_Iters = 0;
m_Badvals = 0;
m_IterMs = 0;
m_RenderMs = 0;
}
EmberStats& operator += (const EmberStats& stats) noexcept
{
m_Success &= stats.m_Success;
m_Iters += stats.m_Iters;
m_Badvals += stats.m_Badvals;
m_IterMs += stats.m_IterMs;
m_RenderMs += stats.m_RenderMs;
return *this;
}
bool m_Success = true;
size_t m_Iters, m_Badvals;
double m_IterMs, m_RenderMs;
};
/// <summary>
/// The types of available renderers.
/// Add more in the future as different rendering methods are experimented with.
/// Possible values might be: CPU+OpenGL, Particle, Inverse.
/// </summary>
enum class eRendererType : et { CPU_RENDERER, OPENCL_RENDERER };
/// <summary>
/// A base class with virtual functions to allow both templating and polymorphism to work together.
/// Derived classes will implement all of these functions.
/// Note that functions which return a decimal number use the most precise type, double.
/// </summary>
class EMBER_API RendererBase : public EmberReport
{
public:
RendererBase();
RendererBase(const RendererBase& renderer) = delete;
RendererBase& operator = (const RendererBase& renderer) = delete;
virtual ~RendererBase() = default;
//Non-virtual processing functions.
void ChangeVal(std::function<void(void)> func, eProcessAction action);
size_t HistMemoryRequired(size_t strips);
pair<size_t, size_t> MemoryRequired(size_t strips, bool includeFinal, bool threadedWrite);
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> RandVec();
bool PrepFinalAccumVector(vector<v4F>& pixels);
//Virtual processing functions.
virtual bool Ok() const;
virtual size_t MemoryAvailable();
virtual void SetEmber(const Ember<float>& ember, eProcessAction action = eProcessAction::FULL_RENDER, bool prep = false) { }
virtual void SetEmber(const Ember<double>& ember, eProcessAction action = eProcessAction::FULL_RENDER, bool prep = false) { }
virtual bool RandVec(vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>>& randVec);
//Abstract processing functions.
virtual bool CreateDEFilter(bool& newAlloc) = 0;
virtual bool CreateSpatialFilter(bool& newAlloc) = 0;
virtual bool CreateTemporalFilter(bool& newAlloc) = 0;
virtual void Prepare() = 0;
virtual void ComputeBounds() = 0;
virtual void ComputeQuality() = 0;
virtual void ComputeCamera() = 0;
virtual eRenderStatus Run(vector<v4F>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) = 0;
virtual EmberImageComments ImageComments(const EmberStats& stats, size_t printEditDepth = 0, bool hexPalette = true) = 0;
virtual DensityFilterBase* GetDensityFilter() = 0;
//Non-virtual renderer properties, getters only.
size_t SuperRasW() const;
size_t SuperRasH() const;
size_t SuperSize() const;
size_t FinalRowSize() const;
size_t FinalDimensions() const;
size_t FinalBufferSize() const;
size_t PixelSize() const;
size_t GutterWidth() const;
size_t DensityFilterOffset() const;
size_t TotalIterCount(size_t strips) const;
size_t ItersPerTemporalSample() const;
eProcessState ProcessState() const;
eProcessAction ProcessAction() const;
EmberStats Stats() const;
//Non-virtual render getters and setters.
bool LockAccum() const;
void LockAccum(bool lockAccum);
bool EarlyClip() const;
void EarlyClip(bool earlyClip);
bool YAxisUp() const;
void YAxisUp(bool yup);
bool InsertPalette() const;
void InsertPalette(bool insertPalette);
bool ReclaimOnResize() const;
void ReclaimOnResize(bool reclaimOnResize);
void Callback(RenderCallback* callback);
void ThreadCount(size_t threads, const char* seedString = nullptr);
size_t BytesPerChannel() const;
size_t NumChannels() const;
eThreadPriority Priority() const;
void Priority(eThreadPriority priority);
eInteractiveFilter InteractiveFilter() const;
void InteractiveFilter(eInteractiveFilter filter);
//Virtual render properties, getters and setters.
virtual size_t ThreadCount() const;
virtual eRendererType RendererType() const;
virtual bool Shared() const;
//Abstract render properties, getters only.
virtual size_t TemporalSamples() const = 0;
virtual size_t HistBucketSize() const = 0;
virtual size_t FinalRasW() const = 0;
virtual size_t FinalRasH() const = 0;
virtual size_t SubBatchSize() const = 0;
virtual size_t FuseCount() const = 0;
virtual double ScaledQuality() const = 0;
virtual double LowerLeftX(bool gutter = true) const = 0;
virtual double LowerLeftY(bool gutter = true) const = 0;
virtual double UpperRightX(bool gutter = true) const = 0;
virtual double UpperRightY(bool gutter = true) const = 0;
//Non-virtual threading control.
void Reset();
void EnterRender();
void LeaveRender();
void EnterFinalAccum();
void LeaveFinalAccum();
void EnterResize();
void LeaveResize();
void Abort();
bool Aborted();
void Pause(bool pause);
bool Paused();
bool InRender();
bool InFinalAccum();
void* m_ProgressParameter = nullptr;
protected:
bool m_EarlyClip = false;
bool m_YAxisUp = false;
bool m_LockAccum = false;
bool m_InRender = false;
bool m_InFinalAccum = false;
bool m_InsertPalette = false;
bool m_ReclaimOnResize = false;
bool m_CurvesSet = false;
volatile bool m_Abort = false;
volatile bool m_Pause = false;
size_t m_SuperRasW;
size_t m_SuperRasH;
size_t m_SuperSize = 0;
size_t m_GutterWidth;
size_t m_DensityFilterOffset;
size_t m_NumChannels = 4;
size_t m_BytesPerChannel = 4;
size_t m_ThreadsToUse;
size_t m_VibGamCount;
size_t m_LastTemporalSample = 0;
size_t m_LastIter = 0;
double m_LastIterPercent = 0;
eThreadPriority m_Priority = eThreadPriority::NORMAL;
eProcessAction m_ProcessAction = eProcessAction::FULL_RENDER;
eProcessState m_ProcessState = eProcessState::NONE;
eInteractiveFilter m_InteractiveFilter = eInteractiveFilter::FILTER_LOG;
EmberStats m_Stats;
RenderCallback* m_Callback = nullptr;
vector<size_t> m_SubBatch;
vector<size_t> m_BadVals;
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> m_Rand;
std::recursive_mutex m_RenderingCs, m_AccumCs, m_FinalAccumCs, m_ResizeCs;
Timing m_RenderTimer, m_IterTimer, m_ProgressTimer;
};
}