video_player: free GL render context on stop to release idle VRAM
behavior change: stop() now calls _gl_widget.release_render_context() after dropping hwdec, which frees the MpvRenderContext's internal textures and FBOs. Previously the render context stayed alive for the widget lifetime — its GPU allocations accumulated across video-to-image switches in the stacked widget even though no video was playing. The context is recreated lazily on the next play_file() via the existing ensure_gl_init() path (~5ms, invisible behind network fetch). After release, paintGL is a no-op (_ctx is None guard) and mpv won't fire frame-ready callbacks, so the hidden QOpenGLWidget is inert. cleanup() now delegates to release_render_context() + terminate() instead of duplicating the ctx.free() logic.
This commit is contained in:
parent
db4348c077
commit
eab805e705
@ -13,6 +13,7 @@
|
|||||||
- Bookmark→library save and bookmark Save As now plumb the active site's `CategoryFetcher` through to the filename template, so `%artist%`/`%character%` tokens render correctly instead of silently dropping out when saving a post that wasn't previewed first
|
- Bookmark→library save and bookmark Save As now plumb the active site's `CategoryFetcher` through to the filename template, so `%artist%`/`%character%` tokens render correctly instead of silently dropping out when saving a post that wasn't previewed first
|
||||||
- Info panel no longer silently drops tags that failed to land in a cached category — any tag from `post.tag_list` not rendered under a known category section now appears in an "Other" bucket, so partial cache coverage can't make individual tags invisible
|
- Info panel no longer silently drops tags that failed to land in a cached category — any tag from `post.tag_list` not rendered under a known category section now appears in an "Other" bucket, so partial cache coverage can't make individual tags invisible
|
||||||
- `BooruClient._request` retries now cover `httpx.RemoteProtocolError` and `httpx.ReadError` in addition to the existing timeout/connect/network set — an overloaded booru that drops the TCP connection mid-response no longer fails the whole search on the first try
|
- `BooruClient._request` retries now cover `httpx.RemoteProtocolError` and `httpx.ReadError` in addition to the existing timeout/connect/network set — an overloaded booru that drops the TCP connection mid-response no longer fails the whole search on the first try
|
||||||
|
- VRAM retained when no video is playing — `stop()` now frees the GL render context (textures + FBOs) instead of just dropping the hwdec surface pool. Context is recreated lazily on next `play_file()` via `ensure_gl_init()` (~5ms, invisible behind network fetch)
|
||||||
|
|
||||||
### Refactored
|
### Refactored
|
||||||
- `category_fetcher` batch tag-API params are now built by a shared `_build_tag_api_params` helper instead of duplicated across `fetch_via_tag_api` and `_probe_batch_api`
|
- `category_fetcher` batch tag-API params are now built by a shared `_build_tag_api_params` helper instead of duplicated across `fetch_via_tag_api` and `_probe_batch_api`
|
||||||
|
|||||||
@ -111,7 +111,20 @@ class _MpvGLWidget(QWidget):
|
|||||||
self._gl.makeCurrent()
|
self._gl.makeCurrent()
|
||||||
self._init_gl()
|
self._init_gl()
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def release_render_context(self) -> None:
|
||||||
|
"""Free the GL render context without terminating mpv.
|
||||||
|
|
||||||
|
Releases all GPU-side textures and FBOs that the render context
|
||||||
|
holds. The next ``ensure_gl_init()`` call (from ``play_file``)
|
||||||
|
recreates the context cheaply (~5ms). This is the difference
|
||||||
|
between "mpv is idle but holding VRAM" and "mpv is idle and
|
||||||
|
clean."
|
||||||
|
|
||||||
|
Safe to call when mpv has no active file (after
|
||||||
|
``mpv.command('stop')``). After this, ``_paint_gl`` is a no-op
|
||||||
|
(``_ctx is None`` guard) and mpv won't fire frame-ready
|
||||||
|
callbacks because there's no render context to trigger them.
|
||||||
|
"""
|
||||||
if self._ctx:
|
if self._ctx:
|
||||||
# GL context must be current so mpv can release its textures
|
# GL context must be current so mpv can release its textures
|
||||||
# and FBOs on the correct context. Without this, drivers that
|
# and FBOs on the correct context. Without this, drivers that
|
||||||
@ -123,6 +136,10 @@ class _MpvGLWidget(QWidget):
|
|||||||
finally:
|
finally:
|
||||||
self._gl.doneCurrent()
|
self._gl.doneCurrent()
|
||||||
self._ctx = None
|
self._ctx = None
|
||||||
|
self._gl_inited = False
|
||||||
|
|
||||||
|
def cleanup(self) -> None:
|
||||||
|
self.release_render_context()
|
||||||
if self._mpv:
|
if self._mpv:
|
||||||
self._mpv.terminate()
|
self._mpv.terminate()
|
||||||
self._mpv = None
|
self._mpv = None
|
||||||
|
|||||||
@ -491,6 +491,11 @@ class VideoPlayer(QWidget):
|
|||||||
# teardown and rejects the write, GL context destruction
|
# teardown and rejects the write, GL context destruction
|
||||||
# still drops the surface pool eventually.
|
# still drops the surface pool eventually.
|
||||||
pass
|
pass
|
||||||
|
# Free the GL render context so its internal textures and FBOs
|
||||||
|
# release VRAM while no video is playing. The next play_file()
|
||||||
|
# call recreates the context via ensure_gl_init() (~5ms cost,
|
||||||
|
# swamped by the network fetch for uncached videos).
|
||||||
|
self._gl_widget.release_render_context()
|
||||||
self._time_label.setText("0:00")
|
self._time_label.setText("0:00")
|
||||||
self._duration_label.setText("0:00")
|
self._duration_label.setText("0:00")
|
||||||
self._seek_slider.setRange(0, 0)
|
self._seek_slider.setRange(0, 0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user