From e62010d5d5ee85d280c105e2adf012fc10d809ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Sat, 14 Sep 2024 12:30:33 +0200 Subject: [PATCH] improvements to MPVGLView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add Pixel Buffer Object to (PBO) - add some debug logging - add scissor testing - add dirty region checking Signed-off-by: Toni Förster --- Open in Yattee/Open in Yattee.entitlements | 2 +- Shared/Player/MPV/MPVOGLView.swift | 62 +++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Open in Yattee/Open in Yattee.entitlements b/Open in Yattee/Open in Yattee.entitlements index 2618bd9b..f2865967 100644 --- a/Open in Yattee/Open in Yattee.entitlements +++ b/Open in Yattee/Open in Yattee.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.78Z5H3M6RJ.stream.yattee.app.urlbookmarks + group.ZYMM2HKXY2.yattee.app.url diff --git a/Shared/Player/MPV/MPVOGLView.swift b/Shared/Player/MPV/MPVOGLView.swift index e3604d1e..606f60d7 100644 --- a/Shared/Player/MPV/MPVOGLView.swift +++ b/Shared/Player/MPV/MPVOGLView.swift @@ -11,6 +11,7 @@ final class MPVOGLView: GLKView { var mpvGL: UnsafeMutableRawPointer? var queue = DispatchQueue(label: "stream.yattee.opengl", qos: .userInteractive) var needsDrawing = true + private var dirtyRegion: CGRect? override init(frame: CGRect) { guard let context = EAGLContext(api: .openGLES2) else { @@ -85,6 +86,7 @@ final class MPVOGLView: GLKView { @objc private func updateFrame() { // Trigger the drawing process if needed if needsDrawing { + markRegionAsDirty(bounds) setNeedsDisplay() } } @@ -100,16 +102,60 @@ final class MPVOGLView: GLKView { glClear(UInt32(GL_COLOR_BUFFER_BIT)) } + // Function to set a dirty region when a part of the screen changes + func markRegionAsDirty(_ region: CGRect) { + if dirtyRegion == nil { + dirtyRegion = region + } else { + // Expand the dirty region to include the new region + dirtyRegion = dirtyRegion!.union(region) + } + } + + // Logic to decide if only part of the screen needs updating + private func needsPartialUpdate() -> Bool { + // Check if there is a defined dirty region that needs updating + if let dirtyRegion, !dirtyRegion.isEmpty { + // Set up glScissor based on dirtyRegion coordinates + glScissor(GLint(dirtyRegion.origin.x), GLint(dirtyRegion.origin.y), GLsizei(dirtyRegion.width), GLsizei(dirtyRegion.height)) + return true + } + return false + } + + // Call this function when you know the entire screen needs updating + private func clearDirtyRegion() { + dirtyRegion = nil + } + override func draw(_: CGRect) { guard needsDrawing, let mpvGL else { return } + // Ensure the correct context is set + guard EAGLContext.setCurrent(context) else { + logger.error("Failed to set current OpenGL context.") + return + } + // Bind the default framebuffer glGetIntegerv(UInt32(GL_FRAMEBUFFER_BINDING), &defaultFBO!) + // Ensure the framebuffer is valid + guard defaultFBO != nil && defaultFBO! != 0 else { + logger.error("Invalid framebuffer ID.") + return + } + // Get the current viewport dimensions var dims: [GLint] = [0, 0, 0, 0] glGetIntegerv(GLenum(GL_VIEWPORT), &dims) + // Check if we need partial updates + if needsPartialUpdate() { + logger.info("Performing partial update with scissor test.") + glEnable(GLenum(GL_SCISSOR_TEST)) + } + // Set up the OpenGL FBO data var data = mpv_opengl_fbo( fbo: Int32(defaultFBO!), @@ -129,9 +175,23 @@ final class MPVOGLView: GLKView { mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: flipPtr), mpv_render_param() ] - mpv_render_context_render(OpaquePointer(mpvGL), ¶ms) + // Call the render function and check for errors + let result = mpv_render_context_render(OpaquePointer(mpvGL), ¶ms) + if result < 0 { + logger.error("mpv_render_context_render() failed with error code: \(result)") + } else { + logger.info("mpv_render_context_render() called successfully.") + } } } + + // Disable the scissor test after rendering if it was enabled + if needsPartialUpdate() { + glDisable(GLenum(GL_SCISSOR_TEST)) + } + + // Clear dirty region after drawing + clearDirtyRegion() } }