fixed opengl context corruption when docking/undocking viewer

This commit is contained in:
itsmattkc
2018-08-31 15:11:32 +10:00
parent f12678aac4
commit 24c3ff647c
13 changed files with 104 additions and 90 deletions
+1
View File
@@ -6,6 +6,7 @@
#include <QThread> #include <QThread>
#include <QDebug> #include <QDebug>
#include <QMessageBox> #include <QMessageBox>
#include <QOpenGLContext>
#include "panels/panels.h" #include "panels/panels.h"
#include "panels/viewer.h" #include "panels/viewer.h"
+5
View File
@@ -8,6 +8,11 @@
#include <QMutex> #include <QMutex>
#include <QPixmap> #include <QPixmap>
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
#define MEDIA_TYPE_FOLDER 2
#define MEDIA_TYPE_SOLID 3
struct Sequence; struct Sequence;
struct Clip; struct Clip;
+5 -2
View File
@@ -21,6 +21,7 @@
#include "dialogs/preferencesdialog.h" #include "dialogs/preferencesdialog.h"
#include "playback/audio.h" #include "playback/audio.h"
#include "playback/playback.h"
#include "ui_timeline.h" #include "ui_timeline.h"
@@ -142,6 +143,8 @@ MainWindow::MainWindow(QWidget *parent) :
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
set_sequence(NULL);
QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) { if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) {
if (QFile::exists(autorecovery_filename)) { if (QFile::exists(autorecovery_filename)) {
@@ -375,7 +378,7 @@ void MainWindow::on_action_Save_Project_triggered()
void MainWindow::on_action_Open_Project_triggered() void MainWindow::on_action_Open_Project_triggered()
{ {
QString fn = QFileDialog::getOpenFileName(this, "Open Project...", "", OLIVE_FILE_FILTER); QString fn = QFileDialog::getOpenFileName(this, "Open Project...", "", OLIVE_FILE_FILTER);
if (!fn.isEmpty() && can_close_project()) { if (!fn.isEmpty() && can_close_project()) {
updateTitle(fn); updateTitle(fn);
panel_project->load_project(); panel_project->load_project();
undo_stack.clear(); undo_stack.clear();
@@ -385,7 +388,7 @@ void MainWindow::on_action_Open_Project_triggered()
void MainWindow::on_actionProject_triggered() void MainWindow::on_actionProject_triggered()
{ {
if (can_close_project()) { if (can_close_project()) {
panel_effect_controls->clear_effects(true); panel_effect_controls->clear_effects(true);
undo_stack.clear(); undo_stack.clear();
project_url.clear(); project_url.clear();
panel_project->new_project(); panel_project->new_project();
-8
View File
@@ -197,14 +197,6 @@ void EffectControls::load_effects() {
} }
} }
if (selected_clips.size() > 0) { if (selected_clips.size() > 0) {
// ui->scrollArea->setMinimumWidth(ui->effects_area->width());
/*ui->effects_area->layout()->update();
ui->effects_area->layout()->activate();
qDebug() << ui->effects_area->height();
ui->keyframeView->resize(ui->keyframeView->width(), ui->effects_area->height());*/
ui->keyframeView->setMinimumHeight(ui->effects_area->height()); ui->keyframeView->setMinimumHeight(ui->effects_area->height());
ui->keyframeView->setEnabled(true); ui->keyframeView->setEnabled(true);
ui->keyframeView->visible_in = effects_in; ui->keyframeView->visible_in = effects_in;
+5 -1
View File
@@ -17,6 +17,7 @@
#include "io/config.h" #include "io/config.h"
#include "playback/cacher.h" #include "playback/cacher.h"
#include "dialogs/replaceclipmediadialog.h" #include "dialogs/replaceclipmediadialog.h"
#include "panels/effectcontrols.h"
#include <QFileDialog> #include <QFileDialog>
#include <QString> #include <QString>
@@ -559,6 +560,9 @@ void Project::delete_clips_using_selected_media() {
} }
void Project::clear() { void Project::clear() {
// clear effects cache
panel_effect_controls->clear_effects(true);
// delete sequences first because it's important to close all the clips before deleting the media // delete sequences first because it's important to close all the clips before deleting the media
QVector<Sequence*> sequences = list_all_project_sequences(); QVector<Sequence*> sequences = list_all_project_sequences();
for (int i=0;i<sequences.size();i++) { for (int i=0;i<sequences.size();i++) {
@@ -574,7 +578,7 @@ void Project::clear() {
} }
void Project::new_project() { void Project::new_project() {
// clear existing project // clear existing project
set_sequence(NULL); set_sequence(NULL);
clear(); clear();
project_changed = false; project_changed = false;
-5
View File
@@ -16,11 +16,6 @@ class QXmlStreamWriter;
class QXmlStreamReader; class QXmlStreamReader;
class QFile; class QFile;
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
#define MEDIA_TYPE_FOLDER 2
#define MEDIA_TYPE_SOLID 3
#define LOAD_TYPE_VERSION 69 #define LOAD_TYPE_VERSION 69
class TimelineAction; class TimelineAction;
+1 -2
View File
@@ -140,8 +140,7 @@ void Viewer::update_sequence() {
update_end_timecode(); update_end_timecode();
} }
viewer_widget->initializeGL(); viewer_widget->update();
viewer_widget->repaint();
update(); update();
} }
+2 -4
View File
@@ -416,13 +416,11 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo
void close_clip_worker(Clip* clip) { void close_clip_worker(Clip* clip) {
// closes ffmpeg file handle and frees any memory used for caching // closes ffmpeg file handle and frees any memory used for caching
MediaStream* ms = static_cast<Media*>(clip->media)->get_stream_from_file_index(clip->track < 0, clip->media_stream); MediaStream* ms = static_cast<Media*>(clip->media)->get_stream_from_file_index(clip->track < 0, clip->media_stream);
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (clip->track < 0) {
sws_freeContext(clip->sws_ctx); sws_freeContext(clip->sws_ctx);
delete [] clip->comp_frame; delete [] clip->comp_frame;
delete clip->fbo; } else {
clip->fbo = NULL;
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
swr_free(&clip->swr_ctx); swr_free(&clip->swr_ctx);
} }
+52 -28
View File
@@ -22,27 +22,32 @@ extern "C" {
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QDebug> #include <QDebug>
#include <QOpenGLPixelTransferOptions> #include <QOpenGLPixelTransferOptions>
#include <QOpenGLFramebufferObject>
bool texture_failed = false; bool texture_failed = false;
void open_clip(Clip* clip, bool multithreaded) { void open_clip(Clip* clip, bool multithreaded) {
if (multithreaded) { if (clip->media_type == MEDIA_TYPE_FOOTAGE) {
if (clip->open_lock.tryLock()) { if (multithreaded) {
clip->multithreaded = true; if (clip->open_lock.tryLock()) {
clip->multithreaded = true;
// maybe keep cacher instance in memory while clip exists for performance? // maybe keep cacher instance in memory while clip exists for performance?
clip->cacher = new Cacher(clip); clip->cacher = new Cacher(clip);
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater())); QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
clip->cacher->start(QThread::LowPriority); clip->cacher->start(QThread::LowPriority);
} }
} else { } else {
clip->multithreaded = false; clip->multithreaded = false;
clip->finished_opening = false; clip->finished_opening = false;
clip->open = true; clip->open = true;
open_clip_worker(clip); open_clip_worker(clip);
} }
} else if (clip->media_type == MEDIA_TYPE_SEQUENCE) {
clip->open = true;
}
} }
void close_clip(Clip* clip) { void close_clip(Clip* clip) {
@@ -52,11 +57,21 @@ void close_clip(Clip* clip) {
clip->texture = NULL; clip->texture = NULL;
} }
if (clip->multithreaded) { if (clip->fbo != NULL) {
clip->cacher->caching = false; delete clip->fbo;
clip->can_cache.wakeAll(); clip->fbo = NULL;
} else { }
close_clip_worker(clip);
if (clip->media_type == MEDIA_TYPE_FOOTAGE) {
if (clip->multithreaded) {
clip->cacher->caching = false;
clip->can_cache.wakeAll();
} else {
close_clip_worker(clip);
}
} else if (clip->media_type == MEDIA_TYPE_SEQUENCE) {
closeActiveClips(static_cast<Sequence*>(clip->media), false);
clip->open = false;
} }
} }
@@ -270,17 +285,26 @@ bool is_clip_active(Clip* c, long playhead) {
} }
void set_sequence(Sequence* s) { void set_sequence(Sequence* s) {
if (sequence != NULL) { closeActiveClips(sequence, true);
// clean up - close all open clips
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c != NULL && c->open) {
close_clip(c);
}
}
}
sequence = s; sequence = s;
panel_timeline->update_sequence(); panel_timeline->update_sequence();
panel_viewer->update_sequence(); panel_viewer->update_sequence();
panel_timeline->setFocus(); panel_timeline->setFocus();
} }
void closeActiveClips(Sequence *s, bool wait) {
if (s != NULL) {
for (int i=0;i<s->clip_count();i++) {
Clip* c = s->get_clip(i);
if (c != NULL) {
if (c->media_type == MEDIA_TYPE_SEQUENCE) {
closeActiveClips(static_cast<Sequence*>(c->media), wait);
close_clip(c);
} else if (c->media_type == MEDIA_TYPE_FOOTAGE && c->open) {
close_clip(c);
if (c->multithreaded && wait) c->cacher->wait();
}
}
}
}
}
+1
View File
@@ -27,6 +27,7 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output);
bool is_clip_active(Clip* c, long playhead); bool is_clip_active(Clip* c, long playhead);
void get_next_audio(Clip* c, bool mix); void get_next_audio(Clip* c, bool mix);
void set_sequence(Sequence* s); void set_sequence(Sequence* s);
void closeActiveClips(Sequence* s, bool wait);
struct ClipCacheData { struct ClipCacheData {
Clip& clip; Clip& clip;
+1 -2
View File
@@ -4,8 +4,7 @@
#include <QResizeEvent> #include <QResizeEvent>
// enforces aspect ratio // enforces aspect ratio
ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent) ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent) {
{
child = NULL; child = NULL;
aspect_ratio = 1; aspect_ratio = 1;
} }
+30 -36
View File
@@ -11,6 +11,7 @@
#include "playback/audio.h" #include "playback/audio.h"
#include "io/media.h" #include "io/media.h"
#include "ui_timeline.h" #include "ui_timeline.h"
#include "playback/cacher.h"
#include <QDebug> #include <QDebug>
#include <QPainter> #include <QPainter>
@@ -18,6 +19,7 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QtMath> #include <QtMath>
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
extern "C" { extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
@@ -41,36 +43,20 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
void ViewerWidget::deleteFunction() { void ViewerWidget::deleteFunction() {
// destroy all textures as well // destroy all textures as well
for (int i=0;i<sequence->clip_count();i++) { makeCurrent();
Clip* c = sequence->get_clip(i); closeActiveClips(sequence, true);
if (c->texture != NULL) { doneCurrent();
/* TODO NOTE: apparently "destroy()" is non-functional here because
* it requires a valid current context, and I guess it's no longer
* valid or current by the time this function is called. Not sure
* how to handle that just yet...
*/
c->texture->destroy();
c->texture = NULL;
}
}
} }
void ViewerWidget::retry() { void ViewerWidget::retry() {
update(); update();
} }
void ViewerWidget::initializeGL() { void ViewerWidget::initializeGL() {
/*if (fbo != NULL) { connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(deleteFunction()), Qt::DirectConnection);
delete fbo; glClearColor(0, 0, 0, 1);
fbo = NULL;
}*/
connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(deleteFunction())); retry_timer.start();
initializeOpenGLFunctions();
update();
} }
//void ViewerWidget::resizeGL(int w, int h) //void ViewerWidget::resizeGL(int w, int h)
@@ -78,7 +64,10 @@ void ViewerWidget::initializeGL() {
//} //}
void ViewerWidget::paintEvent(QPaintEvent *e) { void ViewerWidget::paintEvent(QPaintEvent *e) {
if (enable_paint) QOpenGLWidget::paintEvent(e); if (enable_paint) {
makeCurrent();
QOpenGLWidget::paintEvent(e);
}
} }
GLuint ViewerWidget::draw_clip(Clip* clip, GLuint texture) { GLuint ViewerWidget::draw_clip(Clip* clip, GLuint texture) {
@@ -122,12 +111,12 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) { if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) {
bool clip_is_active = false; bool clip_is_active = false;
switch (c->media_type) { switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE: case MEDIA_TYPE_FOOTAGE:
{ {
Media* m = static_cast<Media*>(c->media); Media* m = static_cast<Media*>(c->media);
if (m->ready) { if (m->ready) {
if (m->get_stream_from_file_index(c->track < 0, c->media_stream) != NULL if (m->get_stream_from_file_index(c->track < 0, c->media_stream) != NULL
&& is_clip_active(c, playhead)) { && is_clip_active(c, playhead)) {
// if thread is already working, we don't want to touch this, // if thread is already working, we don't want to touch this,
// but we also don't want to hang the UI thread // but we also don't want to hang the UI thread
@@ -142,12 +131,17 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
} else { } else {
texture_failed = true; texture_failed = true;
} }
} }
break; break;
case MEDIA_TYPE_SEQUENCE: case MEDIA_TYPE_SEQUENCE:
clip_is_active = true; if (is_clip_active(c, playhead)) {
break; if (!c->open) open_clip(c, multithreaded);
} clip_is_active = true;
} else if (c->open) {
close_clip(c);
}
break;
}
if (clip_is_active) { if (clip_is_active) {
bool added = false; bool added = false;
@@ -294,12 +288,12 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
} }
void ViewerWidget::paintGL() { void ViewerWidget::paintGL() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND); glEnable(GL_BLEND);
bool loop = true; bool loop = true;
while (loop) { while (loop) {
loop = false; loop = false;
texture_failed = false; texture_failed = false;
+1 -2
View File
@@ -2,7 +2,6 @@
#define VIEWERWIDGET_H #define VIEWERWIDGET_H
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QTimer> #include <QTimer>
@@ -13,7 +12,7 @@
struct Clip; struct Clip;
struct Sequence; struct Sequence;
class ViewerWidget : public QOpenGLWidget, public QOpenGLFunctions class ViewerWidget : public QOpenGLWidget
{ {
Q_OBJECT Q_OBJECT
public: public: