From 03508faabfc2f5b76039cfd13d02a341baa848a4 Mon Sep 17 00:00:00 2001
From: Serge Bazanski <serge@bazanski.pl>
Date: Tue, 17 Jul 2018 19:16:26 +0100
Subject: WIP.

---
 common/nextpnr.h      |   2 +-
 common/placer1.cc     |   9 +++
 common/router1.cc     |   2 +
 gui/application.cc    |  20 ++---
 gui/fpgaviewwidget.cc | 220 ++++++++++++++++++++++++++++++++++++--------------
 gui/fpgaviewwidget.h  |  62 ++++++++------
 ice40/arch.h          |   8 ++
 7 files changed, 227 insertions(+), 96 deletions(-)

diff --git a/common/nextpnr.h b/common/nextpnr.h
index 7aa5b100..fb5e042b 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -369,7 +369,7 @@ class BaseCtx : public IdStringDB, public DeterministicRNG
 
     // --------------------------------------------------------------
 
-    bool allUiReload = false;
+    bool allUiReload = true;
     bool frameUiReload = false;
     std::unordered_set<BelId> belUiReload;
     std::unordered_set<WireId> wireUiReload;
diff --git a/common/placer1.cc b/common/placer1.cc
index b229616c..b58893ce 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -29,6 +29,7 @@
 #include <list>
 #include <map>
 #include <ostream>
+#include <pthread.h>
 #include <queue>
 #include <set>
 #include <stdarg.h>
@@ -156,6 +157,14 @@ class SAPlacer
 
         // Main simulated annealing loop
         for (int iter = 1;; iter++) {
+            // TODO(q3k): unwat
+            pthread_yield();
+            pthread_yield();
+            pthread_yield();
+            pthread_yield();
+            pthread_yield();
+            pthread_yield();
+            pthread_yield();
             ctx->lock();
             n_move = n_accept = 0;
             improved = false;
diff --git a/common/router1.cc b/common/router1.cc
index a85de7c6..bde3be31 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -637,7 +637,9 @@ bool router1(Context *ctx)
 
         log_info("Checksum: 0x%08x\n", ctx->checksum());
 #ifndef NDEBUG
+        ctx->lock();
         ctx->check();
+        ctx->unlock();
 #endif
         return true;
     } catch (log_execution_error_exception) {
diff --git a/gui/application.cc b/gui/application.cc
index 58dc23eb..12453b57 100644
--- a/gui/application.cc
+++ b/gui/application.cc
@@ -37,17 +37,17 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
 bool Application::notify(QObject *receiver, QEvent *event)
 {
     bool retVal = true;
-    try {
+    //try {
         retVal = QApplication::notify(receiver, event);
-    } catch (assertion_failure ex) {
-        QString msg;
-        QTextStream out(&msg);
-        out << ex.filename.c_str() << " at " << ex.line << "\n";
-        out << ex.msg.c_str();
-        QMessageBox::critical(0, "Error", msg);
-    } catch (...) {
-        QMessageBox::critical(0, "Error", "Fatal error !!!");
-    }
+    //} catch (assertion_failure ex) {
+    //    QString msg;
+    //    QTextStream out(&msg);
+    //    out << ex.filename.c_str() << " at " << ex.line << "\n";
+    //    out << ex.msg.c_str();
+    //    QMessageBox::critical(0, "Error", msg);
+    //} catch (...) {
+    //    QMessageBox::critical(0, "Error", "Fatal error !!!");
+    //}
     return retVal;
 }
 
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index c926e5fa..f4bd2b97 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -23,6 +23,7 @@
 #include <QApplication>
 #include <QCoreApplication>
 #include <QMouseEvent>
+#include <QTimer>
 #include <QWidget>
 
 #include "fpgaviewwidget.h"
@@ -241,26 +242,25 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi
 }
 
 FPGAViewWidget::FPGAViewWidget(QWidget *parent)
