Просмотр исходного кода

fixed double-double opencl generator and working on naive interpreter

Nicolas Winkler 5 лет назад
Родитель
Сommit
15e476b9c7

+ 1 - 0
Almond.h

@@ -55,6 +55,7 @@ public:
     mnd::MandelGenerator* currentGenerator;
 public:
     Almond(QWidget *parent = Q_NULLPTR);
+    Almond(Almond&&) = default;
     ~Almond(void);
 
     void submitBackgroundTask(BackgroundTask* task);

+ 2 - 2
CMakeLists.txt

@@ -8,7 +8,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules)
 #set(CMAKE_AUTORCC ON)
 #set(CMAKE_AUTOUIC ON)
 
-find_package(Qt5 COMPONENTS Core Widgets OpenGL Xml REQUIRED)
+find_package(Qt5 COMPONENTS Core Widgets OpenGL Xml Concurrent REQUIRED)
 find_package(OpenMP)
 find_package(OpenGL REQUIRED COMPONENTS OpenGL)
 set(Boost_USE_STATIC_LIBS ON)
@@ -35,7 +35,7 @@ add_subdirectory(libalmond)
 target_include_directories(Almond SYSTEM PUBLIC ${FFMPEG_INCLUDE_DIRS})
 
 target_link_libraries(Almond PUBLIC libalmond)
-target_link_libraries(Almond PUBLIC Qt5::Core Qt5::Widgets Qt5::OpenGL Qt5::Xml)
+target_link_libraries(Almond PUBLIC Qt5::Core Qt5::Widgets Qt5::OpenGL Qt5::Xml Qt5::Concurrent)
 target_link_libraries(Almond PUBLIC ${FFMPEG_LIBRARIES})
 target_link_libraries(Almond PUBLIC OpenGL::GL)
 

+ 62 - 0
libmandel/include/NaiveIRGenerator.h

@@ -3,11 +3,68 @@
 
 #include "IterationIR.h"
 #include "Generators.h"
+#include <variant>
 
 namespace mnd
 {
     template<typename T>
     class NaiveIRGenerator;
+
+    namespace eval
+    {
+        struct Load;
+        struct Store;
+        struct Add;
+        struct Sub;
+        struct Mul;
+        struct Div;
+        struct Neg;    
+        struct Atan2;
+        struct Pow;
+        struct Cos;
+        struct Sin;
+        struct Exp;
+        struct Ln;
+
+        using EvalNode = std::variant<
+            Load,
+            Store,
+            Add,
+            Sub,
+            Mul,
+            Div,
+            Neg,
+            Atan2,
+            Pow,
+            Cos,
+            Sin,
+            Exp,
+            Ln
+        >;
+
+        template<typename T>
+        struct EvalStruct
+        {
+            std::map<std::string, size_t> variableNames;
+            std::vector<T> variables;
+
+            void prepare(const T& zre, const T& zim, const T& cre, const T& cim)
+            {
+                auto z_re = variableNames.find("z_re");
+                auto z_im = variableNames.find("z_im");
+                auto c_re = variableNames.find("c_re");
+                auto c_im = variableNames.find("c_im");
+                if (z_re != variableNames.end())
+                    variables[z_re->second] = zre;
+                if (z_im != variableNames.end())
+                    variables[z_im->second] = zre;
+                if (c_re != variableNames.end())
+                    variables[c_re->second] = zre;
+                if (c_im != variableNames.end())
+                    variables[c_im->second] = zre;
+            }
+        };
+    }
 }
 
 
