mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-01-21 21:20:07 -05:00
Report memory required in final render dialog.
Fix broken state of ember during failed render with strips.
This commit is contained in:
parent
9263906cb5
commit
3e70b8eec6
@ -1,3 +1,15 @@
|
|||||||
|
--User changes
|
||||||
|
Use actual strips count when computing memory requirements in the final render dialog.
|
||||||
|
Output CL_DEVICE_ADDRESS_BITS when passing --openclinfo to command line programs.
|
||||||
|
Warn if single/total allocations are greater than the max allowed for OpenCL in the final render dialog.
|
||||||
|
|
||||||
|
--Bug Fixes
|
||||||
|
Fix bad values left in an ember when a render with strips > 1 fails in the final render dialog.
|
||||||
|
|
||||||
|
--Code Changes
|
||||||
|
Break RendererBase::MemoryRequired() into two functions, it and HistMemRequired() and return a tuple.
|
||||||
|
Add GlobalMemSize() and MaxAllocSize() functions in OpenCLWrapper.
|
||||||
|
|
||||||
0.4.1.6 Beta 11/29/2014
|
0.4.1.6 Beta 11/29/2014
|
||||||
--User Changes
|
--User Changes
|
||||||
None.
|
None.
|
||||||
|
@ -116,12 +116,10 @@ void RendererBase::ChangeVal(std::function<void(void)> func, eProcessAction acti
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return the amount of memory needed to render the current ember.
|
/// Return the amount of memory needed for the histogram.
|
||||||
/// Optionally include the memory needed for the final output image.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
|
/// <returns>The memory required for the histogram to render the current ember</returns>
|
||||||
/// <returns>The memory required to render the current ember</returns>
|
size_t RendererBase::HistMemoryRequired(size_t strips)
|
||||||
size_t RendererBase::MemoryRequired(size_t strips, bool includeFinal)
|
|
||||||
{
|
{
|
||||||
bool newFilterAlloc = false;
|
bool newFilterAlloc = false;
|
||||||
|
|
||||||
@ -130,9 +128,24 @@ size_t RendererBase::MemoryRequired(size_t strips, bool includeFinal)
|
|||||||
ComputeBounds();
|
ComputeBounds();
|
||||||
|
|
||||||
//Because ComputeBounds() was called, this includes gutter.
|
//Because ComputeBounds() was called, this includes gutter.
|
||||||
size_t histSize = (SuperSize() * HistBucketSize()) / strips;
|
return (SuperSize() * HistBucketSize()) / strips;
|
||||||
|
}
|
||||||
|
|
||||||
return (histSize * 2) + (includeFinal ? FinalBufferSize() : 0);//Multiply hist by 2 to account for the density filtering buffer which is the same size as the histogram.
|
/// <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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
|
||||||
|
/// <returns>The histogram memory required in first, and the total memory required in second</returns>
|
||||||
|
pair<size_t, size_t> RendererBase::MemoryRequired(size_t strips, bool includeFinal)
|
||||||
|
{
|
||||||
|
pair<size_t, size_t> p;
|
||||||
|
|
||||||
|
p.first = HistMemoryRequired(strips);
|
||||||
|
p.second = (p.first * 2) + (includeFinal ? FinalBufferSize() : 0);//Multiply hist by 2 to account for the density filtering buffer which is the same size as the histogram.
|
||||||
|
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -98,7 +98,8 @@ public:
|
|||||||
|
|
||||||
//Non-virtual processing functions.
|
//Non-virtual processing functions.
|
||||||
void ChangeVal(std::function<void(void)> func, eProcessAction action);
|
void ChangeVal(std::function<void(void)> func, eProcessAction action);
|
||||||
size_t MemoryRequired(size_t strips, bool includeFinal);
|
size_t HistMemoryRequired(size_t strips);
|
||||||
|
pair<size_t, size_t> MemoryRequired(size_t strips, bool includeFinal);
|
||||||
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> RandVec();
|
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> RandVec();
|
||||||
bool PrepFinalAccumVector(vector<byte>& pixels);
|
bool PrepFinalAccumVector(vector<byte>& pixels);
|
||||||
|
|
||||||
|
@ -554,13 +554,13 @@ int OpenCLWrapper::FindImageIndex(const string& name, bool shared)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_GLImages.size(); i++)
|
for (size_t i = 0; i < m_GLImages.size(); i++)
|
||||||
if (m_GLImages[i].m_Name == name)
|
if (m_GLImages[i].m_Name == name)
|
||||||
return i;
|
return int(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_Images.size(); i++)
|
for (size_t i = 0; i < m_Images.size(); i++)
|
||||||
if (m_Images[i].m_Name == name)
|
if (m_Images[i].m_Name == name)
|
||||||
return i;
|
return int(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -966,7 +966,7 @@ bool OpenCLWrapper::RunKernel(uint kernelIndex, uint totalGridWidth, uint totalG
|
|||||||
/// <param name="name">The device field/feature to query</param>
|
/// <param name="name">The device field/feature to query</param>
|
||||||
/// <returns>The value of the field</returns>
|
/// <returns>The value of the field</returns>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T OpenCLWrapper::GetInfo(size_t platform, size_t device, cl_device_info name)
|
T OpenCLWrapper::GetInfo(size_t platform, size_t device, cl_device_info name) const
|
||||||
{
|
{
|
||||||
T val;
|
T val;
|
||||||
|
|
||||||
@ -1094,6 +1094,7 @@ string OpenCLWrapper::DumpInfo()
|
|||||||
os << "CL_DEVICE_MAX_READ_IMAGE_ARGS: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_MAX_READ_IMAGE_ARGS) << endl;
|
os << "CL_DEVICE_MAX_READ_IMAGE_ARGS: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_MAX_READ_IMAGE_ARGS) << endl;
|
||||||
os << "CL_DEVICE_MAX_WRITE_IMAGE_ARGS: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS) << endl;
|
os << "CL_DEVICE_MAX_WRITE_IMAGE_ARGS: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS) << endl;
|
||||||
os << "CL_DEVICE_MAX_MEM_ALLOC_SIZE: " << GetInfo<cl_ulong>(platform, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE) << endl;
|
os << "CL_DEVICE_MAX_MEM_ALLOC_SIZE: " << GetInfo<cl_ulong>(platform, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE) << endl;
|
||||||
|
os << "CL_DEVICE_ADDRESS_BITS: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_ADDRESS_BITS) << endl;
|
||||||
|
|
||||||
os << "CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE) << endl;
|
os << "CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE) << endl;
|
||||||
os << "CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE) << endl;
|
os << "CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: " << GetInfo<cl_uint> (platform, device, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE) << endl;
|
||||||
@ -1126,7 +1127,9 @@ bool OpenCLWrapper::Shared() const { return m_Shared; }
|
|||||||
cl::Context OpenCLWrapper::Context() const { return m_Context; }
|
cl::Context OpenCLWrapper::Context() const { return m_Context; }
|
||||||
uint OpenCLWrapper::PlatformIndex() const { return m_PlatformIndex; }
|
uint OpenCLWrapper::PlatformIndex() const { return m_PlatformIndex; }
|
||||||
uint OpenCLWrapper::DeviceIndex() const { return m_DeviceIndex; }
|
uint OpenCLWrapper::DeviceIndex() const { return m_DeviceIndex; }
|
||||||
|
size_t OpenCLWrapper::GlobalMemSize() const { return GetInfo<cl_ulong>(PlatformIndex(), DeviceIndex(), CL_DEVICE_GLOBAL_MEM_SIZE); }
|
||||||
uint OpenCLWrapper::LocalMemSize() const { return m_LocalMemSize; }
|
uint OpenCLWrapper::LocalMemSize() const { return m_LocalMemSize; }
|
||||||
|
size_t OpenCLWrapper::MaxAllocSize() const { return GetInfo<cl_ulong>(PlatformIndex(), DeviceIndex(), CL_DEVICE_MAX_MEM_ALLOC_SIZE); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Makes the even grid dims.
|
/// Makes the even grid dims.
|
||||||
|
@ -175,7 +175,7 @@ public:
|
|||||||
|
|
||||||
//Info.
|
//Info.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T GetInfo(size_t platform, size_t device, cl_device_info name);
|
T GetInfo(size_t platform, size_t device, cl_device_info name) const;
|
||||||
string PlatformName(size_t platform);
|
string PlatformName(size_t platform);
|
||||||
vector<string> PlatformNames();
|
vector<string> PlatformNames();
|
||||||
string DeviceName(size_t platform, size_t device);
|
string DeviceName(size_t platform, size_t device);
|
||||||
@ -190,6 +190,8 @@ public:
|
|||||||
uint PlatformIndex() const;
|
uint PlatformIndex() const;
|
||||||
uint DeviceIndex() const;
|
uint DeviceIndex() const;
|
||||||
uint LocalMemSize() const;
|
uint LocalMemSize() const;
|
||||||
|
size_t GlobalMemSize() const;
|
||||||
|
size_t MaxAllocSize() const;
|
||||||
|
|
||||||
static void MakeEvenGridDims(uint blockW, uint blockH, uint& gridW, uint& gridH);
|
static void MakeEvenGridDims(uint blockW, uint blockH, uint& gridW, uint& gridH);
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ static bool StripsRender(RendererBase* renderer, Ember<T>& ember, vector<byte>&
|
|||||||
std::function<void(size_t strip)> perStripError,
|
std::function<void(size_t strip)> perStripError,
|
||||||
std::function<void(Ember<T>& finalEmber)> allStripsFinished)
|
std::function<void(Ember<T>& finalEmber)> allStripsFinished)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = false;
|
||||||
size_t origHeight, realHeight = ember.m_FinalRasH;
|
size_t origHeight, realHeight = ember.m_FinalRasH;
|
||||||
T centerY = ember.m_CenterY;
|
T centerY = ember.m_CenterY;
|
||||||
T floatStripH = T(ember.m_FinalRasH) / T(strips);
|
T floatStripH = T(ember.m_FinalRasH) / T(strips);
|
||||||
@ -321,31 +321,28 @@ static bool StripsRender(RendererBase* renderer, Ember<T>& ember, vector<byte>&
|
|||||||
renderer->SetEmber(ember);//Set one final time after modifications for strips.
|
renderer->SetEmber(ember);//Set one final time after modifications for strips.
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((renderer->Run(finalImage, time, 0, false, stripOffset) != RENDER_OK) || renderer->Aborted() || finalImage.empty())
|
if ((renderer->Run(finalImage, time, 0, false, stripOffset) == RENDER_OK) && !renderer->Aborted() && !finalImage.empty())
|
||||||
{
|
|
||||||
perStripError(strip);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
perStripFinish(strip);
|
perStripFinish(strip);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perStripError(strip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (strip == strips - 1)
|
if (strip == strips - 1)
|
||||||
{
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
//Restore the ember values to their original values.
|
//Restore the ember values to their original values.
|
||||||
if (strips > 1)
|
|
||||||
{
|
|
||||||
ember.m_Quality /= strips;
|
ember.m_Quality /= strips;
|
||||||
ember.m_FinalRasH = realHeight;
|
ember.m_FinalRasH = realHeight;
|
||||||
ember.m_CenterY = centerY;
|
ember.m_CenterY = centerY;
|
||||||
renderer->SetEmber(ember);//Further processing will require the dimensions to match the original ember, so re-assign.
|
renderer->SetEmber(ember);//Further processing will require the dimensions to match the original ember, so re-assign.
|
||||||
}
|
|
||||||
|
|
||||||
|
if (success)
|
||||||
allStripsFinished(ember);
|
allStripsFinished(ember);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Memset(finalImage);
|
Memset(finalImage);
|
||||||
|
|
||||||
|
@ -330,6 +330,7 @@ int _tmain(int argc, _TCHAR* argv[])
|
|||||||
//This must be done in the application and not in the EmberCL DLL.
|
//This must be done in the application and not in the EmberCL DLL.
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
_putenv_s("GPU_MAX_ALLOC_PERCENT", "100");
|
_putenv_s("GPU_MAX_ALLOC_PERCENT", "100");
|
||||||
|
//_putenv_s("GPU_FORCE_64BIT_PTR", "1");
|
||||||
#else
|
#else
|
||||||
putenv(const_cast<char*>("GPU_MAX_ALLOC_PERCENT=100"));
|
putenv(const_cast<char*>("GPU_MAX_ALLOC_PERCENT=100"));
|
||||||
#endif
|
#endif
|
||||||
|
@ -708,10 +708,48 @@ bool FractoriumFinalRenderDialog::SetMemory()
|
|||||||
{
|
{
|
||||||
if (isVisible() && CreateControllerFromGUI(true))
|
if (isVisible() && CreateControllerFromGUI(true))
|
||||||
{
|
{
|
||||||
pair<size_t, size_t> p = m_Controller->SyncAndComputeMemory();
|
bool error = false;
|
||||||
|
tuple<size_t, size_t, size_t> p = m_Controller->SyncAndComputeMemory();
|
||||||
|
|
||||||
|
ui.FinalRenderParamsTable->item(m_MemoryCellIndex, 1)->setText(ToString(get<1>(p)));
|
||||||
|
ui.FinalRenderParamsTable->item(m_ItersCellIndex, 1)->setText(ToString(get<2>(p)));
|
||||||
|
|
||||||
|
if (OpenCL())
|
||||||
|
{
|
||||||
|
if (!m_Wrapper.Ok() || PlatformIndex() != m_Wrapper.PlatformIndex() || DeviceIndex() != m_Wrapper.DeviceIndex())
|
||||||
|
m_Wrapper.Init(PlatformIndex(), DeviceIndex());
|
||||||
|
|
||||||
|
if (m_Wrapper.Ok())
|
||||||
|
{
|
||||||
|
size_t histSize = get<0>(p);
|
||||||
|
size_t totalSize = get<1>(p);
|
||||||
|
size_t maxAlloc = m_Wrapper.MaxAllocSize();
|
||||||
|
size_t totalAvail = m_Wrapper.GlobalMemSize();
|
||||||
|
QString s;
|
||||||
|
|
||||||
|
if (histSize > maxAlloc)
|
||||||
|
{
|
||||||
|
s = "Histogram/Accumulator memory size of " + ToString(histSize) +
|
||||||
|
" is greater than the max OpenCL allocation size of " + ToString(maxAlloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalSize > totalAvail)
|
||||||
|
{
|
||||||
|
s += "\n\nTotal required memory size of " + ToString(totalSize) +
|
||||||
|
" is greater than the max OpenCL available memory of " + ToString(totalAvail);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.isEmpty())
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
ui.FinalRenderTextOutput->setText(s + ".\n\nRendering will most likely fail.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
ui.FinalRenderTextOutput->clear();
|
||||||
|
|
||||||
ui.FinalRenderParamsTable->item(m_MemoryCellIndex, 1)->setText(ToString(p.first));
|
|
||||||
ui.FinalRenderParamsTable->item(m_ItersCellIndex, 1)->setText(ToString(p.second));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,8 +151,9 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
{
|
{
|
||||||
m_Run = true;
|
m_Run = true;
|
||||||
m_TotalTimer.Tic();//Begin timing for progress of all operations.
|
m_TotalTimer.Tic();//Begin timing for progress of all operations.
|
||||||
size_t i;
|
|
||||||
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
|
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
|
||||||
|
|
||||||
|
size_t i;
|
||||||
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
|
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
|
||||||
uint currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
|
uint currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
|
||||||
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers[0].m_Name)) : ComposePath(Name());
|
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers[0].m_Name)) : ComposePath(Name());
|
||||||
@ -566,8 +567,9 @@ void FinalRenderEmberController<T>::ResetProgress(bool total)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>If successful, memory required in bytes, else zero.</returns>
|
/// <returns>If successful, memory required in bytes, else zero.</returns>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
pair<size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemory()
|
tuple<size_t, size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemory()
|
||||||
{
|
{
|
||||||
|
size_t iterCount;
|
||||||
pair<size_t, size_t> p(0, 0);
|
pair<size_t, size_t> p(0, 0);
|
||||||
|
|
||||||
if (m_Renderer.get())
|
if (m_Renderer.get())
|
||||||
@ -587,11 +589,12 @@ pair<size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemory()
|
|||||||
m_Renderer->ComputeCamera();
|
m_Renderer->ComputeCamera();
|
||||||
CancelPreviewRender();
|
CancelPreviewRender();
|
||||||
m_FinalPreviewRenderFunc();
|
m_FinalPreviewRenderFunc();
|
||||||
p.first = m_Renderer->MemoryRequired(m_FinalRenderDialog->Strips(), true);
|
|
||||||
p.second = m_Renderer->TotalIterCount(strips);
|
p = m_Renderer->MemoryRequired(strips, true);
|
||||||
|
iterCount = m_Renderer->TotalIterCount(strips);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return tuple<size_t, size_t, size_t>(p.first, p.second, iterCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -63,7 +63,7 @@ public:
|
|||||||
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) { }
|
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) { }
|
||||||
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) { }
|
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) { }
|
||||||
virtual void ResetProgress(bool total = true) { }
|
virtual void ResetProgress(bool total = true) { }
|
||||||
virtual pair<size_t, size_t> SyncAndComputeMemory() { return pair<size_t, size_t>(0, 0); }
|
virtual tuple<size_t, size_t, size_t> SyncAndComputeMemory() { return tuple<size_t, size_t, size_t>(0, 0, 0); }
|
||||||
virtual double OriginalAspect() { return 1; }
|
virtual double OriginalAspect() { return 1; }
|
||||||
virtual QString ComposePath(const QString& name) { return ""; }
|
virtual QString ComposePath(const QString& name) { return ""; }
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ public:
|
|||||||
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) override;
|
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) override;
|
||||||
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) override;
|
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) override;
|
||||||
virtual void ResetProgress(bool total = true) override;
|
virtual void ResetProgress(bool total = true) override;
|
||||||
virtual pair<size_t, size_t> SyncAndComputeMemory() override;
|
virtual tuple<size_t, size_t, size_t> SyncAndComputeMemory() override;
|
||||||
virtual double OriginalAspect() override { return double(m_Ember->m_OrigFinalRasW) / m_Ember->m_OrigFinalRasH; }
|
virtual double OriginalAspect() override { return double(m_Ember->m_OrigFinalRasW) / m_Ember->m_OrigFinalRasH; }
|
||||||
virtual QString Name() const override { return QString::fromStdString(m_Ember->m_Name); }
|
virtual QString Name() const override { return QString::fromStdString(m_Ember->m_Name); }
|
||||||
virtual QString ComposePath(const QString& name) override;
|
virtual QString ComposePath(const QString& name) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user