浏览代码

much better

Nicolas Winkler 5 年之前
父节点
当前提交
01abcf49c2

+ 11 - 10
Almond.cpp

@@ -3,21 +3,17 @@
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QGradient>
-#include "benchmarkdialog.h"
 #include "gradientchoosedialog.h"
 
 #include <cmath>
 
 Almond::Almond(QWidget *parent) :
-    QMainWindow(parent),
-    mandelContext(mnd::initializeContext())
+    QMainWindow{ parent },
+    mandelContext{ mnd::initializeContext() }
 {
     ui.setupUi(this);
-    printf("not yet created!\n");
     mw = std::make_unique<MandelWidget>(mandelContext, ui.centralWidget);
-    //qRegisterMetaType<MandelWidget>("MandelWidget");
-    printf("created!\n");
-    ui.verticalLayout_left->addWidget(mw.get());
+    ui.mainContainer->addWidget(mw.get());
     ui.maxIterations->setValidator(new QIntValidator(1, 1000000000, this));
     //ui.verticalLayout_left->addWidget(new MyGLWidget(ui.centralWidget));
     //mw->show();
@@ -84,9 +80,9 @@ void Almond::on_smooth_stateChanged(int checked)
 
 void Almond::on_runBenchmark_clicked()
 {
-    BenchmarkDialog bd(mandelContext, this);
-    //bd.show();
-    bd.exec();
+    if (!benchmarkDialog)
+        benchmarkDialog = std::make_unique<BenchmarkDialog>(mandelContext, this);
+    benchmarkDialog->exec();
 }
 
 void Almond::on_exportImage_clicked()
@@ -116,3 +112,8 @@ void Almond::on_resetZoom_clicked()
 {
     mw->setViewport(mnd::MandelViewport::standardView());
 }
+
+void Almond::on_displayInfo_stateChanged(int checked)
+{
+    this->mw->setDisplayInfo(checked != Qt::Unchecked);
+}

+ 4 - 0
Almond.h

@@ -7,6 +7,7 @@
 #include "MandelWidget.h"
 #include "exportdialogs.h"
 #include "gradientchoosedialog.h"
+#include "benchmarkdialog.h"
 
 #include <memory>
 
@@ -16,6 +17,7 @@ class Almond : public QMainWindow
 private:
     mnd::MandelContext mandelContext;
     std::unique_ptr<MandelWidget> mw;
+    std::unique_ptr<BenchmarkDialog> benchmarkDialog;
     GradientChooseDialog gcd;
 public:
     Almond(QWidget *parent = Q_NULLPTR);
@@ -31,6 +33,8 @@ private slots:
     void on_exportImage_clicked();
     void on_resetZoom_clicked();
 
+    void on_displayInfo_stateChanged(int arg1);
+
 private:
     Ui::AlmondClass ui;
 };

+ 3 - 3
Almond.pro

@@ -71,10 +71,10 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
 win32:LIBS += -lopengl32
 else:LIBS += -lOpenGL
 
-win32:QMAKE_CXXFLAGS+= -openmp
-else:unix:QMAKE_CXXFLAGS+= -fopenmp
+win32:QMAKE_CXXFLAGS += -openmp
+else:unix:QMAKE_CXXFLAGS +=
 win32:QMAKE_LFLAGS +=  -openmp
-else:unix:QMAKE_LFLAGS+= -fopenmp
+else:unix:QMAKE_LFLAGS+= -fopenmp -flto
 LIBS += -fopenmp
 unix:LIBS += -lm -latomic -lquadmath
 

+ 169 - 137
Almond.ui

