fix a freezing bug

metadata
Wenzel Jakob 2010-11-30 23:07:18 +01:00
parent 407879c389
commit 0b2eb860c5
3 changed files with 80 additions and 23 deletions

View File

@ -131,6 +131,29 @@ struct PreviewQueueEntry {
}
};
struct VisualWorkUnit {
Point2i offset;
Vector2i size;
int worker;
};
struct block_comparator : std::binary_function<VisualWorkUnit, VisualWorkUnit, bool> {
static int compare(const VisualWorkUnit &v1, const VisualWorkUnit &v2) {
if (v1.offset.x < v2.offset.x) return -1;
else if (v1.offset.x > v2.offset.x) return 1;
if (v1.offset.y < v2.offset.y) return -1;
else if (v1.offset.y > v2.offset.y) return 1;
if (v1.size.x < v2.size.x) return -1;
else if (v1.size.x > v2.size.x) return 1;
if (v1.size.y < v2.size.y) return -1;
else if (v1.size.y > v2.size.y) return 1;
return 0;
}
bool operator()(const VisualWorkUnit &v1, const VisualWorkUnit &v2) const {
return compare(v1, v2) < 0;
}
};
struct SceneContext {
/* Scene-related */
@ -147,6 +170,7 @@ struct SceneContext {
float progress;
QString eta, progressName;
ref<Bitmap> framebuffer;
std::set<VisualWorkUnit, block_comparator> workUnits;
EMode mode, cancelMode;
Float gamma, exposure, clamping;
bool srgb;

View File

@ -831,8 +831,10 @@ bool MainWindow::on_tabBar_tabCloseRequested(int index) {
SceneContext *context = m_context[index];
if (context->renderJob != NULL) {
QMessageBox box(QMessageBox::Question, tr("Really close?"),
tr("Rendering of scene \"%1\" is unfinished - all progress will be lost. Are you sure you want to continue?").arg(context->shortName),
QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet);
tr("Rendering of scene \"%1\" is unfinished - all progress "
"will be lost. Are you sure you want to continue?").arg(context->shortName),
QMessageBox::Yes | QMessageBox::No, this,
Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet);
box.setWindowModality(Qt::WindowModal);
if (box.exec() == QMessageBox::No)
return false;
@ -1120,11 +1122,16 @@ void MainWindow::on_actionSettings_triggered() {
void MainWindow::on_actionStop_triggered() {
SceneContext *context = m_context[ui->tabBar->currentIndex()];
m_contextMutex.lock();
context->workUnits.clear();
if (context->renderJob) {
context->cancelled = true;
context->renderJob->cancel();
ref<RenderJob> renderJob = context->renderJob;
m_contextMutex.unlock();
renderJob->cancel();
} else if (context->mode == ERender) {
context->mode = EPreview;
m_contextMutex.unlock();
}
ui->glView->resumePreview();
@ -1370,6 +1377,7 @@ void MainWindow::onJobFinished(const RenderJob *job, bool cancelled) {
m_renderQueue->join();
if (context == NULL)
return;
context->workUnits.clear();
if (cancelled) {
if (!context->cancelled) {
QMessageBox::critical(this, tr("Error while rendering"),
@ -1427,15 +1435,30 @@ void MainWindow::onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu
SceneContext *context = getContext(job, false);
if (context == NULL)
return;
VisualWorkUnit vwu;
/* This is not executed in the event loop -- take some precautions */
m_contextMutex.lock();
vwu.offset = wu->getOffset();
vwu.size = wu->getSize();
vwu.worker = worker;
context->workUnits.insert(vwu);
drawVisualWorkUnit(context, vwu);
bool isCurrentView = ui->tabBar->currentIndex() < m_context.size() &&
m_context[ui->tabBar->currentIndex()] == context;
m_contextMutex.unlock();
if (isCurrentView)
emit updateView();
}
void MainWindow::drawVisualWorkUnit(SceneContext *context, const VisualWorkUnit &vwu) {
Film *film = context->scene->getFilm();
int ox = wu->getOffset().x - film->getCropOffset().x,
oy = wu->getOffset().y - film->getCropOffset().y,
ex = ox + wu->getSize().x, ey = oy + wu->getSize().y;
Point2i co = film->getCropOffset();
int ox = vwu.offset.x - co.x, oy = vwu.offset.y - co.y,
ex = ox + vwu.size.x, ey = oy + vwu.size.y;
const float *color = NULL;
/* Use desaturated colors to highlight the host
responsible for rendering the current image block */
responsible for rendering the current image vwu */
const float white[] = { 1.0f, 1.0f, 1.0f };
const float red[] = { 1.0f, 0.3f, 0.3f };
const float green[] = { 0.3f, 1.0f, 0.3f };
@ -1445,7 +1468,7 @@ void MainWindow::onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu
const float magenta[] = { 1.0f, 0.3f, 1.0f };
const float turquoise[] = { 0.3f, 1.0f, 1.0f };
switch (worker % 8) {
switch (vwu.worker % 8) {
case 1: color = green; break;
case 2: color = yellow; break;
case 3: color = blue; break;
@ -1459,7 +1482,7 @@ void MainWindow::onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu
break;
}
if (wu->getSize().x < 3 || wu->getSize().y < 3)
if (vwu.size.x < 3 || vwu.size.y < 3)
return;
drawHLine(context, ox, oy, ox + 3, color);
@ -1470,23 +1493,14 @@ void MainWindow::onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu
drawVLine(context, ex - 1, oy, oy + 3, color);
drawVLine(context, ex - 1, ey - 4, ey - 1, color);
drawVLine(context, ox, ey - 4, ey - 1, color);
/* This is not executed in the event loop -- take some precautions */
m_contextMutex.lock();
bool isCurrentView = ui->tabBar->currentIndex() < m_context.size() &&
m_context[ui->tabBar->currentIndex()] == context;
m_contextMutex.unlock();
if (isCurrentView)
emit updateView();
}
void MainWindow::on_glView_loadFileRequest(const QString &string) {
loadFile(string);
}
void MainWindow::onWorkEnd(const RenderJob *job, const ImageBlock *block) {
int ox = block->getOffset().x, oy = block->getOffset().y,
ex = ox + block->getSize().x, ey = oy + block->getSize().y;
VisualWorkUnit vwu;
vwu.offset = block->getOffset();
vwu.size = block->getSize();
SceneContext *context = getContext(job, false);
if (context == NULL)
return;
@ -1512,6 +1526,12 @@ void MainWindow::onWorkEnd(const RenderJob *job, const ImageBlock *block) {
m_contextMutex.lock();
bool isCurrentView = ui->tabBar->currentIndex() < m_context.size() &&
m_context[ui->tabBar->currentIndex()] == context;
if (context->workUnits.find(vwu) != context->workUnits.end()) {
context->workUnits.erase(vwu);
} else if (!context->cancelled) {
SLog(EWarn, "Internal error: unable to find previously scheduled"
" rectangular work unit.");
}
m_contextMutex.unlock();
if (isCurrentView)
emit updateView();
@ -1537,11 +1557,23 @@ void MainWindow::onRefresh(const RenderJob *job) {
fbOffset += 4;
}
}
if (m_context[ui->tabBar->currentIndex()] == context)
/* This is executed by worker threads -- take some precautions */
m_contextMutex.lock();
bool isCurrentView = ui->tabBar->currentIndex() < m_context.size() &&
m_context[ui->tabBar->currentIndex()] == context;
for (std::set<VisualWorkUnit, block_comparator>::const_iterator it =
context->workUnits.begin(); it != context->workUnits.end(); ++it)
drawVisualWorkUnit(context, *it);
m_contextMutex.unlock();
if (isCurrentView)
emit updateView();
}
void MainWindow::on_glView_loadFileRequest(const QString &string) {
loadFile(string);
}
bool ServerConnection::createWorker(QWidget *parent) {
ref<Stream> stream;
try {

View File

@ -94,6 +94,7 @@ protected:
SceneContext *getContext(const RenderJob *job, bool failIfNotFound = true);
void drawHLine(SceneContext *ctx, int x1, int y, int x2, const float *color);
void drawVLine(SceneContext *ctx, int x, int y1, int y2, const float *color);
void drawVisualWorkUnit(SceneContext *context, const VisualWorkUnit &block);
void checkForUpdates(bool notifyIfNone = false);
void saveAs(SceneContext *ctx, const QString &targetFile);
QSize sizeHint() const;