-        : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false)
+        : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs)
 {
-    backgroundColor_ = QColor("#000000");
-    gridColor_ = QColor("#333");
-    gFrameColor_ = QColor("#d0d0d0");
-    gHiddenColor_ = QColor("#606060");
-    gInactiveColor_ = QColor("#303030");
-    gActiveColor_ = QColor("#f0f0f0");
-    gSelectedColor_ = QColor("#ff6600");
-    frameColor_ = QColor("#0066ba");
-    highlightColors[0] = QColor("#6495ed");
-    highlightColors[1] = QColor("#7fffd4");
-    highlightColors[2] = QColor("#98fb98");
-    highlightColors[3] = QColor("#ffd700");
-    highlightColors[4] = QColor("#cd5c5c");
-    highlightColors[5] = QColor("#fa8072");
-    highlightColors[6] = QColor("#ff69b4");
-    highlightColors[7] = QColor("#da70d6");
-    for (int i = 0; i < 8; i++)
-        highlightItemsChanged_[i] = false;
+    colors_.background  = QColor("#000000");
+    colors_.grid = QColor("#333");
+    colors_.frame = QColor("#d0d0d0");
+    colors_.hidden = QColor("#606060");
+    colors_.inactive = QColor("#303030");
+    colors_.active = QColor("#f0f0f0");
+    colors_.selected = QColor("#ff6600");
+    colors_.highlight[0] = QColor("#6495ed");
+    colors_.highlight[1] = QColor("#7fffd4");
+    colors_.highlight[2] = QColor("#98fb98");
+    colors_.highlight[3] = QColor("#ffd700");
+    colors_.highlight[4] = QColor("#cd5c5c");
+    colors_.highlight[5] = QColor("#fa8072");
+    colors_.highlight[6] = QColor("#ff69b4");
+    colors_.highlight[7] = QColor("#da70d6");
+
+    rendererArgs_->highlightedOrSelectedChanged = false;
 
     auto fmt = format();
     fmt.setMajorVersion(3);
@@ -268,7 +268,6 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent)
     setFormat(fmt);
 
     fmt = format();
-    // printf("FPGAViewWidget running on OpenGL %d.%d\n", fmt.majorVersion(), fmt.minorVersion());
     if (fmt.majorVersion() < 3) {
         printf("Could not get OpenGL 3.0 context. Aborting.\n");
         log_abort();
@@ -276,6 +275,17 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent)
     if (fmt.minorVersion() < 1) {
         printf("Could not get OpenGL 3.1 context - trying anyway...\n ");
     }
+
+    QTimer *timer = new QTimer(this);
+	connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+	timer->start(1000/20);
+
+    timer = new QTimer(this);
+	connect(timer, SIGNAL(timeout()), this, SLOT(pokeRenderer()));
+	timer->start(1000/2);
+
+    renderThread_ = std::unique_ptr<QThread>(QThread::create([this] { renderLinesWorker(); }));
+    renderThread_->start();
 }
 
 FPGAViewWidget::~FPGAViewWidget() {}
@@ -283,8 +293,7 @@ FPGAViewWidget::~FPGAViewWidget() {}
 void FPGAViewWidget::newContext(Context *ctx)
 {
     ctx_ = ctx;
-    selectedItems_.clear();
-    update();
+    pokeRenderer();
 }
 
 QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); }
@@ -297,7 +306,7 @@ void FPGAViewWidget::initializeGL()
         log_error("Could not compile shader.\n");
     }
     initializeOpenGLFunctions();
-    glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0);
+    glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.blue() / 255, 0.0);
 }
 
 void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal)
@@ -398,67 +407,158 @@ void FPGAViewWidget::paintGL()
         PolyLine(-100.0f, i, 100.0f, i).build(grid);
         PolyLine(i, -100.0f, i, 100.0f).build(grid);
     }
-    lineShader_.draw(grid, gridColor_, thick1Px, matrix);
+    lineShader_.draw(grid, colors_.grid, thick1Px, matrix);
 
-    LineShaderData shaders[4] = {LineShaderData(), LineShaderData(), LineShaderData(), LineShaderData()};
+    rendererDataLock_.lock();
+    lineShader_.draw(rendererData_->decals[0], colors_.frame, thick11Px, matrix);
+    lineShader_.draw(rendererData_->decals[1], colors_.hidden, thick11Px, matrix);
+    lineShader_.draw(rendererData_->decals[2], colors_.inactive, thick11Px, matrix);
+    lineShader_.draw(rendererData_->decals[3], colors_.active, thick11Px, matrix);
 
