]> git.sesse.net Git - pkanalytics/commitdiff
Move to using Qt's OpenGL function pointers.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 30 Jul 2023 21:53:02 +0000 (23:53 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 30 Jul 2023 21:53:02 +0000 (23:53 +0200)
This is so much less ergonomic, but frees us from using libepoxy
on other platforms. Also drop down to OpenGL 4.5, as we don't need
any of the 4.6 stuff and Qt doesn't support it (!).

video_widget.cpp
video_widget.h

index 1f3534f117cdf425c6fc1ba048706f82580f4921..63efa7d866dd363c42f290e0fa6c4e0a867f8517 100644 (file)
@@ -1,5 +1,3 @@
-#define GL_GLEXT_PROTOTYPES
-
 #include "video_widget.h"
 
 #include <assert.h>
@@ -37,6 +35,8 @@ extern "C" {
 #include <QMouseEvent>
 #include <QMouseEvent>
 #include <QHBoxLayout>
+#include <QOpenGLFunctions_4_5_Compatibility>
+#include <QOpenGLVersionFunctionsFactory>
 
 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
 
@@ -260,24 +260,24 @@ VideoWidget::~VideoWidget()
        video_window->set_current_frame(nullptr);
 }
 
-GLuint compile_shader(const string &shader_src, GLenum type)
+GLuint compile_shader(QOpenGLFunctions_4_5_Compatibility *gl, const string &shader_src, GLenum type)
 {
-       GLuint obj = glCreateShader(type);
+       GLuint obj = gl->glCreateShader(type);
        const GLchar* source[] = { shader_src.data() };
        const GLint length[] = { (GLint)shader_src.size() };
-       glShaderSource(obj, 1, source, length);
-       glCompileShader(obj);
+       gl->glShaderSource(obj, 1, source, length);
+       gl->glCompileShader(obj);
 
        GLchar info_log[4096];
        GLsizei log_length = sizeof(info_log) - 1;
-       glGetShaderInfoLog(obj, log_length, &log_length, info_log);
+       gl->glGetShaderInfoLog(obj, log_length, &log_length, info_log);
        info_log[log_length] = 0;
        if (strlen(info_log) > 0) {
                fprintf(stderr, "Shader compile log: %s\n", info_log);
        }
 
        GLint status;
-       glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
+       gl->glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
        if (status == GL_FALSE) {
                // Add some line numbers to easier identify compile errors.
                string src_with_lines = "/*   1 */ ";
@@ -300,13 +300,15 @@ GLuint compile_shader(const string &shader_src, GLenum type)
 
 void VideoWindow::initializeGL()
 {
+       gl = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_5_Compatibility>(context());
+
        glDisable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);
-       glCreateTextures(GL_TEXTURE_2D, 3, tex);
+       gl->glCreateTextures(GL_TEXTURE_2D, 3, tex);
 
-       ycbcr_vertex_shader = compile_shader(R"(
-#version 460 core
+       ycbcr_vertex_shader = compile_shader(gl, R"(
+#version 450 core
 
 layout(location = 0) in vec2 position;
 layout(location = 1) in vec2 texcoord;
@@ -325,8 +327,8 @@ void main()
        tc.y = 1.0f - tc.y;
 }
 )", GL_VERTEX_SHADER);
-       ycbcr_fragment_shader = compile_shader(R"(
-#version 460 core
+       ycbcr_fragment_shader = compile_shader(gl, R"(
+#version 450 core
 
 layout(location = 0) uniform sampler2D tex_y;
 layout(location = 1) uniform sampler2D tex_cb;
@@ -360,25 +362,25 @@ void main()
        FragColor.a = 1.0f;
 }
 )", GL_FRAGMENT_SHADER);
-       ycbcr_program = glCreateProgram();
-       glAttachShader(ycbcr_program, ycbcr_vertex_shader);
-       glAttachShader(ycbcr_program, ycbcr_fragment_shader);
-       glLinkProgram(ycbcr_program);
+       ycbcr_program = gl->glCreateProgram();
+       gl->glAttachShader(ycbcr_program, ycbcr_vertex_shader);
+       gl->glAttachShader(ycbcr_program, ycbcr_fragment_shader);
+       gl->glLinkProgram(ycbcr_program);
 
        GLint success;
-       glGetProgramiv(ycbcr_program, GL_LINK_STATUS, &success);
+       gl->glGetProgramiv(ycbcr_program, GL_LINK_STATUS, &success);
        if (success == GL_FALSE) {
                GLchar error_log[1024] = {0};
-               glGetProgramInfoLog(ycbcr_program, 1024, nullptr, error_log);
+               gl->glGetProgramInfoLog(ycbcr_program, 1024, nullptr, error_log);
                fprintf(stderr, "Error linking program: %s\n", error_log);
                exit(1);
        }
 
-       glCreateSamplers(1, &bilinear_sampler);
-       glSamplerParameteri(bilinear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-       glSamplerParameteri(bilinear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-       glSamplerParameteri(bilinear_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-       glSamplerParameteri(bilinear_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       gl->glCreateSamplers(1, &bilinear_sampler);
+       gl->glSamplerParameteri(bilinear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+       gl->glSamplerParameteri(bilinear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       gl->glSamplerParameteri(bilinear_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       gl->glSamplerParameteri(bilinear_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 }
 
 void VideoWindow::resizeGL(int w, int h)
@@ -410,45 +412,45 @@ void VideoWindow::paintGL()
                return;
        }
 
-       glUseProgram(ycbcr_program);
+       gl->glUseProgram(ycbcr_program);
        if (frame->width != last_width || frame->height != last_height) {
-               glTextureStorage2D(tex[0], num_levels(frame->width, frame->height), GL_R8, frame->width, frame->height);
+               gl->glTextureStorage2D(tex[0], num_levels(frame->width, frame->height), GL_R8, frame->width, frame->height);
        }
        if (frame->chroma_width != last_chroma_width || frame->chroma_height != last_chroma_height) {
                for (GLuint num : { tex[1], tex[2] }) {
-                       glTextureStorage2D(num, num_levels(frame->chroma_width, frame->chroma_height), GL_R8, frame->chroma_width, frame->chroma_height);
+                       gl->glTextureStorage2D(num, num_levels(frame->chroma_width, frame->chroma_height), GL_R8, frame->chroma_width, frame->chroma_height);
                }
        }
 
-       glBindBuffer(GL_PIXEL_UNPACK_BUFFER, frame->pbo);
+       gl->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, frame->pbo);
 
        if (frame->need_flush_len > 0) {
-               glFlushMappedNamedBufferRange(frame->pbo, 0, frame->need_flush_len);
+               gl->glFlushMappedNamedBufferRange(frame->pbo, 0, frame->need_flush_len);
                frame->need_flush_len = 0;
        }
 
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-       glTextureSubImage2D(tex[0], 0, 0, 0, frame->width, frame->height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
-       glGenerateTextureMipmap(tex[0]);
+       gl->glTextureSubImage2D(tex[0], 0, 0, 0, frame->width, frame->height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
+       gl->glGenerateTextureMipmap(tex[0]);
 
-       glTextureSubImage2D(tex[1], 0, 0, 0, frame->chroma_width, frame->chroma_height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(frame->width * frame->height));
-       glGenerateTextureMipmap(tex[1]);
+       gl->glTextureSubImage2D(tex[1], 0, 0, 0, frame->chroma_width, frame->chroma_height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(frame->width * frame->height));
+       gl->glGenerateTextureMipmap(tex[1]);
 
-       glTextureSubImage2D(tex[2], 0, 0, 0, frame->chroma_width, frame->chroma_height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(frame->width * frame->height + frame->chroma_width * frame->chroma_height));
-       glGenerateTextureMipmap(tex[2]);
+       gl->glTextureSubImage2D(tex[2], 0, 0, 0, frame->chroma_width, frame->chroma_height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(frame->width * frame->height + frame->chroma_width * frame->chroma_height));
+       gl->glGenerateTextureMipmap(tex[2]);
 
-       glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+       gl->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
 
-       glBindTextureUnit(0, tex[0]);
-       glBindTextureUnit(1, tex[1]);
-       glBindTextureUnit(2, tex[2]);
-       glBindSampler(0, bilinear_sampler);
-       glBindSampler(1, bilinear_sampler);
-       glBindSampler(2, bilinear_sampler);
-       glProgramUniform1i(ycbcr_program, 0, 0);
-       glProgramUniform1i(ycbcr_program, 1, 1);
-       glProgramUniform1i(ycbcr_program, 2, 2);
-       glProgramUniform2f(ycbcr_program, 3, cbcr_offset[0], -cbcr_offset[1]);
+       gl->glBindTextureUnit(0, tex[0]);
+       gl->glBindTextureUnit(1, tex[1]);
+       gl->glBindTextureUnit(2, tex[2]);
+       gl->glBindSampler(0, bilinear_sampler);
+       gl->glBindSampler(1, bilinear_sampler);
+       gl->glBindSampler(2, bilinear_sampler);
+       gl->glProgramUniform1i(ycbcr_program, 0, 0);
+       gl->glProgramUniform1i(ycbcr_program, 1, 1);
+       gl->glProgramUniform1i(ycbcr_program, 2, 2);
+       gl->glProgramUniform2f(ycbcr_program, 3, cbcr_offset[0], -cbcr_offset[1]);
 
        float tx1 = 0.0f;
        float tx2 = 1.0f;
@@ -469,20 +471,20 @@ void VideoWindow::paintGL()
        glBegin(GL_QUADS);
 
        // (0,0)
-       glVertexAttrib2f(1, tx1, ty1);
+       gl->glVertexAttrib2f(1, tx1, ty1);
        glVertex2f(zoom_matrix[2 * 3 + 0], zoom_matrix[2 * 3 + 1]);
 
        // (0,1)
-       glVertexAttrib2f(1, tx1, ty2);
+       gl->glVertexAttrib2f(1, tx1, ty2);
        glVertex2f(zoom_matrix[1 * 3 + 0] + zoom_matrix[2 * 3 + 0], zoom_matrix[1 * 3 + 1] + zoom_matrix[2 * 3 + 1]);
 
        // (1,1)
-       glVertexAttrib2f(1, tx2, ty2);
+       gl->glVertexAttrib2f(1, tx2, ty2);
        glVertex2f(zoom_matrix[0 * 3 + 0] + zoom_matrix[1 * 3 + 0] + zoom_matrix[2 * 3 + 0],
                   zoom_matrix[1 * 3 + 0] + zoom_matrix[1 * 3 + 1] + zoom_matrix[2 * 3 + 1]);
 
        // (1,0)
-       glVertexAttrib2f(1, tx2, ty1);
+       gl->glVertexAttrib2f(1, tx2, ty1);
        glVertex2f(zoom_matrix[0 * 3 + 0] + zoom_matrix[2 * 3 + 0],
                   zoom_matrix[1 * 3 + 0] + zoom_matrix[2 * 3 + 1]);
 
@@ -1062,9 +1064,10 @@ shared_ptr<VideoWidget::Frame> VideoWidget::alloc_frame(unsigned width, unsigned
 
        post_to_main_thread([this, &frame, len, &done, &mu, &done_cv]{
                video_window->makeCurrent();
-               glCreateBuffers(1, &frame->pbo);
-               glNamedBufferStorage(frame->pbo, len, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
-               frame->data = (uint8_t *)glMapNamedBufferRange(frame->pbo, 0, len, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT);
+               auto gl = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_5_Compatibility>(video_window->context());
+               gl->glCreateBuffers(1, &frame->pbo);
+               gl->glNamedBufferStorage(frame->pbo, len, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
+               frame->data = (uint8_t *)gl->glMapNamedBufferRange(frame->pbo, 0, len, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT);
                video_window->doneCurrent();
 
                lock_guard lock(mu);
@@ -1087,8 +1090,9 @@ void VideoWidget::free_frame(VideoWidget::Frame *frame)
                GLuint pbo = frame->pbo;
                post_to_main_thread([self, pbo]{
                        self->video_window->makeCurrent();
-                       glUnmapNamedBuffer(pbo);
-                       glDeleteBuffers(1, &pbo);
+                       auto gl = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_5_Compatibility>(self->video_window->context());
+                       gl->glUnmapNamedBuffer(pbo);
+                       gl->glDeleteBuffers(1, &pbo);
                        self->video_window->doneCurrent();
                });
                delete self->frame_freelist.front();
index b97be69e753ed92fb1ffc353dec47cfbe9b402f4..8d823d8ed69e118fdf47e7ecbe1346b0dc321b5b 100644 (file)
@@ -17,6 +17,8 @@ extern "C" {
 #include "ffmpeg_raii.h"
 #include "quittable_sleeper.h"
 
+class QOpenGLFunctions_4_5_Compatibility;
+
 // Because QVideoWidget sucks, sadly. (Don't use GStreamer, kids.)
 
 class VideoWindow;
@@ -151,6 +153,7 @@ signals:
        void mouse_moved(QMouseEvent *e);
 
 private:
+       QOpenGLFunctions_4_5_Compatibility *gl = nullptr;
        VideoWidget *video;
        GLuint ycbcr_vertex_shader, ycbcr_fragment_shader, ycbcr_program;
        GLuint bilinear_sampler;