Initial source commit

Initial source commit
This commit is contained in:
mfeemster
2014-07-08 00:11:14 -07:00
parent 1493c22925
commit ef56c16b2b
214 changed files with 108754 additions and 0 deletions

View File

@ -0,0 +1,386 @@
#include "EmberCommonPch.h"
#include "EmberRender.h"
#include "JpegUtils.h"
/// <summary>
/// The core of the EmberRender.exe program.
/// Template argument expected to be float or double.
/// </summary>
/// <param name="opt">A populated EmberOptions object which specifies all program options to be used</param>
/// <returns>True if success, else false.</returns>
template <typename T, typename bucketT>
bool EmberRender(EmberOptions& opt)
{
OpenCLWrapper wrapper;
std::cout.imbue(std::locale(""));
if (opt.DumpArgs())
cout << opt.GetValues(OPT_USE_RENDER) << endl;
if (opt.OpenCLInfo())
{
cout << "\nOpenCL Info: " << endl;
cout << wrapper.DumpInfo();
return true;
}
Timing t;
bool writeSuccess = false;
unsigned char* finalImagep;
unsigned int i, channels, strip, strips, realHeight, origHeight;
size_t stripOffset;
T centerY, centerBase, zoomScale, floatStripH;
string filename;
ostringstream os;
vector<Ember<T>> embers;
vector<unsigned char> finalImage, vecRgb;
EmberStats stats;
EmberReport emberReport;
EmberImageComments comments;
XmlToEmber<T> parser;
EmberToXml<T> emberToXml;
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> randVec;
auto_ptr<RenderProgress<T>> progress(new RenderProgress<T>());
auto_ptr<Renderer<T, bucketT>> renderer(CreateRenderer<T, bucketT>(opt.EmberCL() ? OPENCL_RENDERER : CPU_RENDERER, opt.Platform(), opt.Device(), false, 0, emberReport));
vector<string> errorReport = emberReport.ErrorReport();
if (!errorReport.empty())
emberReport.DumpErrorReport();
if (!renderer.get())
{
cout << "Renderer creation failed, exiting." << endl;
return false;
}
if (opt.EmberCL() && renderer->RendererType() != OPENCL_RENDERER)//OpenCL init failed, so fall back to CPU.
opt.EmberCL(false);
if (!InitPaletteList<T>(opt.PalettePath()))
return false;
if (!ParseEmberFile(parser, opt.Input(), embers))
return false;
if (!opt.EmberCL())
{
if (opt.ThreadCount() == 0)
{
cout << "Using " << Timing::ProcessorCount() << " automatically detected threads." << endl;
opt.ThreadCount(Timing::ProcessorCount());
}
else
{
cout << "Using " << opt.ThreadCount() << " manually specified threads." << endl;
}
renderer->ThreadCount(opt.ThreadCount(), opt.IsaacSeed() != "" ? opt.IsaacSeed().c_str() : NULL);
}
else
{
cout << "Using OpenCL to render." << endl;
if (opt.Verbose())
{
cout << "Platform: " << wrapper.PlatformName(opt.Platform()) << endl;
cout << "Device: " << wrapper.DeviceName(opt.Platform(), opt.Device()) << endl;
}
if (opt.ThreadCount() > 1)
cout << "Cannot specify threads with OpenCL, using 1 thread." << endl;
opt.ThreadCount(1);
renderer->ThreadCount(opt.ThreadCount(), opt.IsaacSeed() != "" ? opt.IsaacSeed().c_str() : NULL);
if (opt.BitsPerChannel() != 8)
{
cout << "Bits per channel cannot be anything other than 8 with OpenCL, setting to 8." << endl;
opt.BitsPerChannel(8);
}
}
if (opt.Format() != "jpg" &&
opt.Format() != "png" &&
opt.Format() != "ppm" &&
opt.Format() != "bmp")
{
cout << "Format must be jpg, png, ppm, or bmp not " << opt.Format() << ". Setting to jpg." << endl;
}
channels = opt.Format() == "png" ? 4 : 3;
if (opt.BitsPerChannel() == 16 && opt.Format() != "png")
{
cout << "Support for 16 bits per channel images is only present for the png format. Setting to 8." << endl;
opt.BitsPerChannel(8);
}
else if (opt.BitsPerChannel() != 8 && opt.BitsPerChannel() != 16)
{
cout << "Unexpected bits per channel specified " << opt.BitsPerChannel() << ". Setting to 8." << endl;
opt.BitsPerChannel(8);
}
if (opt.InsertPalette() && opt.BitsPerChannel() != 8)
{
cout << "Inserting palette only supported with 8 bits per channel, insertion will not take place." << endl;
opt.InsertPalette(false);
}
if (opt.AspectRatio() < 0)
{
cout << "Invalid pixel aspect ratio " << opt.AspectRatio() << endl << ". Must be positive, setting to 1." << endl;
opt.AspectRatio(1);
}
if (!opt.Out().empty() && (embers.size() > 1))
{
cout << "Single output file " << opt.Out() << " specified for multiple images. Changing to use prefix of badname-changethis instead. Always specify prefixes when reading a file with multiple embers." << endl;
opt.Out("");
opt.Prefix("badname-changethis");
}
//Final setup steps before running.
os.imbue(std::locale(""));
renderer->EarlyClip(opt.EarlyClip());
renderer->LockAccum(opt.LockAccum());
renderer->InsertPalette(opt.InsertPalette());
renderer->SubBatchSize(opt.SubBatchSize());
renderer->PixelAspectRatio(T(opt.AspectRatio()));
renderer->Transparency(opt.Transparency());
renderer->NumChannels(channels);
renderer->BytesPerChannel(opt.BitsPerChannel() / 8);
renderer->Callback(opt.DoProgress() ? progress.get() : NULL);
for (i = 0; i < embers.size(); i++)
{
if (opt.Verbose() && embers.size() > 1)
cout << "\nFlame = " << i + 1 << "/" << embers.size() << endl;
else
cout << endl;
embers[i].m_TemporalSamples = 1;//Force temporal samples to 1 for render.
embers[i].m_Quality *= T(opt.QualityScale());
embers[i].m_FinalRasW = (unsigned int)((T)embers[i].m_FinalRasW * opt.SizeScale());
embers[i].m_FinalRasH = (unsigned int)((T)embers[i].m_FinalRasH * opt.SizeScale());
embers[i].m_PixelsPerUnit *= T(opt.SizeScale());
if (embers[i].m_FinalRasW == 0 || embers[i].m_FinalRasH == 0)
{
cout << "Output image " << i << " has dimension 0: " << embers[i].m_FinalRasW << ", " << embers[i].m_FinalRasH << ". Setting to 1920 x 1080." << endl;
embers[i].m_FinalRasW = 1920;
embers[i].m_FinalRasH = 1080;
}
//Cast to double in case the value exceeds 2^32.
double imageMem = (double)renderer->NumChannels() * (double)embers[i].m_FinalRasW
* (double)embers[i].m_FinalRasH * (double)renderer->BytesPerChannel();
double maxMem = pow(2.0, double((sizeof(void*) * 8) - 1));
if (imageMem > maxMem)//Ensure the max amount of memory for a process is not exceeded.
{
cout << "Image " << i << " size > " << maxMem << ". Setting to 1920 x 1080." << endl;
embers[i].m_FinalRasW = 1920;
embers[i].m_FinalRasH = 1080;
}
renderer->SetEmber(embers[i]);
renderer->PrepFinalAccumVector(finalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
if (opt.Strips() > 1)
{
strips = opt.Strips();
}
else
{
strips = CalcStrips((double)renderer->MemoryRequired(false), (double)renderer->MemoryAvailable(), opt.UseMem());
if (strips > 1)
VerbosePrint("Setting strips to " << strips << " with specified memory usage of " << opt.UseMem());
}
if (strips > embers[i].m_FinalRasH)
{
cout << "Cannot have more strips than rows: " << opt.Strips() << " > " << embers[i].m_FinalRasH << ". Setting strips = rows." << endl;
opt.Strips(strips = embers[i].m_FinalRasH);
}
if (embers[i].m_FinalRasH % strips != 0)
{
cout << "A strips value of " << strips << " does not divide evenly into a height of " << embers[i].m_FinalRasH;
strips = NextHighestEvenDiv(embers[i].m_FinalRasH, strips);
if (strips == 1)//No higher divisor, check for a lower one.
strips = NextLowestEvenDiv(embers[i].m_FinalRasH, strips);
cout << ". Setting strips to " << strips << "." << endl;
}
embers[i].m_Quality *= strips;
realHeight = embers[i].m_FinalRasH;
floatStripH = T(embers[i].m_FinalRasH) / T(strips);
embers[i].m_FinalRasH = (unsigned int)ceil(floatStripH);
centerY = embers[i].m_CenterY;
zoomScale = pow(T(2), embers[i].m_Zoom);
centerBase = centerY - ((strips - 1) * floatStripH) / (2 * embers[i].m_PixelsPerUnit * zoomScale);
if (strips > 1)
randVec = renderer->RandVec();
//For testing incremental renderer.
//int sb = 1;
//bool resume = false, success = false;
//do
//{
// success = renderer->Run(finalImage, 0, sb, false/*resume == false*/) == RENDER_OK;
// sb++;
// resume = true;
//}
//while (success && renderer->ProcessState() != ACCUM_DONE);
for (strip = 0; strip < strips; strip++)
{
stripOffset = (size_t)embers[i].m_FinalRasH * strip * renderer->FinalRowSize();
embers[i].m_CenterY = centerBase + embers[i].m_FinalRasH * T(strip) / (embers[i].m_PixelsPerUnit * zoomScale);
if ((embers[i].m_FinalRasH * (strip + 1)) > realHeight)
{
origHeight = embers[i].m_FinalRasH;
embers[i].m_FinalRasH = realHeight - origHeight * strip;
embers[i].m_CenterY -= (origHeight - embers[i].m_FinalRasH) * T(0.5) / (embers[i].m_PixelsPerUnit * zoomScale);
}
if (strips > 1)
{
renderer->RandVec(randVec);//Use the same vector of ISAAC rands for each strip.
renderer->SetEmber(embers[i]);//Set one final time after modifications for strips.
if (opt.Verbose() && (strips > 1) && strip > 0)
cout << endl;
VerbosePrint("Strip = " << (strip + 1) << "/" << strips);
}
if ((renderer->Run(finalImage, 0, 0, false, stripOffset) != RENDER_OK) || renderer->Aborted() || finalImage.empty())
{
cout << "Error: image rendering failed, skipping to next image." << endl;
renderer->DumpErrorReport();//Something went wrong, print errors.
break;//Exit strips loop, resume next iter in embers loop.
}
progress->Clear();
//Original wrote every strip as a full image which could be very slow with many large images.
//Only write once all strips for this image are finished.
if (strip == strips - 1)
{
if (!opt.Out().empty())
{
filename = opt.Out();
}
else if (opt.NameEnable() && !embers[i].m_Name.empty())
{
filename = opt.Prefix() + embers[i].m_Name + opt.Suffix() + "." + opt.Format();
}
else
{
ostringstream ssLocal;
ssLocal << opt.Prefix() << setfill('0') << setw(5) << i << opt.Suffix() << "." << opt.Format();
filename = ssLocal.str();
}
writeSuccess = false;
comments = renderer->ImageComments(opt.PrintEditDepth(), opt.IntPalette(), opt.HexPalette());
stats = renderer->Stats();
os.str("");
os << comments.m_NumIters << "/" << renderer->TotalIterCount() << " (" << std::fixed << std::setprecision(2) << ((double)stats.m_Iters/(double)renderer->TotalIterCount() * 100) << "%)";
VerbosePrint("\nIters ran/requested: " + os.str());
VerbosePrint("Bad values: " << stats.m_Badvals);
VerbosePrint("Render time: " + t.Format(stats.m_RenderSeconds * 1000));
VerbosePrint("Writing " + filename);
if ((opt.Format() == "jpg" || opt.Format() == "bmp") && renderer->NumChannels() == 4)
{
EmberNs::RgbaToRgb(finalImage, vecRgb, renderer->FinalRasW(), realHeight);
finalImagep = vecRgb.data();
}
else
{
finalImagep = finalImage.data();
}
if (opt.Format() == "png")
writeSuccess = WritePng(filename.c_str(), finalImagep, renderer->FinalRasW(), realHeight, opt.BitsPerChannel() / 8, opt.PngComments(), comments, opt.Id(), opt.Url(), opt.Nick());
else if (opt.Format() == "jpg")
writeSuccess = WriteJpeg(filename.c_str(), finalImagep, renderer->FinalRasW(), realHeight, opt.JpegQuality(), opt.JpegComments(), comments, opt.Id(), opt.Url(), opt.Nick());
else if (opt.Format() == "ppm")
writeSuccess = WritePpm(filename.c_str(), finalImagep, renderer->FinalRasW(), realHeight);
else if (opt.Format() == "bmp")
writeSuccess = WriteBmp(filename.c_str(), finalImagep, renderer->FinalRasW(), realHeight);
if (!writeSuccess)
cout << "Error writing " << filename << endl;
}
}
//Restore the ember values to their original values.
if (strips > 1)
{
embers[i].m_Quality /= strips;
embers[i].m_FinalRasH = realHeight;
embers[i].m_CenterY = centerY;
memset(finalImage.data(), 0, finalImage.size());
}
if (opt.EmberCL() && opt.DumpKernel())
cout << "Iteration kernel: \n" << ((RendererCL<T>*)renderer.get())->IterKernel() << endl;
VerbosePrint("Done.");
}
if (opt.Verbose())
t.Toc("\nTotal time: ", true);
return true;
}
/// <summary>
/// Main program entry point for EmberRender.exe.
/// </summary>
/// <param name="argc">The number of command line arguments passed</param>
/// <param name="argv">The command line arguments passed</param>
/// <returns>0 if successful, else 1.</returns>
int _tmain(int argc, _TCHAR* argv[])
{
bool b, d = true;
EmberOptions opt;
//Required for large allocs, else GPU memory usage will be severely limited to small sizes.
//This must be done in the application and not in the EmberCL DLL.
_putenv_s("GPU_MAX_ALLOC_PERCENT", "100");
if (opt.Populate(argc, argv, OPT_USE_RENDER))
return 0;
#ifdef DO_DOUBLE
if (opt.Bits() == 64)
{
b = EmberRender<double, double>(opt);
}
else
#endif
if (opt.Bits() == 33)
{
b = EmberRender<float, float>(opt);
}
else if (opt.Bits() == 32)
{
cout << "Bits 32/int histogram no longer supported. Using bits == 33 (float)." << endl;
b = EmberRender<float, float>(opt);
}
return b ? 0 : 1;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "EmberOptions.h"
/// <summary>
/// Declaration for the EmberRender() function.
/// </summary>
/// <summary>
/// The core of the EmberRender.exe program.
/// Template argument expected to be float or double.
/// </summary>
/// <param name="opt">A populated EmberOptions object which specifies all program options to be used</param>
/// <returns>True if success, else false.</returns>
template <typename T, typename bucketT>
static bool EmberRender(EmberOptions& opt);

View File

@ -0,0 +1,98 @@
// Microsoft Visual C++ generated resource script.
//
#include <windows.h>
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "..\\Fractorium\\Icons\\\\Fractorium.ico"
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,0,2
PRODUCTVERSION 0,4,0,2
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x0L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as single images"
VALUE "FileVersion", "0.4.0.2"
VALUE "InternalName", "EmberRender.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberRender.rc"
VALUE "ProductName", "Ember Render"
VALUE "ProductVersion", "0.4.0.2"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by EmberRender.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif