Search code examples
openglglfwmpv

glBlitNamedFramebuffer vs glBlitFramebuffer


Trying to replace glBlitNamedFramebuffer with glBlitFramebuffer, documentation says that they are equvivalent, just the difference is how fbo's are defined. But in my case glBlitNamedFramebuffer works but glBlitFramebuffer not (does nothing). May be I missed something? Here is the code:

#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 wporks
            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 wporks
            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;
}

Solution

  • GL_DRAW_BUFFER, GL_READ_BUFFER, GL_BUFFER are not valid for glBindFramebuffer. The valid targets are GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER and GL_FRAMEBUFFER:

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);            
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
                        
    glBlitFramebuffer(
        0, 0,
        fbo_width, fbo_height,
        x, y,
        x + fbo_width,
        y + fbo_height,
        GL_COLOR_BUFFER_BIT, GL_NEAREST);
    
    glBindFramebuffer(GL_FRAMEBUFFER, 0);