@@ -15,6 +72,11 @@ template<typename T>
 class mnd::NaiveIRGenerator : public mnd::MandelGenerator
 {
     const ir::Formula& form;
+    eval::EvalStruct<T> es;
+    std::unique_ptr<eval::EvalNode> newz_re;
+    std::unique_ptr<eval::EvalNode> newz_im;
+    std::unique_ptr<eval::EvalNode> start_re;
+    std::unique_ptr<eval::EvalNode> start_im;
 public:
     NaiveIRGenerator(const ir::Formula& irf, mnd::Precision prec = mnd::getType<T>());
     NaiveIRGenerator(NaiveIRGenerator&&) = default;

+ 24 - 0
libmandel/include/Types.h

@@ -44,6 +44,10 @@ namespace mnd
     inline Float128 log(const Float128& x) { return boost::multiprecision::log(x); }
     inline Float128 log2(const Float128& x) { return boost::multiprecision::log2(x); }
     inline Float128 pow(const Float128& x, const Float128& y) { return boost::multiprecision::pow(x, y); }
+    inline Float128 atan2(const Float128& y, const Float128& x) { return boost::multiprecision::atan2(y, x); }
+    inline Float128 cos(const Float128& x) { return boost::multiprecision::cos(x); }
+    inline Float128 sin(const Float128& x) { return boost::multiprecision::sin(x); }
+    inline Float128 exp(const Float128& x) { return boost::multiprecision::exp(x); }
 
     using Float256 = boost::multiprecision::number<
         boost::multiprecision::backends::cpp_bin_float<
@@ -57,6 +61,10 @@ namespace mnd
     inline Float256 log(const Float256& x) { return boost::multiprecision::log(x); }
     inline Float256 log2(const Float256& x) { return boost::multiprecision::log2(x); }
     inline Float256 pow(const Float256& x, const Float256& y) { return boost::multiprecision::pow(x, y); }
+    inline Float256 atan2(const Float256& y, const Float256& x) { return boost::multiprecision::atan2(y, x); }
+    inline Float256 cos(const Float256& x) { return boost::multiprecision::cos(x); }
+    inline Float256 sin(const Float256& x) { return boost::multiprecision::sin(x); }
+    inline Float256 exp(const Float256& x) { return boost::multiprecision::exp(x); }
 
     using Float512 = boost::multiprecision::number<
         boost::multiprecision::backends::cpp_bin_float<
@@ -91,6 +99,10 @@ namespace mnd
     inline DoubleDouble log(const DoubleDouble& x) { return ::log(x); }
     inline DoubleDouble log2(const DoubleDouble& x) { return ::log(x) / ::log(DoubleDouble(2.0)); }
     inline DoubleDouble pow(const DoubleDouble& x, const DoubleDouble& y) { return ::pow(x, y); }
+    inline DoubleDouble atan2(const DoubleDouble& y, const DoubleDouble& x) { return ::atan2(y, x); }
+    inline DoubleDouble cos(const DoubleDouble& x) { return ::cos(x); }
+    inline DoubleDouble sin(const DoubleDouble& x) { return ::sin(x); }
+    inline DoubleDouble exp(const DoubleDouble& x) { return ::exp(x); }
 
 
     inline QuadDouble abs(const QuadDouble& x) { return ::abs(x); }
@@ -99,6 +111,10 @@ namespace mnd
     inline QuadDouble log(const QuadDouble& x) { return ::log(x); }
     inline QuadDouble log2(const QuadDouble& x) { return ::log(x) / ::log(QuadDouble(2.0)); }
     inline QuadDouble pow(const QuadDouble& x, const QuadDouble& y) { return ::pow(x, y); }
+    inline QuadDouble atan2(const QuadDouble& y, const QuadDouble& x) { return ::atan2(y, x); }
+    inline QuadDouble cos(const QuadDouble& x) { return ::cos(x); }
+    inline QuadDouble sin(const QuadDouble& x) { return ::sin(x); }
+    inline QuadDouble exp(const QuadDouble& x) { return ::exp(x); }
 
     inline double abs(double x) { return ::abs(x); }
     inline float abs(float x) { return ::abs(x); }
@@ -110,8 +126,16 @@ namespace mnd
     inline float log(float x) { return ::logf(x); }
     inline double log2(double x) { return ::log2(x); }
     inline float log2(float x) { return ::log2f(x); }
+    inline double atan2(double x, double y) { return ::atan2(x, y); }
+    inline float atan2(float x, float y) { return ::atan2(x, y); }
     inline double pow(double x, double y) { return ::pow(x, y); }
     inline float pow(float x, float y) { return ::powf(x, y); }
+    inline double cos(double x) { return ::cos(x); }
+    inline float cos(float x) { return ::cos(x); }
+    inline double sin(double x) { return ::sin(x); }
+    inline float sin(float x) { return ::sin(x); }
+    inline double exp(double x) { return ::exp(x); }
+    inline float exp(float x) { return ::exp(x); }
 
 
     template<typename T, typename U>

+ 2 - 2
libmandel/src/IterationCompiler.cpp

@@ -794,8 +794,8 @@ namespace mnd
         }
 #endif // WITH_ASMJIT
 
