Report memory required in final render dialog.

Fix broken state of ember during failed render with strips.
This commit is contained in:
mfeemster 2014-12-09 00:24:28 -08:00
parent 9263906cb5
commit 3e70b8eec6
10 changed files with 112 additions and 42 deletions

View File

@ -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
--User Changes
None.

View File

@ -116,12 +116,10 @@ void RendererBase::ChangeVal(std::function<void(void)> func, eProcessAction acti
}
/// <summary>
/// Return the amount of memory needed to render the current ember.
/// Optionally include the memory needed for the final output image.
/// Return the amount of memory needed for the histogram.
/// </summary>
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
/// <returns>The memory required to render the current ember</returns>
size_t RendererBase::MemoryRequired(size_t strips, bool includeFinal)
/// <returns>The memory required for the histogram to render the current ember</returns>
size_t RendererBase::HistMemoryRequired(size_t strips)
{
bool newFilterAlloc = false;
@ -130,9 +128,24 @@ size_t RendererBase::MemoryRequired(size_t strips, bool includeFinal)
ComputeBounds();
//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>

View File

@ -98,7 +98,8 @@ public:
//Non-virtual processing functions.
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();
bool PrepFinalAccumVector(vector<byte>& pixels);

View File

@ -554,13 +554,13 @@ int OpenCLWrapper::FindImageIndex(const string& name, bool shared)
{
for (size_t i = 0; i < m_GLImages.size(); i++)
if (m_GLImages[i].m_Name == name)
return i;
return int(i);
}
else
{
for (size_t i = 0; i < m_Images.size(); i++)
if (m_Images[i].m_Name == name)
return i;
return int(i);
}
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>
/// <returns>The value of the field</returns>
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;
@ -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_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_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_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; }
uint OpenCLWrapper::PlatformIndex() const { return m_PlatformIndex; }
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; }
size_t OpenCLWrapper::MaxAllocSize() const { return GetInfo<cl_ulong>(PlatformIndex(), DeviceIndex(), CL_DEVICE_MAX_MEM_ALLOC_SIZE); }
/// <summary>
/// Makes the even grid dims.

View File

@ -175,7 +175,7 @@ public:
//Info.
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);
vector<string> PlatformNames();
string DeviceName(size_t platform, size_t device);
@ -190,6 +190,8 @@ public:
uint PlatformIndex() const;
uint DeviceIndex() const;
uint LocalMemSize() const;
size_t GlobalMemSize() const;
size_t MaxAllocSize() const;
static void MakeEvenGridDims(uint blockW, uint blockH, uint& gridW, uint& gridH);

View File

@ -281,7 +281,7 @@ static bool StripsRender(RendererBase* renderer, Ember<T>& ember, vector<byte>&
std::function<void(size_t strip)> perStripError,
std::function<void(Ember<T>& finalEmber)> allStripsFinished)
{
bool success = true;
bool success = false;
size_t origHeight, realHeight = ember.m_FinalRasH;
T centerY = ember.m_CenterY;
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.
}
if ((renderer->Run(finalImage, time, 0, false, stripOffset) != RENDER_OK) || renderer->Aborted() || finalImage.empty())
{
perStripError(strip);
success = false;
break;
}
else
if ((renderer->Run(finalImage, time, 0, false, stripOffset) == RENDER_OK) && !renderer->Aborted() && !finalImage.empty())
{
perStripFinish(strip);
}
else
{
perStripError(strip);
break;
}
if (strip == strips - 1)
{
success = true;
}
//Restore the ember values to their original values.
if (strips > 1)
{
ember.m_Quality /= strips;
ember.m_FinalRasH = realHeight;
ember.m_CenterY = centerY;
renderer->SetEmber(ember);//Further processing will require the dimensions to match the original ember, so re-assign.
}
if (success)
allStripsFinished(ember);
}
}
Memset(finalImage);

View File

@ -330,6 +330,7 @@ int _tmain(int argc, _TCHAR* argv[])
//This must be done in the application and not in the EmberCL DLL.
#ifdef WIN32
_putenv_s("GPU_MAX_ALLOC_PERCENT", "100");
//_putenv_s("GPU_FORCE_64BIT_PTR", "1");
#else
putenv(const_cast<char*>("GPU_MAX_ALLOC_PERCENT=100"));
#endif

View File

@ -708,10 +708,48 @@ bool FractoriumFinalRenderDialog::SetMemory()
{
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;
}

View File

@ -151,8 +151,9 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
{
m_Run = true;
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.
size_t i;
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.
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>
/// <returns>If successful, memory required in bytes, else zero.</returns>
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);
if (m_Renderer.get())
@ -587,11 +589,12 @@ pair<size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemory()
m_Renderer->ComputeCamera();
CancelPreviewRender();
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>

View File

@ -63,7 +63,7 @@ public:
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) { }
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) { }
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 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 SyncCurrentToSizeSpinners(bool scale, bool size) 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 QString Name() const override { return QString::fromStdString(m_Ember->m_Name); }
virtual QString ComposePath(const QString& name) override;