From 90e245965090b9514e18b67d3e79edde1b2c711b Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 30 Jul 2023 23:53:02 +0200 Subject: [PATCH] Move to using Qt's OpenGL function pointers. 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 | 114 ++++++++++++++++++++++++----------------------- video_widget.h | 3 ++ 2 files changed, 62 insertions(+), 55 deletions(-) diff --git a/video_widget.cpp b/video_widget.cpp index 1f3534f..63efa7d 100644 --- a/video_widget.cpp +++ b/video_widget.cpp @@ -1,5 +1,3 @@ -#define GL_GLEXT_PROTOTYPES - #include "video_widget.h" #include @@ -37,6 +35,8 @@ extern "C" { #include #include #include +#include +#include #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(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::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(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(self->video_window->context()); + gl->glUnmapNamedBuffer(pbo); + gl->glDeleteBuffers(1, &pbo); self->video_window->doneCurrent(); }); delete self->frame_freelist.front(); diff --git a/video_widget.h b/video_widget.h index b97be69..8d823d8 100644 --- a/video_widget.h +++ b/video_widget.h @@ -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; -- 2.39.2