You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:34:58