mcst-linux-kernel/patches-2024.06.26/mplayer-1.3.0/0007-Add-vo-gles-support.ad...

490 lines
18 KiB
Diff
Raw Normal View History

2024-07-09 13:51:45 +03:00
diff --git a/libvo/vo_gles.c b/libvo/vo_gles.c
new file mode 100644
index 0000000..cecc01a
--- /dev/null
+++ b/libvo/vo_gles.c
@@ -0,0 +1,480 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can alternatively redistribute this file and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+// TODO
+// - handle aspect
+// - check for extensions
+// - fallback if no support for NPOT textures
+// - GLES 2.0 (YUV conversion using shader)
+// MPlayer quirks
+// - OSD resize delay
+// - fixed-vo no resize event on nofs->fs->loop->nofs
+// - 640x480 default on fs->nofs
+// - drawing before check_events(resize)
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mp_core.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "x11_common.h"
+#include "sub/sub.h"
+
+#include <GLES/egl.h>
+#include <GLES/gl.h>
+#define GL_GLEXT_PROTOTYPES 1
+#include <GLES/glext.h>
+
+#ifndef GL_EXT_bgra // not defined in Khronos GLES/glext.h
+#define GL_EXT_bgra 1
+#define GL_BGR_EXT 0x80E0
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+//uncomment to disable extensions
+#undef GL_OES_draw_texture
+//#undef GL_EXT_bgra
+//#undef GL_EXT_texture_format_BGRA8888
+
+#define IS_ALIGNED(a, b) ((((uintptr_t)(const void *)(a)) & ((b) - 1)) == 0)
+#define MAX_CONFIGS 10
+
+//#define FAST_OSD 1
+
+static const vo_info_t info = {
+ "OpenGL ES (X11)",
+ "gles",
+ "kirin_e at users.sourceforge.net",
+ ""
+};
+
+const LIBVO_EXTERN(gles)
+
+static int unshown = 0;
+static unsigned int src_width = 0, src_height = 0;
+static unsigned int win_width = 0, win_height = 0;
+static unsigned int src_pixel_bytes = 0;
+static GLenum tex_format = GL_RGBA;
+static GLuint texture[2] = { 0, 0 };
+
+#ifndef GL_OES_draw_texture
+static const GLshort texcoord_buffer[16] = { 0, 1, 0, 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 1, 1, 1, 0 };
+static GLshort vertex_buffer[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+
+static void draw(uint8_t *src[], int stride[], int w, int h, int x, int y)
+{
+ int src_align, align, w_bytes_aligned, i;
+
+ for (src_align = 8; !IS_ALIGNED(src[0], src_align); src_align >>= 1);
+ for (align = src_align; !IS_ALIGNED(stride[0], align); align >>= 1);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, align);
+ glBindTexture(GL_TEXTURE_2D, texture[0]);
+
+ w_bytes_aligned = (w * src_pixel_bytes + align - 1) & ~(align - 1);
+ if (w_bytes_aligned == stride[0]) {
+ if (x != 0 || y != 0 || w != src_width || h != src_height) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, tex_format, GL_UNSIGNED_BYTE, src[0]);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, tex_format, w, h, 0, tex_format, GL_UNSIGNED_BYTE, src[0]);
+ }
+ } else {
+ for (i = 0; i < h; i++) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y + i, w, 1, tex_format, GL_UNSIGNED_BYTE, src[0] + stride[0] * i);
+ }
+ }
+#ifndef GL_OES_draw_texture
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+#else
+ glDrawTexiOES(0, 0, 0, win_width, win_height);
+#endif
+ unshown = 1;
+}
+
+static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+ unsigned char *srca, int stride)
+{
+ int src_align, align, w_bytes_aligned, i;
+#ifdef FAST_OSD
+ GLenum osd_tex_format = GL_LUMINANCE;
+ int osd_pixel_bytes = 1;
+#else
+ GLenum osd_tex_format = GL_LUMINANCE_ALPHA;
+ int osd_pixel_bytes = 2, j;
+ char src_la[h * stride * 2];
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ src_la[i * stride * 2 + j * 2] = src[i * stride + j];
+ src_la[i * stride * 2 + j * 2 + 1] = srca[i * stride + j] ? srca[i * stride + j] : 255;
+ }
+ }
+ src = src_la;
+ stride = stride * 2;
+#endif
+
+ //printf("\n at draw_alpha: %ix%i xoffset %i yoffset %i stride %i (%p %p)\n", w, h, x0, y0, stride, src, srca);
+ for (src_align = 8; !IS_ALIGNED(src, src_align); src_align >>= 1);
+ for (align = src_align; !IS_ALIGNED(stride, align); align >>= 1);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, align);
+ glBindTexture(GL_TEXTURE_2D, texture[1]);
+#ifdef GL_OES_draw_texture
+ {
+ GLint crop_rect[4] = { 0, h, w, -h };
+
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_rect);
+ }
+#endif
+
+ w_bytes_aligned = (w * osd_pixel_bytes + align - 1) & ~(align - 1);
+ //printf("osd data alignment: %i, w_bytes_aligned: %i\n", align, w_bytes_aligned);
+ if (w_bytes_aligned == stride) {
+ glTexImage2D(GL_TEXTURE_2D, 0, osd_tex_format, w, h, 0, osd_tex_format, GL_UNSIGNED_BYTE, src);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, osd_tex_format, w, h, 0, osd_tex_format, GL_UNSIGNED_BYTE, NULL);
+ for (i = 0; i < h; i ++) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, w, 1, osd_tex_format, GL_UNSIGNED_BYTE, src + stride * i);
+ }
+ }
+ glEnable(GL_BLEND);
+#ifndef GL_OES_draw_texture
+ {
+ int y0i = win_height - y0 - h;
+
+ vertex_buffer[8] = x0;
+ vertex_buffer[9] = y0i;
+ vertex_buffer[10] = x0;
+ vertex_buffer[11] = y0i + h;
+ vertex_buffer[12] = x0 + w;
+ vertex_buffer[13] = y0i;
+ vertex_buffer[14] = x0 + w;
+ vertex_buffer[15] = y0i + h;
+ glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
+ }
+#else
+ glDrawTexiOES(x0, win_height - y0 - h, 0, w, h);
+#endif
+ glDisable(GL_BLEND);
+}
+
+static void reshape(int width, int height)
+{
+#ifndef GL_OES_draw_texture
+ vertex_buffer[3] = height;
+ vertex_buffer[4] = width;
+ vertex_buffer[6] = width;
+ vertex_buffer[7] = height;
+#endif
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthox(0 << 16, width << 16, 0 << 16, height << 16, -1 << 16, 1 << 16);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+static void gl_init(void)
+{
+ mp_msg(MSGT_VO, MSGL_V, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ mp_msg(MSGT_VO, MSGL_V, "GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ mp_msg(MSGT_VO, MSGL_V, "GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ mp_msg(MSGT_VO, MSGL_V, "GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+
+ reshape(win_width, win_height);
+ glGenTextures(2, texture);
+
+ glBindTexture(GL_TEXTURE_2D, texture[0]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+#ifdef GL_OES_draw_texture
+ {
+ GLint crop_rect[4] = { 0, src_height, src_width, -src_height };
+
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_rect);
+ }
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, tex_format, src_width, src_height, 0, tex_format, GL_UNSIGNED_BYTE, NULL);
+
+ glBindTexture(GL_TEXTURE_2D, texture[1]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+#ifndef GL_OES_draw_texture
+ glTexCoordPointer(2, GL_SHORT, 0, texcoord_buffer);
+ glVertexPointer(2, GL_SHORT, 0, vertex_buffer);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#endif
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_ONE, GL_SRC_ALPHA);
+}
+
+// -----------------------------------------------
+
+static Display *dpy = NULL;
+static Window window = 0;
+static Colormap colormap = 0;
+
+static EGLDisplay egldpy;
+static EGLSurface eglwindow;
+static EGLContext eglctx;
+
+static void createEGLWindow(int width, int height, char *name, uint32_t flags)
+{
+ const EGLint attrib_list[] = { EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, EGL_NONE };
+ EGLConfig configs[MAX_CONFIGS];
+ EGLint num_configs;
+ EGLint visual_id = 0, attrib;
+
+ XVisualInfo *vinfo, vinfo_template;
+ int i, cfg, num_visuals;
+
+ dpy = mDisplay; // set by vo_init()
+
+ egldpy = eglGetDisplay(dpy);
+ if (egldpy == EGL_NO_DISPLAY) exit_player(EXIT_ERROR);
+ if (eglInitialize(egldpy, NULL, NULL) == EGL_FALSE) exit_player(EXIT_ERROR);
+ if (eglChooseConfig(egldpy, attrib_list, configs, MAX_CONFIGS, &num_configs) == EGL_FALSE) exit_player(EXIT_ERROR);
+ if (num_configs == 0) {
+ mp_msg(MSGT_VO, MSGL_ERR, "gles: no matching EGL frame buffer configurations found!\n");
+ exit_player(EXIT_ERROR);
+ }
+ for (cfg = 0; cfg < num_configs && visual_id == 0; cfg++) {
+ mp_msg(MSGT_VO, MSGL_V, "gles: configs[%i]: ", cfg);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_NATIVE_VISUAL_ID, &visual_id);
+ mp_msg(MSGT_VO, MSGL_V, "VisualID: 0x%02x ", visual_id);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_BUFFER_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "bpp: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_RED_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "R: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_GREEN_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "G: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_BLUE_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "B: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_ALPHA_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "A: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_DEPTH_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "Z: %i ", attrib);
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_STENCIL_SIZE, &attrib);
+ mp_msg(MSGT_VO, MSGL_V, "S: %i\n", attrib);
+ }
+ if (visual_id == 0) {
+ mp_msg(MSGT_VO, MSGL_INFO, "gles: no useable VisualID found in configs, matching on depth instead!\n");
+ cfg = 0;
+ eglGetConfigAttrib(egldpy, configs[cfg], EGL_BUFFER_SIZE, &vinfo_template.depth);
+ vinfo = XGetVisualInfo(dpy, VisualDepthMask, &vinfo_template, &num_visuals);
+ } else {
+ vinfo_template.visualid = visual_id;
+ vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_template, &num_visuals);
+ }
+ if (vinfo == NULL || num_visuals == 0) exit_player(EXIT_ERROR);
+ for (i = 0; i < num_visuals; i++) {
+ mp_msg(MSGT_VO, MSGL_V, "gles: visuals[%i]: visual depth: %i\n", i, vinfo[i].depth);
+ }
+
+ colormap = XCreateColormap(dpy, RootWindow(dpy, vinfo->screen), vinfo->visual, AllocNone);
+
+ vo_x11_create_vo_window(vinfo, 0, 0, width, height, flags, colormap, "EGL", name);
+ window = vo_window; // set by vo_x11_create_vo_window()
+
+ XFree(vinfo);
+
+ eglctx = eglCreateContext(egldpy, configs[cfg], EGL_NO_CONTEXT, NULL);
+ if (eglctx == EGL_NO_CONTEXT) exit_player(EXIT_ERROR);
+ eglwindow = eglCreateWindowSurface(egldpy, configs[cfg], (NativeWindowType) window, NULL);
+ if (eglwindow == EGL_NO_SURFACE) exit_player(EXIT_ERROR);
+ if (eglMakeCurrent(egldpy, eglwindow, eglwindow, eglctx) == EGL_FALSE) exit_player(EXIT_ERROR);
+
+ win_width = width;
+ win_height = height;
+}
+
+static void destroyEGLWindow(void)
+{
+ eglMakeCurrent(egldpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(egldpy, eglwindow);
+ eglDestroyContext(egldpy, eglctx);
+ eglTerminate(egldpy);
+}
+
+static void postEGLWindow(void)
+{
+ eglSwapBuffers(egldpy, eglwindow);
+}
+
+// -----------------------------------------------
+
+static int query_format(uint32_t format)
+{
+ int flags = VFCAP_CSP_SUPPORTED | VFCAP_ACCEPT_STRIDE | VFCAP_OSD;
+ //uint32_t fourcc[2] = { format, 0 };
+
+ //printf("\n at query_format: 0x%08x (%s)\n", format, (char *) fourcc);
+ switch (format) {
+ case IMGFMT_RGB32:
+ case IMGFMT_RGB24:
+#if defined(GL_EXT_bgra) || defined(GL_EXT_texture_format_BGRA8888)
+ case IMGFMT_BGR32:
+#endif
+#if defined(GL_EXT_bgra)
+ case IMGFMT_BGR24:
+#endif
+ return flags;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------
+
+static int draw_frame(uint8_t *src[])
+{
+ int stride[] = { src_width * src_pixel_bytes };
+
+ //printf("\n at draw_frame\n");
+ draw(src, stride, src_width, src_height, 0, 0);
+
+ return 0;
+}
+
+static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y)
+{
+ //printf("\n at draw_slice x: %i y: %i w: %i h: %i stride: %i src@%p\n", x, y, w, h, stride[0], src[0]);
+ draw(src, stride, w, h, x, y);
+
+ return 0;
+}
+
+static void draw_osd(void)
+{
+ vo_draw_text(win_width, win_height, draw_alpha);
+}
+
+static void check_events(void)
+{
+ int event = vo_x11_check_events(dpy);
+
+ if (event & VO_EVENT_RESIZE) {
+ XWindowAttributes window_attributes;
+
+ XGetWindowAttributes(dpy, window, &window_attributes);
+ mp_msg(MSGT_VO, MSGL_INFO, "gles: resize event! (%ix%i, vo: %ix%i)\n",
+ window_attributes.width, window_attributes.height, vo_dwidth, vo_dheight);
+ if (unshown) mp_msg(MSGT_VO, MSGL_INFO, "gles: resizing with non-empty buffer!\n");
+ if (win_width != window_attributes.width || win_height != window_attributes.height) {
+ win_width = window_attributes.width;
+ win_height = window_attributes.height;
+ reshape(win_width, win_height);
+ } else mp_msg(MSGT_VO, MSGL_INFO, "gles: hmm.. resize event without size change!\n");
+ }
+}
+
+static void flip_page(void)
+{
+ if (!unshown) mp_msg(MSGT_VO, MSGL_INFO, "gles: flipping empty buffer!\n");
+ postEGLWindow();
+ unshown = 0;
+}
+
+static int config(uint32_t width, uint32_t height, uint32_t d_width,
+ uint32_t d_height, uint32_t flags, char *title,
+ uint32_t format)
+{
+ switch (format) {
+ case IMGFMT_RGB32:
+ tex_format = GL_RGBA;
+ src_pixel_bytes = 4;
+ break;
+ case IMGFMT_RGB24:
+ tex_format = GL_RGB;
+ src_pixel_bytes = 3;
+ break;
+#if defined(GL_EXT_bgra) || defined(GL_EXT_texture_format_BGRA8888)
+ case IMGFMT_BGR32:
+ tex_format = GL_BGRA_EXT;
+ src_pixel_bytes = 4;
+ break;
+#endif
+#if defined(GL_EXT_bgra)
+ case IMGFMT_BGR24:
+ tex_format = GL_BGR_EXT;
+ src_pixel_bytes = 3;
+ break;
+#endif
+ default: /* unsupported */
+ return 1;
+ };
+
+ src_width = width;
+ src_height = height;
+
+ if (!eglwindow) createEGLWindow(width, height, title, flags);
+ gl_init();
+
+ return 0;
+}
+
+static int preinit(const char *arg)
+{
+ if (!vo_init()) return VO_FALSE; // x11 init
+
+ return 0;
+}
+
+static void uninit(void)
+{
+ if (eglwindow) destroyEGLWindow();
+ vo_x11_uninit();
+ if (colormap) XFreeColormap(dpy, colormap);
+}
+
+static int control(uint32_t request, void *data)
+{
+ switch (request) {
+ case VOCTRL_QUERY_FORMAT:
+ return query_format(*((uint32_t *) data));
+ case VOCTRL_ONTOP:
+ vo_x11_ontop();
+ return VO_TRUE;
+ case VOCTRL_BORDER:
+ vo_x11_border();
+ return VO_TRUE;
+ case VOCTRL_FULLSCREEN:
+ vo_x11_fullscreen();
+ return VO_TRUE;
+ case VOCTRL_UPDATE_SCREENINFO:
+ update_xinerama_info();
+ return VO_TRUE;
+ }
+
+ return VO_NOTIMPL;
+}
--
2.16.4