From 582e947c75a25e53756ed1784c5a24ffa4386537 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Tue, 3 Apr 2012 17:38:38 +0000 Subject: [PATCH] Fix errors when reattaching video with some video cards With ATI cards, deleting a wxGLContext seems to invalidate ALL wxGlContexts, rather than just things associated with the deleted one. This resulted in video breaking after closing the detached video dialog, as the embedded video display was trying to use an invalidated context. To work around this, delete and recreate the context when reattaching video. Also recreate the visual typesetting tool as OpenGLText holds references to textures created on construction. Originally committed to SVN as r6646. --- aegisub/src/dialog_detached_video.cpp | 11 +++++-- aegisub/src/frame_main.cpp | 1 + aegisub/src/video_context.cpp | 7 ++--- aegisub/src/video_display.cpp | 43 ++++++++++++++++----------- aegisub/src/video_display.h | 5 ++-- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/aegisub/src/dialog_detached_video.cpp b/aegisub/src/dialog_detached_video.cpp index 44071d594..0fa4393d8 100644 --- a/aegisub/src/dialog_detached_video.cpp +++ b/aegisub/src/dialog_detached_video.cpp @@ -100,11 +100,18 @@ DialogDetachedVideo::DialogDetachedVideo(agi::Context *context) DialogDetachedVideo::~DialogDetachedVideo() { } void DialogDetachedVideo::OnClose(wxCloseEvent &evt) { - evt.Skip(); + // Deleting a GL context seems to invalidate ALL contexts, so we need to + // delete both the detached and undetached contexts here, then recreate + // the undetached one later + context->videoDisplay->Destroy(); + old_display->Reload(); + context->videoDisplay = old_display; context->videoSlider = old_slider; + OPT_SET("Video/Detached/Enabled")->SetBool(false); - context->videoController->Reload(); + + evt.Skip(); } void DialogDetachedVideo::OnMinimize(wxIconizeEvent &event) { diff --git a/aegisub/src/frame_main.cpp b/aegisub/src/frame_main.cpp index e5788665c..573c588bf 100644 --- a/aegisub/src/frame_main.cpp +++ b/aegisub/src/frame_main.cpp @@ -439,6 +439,7 @@ void FrameMain::OnVideoOpen() { try { context->audioController->OpenAudio(context->videoController->GetVideoName()); } + catch (agi::UserCancelException const&) { } // Opening a video with no audio data isn't an error, so just log // and move on catch (agi::FileNotAccessibleError const&) { diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index 60551a78f..35ddb5a09 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -202,12 +202,9 @@ void VideoContext::SetVideo(const wxString &filename) { config::mru->Add("Video", STD_STR(filename)); StandardPaths::SetPathValue("?video", wxFileName(filename).GetPath()); - // Get frame - frame_n = 0; - // Show warning wxString warning = videoProvider->GetWarning(); - if (!warning.empty()) wxMessageBox(warning,"Warning",wxICON_WARNING | wxOK); + if (!warning.empty()) wxMessageBox(warning, "Warning", wxICON_WARNING | wxOK); hasSubtitles = false; if (filename.Right(4).Lower() == ".mkv") { @@ -230,6 +227,8 @@ void VideoContext::SetVideo(const wxString &filename) { if (commit_subs) context->ass->Commit(_("change script resolution"), AssFile::COMMIT_SCRIPTINFO); + else + JumpToFrame(0); } void VideoContext::Reload() { diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index cfb990cea..0f819974c 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -114,7 +114,7 @@ VideoDisplay::VideoDisplay( zoomBox->Bind(wxEVT_COMMAND_TEXT_ENTER, &VideoDisplay::SetZoomFromBoxText, this); con->videoController->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this); - slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this)); + slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::UpdateSize, this, false)); slots.push_back(con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this, true)); Bind(wxEVT_PAINT, std::tr1::bind(&VideoDisplay::Render, this)); @@ -133,8 +133,9 @@ VideoDisplay::VideoDisplay( c->videoDisplay = this; + UpdateSize(); if (con->videoController->IsLoaded()) - OnVideoOpen(); + con->videoController->JumpToFrame(con->videoController->GetFrameN()); } VideoDisplay::~VideoDisplay () { @@ -158,11 +159,17 @@ bool VideoDisplay::InitContext() { } void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) { - if (!InitContext()) return; + if (!InitContext()) { + evt.Skip(); + return; + } if (!videoOut) videoOut.reset(new VideoOutGL); + if (!tool) + cmd::call("video/tool/cross", con); + try { videoOut->UploadFrameData(*evt.frame); } @@ -183,14 +190,6 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) { Render(); } -void VideoDisplay::OnVideoOpen() { - if (!con->videoController->IsLoaded()) return; - if (!tool) - cmd::call("video/tool/cross", con); - UpdateSize(); - con->videoController->JumpToFrame(0); -} - void VideoDisplay::Render() try { if (!con->videoController->IsLoaded() || !videoOut || !InitContext() ) return; @@ -221,7 +220,7 @@ void VideoDisplay::Render() try { } } - if (mouse_pos || alwaysShowTools->GetBool()) + if ((mouse_pos || alwaysShowTools->GetBool()) && tool) tool->Draw(); SwapBuffers(); @@ -273,8 +272,7 @@ void VideoDisplay::DrawOverscanMask(float horizontal_percent, float vertical_per } void VideoDisplay::UpdateSize(bool force) { - if (!con->videoController->IsLoaded()) return; - if (!IsShownOnScreen()) return; + if (!con->videoController->IsLoaded() || !IsShownOnScreen()) return; int vidW = con->videoController->GetWidth(); int vidH = con->videoController->GetHeight(); @@ -359,7 +357,7 @@ void VideoDisplay::UpdateSize(bool force) { } } - if (tool.get()) + if (tool) tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height); Refresh(false); @@ -378,12 +376,14 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { mouse_pos = event.GetPosition(); - tool->OnMouseEvent(event); + if (tool) + tool->OnMouseEvent(event); } void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { mouse_pos = Vector2D(); - tool->OnMouseEvent(event); + if (tool) + tool->OnMouseEvent(event); } void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { @@ -449,3 +449,12 @@ bool VideoDisplay::ToolIsType(std::type_info const& type) const { Vector2D VideoDisplay::GetMousePosition() const { return mouse_pos ? tool->ToScriptCoords(mouse_pos) : mouse_pos; } + +void VideoDisplay::Reload() { + glContext.reset(); + videoOut.reset(); + tool.reset(); + + if (con->videoController->IsLoaded()) + con->videoController->JumpToFrame(con->videoController->GetFrameN()); +} diff --git a/aegisub/src/video_display.h b/aegisub/src/video_display.h index 7d23096a9..819fcd5a0 100644 --- a/aegisub/src/video_display.h +++ b/aegisub/src/video_display.h @@ -127,8 +127,6 @@ class VideoDisplay : public wxGLCanvas { /// @return Could the context be set? bool InitContext(); - void OnVideoOpen(); - /// @brief Set the size of the display based on the current zoom and video resolution /// @param force Force the size to be set based on zoom even in detached mode void UpdateSize(bool force = false); @@ -172,4 +170,7 @@ public: void SetTool(VisualToolBase *new_tool); bool ToolIsType(std::type_info const& type) const; + + /// Discard all OpenGL state + void Reload(); };