@@ -19,146 +19,178 @@
   <widget class="QWidget" name="centralWidget">
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
-     <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="2,0">
-      <item>
-       <layout class="QVBoxLayout" name="verticalLayout_left">
-        <item>
-         <layout class="QHBoxLayout" name="horizontalLayout_3"/>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QVBoxLayout" name="verticalLayout_right">
-        <item>
-         <layout class="QFormLayout" name="formLayout">
-          <item row="1" column="0">
-           <widget class="QLabel" name="label">
-            <property name="text">
-             <string>max. iterations</string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="QLineEdit" name="maxIterations">
-            <property name="text">
-             <string>2000</string>
-            </property>
-            <property name="maxLength">
-             <number>32</number>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="0" colspan="2">
-           <widget class="QPushButton" name="chooseGradient">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Choose Gradient</string>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="0" colspan="2">
-           <widget class="QCheckBox" name="smooth">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>smooth coloring</string>
-            </property>
-            <property name="checked">
-             <bool>true</bool>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </item>
-        <item>
-         <spacer name="verticalSpacer">
-          <property name="orientation">
-           <enum>Qt::Vertical</enum>
-          </property>
-          <property name="sizeType">
-           <enum>QSizePolicy::Expanding</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>20</width>
-            <height>40</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item>
-         <widget class="QPushButton" name="zoom_in">
-          <property name="text">
-           <string>Zoom In</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="zoom_out">
-          <property name="text">
-           <string>Zoom Out</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="resetZoom">
-          <property name="text">
-           <string>Reset Zoom</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="verticalSpacer_2">
-          <property name="orientation">
-           <enum>Qt::Vertical</enum>
-          </property>
-          <property name="sizeType">
-           <enum>QSizePolicy::MinimumExpanding</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>20</width>
-            <height>40</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item>
-         <widget class="QPushButton" name="runBenchmark">
-          <property name="text">
-           <string>Run Benchmark</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="exportVideo">
-          <property name="text">
-           <string>Export Video</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="exportImage">
-          <property name="text">
-           <string>Export Image</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
+     <layout class="QVBoxLayout" name="mainContainer"/>
     </item>
    </layout>
   </widget>
+  <widget class="QDockWidget" name="dockWidget_2">
+   <property name="floating">
+    <bool>false</bool>
+   </property>
+   <property name="features">
+    <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
+   </property>
+   <property name="allowedAreas">
+    <set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
+   </property>
+   <property name="windowTitle">
+    <string>Options</string>
+   </property>
+   <attribute name="dockWidgetArea">
+    <number>2</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents_2">
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_right">
+       <item>
+        <layout class="QFormLayout" name="formLayout">
+         <item row="1" column="0">
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>max. iterations</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QLineEdit" name="maxIterations">
+           <property name="minimumSize">
+            <size>
+             <width>70</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>2000</string>
+           </property>
+           <property name="maxLength">
+            <number>32</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0" colspan="2">
+          <widget class="QPushButton" name="chooseGradient">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>Choose Gradient</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0" colspan="2">
+          <widget class="QCheckBox" name="smooth">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>smooth coloring</string>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="0" colspan="2">
+          <widget class="QCheckBox" name="displayInfo">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>display scale</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Expanding</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="zoom_in">
+         <property name="text">
+          <string>Zoom In</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="zoom_out">
+         <property name="text">
+          <string>Zoom Out</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="resetZoom">
+         <property name="text">
+          <string>Reset Zoom</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::MinimumExpanding</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="runBenchmark">
+         <property name="text">
+          <string>Run Benchmark</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="exportVideo">
+         <property name="text">
+          <string>Export Video</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="exportImage">
+         <property name="text">
+          <string>Export Image</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </widget>
+  </widget>
   <action name="actionExit">
    <property name="text">
     <string>Exit</string>

+ 55 - 2
MandelWidget.cpp

@@ -1,9 +1,10 @@
 #include "MandelWidget.h"
 #include <cmath>
+#include <sstream>
 
 using namespace mnd;
 
-#include <QOpenGLVertexArrayObject>
+#include <QPainter>
 
 
 Texture::Texture(const Bitmap<RGBColor>& bitmap, GLint param)
@@ -236,6 +237,7 @@ void Calcer::setMaxIter(int maxIter)
 {
     this->maxIter = maxIter;
     clearAll();
+    changeState();
 }
 
 
@@ -472,7 +474,6 @@ GridElement* MandelView::searchUnder(int level, GridIndex i, GridIndex j, int re
         && u01 != nullptr
         && u10 != nullptr
         && u11 != nullptr) {
-        GLuint FramebufferName = 0;
         auto newElement = std::make_unique<GridElement>(
             false, std::make_shared<QuadImage>(u00->img, u01->img, u10->img, u11->img)
         );
@@ -605,6 +606,15 @@ void MandelWidget::setSmoothColoring(bool sc)
 }
 
 
+void MandelWidget::setDisplayInfo(bool di)
+{
+    if (di != this->displayInfo) {
+        this->displayInfo = di;
+        emit update();
+    }
+}
+
+
 void MandelWidget::initializeGL(void)
 {
     this->context()->functions()->glClearColor(0, 0, 0, 0);
@@ -653,6 +663,8 @@ void MandelWidget::paintGL(void)
 
     if (rubberbanding)
         drawRubberband();
+    if (displayInfo)
+        drawInfo();
 }
 
 
@@ -703,6 +715,47 @@ void MandelWidget::drawRubberband(void)
 }
 
 