-    if (ctx_) {
-        // Draw Bels.
+    for (int i = 0; i < 8; i++)
+        lineShader_.draw(rendererData_->highlighted[i], colors_.highlight[i], thick11Px, matrix);
+
+    lineShader_.draw(rendererData_->selected, colors_.selected, thick11Px, matrix);
+    rendererDataLock_.unlock();
+}
+
+void FPGAViewWidget::pokeRenderer(void) {
+    render_.wakeOne();
+}
+
+void FPGAViewWidget::renderLinesWorker(void) {
+    for (;;) {
+        QMutex mutex;
+        mutex.lock();
+        render_.wait(&mutex);
+
+        renderLines();
+
+        mutex.unlock();
+    }
+}
+
+void FPGAViewWidget::renderLines(void)
+{
+    if (ctx_ == nullptr)
+        return;
+
+    ctx_->lock();
+
+    // For now, collapse any decal changes into change of all decals.
+    // TODO(q3k): fix this
+    bool decalsChanged = false;
+    if (ctx_->allUiReload) {
+        ctx_->allUiReload = false;
+        decalsChanged = true;
+    }
+    if (ctx_->frameUiReload) {
+        ctx_->frameUiReload = false;
+        decalsChanged = true;
+    }
+    if (ctx_->belUiReload.size() > 0){
+        ctx_->belUiReload.clear();
+        decalsChanged = true;
+    }
+    if (ctx_->wireUiReload.size() > 0) {
+        ctx_->wireUiReload.clear();
+        decalsChanged = true;
+    }
+    if (ctx_->pipUiReload.size() > 0) {
+        ctx_->pipUiReload.clear();
+        decalsChanged = true;
+    }
+    if (ctx_->groupUiReload.size() > 0) {
+        ctx_->groupUiReload.clear();
+        decalsChanged = true;
+    }
+
+    // Local copy of decals, taken as fast as possible to not block the P&R.
+    std::vector<DecalXY> belDecals;
+    std::vector<DecalXY> wireDecals;
+    std::vector<DecalXY> pipDecals;
+    std::vector<DecalXY> groupDecals;
+    if (decalsChanged) {
         for (auto bel : ctx_->getBels()) {
-            drawDecal(shaders, ctx_->getBelDecal(bel));
+            belDecals.push_back(ctx_->getBelDecal(bel));
         }
-        // Draw Wires.
         for (auto wire : ctx_->getWires()) {
-            drawDecal(shaders, ctx_->getWireDecal(wire));
+            wireDecals.push_back(ctx_->getWireDecal(wire));
         }
-        // Draw Pips.
         for (auto pip : ctx_->getPips()) {
-            drawDecal(shaders, ctx_->getPipDecal(pip));
+            pipDecals.push_back(ctx_->getPipDecal(pip));
         }
-        // Draw Groups.
         for (auto group : ctx_->getGroups()) {
-            drawDecal(shaders, ctx_->getGroupDecal(group));
+            groupDecals.push_back(ctx_->getGroupDecal(group));
         }
+    }
+    ctx_->unlock();
 
-        if (selectedItemsChanged_) {
-            selectedItemsChanged_ = false;
-            selectedShader_.clear();
-            for (auto decal : selectedItems_) {
-                drawDecal(selectedShader_, decal);
-            }
+    rendererArgsLock_.lock();
+    auto selectedItems = rendererArgs_->selectedItems;
+    auto highlightedItems = rendererArgs_->highlightedItems;
+    auto highlightedOrSelectedChanged = rendererArgs_->highlightedOrSelectedChanged;
+    rendererArgs_->highlightedOrSelectedChanged = false;
+    rendererArgsLock_.unlock();
+
+    if (decalsChanged) {
+        auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData);
+        // Draw Bels.
+        for (auto const &decal : belDecals) {
+            drawDecal(data->decals, decal);
+        }
+        // Draw Wires.
+        for (auto const &decal : wireDecals) {
+            drawDecal(data->decals, decal);
+        }
+        // Draw Pips.
+        for (auto const &decal : pipDecals) {
+            drawDecal(data->decals, decal);
+        }
+        // Draw Groups.
+        for (auto const &decal : groupDecals) {
+            drawDecal(data->decals, decal);
+        }
+
+        // Swap over.
+        rendererDataLock_.lock();
+        rendererData_ = std::move(data);
+        rendererDataLock_.unlock();
+    }
+
+    rendererDataLock_.lock();
+    if (decalsChanged || highlightedOrSelectedChanged) {
+        rendererData_->selected.clear();
+        for (auto &decal : selectedItems) {
+            drawDecal(rendererData_->selected, decal);
         }
         for (int i = 0; i < 8; i++) {
-            if (highlightItemsChanged_[i]) {
-                highlightItemsChanged_[i] = false;
-                highlightShader_[i].clear();
-                for (auto decal : highlightItems_[i]) {
-                    drawDecal(highlightShader_[i], decal);
-                }
+            rendererData_->highlighted[i].clear();
+            for (auto &decal : highlightedItems[i]) {
+                drawDecal(rendererData_->highlighted[i], decal);
             }
         }
     }
-
-    lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix);
-    lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix);
-    lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix);
-    lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix);
-    for (int i = 0; i < 8; i++)
-        lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix);
-    lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix);
+    rendererDataLock_.unlock();
 }
 
+
 void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
 {
-    selectedItems_ = decals;
-    selectedItemsChanged_ = true;
-    update();
+    rendererArgsLock_.lock();
+    rendererArgs_->selectedItems = decals;
+    rendererArgs_->highlightedOrSelectedChanged = true;
+    rendererArgsLock_.unlock();
+    pokeRenderer();
 }
 
 void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int group)
 {
-    highlightItems_[group] = decals;
-    highlightItemsChanged_[group] = true;
-    update();
+    rendererArgsLock_.lock();
+    rendererArgs_->highlightedItems[group] = decals;
+    rendererArgs_->highlightedOrSelectedChanged = true;
+    rendererArgsLock_.unlock();
+    pokeRenderer();
 }
 
 void FPGAViewWidget::resizeGL(int width, int height) {}
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index 33eb2800..19440054 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -21,12 +21,15 @@
 #define MAPGLWIDGET_H
 
 #include <QMainWindow>
