fixed opengl context corruption when docking/undocking viewer
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-35
@@ -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,19 +43,9 @@ 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() {
|
||||||
@@ -61,16 +53,10 @@ void ViewerWidget::retry() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user