+void MandelWidget::drawInfo(void)
+{
+    const float DIST_FROM_BORDER = 15;
+    float maxWidth = this->width() - 2 * DIST_FROM_BORDER;
+    mnd::Real distPerPixel = currentViewport.width / this->width();
+    float log10 = (mnd::convert<float>(mnd::log(distPerPixel)) + ::logf(maxWidth)) / ::log(10);
+    mnd::Real displayDist = mnd::pow(mnd::Real(10), ::floor(log10));
+    float pixels = mnd::convert<float>(displayDist / distPerPixel);
+    int factor = 1;
+    for (int i = 9; i > 1; i--) {
+        if (pixels * i < maxWidth) {
+            factor *= i;
+            pixels *= i;
+            displayDist *= i;
+            break;
+        }
+    }
+
+    std::stringstream dis;
+    if (::abs(log10) < 3) {
+        dis << mnd::convert<float>(displayDist);
+    }
+    else {
+        dis << factor << "e" << int(::floor(log10));
+    }
+
+    float lineY = this->height() - DIST_FROM_BORDER;
+    float lineXEnd = DIST_FROM_BORDER + pixels;
+
+    QPainter infoPainter{ this };
+    infoPainter.setPen(Qt::white);
+    infoPainter.setFont(QFont("Arial", 12));
+    infoPainter.drawLine(QPointF{ DIST_FROM_BORDER, lineY }, QPointF{ lineXEnd, lineY });
+    infoPainter.drawLine(QPointF{ DIST_FROM_BORDER, lineY }, QPointF{ DIST_FROM_BORDER, lineY - 5 });
+    infoPainter.drawLine(QPointF{ lineXEnd, lineY }, QPointF{ lineXEnd, lineY - 5 });
+    infoPainter.drawText(DIST_FROM_BORDER, lineY - 20, lineXEnd - DIST_FROM_BORDER, 20, Qt::AlignCenter, QString::fromStdString(dis.str()));
+    //infoPainter.drawText(0, this->height() - 30, this->width(), 30, Qt::AlignBottom | Qt::AlignVCenter, QString::fromStdString(ss.str()));
+    infoPainter.end();
+}
+
+
 void MandelWidget::zoom(float scale, float x, float y)
 {
     targetViewport.zoom(scale, x, y);

+ 6 - 0
MandelWidget.h

@@ -297,6 +297,8 @@ private:
     volatile bool dragging = false;
     int dragX, dragY;
 
+    bool displayInfo = false;
+
     mnd::MandelViewport currentViewport;
     mnd::MandelViewport targetViewport;
     std::chrono::time_point<std::chrono::high_resolution_clock> lastAnimUpdate;
@@ -312,6 +314,9 @@ public:
     inline bool getSmoothColoring(void) const { return smoothColoring; }
     void setSmoothColoring(bool sc);
 
+    inline bool doesDisplayInfo(void) const { return displayInfo; }
+    void setDisplayInfo(bool di);
+
     void initializeGL(void) override;
 
     void resizeGL(int w, int h) override;
@@ -322,6 +327,7 @@ private:
     void updateAnimations(void);
 
     void drawRubberband(void);
+    void drawInfo(void);
 public:
 
     void zoom(float scale, float x = 0.5f, float y = 0.5f);

+ 20 - 4
benchmarkdialog.cpp

@@ -105,14 +105,19 @@ void Benchmarker::start(void)
 {
     mnd::Generator& cpuf = mndContext.getCpuGeneratorFloat();
     mnd::Generator& cpud = mndContext.getCpuGeneratorDouble();
+    mnd::Generator* cpudd = mndContext.getCpuGeneratorDD();
+    mnd::Generator* cpuqd = mndContext.getCpuGeneratorQD();
     mnd::Generator* cpu128 = mndContext.getCpuGeneratorQuad();
-    mnd::Generator* cpu256 = mndContext.getCpuGeneratorDD();
+    mnd::Generator* cpu256 = mndContext.getCpuGeneratorOct();
 
     double nTests = 2;
 
+    if (cpudd)
+        nTests++;
+    if (cpuqd)
+        nTests++;
     if (cpu128)
         nTests++;
-
     if (cpu256)
         nTests++;
 
@@ -145,6 +150,17 @@ void Benchmarker::start(void)
     cpu.push_back(benchmarkResult(cpud));
     br.percentage += progress;
     emit update(br);
+
+    if (cpudd) {
+        cpu.push_back(benchmarkResult(*cpudd));
+        br.percentage += progress;
+        emit update(br);
+    }
+    if (cpuqd) {
+        cpu.push_back(benchmarkResult(*cpuqd));
+        br.percentage += progress;
+        emit update(br);
+    }
     if (cpu128) {
         cpu.push_back(benchmarkResult(*cpu128));
         br.percentage += progress;
@@ -190,9 +206,9 @@ BenchmarkDialog::BenchmarkDialog(mnd::MandelContext& mndContext, QWidget *parent
 
     auto& devices = mndContext.getDevices();
     int nDevices = devices.size() + 1;
-    ui.tableWidget->setColumnCount(4);
+    ui.tableWidget->setColumnCount(6);
     ui.tableWidget->setRowCount(nDevices);
-    ui.tableWidget->setHorizontalHeaderLabels({"Single Precision", "Double Precision", "Quad Precision", "Oct Precision"});
+    ui.tableWidget->setHorizontalHeaderLabels({"Single Precision", "Double Precision", "Double-Double Precision", "Quad-Double Precision", "Quad Precision", "Oct Precision"});
 
     QString cpuDesc = ("CPU [" + mndContext.getCpuInfo().getBrand() + "]").c_str();
     ui.tableWidget->setVerticalHeaderItem(0, new QTableWidgetItem(cpuDesc));

+ 43 - 42
benchmarks.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1064</width>
-    <height>423</height>
+    <width>864</width>
+    <height>401</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -25,8 +25,17 @@
      </item>
      <item>
       <widget class="QLabel" name="label">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
        <property name="text">
-        <string>All results are measured in mega-iterations per second.</string>
+        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Measure the preformance of Almond on this machine. To obtain good results, run the benchmarks while no other compute-heavy tasks are running on the computer.&lt;/p&gt;&lt;p&gt;The benchmarking consists of several renders of the Mandelbrot fractal each using a different datatype for the underlying operations. The more precision the type allows for, the slower it performs (normally). If you have a video card, Almond will try to use it to do calculations as the tasks are exceptionally well suited for parallel execution.&lt;/p&gt;&lt;p&gt;All results are measured in mega-iterations per second.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
        </property>
       </widget>
      </item>
@@ -38,51 +47,43 @@
       </widget>
      </item>
      <item>
-      <widget class="QPushButton" name="run">
-       <property name="text">
-        <string>Run</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QProgressBar" name="progressBar">
-       <property name="enabled">
-        <bool>false</bool>
-       </property>
-       <property name="maximum">
-        <number>100</number>
-       </property>
-       <property name="value">
-        <number>0</number>
-       </property>
-       <property name="textVisible">
-        <bool>false</bool>
-       </property>
-       <property name="invertedAppearance">
-        <bool>false</bool>
-       </property>
-      </widget>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QPushButton" name="run">
+         <property name="text">
+          <string>Run</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QProgressBar" name="progressBar">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="maximum">
+          <number>100</number>
+         </property>
+         <property name="value">
+          <number>0</number>
+         </property>
+         <property name="textVisible">
+          <bool>false</bool>
+         </property>
+         <property name="invertedAppearance">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
      </item>
      <item>
       <widget class="QTableWidget" name="tableWidget">
        <property name="editTriggers">
         <set>QAbstractItemView::NoEditTriggers</set>
        </property>
-       <property name="alternatingRowColors">
-        <bool>true</bool>
-       </property>
-       <property name="verticalScrollMode">
-        <enum>QAbstractItemView::ScrollPerPixel</enum>
-       </property>
-       <property name="horizontalScrollMode">
-        <enum>QAbstractItemView::ScrollPerPixel</enum>
-       </property>
-       <property name="rowCount">
-        <number>0</number>
-       </property>
-       <property name="columnCount">
-        <number>0</number>
-       </property>
+       <attribute name="horizontalHeaderMinimumSectionSize">
+        <number>130</number>
+       </attribute>
       </widget>
      </item>
     </layout>

+ 11 - 9
libmandel/CMakeLists.txt

@@ -33,6 +33,7 @@ SET(MandelSources
     src/Mandel.cpp
     src/Hardware.cpp
     src/MandelUtil.cpp
+    src/Types.cpp
 )
 FILE(GLOB MandelHeaders include/*.h)
 
@@ -46,15 +47,6 @@ endif()
 
 add_library(mandel STATIC ${MandelSources})
 
-
-include(CheckIPOSupported)
-check_ipo_supported(RESULT LTO_SUPPORTED)
-
-if (LTO_SUPPORTED)
-    message("enable link-time optimization")
-    set_property(TARGET mandel PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
-endif(LTO_SUPPORTED)
-
 FILE(GLOB QdSources qd-2.3.22/src/*.cpp)
 
 target_compile_definitions(mandel PUBLIC WITH_QD)
@@ -65,6 +57,16 @@ target_include_directories(qd PUBLIC qd-2.3.22)
 #target_include_directories(mandel PUBLI#C qd-2.3.22/include)
 target_link_libraries(mandel PUBLIC qd)
 
+include(CheckIPOSupported)
+check_ipo_supported(RESULT LTO_SUPPORTED)
+
+if (LTO_SUPPORTED AND WITH_LTO)
+    message("Enabling link-time optimization.")
+    set_property(TARGET mandel PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+    set_property(TARGET qd PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+endif()
+
+
 if(MPFR_INCLUDES AND MPFR_LIBRARIES)
     set(MPFR_FOUND TRUE)
     #target_compile_definitions(mandel PUBLIC WITH_MPFR)

+ 4 - 2
libmandel/include/Generators.h

@@ -35,12 +35,14 @@ public:
 
 class mnd::AdaptiveGenerator : public Generator
 {
-    std::vector<std::pair<Real, Generator*>> generators;
+    std::map<Real, Generator*, std::greater<Real>> generators;
 public:
+    AdaptiveGenerator(void) = default;
     AdaptiveGenerator(Generator* floatGen, Generator* doubleGen);
-    AdaptiveGenerator(Generator* floatGen, Generator* doubleGen, Generator* quadGen);
     virtual ~AdaptiveGenerator(void) = default;
 
+    void addGenerator(const Real& precision, Generator& generator);
+
     virtual void generate(const MandelInfo& info, float* data);
 };
 

+ 5 - 2
libmandel/include/Mandel.h

@@ -65,15 +65,17 @@ private:
     std::unique_ptr<Generator> cpuGeneratorOct;
     std::unique_ptr<Generator> cpuGenerator128;
     std::unique_ptr<Generator> cpuGeneratorDD;
+    std::unique_ptr<Generator> cpuGeneratorQD;
 
     std::unique_ptr<Generator> cpuGeneratorFloatSmooth;
     std::unique_ptr<Generator> cpuGeneratorDoubleSmooth;
     std::unique_ptr<Generator> cpuGeneratorQuadSmooth;
     std::unique_ptr<Generator> cpuGenerator128Smooth;
     std::unique_ptr<Generator> cpuGeneratorDDSmooth;
+    std::unique_ptr<Generator> cpuGeneratorQDSmooth;
 
-    std::unique_ptr<Generator> adaptiveGenerator;
-    std::unique_ptr<Generator> adaptiveGeneratorSmooth;
+    std::unique_ptr<AdaptiveGenerator> adaptiveGenerator;
+    std::unique_ptr<AdaptiveGenerator> adaptiveGeneratorSmooth;
 
     std::vector<MandelDevice> devices;
 
@@ -91,6 +93,7 @@ public:
     Generator* getCpuGeneratorOct(void);
     Generator* getCpuGenerator128(void);
     Generator* getCpuGeneratorDD(void);
+    Generator* getCpuGeneratorQD(void);
 
     const CpuInfo& getCpuInfo(void) const { return cpuInfo; }
 };

+ 33 - 11
libmandel/include/Types.h

@@ -9,13 +9,14 @@
 #ifdef WITH_BOOST
 #   include <boost/multiprecision/cpp_bin_float.hpp>
 #   if defined(__GNUC__) || defined(__INTEL_COMPILER)
-#       include <boost/multiprecision/float128.hpp>
+//#       include <boost/multiprecision/float128.hpp>
 #   endif
 #   include <boost/multiprecision/cpp_int.hpp>
 #endif
 
 #ifdef WITH_QD
 #   include <qd/dd_real.h>
+#   include <qd/qd_real.h>
 #endif
 
 namespace mnd
@@ -26,11 +27,11 @@ namespace mnd
 #   if 0//defined(__GNUC__) || defined(__INTEL_COMPILER)
     using Float128 = boost::multiprecision::float128;
 #   else
-    //using Float128 = boost::multiprecision::cpp_bin_float_quad;
-    using Float128 = boost::multiprecision::number<
+    using Float128 = boost::multiprecision::cpp_bin_float_quad;
+    /*using Float128 = boost::multiprecision::number<
         boost::multiprecision::backends::cpp_bin_float<
             112, boost::multiprecision::backends::digit_base_2, void, boost::int16_t, -16382, 16383>,
-            boost::multiprecision::et_off>;
+            boost::multiprecision::et_off>;*/
 #   endif
     inline Float128 abs(const Float128& x) { return boost::multiprecision::abs(x); }
     inline Float128 floor(const Float128& x) { return boost::multiprecision::floor(x); }
@@ -38,21 +39,19 @@ namespace mnd
     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); }
 
-
-/*
     using Float256 = boost::multiprecision::number<
         boost::multiprecision::backends::cpp_bin_float<
             240, boost::multiprecision::backends::digit_base_2, void, boost::int16_t, -16382, 16383>,
             boost::multiprecision::et_off>;
-*/
-    using Float256 = long double;
-    /*inline Float256 abs(const Float256& x) { return boost::multiprecision::abs(x); }
+
+    //using Float256 = long double;
+    inline Float256 abs(const Float256& x) { return boost::multiprecision::abs(x); }
     inline Float256 floor(const Float256& x) { return boost::multiprecision::floor(x); }
     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); }
-*/
-    using Real = Float128;
+
+    using Real = Float256;
     using Integer = boost::multiprecision::int256_t;
 #else
     using Real = double;
@@ -62,12 +61,20 @@ namespace mnd
 
 #ifdef WITH_QD
     using DoubleDouble = dd_real;
+    using QuadDouble = qd_real;
 
     inline DoubleDouble abs(const DoubleDouble& x) { return ::abs(x); }
     inline DoubleDouble floor(const DoubleDouble& x) { return ::floor(x); }
     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 QuadDouble abs(const QuadDouble& x) { return ::abs(x); }
+    inline QuadDouble floor(const QuadDouble& x) { return ::floor(x); }
+    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); }
 #endif
 
     inline double abs(double x) { return ::abs(x); }
@@ -101,7 +108,22 @@ namespace mnd
     {
         return float(x.x[0] + x.x[1]);
     }
+
+        template<>
+    inline QuadDouble convert<QuadDouble, Real>(const Real& x)
+    {
+        std::string s = x.str();
+        return QuadDouble(s.c_str());
+    }
+
+    template<>
+    inline float convert<float, QuadDouble>(const QuadDouble& x)
+    {
+        return float(x.x[0] + x.x[1]);
+    }
 #endif
+
+    std::string toString(const Real& num);
 }
 
 