+#include <QMutex>
 #include <QOpenGLBuffer>
 #include <QOpenGLFunctions>
 #include <QOpenGLShaderProgram>
 #include <QOpenGLVertexArrayObject>
 #include <QOpenGLWidget>
 #include <QPainter>
+#include <QThread>
+#include <QWaitCondition>
 
 #include "nextpnr.h"
 
@@ -209,14 +212,6 @@ class LineShader
 class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
 {
     Q_OBJECT
-    Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gridColor MEMBER gridColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor gSelectedColor MEMBER gSelectedColor_ DESIGNABLE true)
-    Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true)
 
   public:
     FPGAViewWidget(QWidget *parent = 0);
@@ -246,8 +241,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
     void newContext(Context *ctx);
     void onSelectedArchItem(std::vector<DecalXY> decals);
     void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
+    void pokeRenderer(void);
 
   private:
+    void renderLines(void);
+    void renderLinesWorker(void);
+
     QPoint lastPos_;
     LineShader lineShader_;
     QMatrix4x4 viewMove_;
@@ -263,23 +262,36 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
 
     Context *ctx_;
 
-    QColor backgroundColor_;
-    QColor gridColor_;
-    QColor gFrameColor_;
-    QColor gHiddenColor_;
-    QColor gInactiveColor_;
-    QColor gActiveColor_;
-    QColor gSelectedColor_;
-    QColor frameColor_;
-
-    LineShaderData selectedShader_;
-    std::vector<DecalXY> selectedItems_;
-    bool selectedItemsChanged_;
-
-    LineShaderData highlightShader_[8];
-    std::vector<DecalXY> highlightItems_[8];
-    bool highlightItemsChanged_[8];
-    QColor highlightColors[8];
+    QWaitCondition render_;
+    std::unique_ptr<QThread> renderThread_;
+
+    struct {
+        QColor background;
+        QColor grid;
+        QColor frame;
+        QColor hidden;
+        QColor inactive;
+        QColor active;
+        QColor selected;
+        QColor highlight[8];
+    } colors_;
+
+    struct RendererData {
+        LineShaderData decals[4];
+        LineShaderData selected;
+        LineShaderData highlighted[8];
+    };
+    
+    struct RendererArgs {
+        std::vector<DecalXY> selectedItems;
+        std::vector<DecalXY> highlightedItems[8];
+        bool highlightedOrSelectedChanged;
+    };
+
+    std::unique_ptr<RendererData> rendererData_;
+    QMutex rendererDataLock_;
+    std::unique_ptr<RendererArgs> rendererArgs_;
+    QMutex rendererArgsLock_;
 };
 
 NEXTPNR_NAMESPACE_END
diff --git a/ice40/arch.h b/ice40/arch.h
index 5dab414b..b89a0b54 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -373,6 +373,7 @@ struct Arch : BaseCtx
         bel_to_cell[bel.index] = cell;
         cells[cell]->bel = bel;
         cells[cell]->belStrength = strength;
+        refreshUiBel(bel);
     }
 
     void unbindBel(BelId bel)
@@ -382,6 +383,7 @@ struct Arch : BaseCtx
         cells[bel_to_cell[bel.index]]->bel = BelId();
         cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
         bel_to_cell[bel.index] = IdString();
+        refreshUiBel(bel);
     }
 
     bool checkBelAvail(BelId bel) const
@@ -475,6 +477,7 @@ struct Arch : BaseCtx
         wire_to_net[wire.index] = net;
         nets[net]->wires[wire].pip = PipId();
         nets[net]->wires[wire].strength = strength;
+        refreshUiWire(wire);
     }
 
     void unbindWire(WireId wire)
@@ -494,6 +497,7 @@ struct Arch : BaseCtx
 
         net_wires.erase(it);
         wire_to_net[wire.index] = IdString();
+        refreshUiWire(wire);
     }
 
     bool checkWireAvail(WireId wire) const
@@ -541,6 +545,8 @@ struct Arch : BaseCtx
         wire_to_net[dst.index] = net;
         nets[net]->wires[dst].pip = pip;
         nets[net]->wires[dst].strength = strength;
+        refreshUiPip(pip);
+        refreshUiWire(dst);
     }
 
     void unbindPip(PipId pip)
@@ -557,6 +563,8 @@ struct Arch : BaseCtx
 
         pip_to_net[pip.index] = IdString();
         switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
+        refreshUiPip(pip);
+        refreshUiWire(dst);
     }
 
     bool checkPipAvail(PipId pip) const
-- 
cgit v1.2.3