glBlitFramebuffer替换glBlitNamedFramebuffer无效果,求排查原因
问题:glBlitFramebuffer替换glBlitNamedFramebuffer后无效果
我尝试将glBlitNamedFramebuffer替换为glBlitFramebuffer,根据OpenGL文档说明,两者功能等价,仅帧缓冲对象(FBO)的指定方式存在差异。但实际测试中,glBlitNamedFramebuffer可正常完成帧缓冲复制,glBlitFramebuffer却无任何效果,怀疑遗漏了某些关键配置,相关代码如下:
#include "GL/glew.h" #include <iostream> #define GLEW_STATIC //#include "linmath.h" #include <GLFW/glfw3.h> #include <stdio.h> #include <stdlib.h> #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include "fbo.h" //#include "shader.hpp" #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif #include <mpv/client.h> #include <mpv/render_gl.h> #ifdef __cplusplus } #endif bool wakeup_on_mpv_render_update = false; bool wakeup_on_mpv_events = false; bool redraw = false; // -------------------------------------------------------- // // -------------------------------------------------------- void ProcessInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } } // -------------------------------------------------------- // // -------------------------------------------------------- static void die(const char* msg) { std::cout << msg << std::endl; exit(1); } // -------------------------------------------------------- // // -------------------------------------------------------- static void* get_proc_address_mpv(void* fn_ctx, const char* name) { return glfwGetProcAddress(name); } // -------------------------------------------------------- // ON EVENT // -------------------------------------------------------- static void on_mpv_events(void* ctx) { wakeup_on_mpv_events = true; } // -------------------------------------------------------- // Render update callback // -------------------------------------------------------- static void on_mpv_render_update(void* ctx) { wakeup_on_mpv_render_update = true; } // ---------------------------------------- // // ---------------------------------------- static void error_callback(int error, const char* description) { std::cout << "Error: " << description << std::endl;; } // ---------------------------------------- // // ---------------------------------------- static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { glfwSetWindowShouldClose(window, GLFW_TRUE); } } // -------------------------------------------------------- // MAIN // -------------------------------------------------------- int main(void) { int width = 1024; int height = 1024; // -------------------------------------------------------- // // -------------------------------------------------------- GLFWwindow* window; if (!glfwInit()) { std::cout << "glfw init err" << std::endl; return -1; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ cout << "I'm apple machine" << endl; glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif window = glfwCreateWindow(width, height, "Learngl", NULL, NULL); if (!window) { std::cout << " can't create window!!!" << std::endl; glfwTerminate(); return -1; } // -------------------------------------------------------- // OpenGL 3.3 // -------------------------------------------------------- unsigned int major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); unsigned int minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); std::cout << "oepngl shader version: " << major << "." << minor << std::endl; glfwMakeContextCurrent(window); if (glewInit() != GLEW_OK) { std::cout << "Error ! " << std::endl; } std::cout << glGetString(GL_VERSION) << std::endl; // ---------------------------------------- // MPV create and init // ---------------------------------------- mpv_handle* mpv = mpv_create(); if (!mpv) { die("context init failed"); } // Some minor options can only be set before mpv_initialize(). if (mpv_initialize(mpv) < 0) { die("mpv init failed"); } // -------------------------------------------------------- // turn on some MPV events // -------------------------------------------------------- mpv_request_log_messages(mpv, "debug"); mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); // -------------------------------------------------------- // Create MPV context // -------------------------------------------------------- mpv_opengl_init_params opengl_init_params { get_proc_address_mpv, nullptr }; int adv { 1 }; // we will use the update callback mpv_render_param render_param[] { { MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL) }, { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &opengl_init_params }, { MPV_RENDER_PARAM_ADVANCED_CONTROL, &adv }, { MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME, (int)0 }, { MPV_RENDER_PARAM_INVALID, nullptr }, }; mpv_render_context* mpv_gl; if (mpv_render_context_create(&mpv_gl, mpv, render_param) < 0) { die("failed to initialize mpv GL context"); } GLuint fbo = 0; GLuint fbo_width = width; GLuint fbo_height = height; Fbo fboStruct; fboStruct.allocate(fbo_width,fbo_height,0); fbo=fboStruct.getId(); // -------------------------------------------------------- // // -------------------------------------------------------- int one = 1; mpv_opengl_fbo gl_fbo_params[1] = { fbo, fbo_width, fbo_height }; mpv_render_param render_params[] = { { MPV_RENDER_PARAM_OPENGL_FBO, gl_fbo_params }, // Flip rendering (needed due to flipped GL coordinate system). { MPV_RENDER_PARAM_FLIP_Y, &one }, { MPV_RENDER_PARAM_INVALID, nullptr }, }; // -------------------------------------------------------- //Event processing for mpv player // -------------------------------------------------------- mpv_set_wakeup_callback(mpv, on_mpv_events, NULL); mpv_render_context_set_update_callback(mpv_gl, on_mpv_render_update, NULL); mpv_set_option_string(mpv, "loop", ""); mpv_set_option_string(mpv, "gpu-api", "opengl"); mpv_set_option_string(mpv, "hwdec", "auto"); mpv_set_option_string(mpv, "vd-lavc-dr", "yes"); mpv_set_option_string(mpv, "terminal", "yes"); // -------------------------------------------------------- // Load video // -------------------------------------------------------- const char* cmd[] = { "loadfile", "video0.mp4", NULL }; mpv_command_async(mpv, 0, cmd); // -------------------------------------------------------- // Main loop // -------------------------------------------------------- while (!glfwWindowShouldClose(window)) { ProcessInput(window); // Happens when there is new work for the render thread (such as // rendering a new video frame or redrawing it). if (wakeup_on_mpv_render_update) { uint64_t flags = mpv_render_context_update(mpv_gl); if (flags & MPV_RENDER_UPDATE_FRAME) { redraw = 1; } wakeup_on_mpv_render_update = false; } // Happens when at least 1 new event is in the mpv event queue. if (wakeup_on_mpv_events) { // Handle all remaining mpv events. while (1) { mpv_event* mp_event = mpv_wait_event(mpv, 0); if (mp_event->event_id == MPV_EVENT_NONE) { break; } if (mp_event->event_id == MPV_EVENT_LOG_MESSAGE) { mpv_event_log_message* msg = (mpv_event_log_message*)mp_event->data; if (strstr(msg->text, "DR image")) { std::cout << "log:" << msg->text << std::endl; } continue; } // ------------ if (mp_event->event_id == MPV_EVENT_PROPERTY_CHANGE) { mpv_event_property* prop = (mpv_event_property*)mp_event->data; if (strcmp(prop->name, "time-pos") == 0) { if (prop->format == MPV_FORMAT_DOUBLE) { double time = *(double*)prop->data; std::cout << time << std::endl; } continue; } else if (strcmp(prop->name, "duration") == 0) { if (prop->format == MPV_FORMAT_DOUBLE) { double time = *(double*)prop->data; std::cout << time << std::endl; } continue; } } // ------------ std::cout << "event: " << mpv_event_name(mp_event->event_id) << std::endl; } wakeup_on_mpv_events = false; } // -------------------------------------------------------- // DRAW FRAME // -------------------------------------------------------- if (redraw) { glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); mpv_render_context_render(mpv_gl, render_params); int x = 0; int y = 0; #if 1 // this works glBlitNamedFramebuffer(fbo, 0, 0,0, fbo_width, fbo_height, x, y, x + fbo_width, y + fbo_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); #else // this not works glBindFramebuffer(GL_DRAW_BUFFER,0); glBindFramebuffer(GL_READ_BUFFER,fbo); glBlitFramebuffer( 0,0, fbo_width, fbo_height, x, y, x + fbo_width, y + fbo_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_BUFFER,0); glBindFramebuffer(GL_DRAW_BUFFER,0); #endif redraw=0; glfwSwapBuffers(window); } glfwPollEvents(); } mpv_render_context_free(mpv_gl); mpv_terminate_destroy(mpv); std::cout << "properly terminated" << std::endl; glfwTerminate(); return 0; }
问题原因与修正方案
你在使用glBlitFramebuffer时犯了两个关键枚举错误:
- 绑定帧缓冲时误用了
GL_DRAW_BUFFER和GL_READ_BUFFER,这两个是颜色缓冲附件的枚举,不是glBindFramebuffer的合法目标,正确目标应为GL_DRAW_FRAMEBUFFER和GL_READ_FRAMEBUFFER - 解绑时使用了不存在的
GL_BUFFER枚举,正确的解绑操作需要针对读/画帧缓冲目标绑定0
修正后的glBlitFramebuffer代码片段:
// 修正后的代码 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer( 0, 0, fbo_width, fbo_height, x, y, x + fbo_width, y + fbo_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); // 可选:解绑帧缓冲(后续操作使用默认帧缓冲时可省略) glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
补充说明:glBlitNamedFramebuffer直接指定读/画FBO的ID,无需手动绑定;而glBlitFramebuffer依赖当前绑定的GL_READ_FRAMEBUFFER和GL_DRAW_FRAMEBUFFER目标,之前的枚举错误导致OpenGL无法识别正确的帧缓冲,因此blit操作无效果。
内容的提问来源于stack exchange,提问作者Andrey Smorodov
相关产品推荐
相关产品推荐