+ 1 - 1
libmandel/src/ClGenerators.cpp

@@ -266,7 +266,7 @@ std::string ClGeneratorDouble::getKernelCode(bool smooth) const
             "   if (n >= max - 1)\n"
             "       A[index] = max;\n"
             "   else"
-            "       A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
+            "       A[index] = ((float)n) + 1 - log(log((float)(a * a + b * b)) / 2) / log(2.0f);\n"
             //            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
             //        "   A[get_global_id(0)] = 5;"
             "}";

+ 11 - 5
libmandel/src/CpuGenerators.cpp

@@ -25,10 +25,10 @@ namespace mnd
     template class CpuGenerator<double, mnd::NONE, true, true>;
 
     
-    template class CpuGenerator<Fixed128, mnd::NONE, false, false>;
-    template class CpuGenerator<Fixed128, mnd::NONE, false, true>;
-    template class CpuGenerator<Fixed128, mnd::NONE, true, false>;
-    template class CpuGenerator<Fixed128, mnd::NONE, true, true>;
+    //template class CpuGenerator<Fixed128, mnd::NONE, false, false>;
+    //template class CpuGenerator<Fixed128, mnd::NONE, false, true>;
+    //template class CpuGenerator<Fixed128, mnd::NONE, true, false>;
+    //template class CpuGenerator<Fixed128, mnd::NONE, true, true>;
     
 
 #ifdef WITH_BOOST