-        //vec.push_back(std::make_unique<NaiveIRGenerator<mnd::DoubleDouble>>(irf));
-        //vec.push_back(std::make_unique<NaiveIRGenerator<mnd::QuadDouble>>(irf));
+        vec.push_back(std::make_unique<NaiveIRGenerator<mnd::DoubleDouble>>(irf));
+        vec.push_back(std::make_unique<NaiveIRGenerator<mnd::QuadDouble>>(irf));
         
         //auto dg = std::make_unique<NaiveIRGenerator>(*irf, mnd::getPrecision<double>());
 

+ 180 - 131
libmandel/src/NaiveIRGenerator.cpp

@@ -13,39 +13,16 @@ namespace mnd
     template class NaiveIRGenerator<mnd::QuadDouble>;
 }
 
-namespace eval {
-    struct Load;
-    struct Store;
-    struct Add;
-    struct Sub;
-    struct Mul;
-    struct Div;
-    struct Neg;    
-    struct Atan;
-    struct Pow;
-    struct Cos;
-    struct Sin;
-    struct Exp;
-    struct Ln;
-
-    using EvalNode = std::variant<
-        Load,
-        Store,
-        Add,
-        Sub,
-        Mul,
-        Div,
-        Neg,
-        Atan,
-        Pow,
-        Cos,
-        Sin,
-        Exp,
-        Ln
-    >;
-
-    struct Load { int index; };
-    struct Store { int index; };
+namespace mnd::eval
+{
+
+
+    struct Load { size_t index; };
+    struct Store
+    {
+        size_t index;
+        std::unique_ptr<EvalNode> v;
+    };
 
     struct BinaryOperation
     {
@@ -66,125 +43,195 @@ namespace eval {
     struct Neg : UnaryOperation {};
 
 
-    struct Atan : BinaryOperation {};
+    struct Atan2 : BinaryOperation {};
     struct Pow : BinaryOperation {};
     struct Cos : UnaryOperation {};
     struct Sin : UnaryOperation {};
     struct Exp : UnaryOperation {};
     struct Ln : UnaryOperation {};
-}
 
 
-template<typename T>
-NaiveIRGenerator<T>::NaiveIRGenerator(const mnd::ir::Formula& irf,
-    mnd::Precision prec) :
-    mnd::MandelGenerator{ prec },
-    form{ irf }
-{
-}
+    using namespace mnd;
+    using namespace mnd::ir;
+    template<typename T>
+    struct ToEvalVisitor
+    {
+        EvalStruct<T>& es;
+
+        std::unique_ptr<EvalNode> visit(ir::Node* f)
+        {
+            std::any& nodeData = getNodeData(f);
+            if (EvalNode** en = std::any_cast<EvalNode*>(&nodeData)) {
+                
+                size_t tmpStore;
+                if (Store* s = std::get_if<Store>(*en)) {
+                    tmpStore = s->index;
+                }
+                else {
+                    tmpStore = createTemp();
+                    EvalNode store = Store{ tmpStore, std::make_unique<EvalNode>(std::move(**en)) };
+                    **en = std::move(store);
+                }
+                auto l = std::make_unique<EvalNode>(Load{ tmpStore });
+                setNodeData(f, l.get());
+                return l;
+            }
+            EvalNode n = std::visit(*this, *f);
+            auto r = std::make_unique<EvalNode>(std::move(n));
+            setNodeData(f, r.get());
+            return r;
+        }
 
+        std::any& getNodeData(ir::Node* n)
+        {
+            return std::visit([](auto& x) -> std::any& { return x.nodeData; }, *n);
+        }
 
-template<typename T>
-struct EvalRes
-{
-    size_t incVal;
-    T result;
-};
+        void setNodeData(ir::Node* n, EvalNode* en)
+        {
+            std::visit([en](auto& x) { x.nodeData = en; }, *n);
+        }
+
+        size_t createTemp(void)
+        {
+            es.variables.push_back(0);
+            return es.variables.size() - 1;
+        }
 
+        size_t createConstant(mnd::Real& value)
+        {
+            es.variables.push_back(mnd::convert<T>(value));
+            return es.variables.size() - 1;
+        }
 
-using namespace mnd;
-template<typename T>
-struct TVisitor
-{
-    T a, b, x, y;
-    size_t incrementValue;
+        size_t createVariable(std::string& value)
+        {
+            es.variables.push_back(0);
+            es.variableNames.emplace(value, es.variables.size() - 1);
+            return es.variables.size() - 1;
+        }
 
-    T visitNode(ir::Node* n) {
-        EvalRes<T>* nodeData = getNodeData(n);
-        if (nodeData) {
-            if (nodeData->incVal == incrementValue)
-                return nodeData->result;
+        EvalNode operator()(ir::Constant& x) {
+            return Load{ createConstant(x.value) };
         }
-        T res = std::visit(*this, *n);
-        if (nodeData) {
-            nodeData->incVal = incrementValue;
-            nodeData->result = res;
+        EvalNode operator()(ir::Variable& x) {
+            return Load{ createVariable(x.name) };
         }
-        return res;
-    }
+        EvalNode operator()(ir::Addition& x) {
+            return Add{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Subtraction& x) {
+            return Sub{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Multiplication& x) {
+            return Mul{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Division& x) {
+            return Div{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Negation& x) {
+            return Neg{ visit(x.value) };
+        }
+        EvalNode operator()(ir::Atan2& x) {
+            return Atan2{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Pow& x) {
+            return Pow{ visit(x.left), visit(x.right) };
+        }
+        EvalNode operator()(ir::Cos& x) {
+            return Cos{ visit(x.value) };
+        }
+        EvalNode operator()(ir::Sin& x) {
+            return Sin{ visit(x.value) };
+        }
+        EvalNode operator()(ir::Exp& x) {
+            return Exp{ visit(x.value) };
+        }
+        EvalNode operator()(ir::Ln& x) {
+            return Ln{ visit(x.value) };
+        }
+    };
 
-    EvalRes<T>* getNodeData(ir::Node* n) {
-        assert(n != nullptr);
-        std::any& x = std::visit([](auto& n) -> std::any& {
-            return n.nodeData;
-        }, *n);
-        if (auto* v = std::any_cast<EvalRes<T>>(&x))
-            return v;
-        else
-            return nullptr;
-    }
 
-    T operator()(const ir::Constant& c) {
-        return mnd::convert<double>(c.value);
-    }
 
-    T operator()(const ir::Variable& v) {
-        if (v.name == "z_re")
-            return a;
-        else if (v.name == "z_im")
-            return b;
-        else if (v.name == "c_re")
-            return x;
-        else if (v.name == "c_im")
-            return y;
-        else
-            return 0.0;
-    }
+    template<typename T>
+    struct EvalVisitor
+    {
+        mnd::eval::EvalStruct<T>& es;
 
-    T operator()(const ir::Negation& n) {
-        return -visitNode(n.value);
-    }
+        T visit(const EvalNode& en) {
+            return std::visit(*this, en);
+        }
 
-    T operator()(const ir::Addition& n) {
-        return visitNode(n.left) + visitNode(n.right);
-    }
+        T operator()(const Load& x) {
+            return es.variables[x.index];
+        }
 
-    T operator()(const ir::Subtraction& n) {
-        return visitNode(n.left) - visitNode(n.right);
-    }
+        T operator()(const Store& x) {
+            T r = visit(*x.v);
+            es.variables[x.index] = r;
+            return r;
+        }
 
-    T operator()(const ir::Multiplication& n) {
-        return visitNode(n.left) * visitNode(n.right);
-    }
+        T operator()(const Add& x) {
+            return visit(*x.a) + visit(*x.b);
+        }
 
-    T operator()(const ir::Division& n) {
-        return visitNode(n.left) / visitNode(n.right);
-    }
+        T operator()(const Sub& x) {
+            return visit(*x.a) - visit(*x.b);
+        }
 
-    T operator()(const ir::Atan2& n) {
-        return ::atan2(visitNode(n.left), visitNode(n.right));
-    }
+        T operator()(const Mul& x) {
+            return visit(*x.a) * visit(*x.b);
+        }
 
-    T operator()(const ir::Pow& n) {
-        return ::pow(visitNode(n.left), visitNode(n.right));
-    }
+        T operator()(const Div& x) {
+            return visit(*x.a) / visit(*x.b);
+        }
 
-    T operator()(const ir::Cos& n) {
-        return ::cos(visitNode(n.value));
-    }
+        T operator()(const Neg& x) {
+            return -visit(*x.a);
+        }
 
-    T operator()(const ir::Sin& n) {
-        return ::sin(visitNode(n.value));
-    }
+        T operator()(const Atan2& x) {
+            return mnd::atan2(visit(*x.a), visit(*x.b));
+        }
 
-    T operator()(const ir::Exp& n) {
-        return ::exp(visitNode(n.value));
-    }
+        T operator()(const Pow& x) {
+            return mnd::pow(visit(*x.a), visit(*x.b));
+        }
 
-    T operator()(const ir::Ln& n) {
-        return ::log(visitNode(n.value));
-    }
-};
+        T operator()(const Cos& x) {
+            return mnd::cos(visit(*x.a));
+        }
+
+        T operator()(const Sin& x) {
+            return mnd::sin(visit(*x.a));
+        }
+
+        T operator()(const Exp& x) {
+            return mnd::exp(visit(*x.a));
+        }
+
+        T operator()(const Ln& x) {
+            return mnd::log(visit(*x.a));
+        }
+    };
+}
+
+
+template<typename T>
+NaiveIRGenerator<T>::NaiveIRGenerator(const mnd::ir::Formula& irf,
+    mnd::Precision prec) :
+    mnd::MandelGenerator{ prec },
+    form{ irf }
+{
+    eval::ToEvalVisitor<T> tev{ es };
+    newz_re = tev.visit(irf.newA);
+    newz_im = tev.visit(irf.newB);
+    start_re = tev.visit(irf.startA);
+    start_im = tev.visit(irf.startB);
+}
 
 
 template<typename T>
@@ -209,21 +256,23 @@ void NaiveIRGenerator<T>::generate(const mnd::MandelInfo& info, float* data)
         for (i; i < info.bWidth; i++) {
             T x = viewx + T(double(i)) * wpp;
 
-            TVisitor<T> beforeVisitor{ 0, 0, x, y, 0 };
+            es.prepare(0, 0, x, y);
+
+            eval::EvalVisitor<T> visitor{ es };
+
+            T a = visitor.visit(*start_re);
+            T b = visitor.visit(*start_im);
 
-            T a = beforeVisitor.visitNode(form.startA);
-            T b = beforeVisitor.visitNode(form.startB);
+            es.prepare(a, b, x, y);
 
-            TVisitor<T> visitor{ a, b, x, y, 0 };
             int k = 0;
             for (k = 0; k < info.maxIter; k++) {
-                T newA = visitor.visitNode(form.newA);
-                T newB = visitor.visitNode(form.newB);
+                T newA = visitor.visit(*newz_re);
+                T newB = visitor.visit(*newz_im);
                 a = newA;
                 b = newB;
                 if (a * a + b * b >= 16.0)
                     break;
-                visitor.incrementValue++;
             }
             data[i + j * info.bWidth] = float(k);
         }

+ 2 - 2
libmandel/src/opencl/doubledouble.cl

@@ -60,8 +60,8 @@ __kernel void iterate(__global float* A, const int width,
     double2 pixelScaleY = (double2)(ph1, ph2);
     double2 a = add(mulDouble(pixelScaleX, (double) px), xl); // pixelScaleX * px + xl
     double2 b = add(mulDouble(pixelScaleY, (double) py), yt); // pixelScaleY * py + yt
-    double2 ca = julia != 0 ? ((double2) (jx1, jx2)) : ca;
-    double2 cb = julia != 0 ? ((double2) (jy1, jy2)) : cb;
+    double2 ca = julia != 0 ? ((double2) (jx1, jx2)) : a;
+    double2 cb = julia != 0 ? ((double2) (jy1, jy2)) : b;
 
 
     int n = 0;

+ 67 - 67
libmandel/src/opencl/doubledouble.h

@@ -159,73 +159,73 @@ unsigned char doubledouble_cl[] = {
   0x65, 0x32, 0x20, 0x63, 0x61, 0x20, 0x3d, 0x20, 0x6a, 0x75, 0x6c, 0x69,
   0x61, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x28, 0x28, 0x64,
   0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x29, 0x20, 0x28, 0x6a, 0x78, 0x31,
-  0x2c, 0x20, 0x6a, 0x78, 0x32, 0x29, 0x29, 0x20, 0x3a, 0x20, 0x63, 0x61,
-  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65,
-  0x32, 0x20, 0x63, 0x62, 0x20, 0x3d, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x61,
-  0x20, 0x21, 0x3d, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x28, 0x28, 0x64, 0x6f,
-  0x75, 0x62, 0x6c, 0x65, 0x32, 0x29, 0x20, 0x28, 0x6a, 0x79, 0x31, 0x2c,
-  0x20, 0x6a, 0x79, 0x32, 0x29, 0x29, 0x20, 0x3a, 0x20, 0x63, 0x62, 0x3b,
-  0x0a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6e,
-  0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68,
-  0x69, 0x6c, 0x65, 0x20, 0x28, 0x6e, 0x20, 0x3c, 0x20, 0x6d, 0x61, 0x78,
-  0x20, 0x2d, 0x20, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x20,
-  0x61, 0x61, 0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c, 0x28, 0x61, 0x2c, 0x20,
-  0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x20, 0x62, 0x62, 0x20, 0x3d,
-  0x20, 0x6d, 0x75, 0x6c, 0x28, 0x62, 0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62,
-  0x6c, 0x65, 0x32, 0x20, 0x61, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c,
-  0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x61, 0x2e, 0x73,
-  0x30, 0x20, 0x2b, 0x20, 0x61, 0x61, 0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20,
-  0x62, 0x62, 0x2e, 0x73, 0x30, 0x20, 0x2b, 0x20, 0x62, 0x62, 0x2e, 0x73,
-  0x31, 0x20, 0x3e, 0x20, 0x31, 0x36, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61,
-  0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64,
-  0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x73,
-  0x62, 0x62, 0x20, 0x3d, 0x20, 0x28, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65,
-  0x32, 0x29, 0x28, 0x2d, 0x62, 0x62, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x2d,
-  0x62, 0x62, 0x2e, 0x73, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x64, 0x28,
-  0x61, 0x64, 0x64, 0x28, 0x61, 0x61, 0x2c, 0x20, 0x6d, 0x69, 0x6e, 0x75,
-  0x73, 0x62, 0x62, 0x29, 0x2c, 0x20, 0x63, 0x61, 0x29, 0x3b, 0x0a, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x61,
-  0x64, 0x64, 0x28, 0x61, 0x64, 0x64, 0x28, 0x61, 0x62, 0x2c, 0x20, 0x61,
-  0x62, 0x29, 0x2c, 0x20, 0x63, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x2b, 0x2b, 0x3b, 0x0a, 0x20, 0x20,
-  0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20,
-  0x4e, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x6c, 0x6f, 0x67, 0x20,
-  0x28, 0x6c, 0x6f, 0x67, 0x20, 0x20, 0x7c, 0x5a, 0x28, 0x4e, 0x29, 0x7c,
-  0x29, 0x20, 0x2f, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x32, 0x0a, 0x20, 0x20,
-  0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20, 0x3e, 0x3d, 0x20, 0x6d,
-  0x61, 0x78, 0x20, 0x2d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5d,
-  0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x6d, 0x6f, 0x6f, 0x74,
-  0x68, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e,
-  0x64, 0x65, 0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f,
-  0x61, 0x74, 0x29, 0x20, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d,
-  0x20, 0x6c, 0x6f, 0x67, 0x28, 0x6c, 0x6f, 0x67, 0x28, 0x61, 0x2e, 0x73,
-  0x30, 0x20, 0x2a, 0x20, 0x61, 0x2e, 0x73, 0x30, 0x20, 0x2b, 0x20, 0x62,
-  0x2e, 0x73, 0x30, 0x20, 0x2a, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x29, 0x20,
-  0x2f, 0x20, 0x32, 0x29, 0x20, 0x2f, 0x20, 0x6c, 0x6f, 0x67, 0x28, 0x32,
-  0x2e, 0x30, 0x66, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x2c, 0x20, 0x6a, 0x78, 0x32, 0x29, 0x29, 0x20, 0x3a, 0x20, 0x61, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32,
+  0x20, 0x63, 0x62, 0x20, 0x3d, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x61, 0x20,
+  0x21, 0x3d, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x28, 0x28, 0x64, 0x6f, 0x75,
+  0x62, 0x6c, 0x65, 0x32, 0x29, 0x20, 0x28, 0x6a, 0x79, 0x31, 0x2c, 0x20,
+  0x6a, 0x79, 0x32, 0x29, 0x29, 0x20, 0x3a, 0x20, 0x62, 0x3b, 0x0a, 0x0a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6e, 0x20, 0x3d,
+  0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c,
+  0x65, 0x20, 0x28, 0x6e, 0x20, 0x3c, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x2d,
+  0x20, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x20, 0x61, 0x61,
+  0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c, 0x28, 0x61, 0x2c, 0x20, 0x61, 0x29,
+  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f,
+  0x75, 0x62, 0x6c, 0x65, 0x32, 0x20, 0x62, 0x62, 0x20, 0x3d, 0x20, 0x6d,
+  0x75, 0x6c, 0x28, 0x62, 0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65,
+  0x32, 0x20, 0x61, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c, 0x28, 0x61,
+  0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x61, 0x2e, 0x73, 0x30, 0x20,
+  0x2b, 0x20, 0x61, 0x61, 0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x62, 0x62,
+  0x2e, 0x73, 0x30, 0x20, 0x2b, 0x20, 0x62, 0x62, 0x2e, 0x73, 0x31, 0x20,
+  0x3e, 0x20, 0x31, 0x36, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75,
+  0x62, 0x6c, 0x65, 0x32, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x62, 0x62,
+  0x20, 0x3d, 0x20, 0x28, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x32, 0x29,
+  0x28, 0x2d, 0x62, 0x62, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x2d, 0x62, 0x62,
+  0x2e, 0x73, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x64, 0x28, 0x61, 0x64,
+  0x64, 0x28, 0x61, 0x61, 0x2c, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x62,
+  0x62, 0x29, 0x2c, 0x20, 0x63, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x64,
+  0x28, 0x61, 0x64, 0x64, 0x28, 0x61, 0x62, 0x2c, 0x20, 0x61, 0x62, 0x29,
+  0x2c, 0x20, 0x63, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x6e, 0x2b, 0x2b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x20,
+  0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x28, 0x6c,
+  0x6f, 0x67, 0x20, 0x20, 0x7c, 0x5a, 0x28, 0x4e, 0x29, 0x7c, 0x29, 0x20,
+  0x2f, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x32, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x69, 0x66, 0x20, 0x28, 0x6e, 0x20, 0x3e, 0x3d, 0x20, 0x6d, 0x61, 0x78,
+  0x20, 0x2d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5d, 0x20, 0x3d,
+  0x20, 0x6d, 0x61, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
+  0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x20,
+  0x21, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65,
+  0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x29, 0x20, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x6c,
+  0x6f, 0x67, 0x28, 0x6c, 0x6f, 0x67, 0x28, 0x61, 0x2e, 0x73, 0x30, 0x20,
+  0x2a, 0x20, 0x61, 0x2e, 0x73, 0x30, 0x20, 0x2b, 0x20, 0x62, 0x2e, 0x73,
+  0x30, 0x20, 0x2a, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x29, 0x20, 0x2f, 0x20,
+  0x32, 0x29, 0x20, 0x2f, 0x20, 0x6c, 0x6f, 0x67, 0x28, 0x32, 0x2e, 0x30,
+  0x66, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78,
+  0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x29,
+  0x6e, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64,
   0x65, 0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61,
-  0x74, 0x29, 0x6e, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69,
-  0x6e, 0x64, 0x65, 0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c,
-  0x6f, 0x61, 0x74, 0x29, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d,
-  0x20, 0x28, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2b, 0x20, 0x62, 0x20,
-  0x2a, 0x20, 0x62, 0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x20, 0x2f, 0x20,
-  0x28, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x3b, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x67, 0x65, 0x74, 0x5f, 0x67,
-  0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x28, 0x30, 0x29, 0x5d,
-  0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x7d, 0x0a
+  0x74, 0x29, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x28,
+  0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2b, 0x20, 0x62, 0x20, 0x2a, 0x20,
+  0x62, 0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x32,
+  0x35, 0x36, 0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x41, 0x5b, 0x67, 0x65, 0x74, 0x5f, 0x67, 0x6c, 0x6f,
+  0x62, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x28, 0x30, 0x29, 0x5d, 0x20, 0x3d,
+  0x20, 0x35, 0x3b, 0x0a, 0x7d, 0x0a
 };
-unsigned int doubledouble_cl_len = 2732;
+unsigned int doubledouble_cl_len = 2730;

+ 7 - 2
main.cpp

@@ -5,7 +5,9 @@
 #include <QSplashScreen>
 #include <QMovie>
 #include <QTimer>
+#include <QFuture>
 #include <cmath>
+#include <QtConcurrent>
 
 class AlmondSplashScreen : public QSplashScreen
 {
@@ -64,7 +66,7 @@ public:
             QPen pen(QColor(255, 255, 255, int(opacity)));
             pen.setWidth(4);
             painter->setPen(pen);
-            painter->drawEllipse(QRectF{ x, height - 40, 16, 16 });
+            painter->drawEllipse(QRectF{ x, double(height - 40), 16, 16 });
         }
     }
 
@@ -72,7 +74,7 @@ public slots:
     void nextFrame() //(const QRect& rect)
     {
         emit this->repaint();
-        animOff += 7;
+        animOff += 3;
     }
 };
 
@@ -86,7 +88,9 @@ int main(int argc, char *argv[])
     QPixmap splashImg(":/splash/splash");
     QPixmap splashScaled = splashImg.scaled(splashW, splashW * splashImg.height() / splashImg.width());
     AlmondSplashScreen splash{ splashScaled };
+    a.processEvents();
     splash.show();
+    a.processEvents();
     /*for (int i = 0; i < 100; i++) {
         a.processEvents();
         system("sleep 0.03");
@@ -94,6 +98,7 @@ int main(int argc, char *argv[])
     Almond w;
     a.processEvents();
     splash.finish(&w);
+    a.processEvents();
     w.show();
     return a.exec();
 }