Commit 4b251745 authored by Jehferson Mello's avatar Jehferson Mello

Implemented float/double and config file for TBB

parent 0028c29b
......@@ -4,34 +4,49 @@ set(TBB_CXX_SRCS "main.cpp"
"FracGen.hpp"
"${TB_COMMON_SRC_DIR}/Vec.hxx"
"${TB_COMMON_SRC_DIR}/dataTypes.hxx"
"${TB_COMMON_SRC_DIR}/defines.hxx" )
"${TB_COMMON_SRC_DIR}/defines.hpp" )
set(TBB_TBB_SRCS "FracGen.cpp" )
add_executable(${PROJECT_NAME} ${TBB_CXX_SRCS} ${TBB_TBB_SRCS} )
add_executable(${PROJECT_NAME} ${TBB_CXX_SRCS} ${TBB_TBB_SRCS} )
add_executable(${PROJECT_NAME}-db ${TBB_CXX_SRCS} ${TBB_TBB_SRCS} )
target_compile_definitions(${PROJECT_NAME}-db PRIVATE "TOYBROT_USE_DOUBLES")
if(NOT WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE pthread)
target_link_libraries(${PROJECT_NAME} PRIVATE pthread)
target_link_libraries(${PROJECT_NAME}-db PRIVATE pthread)
endif()
if(TB_SDL_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE SDL2::SDL2)
target_compile_definitions(${PROJECT_NAME} PRIVATE "TOYBROT_ENABLE_GUI")
target_sources(${PROJECT_NAME} PRIVATE "${TB_COMMON_SRC_DIR}/FracGenWindow.cpp" "${TB_COMMON_SRC_DIR}/FracGenWindow.hpp")
target_link_libraries(${PROJECT_NAME}-db PRIVATE SDL2::SDL2)
target_compile_definitions(${PROJECT_NAME}-db PRIVATE "TOYBROT_ENABLE_GUI")
target_sources(${PROJECT_NAME}-db PRIVATE "${TB_COMMON_SRC_DIR}/FracGenWindow.cpp" "${TB_COMMON_SRC_DIR}/FracGenWindow.hpp")
endif()
if(TB_PNG_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE PNG::PNG)
target_compile_definitions(${PROJECT_NAME} PRIVATE "TOYBROT_ENABLE_PNG")
target_sources(${PROJECT_NAME} PRIVATE "${TB_COMMON_SRC_DIR}/pngWriter.cpp" "${TB_COMMON_SRC_DIR}/pngWriter.hpp" )
target_link_libraries(${PROJECT_NAME}-db PRIVATE PNG::PNG)
target_compile_definitions(${PROJECT_NAME}-db PRIVATE "TOYBROT_ENABLE_PNG")
target_sources(${PROJECT_NAME}-db PRIVATE "${TB_COMMON_SRC_DIR}/pngWriter.cpp" "${TB_COMMON_SRC_DIR}/pngWriter.hpp" )
endif()
target_link_libraries(${PROJECT_NAME} PRIVATE TBB::tbb)
target_link_libraries(${PROJECT_NAME} PRIVATE TBB::tbb)
target_link_libraries(${PROJECT_NAME}-db PRIVATE TBB::tbb)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${TB_COMMON_SRC_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${TB_COMMON_SRC_DIR})
target_include_directories(${PROJECT_NAME}-db PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${TB_COMMON_SRC_DIR})
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
install(TARGETS ${PROJECT_NAME}-db RUNTIME DESTINATION bin)
......@@ -9,46 +9,11 @@
#include <tbb/parallel_for.h>
#include <tbb/blocked_range2d.h>
//static Vec3f boxMaxes;
//static Vec3f boxMins;
//static Vec3<tbFPType> boxMaxes;
//static Vec3<tbFPType> boxMins;
using estimatorFunction = std::function<float(Vec3f)>;
/******************************************************************************
*
* Tweakable parameters
*
******************************************************************************/
static constexpr const size_t maxRaySteps = 7500;
static constexpr const float collisionMinDist = 0.00055f;
static constexpr const float cameraX = 0.0f;
static constexpr const float cameraY = 0.0f;
static constexpr const float cameraZ = -3.8f;
static constexpr const float targetX = 0.0f;
static constexpr const float targetY = 0.0f;
static constexpr const float targetZ = 0.0f;
// coulouring parameters
static constexpr const float hueFactor = -10.0f;
static constexpr const int hueOffset = 195;
static constexpr const float valueFactor = 62;
static constexpr const float valueRange = 1.0f;
static constexpr const float valueClamp = 0.9f;
static constexpr const float satValue = 0.7f;
static constexpr const float bgValue = 0.05f;
static constexpr const float bgAlpha = 1.0f;
// Mandelbox constants
static constexpr const float fixedRadiusSq = 2.2f;
static constexpr const float minRadiusSq = 0.8f;
static constexpr const float foldingLimit = 1.45;
static constexpr const float boxScale = -3.5f;
static constexpr const size_t boxIterations = 30;
using estimatorFunction = std::function<tbFPType(Vec3<tbFPType>, const Parameters<tbFPType>&)>;
/******************************************************************************
*
......@@ -58,31 +23,31 @@ static constexpr const size_t boxIterations = 30;
void sphereFold(Vec3f& z, float& dz)
void sphereFold(Vec3<tbFPType>& z, tbFPType& dz, const Parameters<tbFPType>& params)
{
float r2 = z.sqMod();
if ( r2 < minRadiusSq)
tbFPType r2 = z.sqMod();
if ( r2 < params.MinRadiusSq())
{
// linear inner scaling
float temp = (fixedRadiusSq/minRadiusSq);
tbFPType temp = (params.FixedRadiusSq()/params.MinRadiusSq());
z *= temp;
dz *= temp;
}
else if(r2<fixedRadiusSq)
else if(r2<params.FixedRadiusSq())
{
// this is the actual sphere inversion
float temp =(fixedRadiusSq/r2);
tbFPType temp =(params.FixedRadiusSq()/r2);
z *= temp;
dz*= temp;
}
}
void boxFold(Vec3f& z)
void boxFold(Vec3<tbFPType>& z, const Parameters<tbFPType>& params)
{
z = z.clamp(-foldingLimit, foldingLimit)* 2.0f - z;
z = z.clamp(-params.FoldingLimit(), params.FoldingLimit())* static_cast<tbFPType>(2.0f) - z;
}
float boxDist(const Vec3f& p)
tbFPType boxDist(const Vec3<tbFPType>& p, const Parameters<tbFPType>& params)
{
/**
* Distance estimator for a mandelbox
......@@ -90,25 +55,25 @@ float boxDist(const Vec3f& p)
* Distance estimator adapted from
* https://http://blog.hvidtfeldts.net/index.php/2011/11/distance-estimated-3d-fractals-vi-the-mandelbox/
*/
const Vec3f& offset = p;
float dr = boxScale;
Vec3f z{p};
for (size_t n = 0; n < boxIterations; n++)
const Vec3<tbFPType>& offset = p;
tbFPType dr = params.BoxScale();
Vec3<tbFPType> z{p};
for (size_t n = 0; n < params.BoxIterations(); n++)
{
boxFold(z); // Reflect
sphereFold(z,dr); // Sphere Inversion
boxFold(z, params); // Reflect
sphereFold(z,dr, params); // Sphere Inversion
z = z * boxScale + offset; // Scale & Translate
dr = dr * std::abs(boxScale) + 1.0f;
z = z * params.BoxScale() + offset; // Scale & Translate
dr = dr * std::abs(params.BoxScale()) + 1.0f;
}
float r = z.mod();
tbFPType r = z.mod();
return r/std::abs(dr);
}
float bulbDist(const Vec3f& p)
tbFPType bulbDist(const Vec3<tbFPType>& p)
{
/**
......@@ -119,28 +84,28 @@ float bulbDist(const Vec3f& p)
* https://www.shadertoy.com/view/ltfSWn
*/
Vec3f w = p;
float m = w.sqMod();
Vec3<tbFPType> w = p;
tbFPType m = w.sqMod();
//vec4 trap = vec4(abs(w),m);
float dz = 3.0f;
tbFPType dz = 3.0f;
for( int i=0; i<4; i++ )
{
#if 1
float m2 = m*m;
float m4 = m2*m2;
tbFPType m2 = m*m;
tbFPType m4 = m2*m2;
dz = 8.0f*sqrt(m4*m2*m)*dz + 1.0f;
float x = w.X(); float x2 = x*x; float x4 = x2*x2;
float y = w.Y(); float y2 = y*y; float y4 = y2*y2;
float z = w.Z(); float z2 = z*z; float z4 = z2*z2;
tbFPType x = w.X(); tbFPType x2 = x*x; tbFPType x4 = x2*x2;
tbFPType y = w.Y(); tbFPType y2 = y*y; tbFPType y4 = y2*y2;
tbFPType z = w.Z(); tbFPType z2 = z*z; tbFPType z4 = z2*z2;
float k3 = x2 + z2;
float k2 = 1/sqrt( k3*k3*k3*k3*k3*k3*k3 );
float k1 = x4 + y4 + z4 - 6.0f*y2*z2 - 6.0f*x2*y2 + 2.0f*z2*x2;
float k4 = x2 - y2 + z2;
tbFPType k3 = x2 + z2;
tbFPType k2 = 1/sqrt( k3*k3*k3*k3*k3*k3*k3 );
tbFPType k1 = x4 + y4 + z4 - 6.0f*y2*z2 - 6.0f*x2*y2 + 2.0f*z2*x2;
tbFPType k4 = x2 - y2 + z2;
w.setX(p.X() + 64.0f*x*y*z*(x2-z2)*k4*(x4-6.0f*x2*z2+z4)*k1*k2);
w.setY(p.Y() + -16.0f*y2*k3*k4*k4 + k1*k1);
......@@ -149,10 +114,10 @@ float bulbDist(const Vec3f& p)
dz = 8.0*pow(sqrt(m),7.0)*dz + 1.0;
//dz = 8.0*pow(m,3.5)*dz + 1.0;
float r = w.mod();
float b = 8.0*acos( w.Y()/r);
float a = 8.0*atan2( w.X(), w.Z() );
w = p + Vec3f( sin(b)*sin(a), cos(b), sin(b)*cos(a) ) * pow(r,8.0);
tbFPType r = w.mod();
tbFPType b = 8.0*acos( w.Y()/r);
tbFPType a = 8.0*atan2( w.X(), w.Z() );
w = p + Vec3<tbFPType>( sin(b)*sin(a), cos(b), sin(b)*cos(a) ) * pow(r,8.0);
#endif
// trap = min( trap, vec4(abs(w),m) );
......@@ -165,9 +130,9 @@ float bulbDist(const Vec3f& p)
return 0.25f*log(m)*sqrt(m)/dz;
}
float sphereDist(Vec3f p)
tbFPType sphereDist(Vec3<tbFPType> p)
{
float radius = 2.f;
tbFPType radius = 2.f;
return p.mod() - radius;
}
......@@ -177,7 +142,7 @@ float sphereDist(Vec3f p)
*
******************************************************************************/
RGBA HSVtoRGB(int H, float S, float V)
RGBA HSVtoRGB(int H, tbFPType S, tbFPType V)
{
/**
......@@ -186,10 +151,10 @@ RGBA HSVtoRGB(int H, float S, float V)
*/
RGBA output;
float C = S * V;
float X = C * (1 - std::abs(std::fmod(H / 60.0, 2) - 1));
float m = V - C;
float Rs, Gs, Bs;
tbFPType C = S * V;
tbFPType X = C * (1 - std::abs(std::fmod(H / 60.0, 2) - 1));
tbFPType m = V - C;
tbFPType Rs, Gs, Bs;
if(H >= 0 && H < 60)
{
......@@ -235,20 +200,19 @@ RGBA HSVtoRGB(int H, float S, float V)
return output;
}
RGBA getColour(const Vec4f& steps)
RGBA getColour(const Vec4<tbFPType>& steps, const Parameters<tbFPType>& params )
{
RGBA colour;
Vec3f position(steps.X(),steps.Y(),steps.Z());
Vec3<tbFPType> position(steps.X(),steps.Y(),steps.Z());
static const RGBA background(bgValue,bgValue,bgValue,bgAlpha);
if(steps.W() >= maxRaySteps)
if(steps.W() >= params.MaxRaySteps())
{
return background;
return RGBA(params.BgRed(),params.BgGreen(),params.BgBlue(),params.BgAlpha());
}
// This is a good place to float check your bounds if you need to
// This is a good place to tbFPType check your bounds if you need to
// boxMins.setX(std::min(boxMins.X(),position.X()));
// boxMins.setY(std::min(boxMins.Y(),position.Y()));
......@@ -258,11 +222,11 @@ RGBA getColour(const Vec4f& steps)
// boxMaxes.setY(std::max(boxMaxes.Y(),position.Y()));
// boxMaxes.setZ(std::max(boxMaxes.Z(),position.Z()));
float saturation = satValue;
float hueVal = (position.Z() * hueFactor) + hueOffset;
tbFPType saturation = params.SatValue();
tbFPType hueVal = (position.Z() * params.HueFactor()) + params.HueOffset();
int hue = static_cast<int>( trunc(fmod(hueVal, 360.0f) ) );
hue = hue < 0 ? 360 + hue: hue;
float value = valueRange*(1.0f - std::min(steps.W()*valueFactor/maxRaySteps, valueClamp));
tbFPType value = params.ValueRange()*(1.0f - std::min(steps.W()*params.ValueFactor()/params.MaxRaySteps(), params.ValueClamp()));
colour = HSVtoRGB(hue, saturation, value);
......@@ -278,35 +242,36 @@ RGBA getColour(const Vec4f& steps)
*
******************************************************************************/
Vec4f trace(const Camera<float>& cam,size_t x, size_t y, const estimatorFunction& f)
Vec4<tbFPType> trace(const Camera<tbFPType>& cam, const Parameters<tbFPType>& params, size_t x, size_t y, const estimatorFunction& f)
{
/**
* This function taken from
* http://blog.hvidtfeldts.net/index.php/2011/06/distance-estimated-3d-fractals-part-i/
*/
float totalDistance = 0.0f;
tbFPType totalDistance = 0.0f;
unsigned int steps;
Vec3f pixelPosition = cam.ScreenTopLeft() + (cam.ScreenRight() * static_cast<float>(x)) + (cam.ScreenUp() * static_cast<float>(y));
Vec3<tbFPType> pixelPosition = cam.ScreenTopLeft() + (cam.ScreenRight() * static_cast<tbFPType>(x)) + (cam.ScreenUp() * static_cast<tbFPType>(y));
Vec3f rayDir = pixelPosition - cam.Pos();
Vec3<tbFPType> rayDir = pixelPosition - cam.Pos();
rayDir.normalise();
Vec3f p;
for (steps=0; steps < maxRaySteps; steps++)
Vec3<tbFPType> p;
for (steps=0; steps < params.MaxRaySteps(); steps++)
{
p = cam.Pos() + (rayDir * totalDistance);
float distance = f(p);
tbFPType distance = f(p, params);
totalDistance += distance;
if (distance < collisionMinDist) break;
if (distance < params.CollisionMinDist()) break;
}
//return both the steps and the actual position in space for colouring purposes
return Vec4f{p,static_cast<float>(steps)};
return Vec4<tbFPType>{p,static_cast<tbFPType>(steps)};
}
void traceRegion(colourVec& data,
const Camera<float>& cam,
const Camera<tbFPType>& cam,
const Parameters<tbFPType>& params,
const estimatorFunction& f,
const tbb::blocked_range2d<size_t,size_t>& range)
{
......@@ -314,7 +279,7 @@ void traceRegion(colourVec& data,
{
for(size_t w = range.cols().begin(); w < range.cols().end(); w++ )
{
data[(h*cam.ScreenWidth())+w] = getColour(trace(cam, w, h, f));
data[(h*cam.ScreenWidth())+w] = getColour(trace(cam, params, w, h, f), params);
}
}
}
......@@ -325,23 +290,28 @@ void traceRegion(colourVec& data,
*
******************************************************************************/
bool FracGen::Generate(int width, int height)
bool FracGen::Generate()
{
if(outBuffer->size() != cam->ScreenWidth()*cam->ScreenHeight())
{
outBuffer->resize(cam->ScreenWidth()*cam->ScreenHeight());
}
bool finishedGeneration = false;
int heightStep = bench ? height : 10;
int heightStep = bench ? cam->ScreenHeight() : 10;
estimatorFunction bulb(bulbDist);
//estimatorFunction bulb(bulbDist);
estimatorFunction box(boxDist);
estimatorFunction sphere(sphereDist);
//estimatorFunction sphere(sphereDist);
auto tbbTrace = [this, f = box](const tbb::blocked_range2d<size_t,size_t>& range)
{traceRegion(*(this->outBuffer), *(this->cam), f, range); };
{traceRegion(*(this->outBuffer), *(this->cam), *(this->parameters), f, range); };
// Minor optimization in TBB: Since we can define the range here, we don't need to check bounds in
// traceRegion. This is very similar to how SYCL and OpenCL do things
tbb::blocked_range2d<size_t,size_t> range(lastHeight, std::min(lastHeight+heightStep, static_cast<size_t>(height)), 0, width);
tbb::blocked_range2d<size_t,size_t> range( lastHeight, std::min(lastHeight+heightStep, static_cast<size_t>(cam->ScreenHeight()))
, 0, cam->ScreenWidth());
tbb::parallel_for(range, tbbTrace);
lastHeight+= heightStep;
......@@ -351,7 +321,7 @@ bool FracGen::Generate(int width, int height)
* At least not in the initial tutorials and beginner documentation
*/
if (lastHeight >=static_cast<size_t>(height) )
if (lastHeight >=static_cast<size_t>(cam->ScreenHeight()) )
{
lastHeight = 0;
finishedGeneration = true;
......@@ -360,12 +330,13 @@ bool FracGen::Generate(int width, int height)
return finishedGeneration;
}
FracGen::FracGen(bool benching, size_t width, size_t height)
FracGen::FracGen(bool benching, CameraPtr c, ParamPtr p)
: bench{benching}
, cam{c}
, parameters{p}
, lastHeight{0}
{
outBuffer = std::make_shared< colourVec >(width*height);
cam = std::make_shared<Camera<float> >(Vec3f{cameraX, cameraY, cameraZ},Vec3f{targetX,targetY,targetZ}, width, height, 0.1f, 45);
outBuffer = std::make_shared< colourVec >(cam->ScreenWidth()*cam->ScreenHeight());
static bool once = false;
if(!bench || !once)
......
......@@ -5,32 +5,35 @@
#include <cstdint>
#include <memory>
#include "defines.hpp"
#include "Vec.hxx"
#include "dataTypes.hxx"
using colourType = float;
using RGBA = Vec4<colourType>;
using RGBA = Vec4<tbFPType>;
using colourVec = std::vector<RGBA>;
using FracPtr = std::shared_ptr< colourVec >;
using CameraPtr = std::shared_ptr< Camera<tbFPType> >;
using ParamPtr = std::shared_ptr< Parameters<tbFPType> >;
class FracGen
{
public:
FracGen(bool bench = false, size_t width = 1820, size_t height = 980);
FracGen(bool bench = false, CameraPtr c = nullptr, ParamPtr p = nullptr);
~FracGen();
FracPtr getBuffer() noexcept { return outBuffer;}
size_t outLength() const noexcept { return outBuffer->size();}
size_t outSize() const noexcept { return sizeof(RGBA) * outBuffer->size();}
bool Generate( int width, int height);
bool Generate();
private:
bool bench;
std::shared_ptr<Camera<float> > cam;
CameraPtr cam;
ParamPtr parameters;
FracPtr outBuffer;
size_t lastHeight;
......
......@@ -13,6 +13,8 @@
#include <fstream>
#include <thread>
#include "defines.hpp"
/*
* Some preprocessor shenanigans to make both
* the SDL2 and libPNG dependencies optional
......@@ -30,18 +32,68 @@
#include "FracGen.hpp"
#if TOYBROT_USE_DOUBLES
static std::string flavourName = "TBB-db";
static std::string fileName = "tbb-db.c";
#else
static std::string flavourName = "TBB";
static std::string fileName = "tbb.c";
#endif
static auto genTime (std::chrono::high_resolution_clock::now());
static constexpr const int defaultWidth = 1820;
static constexpr const int defaultHeight = 980;
static int windowWidth = defaultWidth;
static int windowHeight = defaultHeight;
static std::string flavourName = "TBB";
static uint32_t windowWidth = 0;
static uint32_t windowHeight = 0;
static std::vector<size_t> results;
static size_t setupTime;
static size_t lastRunTime;
static size_t iterations = 1;
static bool forceHeadless = false;
static bool pngExport = false;
static CameraPtr camera;
static ParamPtr params;
/******************************************************************************
*
* Default parameters
*
******************************************************************************/
// Camera parameters
static constexpr const tbFPType cameraX = 0.0f;
static constexpr const tbFPType cameraY = 0.0f;
static constexpr const tbFPType cameraZ = -3.8f;
static constexpr const tbFPType targetX = 0.0f;
static constexpr const tbFPType targetY = 0.0f;
static constexpr const tbFPType targetZ = 0.0f;
static constexpr const uint32_t screenWidth = 1820;
static constexpr const uint32_t screenHeight = 980;
static constexpr const tbFPType fovY = 45;
static constexpr const tbFPType near = 0.1f;
// Coulouring parameters
static constexpr const tbFPType hueFactor = -10.0f;
static constexpr const int32_t hueOffset = 195;
static constexpr const tbFPType valueFactor = 62;
static constexpr const tbFPType valueRange = 1.0f;
static constexpr const tbFPType valueClamp = 0.9f;
static constexpr const tbFPType satValue = 0.7f;
static constexpr const tbFPType bgRed = 0.05f;
static constexpr const tbFPType bgGreen = 0.05f;
static constexpr const tbFPType bgBlue = 0.05f;
static constexpr const tbFPType bgAlpha = 1.0f;
// Raymarching parameters
static constexpr const uint32_t maxRaySteps = 7500;
static constexpr const tbFPType collisionMinDist = 0.00055f;
// Mandelbox parameters
static constexpr const tbFPType fixedRadiusSq = 2.2f;
static constexpr const tbFPType minRadiusSq = 0.8f;
static constexpr const tbFPType foldingLimit = 1.45f;
static constexpr const tbFPType boxScale = -3.5;
static constexpr const uint32_t boxIterations = 30;
int runProgram(bool benching) noexcept
{
......@@ -56,14 +108,14 @@ int runProgram(bool benching) noexcept
#ifdef TOYBROT_ENABLE_GUI
if(!forceHeadless)
{
mainWindow = new FracGenWindow(windowWidth,windowHeight, flavourName, redraw, exit);
mainWindow = new FracGenWindow(camera, flavourName, redraw, exit);
}
#endif
genTime = std::chrono::high_resolution_clock::now();
//needed for CPU versions because they partition the work for gui update
FracGen cpuFrac(forceHeadless?true:benching, windowWidth, windowHeight);
FracGen cpuFrac(forceHeadless?true:benching, camera, params);
setupTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - genTime).count();
......@@ -73,7 +125,7 @@ int runProgram(bool benching) noexcept
std::string exportName("toyBrot_");
exportName += flavourName;
exportName += ".png";
exportWriter = new pngWriter(windowWidth, windowHeight, exportName);
exportWriter = new pngWriter(camera, params, exportName);
exportWriter->setFractal(cpuFrac.getBuffer());
exportWriter->Init();
}
......@@ -102,7 +154,7 @@ int runProgram(bool benching) noexcept
genTime = std::chrono::high_resolution_clock::now();
}
bool completed = cpuFrac.Generate(windowWidth, windowHeight);
bool completed = cpuFrac.Generate();
if (completed)
{
......@@ -138,7 +190,7 @@ int runProgram(bool benching) noexcept
{