@@ -49,6 +49,11 @@ namespace mnd
     template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, false, true>;
     template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, true, false>;
     template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, true, true>;
+
+    template class CpuGenerator<mnd::QuadDouble, mnd::NONE, false, false>;
+    template class CpuGenerator<mnd::QuadDouble, mnd::NONE, false, true>;
+    template class CpuGenerator<mnd::QuadDouble, mnd::NONE, true, false>;
+    template class CpuGenerator<mnd::QuadDouble, mnd::NONE, true, true>;
 #endif
 }
 
@@ -98,7 +103,7 @@ void CpuGenerator<T, mnd::NONE, parallel, smooth>::generate(const mnd::MandelInf
     }
 }
 
-
+/*
 #if defined(WITH_BOOST) || 1
 template<bool parallel, bool smooth>
 void CpuGenerator<Fixed128, mnd::NONE, parallel, smooth>::generate(const mnd::MandelInfo& info, float* data)
@@ -150,6 +155,7 @@ void CpuGenerator<Fixed128, mnd::NONE, parallel, smooth>::generate(const mnd::Ma
     }
 }
 #endif // WITH_BOOST
+*/
 
 #ifdef WITH_MPFR
 template<unsigned int bits, bool parallel, bool smooth>

+ 29 - 11
libmandel/src/Generators.cpp

