diff --git a/src/libcore/lock.cpp b/src/libcore/lock.cpp index 80dd2bb5..eeb8a568 100644 --- a/src/libcore/lock.cpp +++ b/src/libcore/lock.cpp @@ -74,12 +74,15 @@ bool ConditionVariable::wait(int ms) { struct timespec ts; ts.tv_sec = tv.tv_sec + ms/1000; - ts.tv_nsec = (tv.tv_usec + ms % 1000) * 1000; - + ts.tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } int retval = pthread_cond_timedwait(&m_cond, &m_mutex->m_mutex, &ts); #if defined(WIN32) /* Should be outside of the switch statement (depending - on the used compiler, the constants ETIMEDOUT and WSAETIMEDOUT + on the used environment, the constants ETIMEDOUT and WSAETIMEDOUT are potentially identical */ if (retval == WSAETIMEDOUT) return false; diff --git a/src/mtsgui/mainwindow.cpp b/src/mtsgui/mainwindow.cpp index bcaaa44d..698cb91c 100644 --- a/src/mtsgui/mainwindow.cpp +++ b/src/mtsgui/mainwindow.cpp @@ -163,12 +163,11 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_renderListener, SIGNAL(jobFinished(const RenderJob *, bool)), this, SLOT(onJobFinished(const RenderJob *, bool)), Qt::QueuedConnection); - connect(m_renderListener, SIGNAL(refresh(const RenderJob *)), - this, SLOT(onRefresh(const RenderJob *)), Qt::QueuedConnection); connect(m_renderListener, SIGNAL(workEnd(const RenderJob *, const ImageBlock *)), this, SLOT(onWorkEnd(const RenderJob *, const ImageBlock *)), Qt::DirectConnection); connect(m_renderListener, SIGNAL(workBegin(const RenderJob *, const RectangularWorkUnit *, int)), this, SLOT(onWorkBegin(const RenderJob *, const RectangularWorkUnit *, int)), Qt::DirectConnection); + connect(m_renderListener, SIGNAL(refresh()), this, SLOT(onRefresh()), Qt::QueuedConnection); connect(m_consoleAppender, SIGNAL(progressMessage(const RenderJob *, const QString &, float, const QString &)), this, SLOT(onProgressMessage(const RenderJob *, const QString &, float, const QString &)), @@ -1513,7 +1512,7 @@ void MainWindow::onJobFinished(const RenderJob *job, bool cancelled) { ui->glView->resumePreview(); } } - onRefresh(job, NULL); + refresh(job, NULL); context->renderJob = NULL; updateUI(); if (ui->tabBar->currentIndex() != -1 && @@ -1673,7 +1672,14 @@ void MainWindow::onWorkEnd(const RenderJob *job, const ImageBlock *block) { emit updateView(); } -void MainWindow::onRefresh(const RenderJob *job) { +void MainWindow::onRefresh() { + const QRenderListener::RefreshRequest *req = m_renderListener->acquireRefreshRequest(); + if (req) + refresh(req->first, req->second); + m_renderListener->releaseRefreshRequest(); +} + +void MainWindow::refresh(const RenderJob *job, const Bitmap *_bitmap) { SceneContext *context = getContext(job, false); if (context == NULL) return; diff --git a/src/mtsgui/mainwindow.h b/src/mtsgui/mainwindow.h index 1d5e8cd1..cc32f703 100644 --- a/src/mtsgui/mainwindow.h +++ b/src/mtsgui/mainwindow.h @@ -25,6 +25,10 @@ #define MAX_RECENT_FILES 10 +// amount of time that a rendering thread will wait for the GUI to accept a +// render view refresh request to show intermediate progress (in ms) +#define REFRESH_TIMEOUT 50 + namespace Ui { class MainWindow; } @@ -41,9 +45,12 @@ class PreviewSettingsDlg; class QRenderListener : public QObject, public RenderListener { Q_OBJECT public: + typedef std::pair RefreshRequest; + QRenderListener() { m_mutex = new Mutex(); m_cond = new ConditionVariable(m_mutex); + m_refreshRequest = NULL; } /// Called when work has begun in a rectangular image region @@ -55,14 +62,24 @@ public: inline void workEndEvent(const RenderJob *job, const ImageBlock *wr) { emit workEnd(job, wr); } + /// Called when the whole target image has been altered in some way inline void refreshEvent(const RenderJob *job, const Bitmap *bitmap) { m_mutex->lock(); - m_bitmap = bitmap; - emit refresh(job); - m_cond->wait(500); - m_bitmap = NULL; + RefreshRequest request = std::make_pair(job, bitmap); + + /* Potentially overwrite a previous refresh request */ + m_refreshRequest = &request; + + /* Asynchronously signal the GUI */ + emit refresh(); + + /* Wait for the GUI to draw the image (or another + thread to overwrite the refresh request) */ + m_cond->wait(REFRESH_TIMEOUT); + + m_refreshRequest = NULL; m_mutex->unlock(); } @@ -71,21 +88,15 @@ public: emit jobFinished(job, cancelled); } - /// Lock the mutex - inline void lock() { m_mutex->lock(); } - - /// Access the image associated with the last refresh event - inline const Bitmap *getBitmap() const { return m_bitmap.get(); } - - /// Unlock the mutex - inline void unlock() { m_mutex->unlock(); } + inline const RefreshRequest *acquireRefreshRequest() { m_mutex->lock(); return m_refreshRequest; } + inline void releaseRefreshRequest() { m_refreshRequest = NULL; m_cond->signal(); m_mutex->unlock(); } MTS_DECLARE_CLASS() signals: void workBegin(const RenderJob *job, const RectangularWorkUnit *wu, int worker); void workEnd(const RenderJob *job, const ImageBlock *wr); - void refresh(const RenderJob *job); void jobFinished(const RenderJob *job, bool cancelled); + void refresh(); protected: virtual ~QRenderListener() { } @@ -93,7 +104,7 @@ protected: private: ref m_mutex; ref m_cond; - ref m_bitmap; + RefreshRequest *m_refreshRequest; }; class PreviewSettingsDialog; @@ -122,6 +133,7 @@ protected: void drawVisualWorkUnit(SceneContext *context, const VisualWorkUnit &block); void checkForUpdates(bool notifyIfNone = false); void saveAs(SceneContext *ctx, const QString &targetFile); + void refresh(const RenderJob *job, const Bitmap *bitmap); QSize sizeHint() const; signals: @@ -162,7 +174,7 @@ private slots: void onClearRecent(); void onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu, int worker); void onWorkEnd(const RenderJob *job, const ImageBlock *wr); - void onRefresh(const RenderJob *job, const Bitmap *bitmap); + void onRefresh(); void onJobFinished(const RenderJob *job, bool cancelled); void onProgressMessage(const RenderJob *job, const QString &name, float progress, const QString &eta);