@@ -12,16 +12,22 @@ Generator::~Generator(void)
 
 AdaptiveGenerator::AdaptiveGenerator(Generator* floatGen, Generator* doubleGen)
 {
-    generators.push_back({ 0.0000001, floatGen });
-    generators.push_back({ 0.0, doubleGen });
+    generators.insert({ 0.0000001, floatGen });
+    generators.insert({ 0.0, doubleGen });
 }
 
-
+/*
 AdaptiveGenerator::AdaptiveGenerator(Generator* floatGen, Generator* doubleGen, Generator* quadGen)
 {
-    //generators.push_back({ 0.0000001, floatGen });
-    //generators.push_back({ 5.0e-16, doubleGen });
-    generators.push_back({ 0.0, quadGen });
+    generators.insert({ 0.0000001, floatGen });
+    generators.insert({ 5.0e-16, doubleGen });
+    generators.insert({ Real("1.0e-28"), quadGen });
+}*/
+
+
+void AdaptiveGenerator::addGenerator(const Real& precision, Generator& generator)
+{
+    generators.insert({ precision, &generator });
 }
 
 
@@ -29,16 +35,28 @@ void AdaptiveGenerator::generate(const mnd::MandelInfo& info, float* data)
 {
     Real pixelW = info.view.width / info.bWidth;
     Real pixelH = info.view.height / info.bHeight;
-    Real minimum = pixelW < pixelH ? pixelW : pixelH;
+    Real neededPrecision = pixelW < pixelH ? pixelW : pixelH;
+
+    //Generator* toUse = nullptr;
+    auto firstSmaller = generators.lower_bound(neededPrecision);
+    if (firstSmaller != generators.end()) {
+        //printf("use generator with precision: %s\n", mnd::toString(firstSmaller->first).c_str());
+        firstSmaller->second->generate(info, data);
+    }
+    else {
+        for (long s = 0; s < info.bWidth * info.bHeight; s++) {
+            data[s] = 0.0;
+        }
+    }
+    return;
 
-    Generator* toUse = nullptr;
+/*
     int i = 0;
 
     for (auto [thresh, gen] : generators) {
         ++i;
-        if (minimum > thresh) {
+        if (neededPrecision > thresh) {
             toUse = gen;
-            break;
         }
     }
     if (toUse != nullptr) {
@@ -48,7 +66,7 @@ void AdaptiveGenerator::generate(const mnd::MandelInfo& info, float* data)
         for (long s = 0; s < info.bWidth * info.bHeight; s++) {
             data[s] = 0.0;
         }
-    }
+    }*/
 }
 
 

+ 41 - 32
libmandel/src/Mandel.cpp

@@ -76,7 +76,8 @@ MandelContext::MandelContext(void) :
         cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true, false>>();
         cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true, false>>();
         cpuGeneratorFloatSmooth = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true, true>>();
-        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true, true>>();
+        //cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true, true>>();
+        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::NONE, true, true>>();
     }
     else if (cpuInfo.hasSse2()) {
         cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_SSE2, true, false>>();
@@ -108,52 +109,54 @@ MandelContext::MandelContext(void) :
     cpuGeneratorQuad = std::make_unique<CpuGenerator<Float128, mnd::NONE, true, false>>();
     cpuGeneratorQuadSmooth = std::make_unique<CpuGenerator<Float128, mnd::NONE, true, true>>();
     cpuGeneratorOct = std::make_unique<CpuGenerator<Float256, mnd::NONE, true, false>>();
-    cpuGenerator128 = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, false>>();
-    cpuGenerator128Smooth = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, true>>();
+    //cpuGenerator128 = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, false>>();
+    //cpuGenerator128Smooth = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, true>>();
 #endif // WITH_BOOST
 
 #ifdef WITH_QD
     cpuGeneratorDD = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true, false>>();
     cpuGeneratorDDSmooth = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true, true>>();
+    cpuGeneratorQD = std::make_unique<CpuGenerator<QuadDouble, mnd::NONE, true, false>>();
+    cpuGeneratorQDSmooth = std::make_unique<CpuGenerator<QuadDouble, mnd::NONE, true, true>>();
 #endif
 
     devices = createDevices();
-    if (devices.empty()) {
-#ifdef WITH_BOOST
-        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(
-            cpuGeneratorFloat.get(), cpuGeneratorDouble.get(), cpuGeneratorQuad.get());
-        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(
-            cpuGeneratorFloatSmooth.get(), cpuGeneratorDoubleSmooth.get(),
-            cpuGeneratorQuadSmooth.get());
-#else
-        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(
-            cpuGeneratorFloat.get(), cpuGeneratorDouble.get());
-        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(
-            cpuGeneratorFloatSmooth.get(), cpuGeneratorDoubleSmooth.get());
-#endif
-    }
-    else {
+
+
+    adaptiveGenerator = std::make_unique<AdaptiveGenerator>();
+    adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>();
+
+    adaptiveGenerator->addGenerator(1.0e-7, *cpuGeneratorFloat);
+    adaptiveGenerator->addGenerator(0.5e-15, *cpuGeneratorDouble);
+    adaptiveGeneratorSmooth->addGenerator(1.0e-7, *cpuGeneratorFloatSmooth);
+    adaptiveGeneratorSmooth->addGenerator(0.5e-15, *cpuGeneratorDoubleSmooth);
+
+    {
         auto& device1 = devices[0];
         Generator* floatGenerator = device1.getGeneratorFloat(false);
         Generator* doubleGenerator = device1.getGeneratorDouble(false);
         Generator* floatGeneratorSmooth = device1.getGeneratorFloat(true);
         Generator* doubleGeneratorSmooth = device1.getGeneratorDouble(true);
-        if (floatGenerator == nullptr)
-            floatGenerator = cpuGeneratorFloat.get();
-        if (doubleGenerator == nullptr)
-            doubleGenerator = cpuGeneratorDouble.get();
-        if (floatGeneratorSmooth == nullptr)
-            floatGeneratorSmooth = cpuGeneratorFloatSmooth.get();
-        if (doubleGeneratorSmooth == nullptr)
-            doubleGeneratorSmooth = cpuGeneratorDoubleSmooth.get();
+        if (floatGenerator != nullptr)
+            adaptiveGenerator->addGenerator(1.0e-7, *floatGenerator);
+        if (doubleGenerator != nullptr)
+            adaptiveGenerator->addGenerator(0.5e-15, *doubleGenerator);
+        if (floatGeneratorSmooth != nullptr)
+            adaptiveGeneratorSmooth->addGenerator(1.0e-7, *floatGeneratorSmooth);
+        if (doubleGeneratorSmooth != nullptr)
+            adaptiveGeneratorSmooth->addGenerator(0.5e-15, *doubleGeneratorSmooth);
+    }
+
+#ifdef WITH_QD
+        adaptiveGenerator->addGenerator(Real("1.0e-29"), *cpuGeneratorDD);
+        adaptiveGeneratorSmooth->addGenerator(Real("1.0e-29"), *cpuGeneratorDDSmooth);
+        adaptiveGenerator->addGenerator(Real("1.0e-50"), *cpuGeneratorQD);
+        adaptiveGeneratorSmooth->addGenerator(Real("1.0e-50"), *cpuGeneratorQDSmooth);
+#endif
 #ifdef WITH_BOOST
-        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth, cpuGeneratorDDSmooth.get());
-        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator, cpuGeneratorDD.get());
-#else
-        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth);
-        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator);
+        //adaptiveGenerator->addGenerator(1.0e-28, *cpuGeneratorQuad);
+        //adaptiveGeneratorSmooth->addGenerator(1.0e-28, *cpuGeneratorQuadSmooth);
 #endif
-    }
 }
 
 
@@ -278,3 +281,9 @@ Generator* MandelContext::getCpuGeneratorDD(void)
 {
     return cpuGeneratorDD.get();
 }
+
+
+Generator* MandelContext::getCpuGeneratorQD(void)
+{
+    return cpuGeneratorQD.get();
+}

+ 21 - 0
libmandel/src/Types.cpp

@@ -0,0 +1,21 @@
+#include "Types.h"
+#include <sstream>
+
+
+namespace mnd
+{
+#ifdef WITH_BOOST
+    std::string toString(const Real& num)
+    {
+        return num.str();
+    }
+#else // !WITH_BOOST
+    std::string toString(const Real& num)
+    {
+        std::stringstream ss;
+        ss << num;
+        return ss.str();
+    }
+#endif // WITH_BOOST
+}
+