通过OpenGL编程访问整个视频内存

时间:2012-05-11 17:22:43

标签: opengl fbo video-memory

如何通过OpenGL编程访问显卡的视频内存,具体来说,是为了获取所有内存的视频内存?

我尝试了以下两种方法,但都失败了。将它们连接起来,我希望你能指出我的程序中的错误或我对视频内存结构的理解。提前谢谢!

我的基本想法是继续在视频内存中分配未初始化的区域,直到探索视频内存的所有内容。

(1)在main函数中,我创建了一个带有双缓冲区的窗口(参见下面的代码)。

int main(int argc,char ** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); // double buffers
    glutInitWindowPosition(0,0);
    glutInitWindowSize(windowWidth, windowHeight);
    glutCreateWindow("Hope to be successful!");
    glutDisplayFunc(myDisplay); // call back function "myDisplay"
    glutKeyboardFunc(keyboard);
    glutMainLoop();

    free(PixelData);
    return 0;
}

然后,在“myDisplay”函数中,首先我调用glReadPixels()函数从后面的framebuffer中读出给定大小的像素矩形,将这些像素信息保存在数组“PixelData”中,最后显示那些通过调用glDrawPixels()函数在屏幕上显示像素信息。执行此程序后,只显示一个黑色窗口。黑色是默认颜色。所以这意味着窗口什么都没有。然后我试图从后面的帧缓冲区中读取其他区域,并且它们都不包含任何内容。

以上结论是后框架缓冲器中不包含任何内容。但是,这是不合理的,因为前缓冲区应该只包含当前的屏幕内容/窗口,因此在屏幕底部打开和最小化的其他窗口应该将其内容放在后面的帧缓冲区中,但后面的帧缓冲区是空的。那些存储了哪些窗口(由我在底部打开并最小化)?

我想为我的程序分配的帧缓冲区(后面和前面)只占整个视频内存的一小部分。因此,那些最小化的窗口内容应存储在视频内存的其他位置。

过了一段时间,我阅读了OpenGL frameBuffer对象(FBO)的介绍,并且有一句话:默认情况下,OpenGL使用帧缓冲作为完全由窗口系统创建和管理的渲染目标。此默认帧缓冲区称为窗口系统提供的帧缓冲区。这似乎证实了我的上述猜测。

(2)然后我开始研究FBO,希望FBO可以帮助我探索整个视频内存。

在下面的main函数中,我创建了一个FBO和7个渲染缓冲对象(RBO),然后通过颜色附加点将这7个RBO附加到此FBO。

const int RBO_COUNT = 7; //how many renderBuffer objects are created to attach to the frameBuffer object

int main(int argc, char **argv)
{
    ....
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_ALPHA); // display mode
    ...  

    // create a framebuffer object
    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);

    //Create several 7 render buffer objects and attach all of them to the FBO.
    glGenRenderbuffers(RBO_COUNT, rbo);
    for (int i = 0; i < RBO_COUNT; i++)
    {
        glBindRenderbuffer(GL_RENDERBUFFER, rbo[i]);
        glRenderbufferStorage(GL_RENDERBUFFER, PIXEL_FORMAT, SCREEN_WIDTH, SCREEN_HEIGHT);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, colorAttach[i], GL_RENDERBUFFER, rbo[i]);
    }

   // check FBO status
   bool status = checkFramebufferStatus();
   if(!status) fboUsed = false;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    ...

    glutMainLoop(); /* Start GLUT event-processing loop */
    return 0;
}

以下是我的显示回调函数的主要部分。它的功能是使用空格键来控制要读取的renderBuffer对象,然后在屏幕上显示其内容。

void displayCB()
{
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

//read this FBO attached RBO, save its content to fboContent
//"count" is a global variable, and is incremented by 1 (mod )every time pressing the space key of the keyboard.
glReadBuffer(colorAttach[count]); 
glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, fboContent);

// back to normal window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind

// render to the default framebuffer //////////////////////////
glClear(GL_COLOR_BUFFER_BIT); // clear buffer
glClearColor(1, 0, 0, 1);
glDrawBuffer(GL_BACK);
glRasterPos2i(-1, -1);  
glDrawPixels(SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, fboContent);
glutSwapBuffers();
}

最终结果令人失望。所有renderBuffer对象的内容都是空的。我不知道原因,因为我认为所有这些RBO都没有初始化,应该包含一些剩余的内容。

3 个答案:

答案 0 :(得分:6)

  

如何通过OpenGL编程访问显卡的视频内存,具体来说,是为了获取所有内存的视频内存?

你做不到。无法通过OpenGL或DirectX访问原始视频内存。 OpenGL只有各种“缓冲区”。唯一可以访问它的是视频驱动程序,它是Windows平台专有的。免费视频内存由视频驱动程序管理,视频内存中的某些对象可能只是暂时存在 - 驱动程序可以将副本存储在系统内存中,移动它们并在必要时将它们卸载到磁盘。因此,您手动管理空闲内存的想法没有实际应用。

你应该可以直接在OLD硬件上访问视频内存 - 东西EGA / CGA / VGA,也可以在支持VESA的卡上访问,但是你没有硬件加速,你需要运行类似于MS的东西-DOS或具有内核/驱动程序访问权限。 您可以在Linux上访问内存内容,但我认为它没有帮助。

我建议忘记这个想法。

  

你的意思是OpenGL不能做这样的任务吗?实际上,我已经解决了这个问题将近两个月。

当你开始一个宏大的项目而没有先做足够的研究时,通常会发生类似的事情。我建议学习这个经验。在开始编码之前,请记住检查您的应用程序是否尚未编写,是否有任何实际应用程序,是否可以创建,是否需要该应用程序,以及您是否拥有足够的资源来创建它。

目前管理存储在视频内存中的对象是驱动程序的工作。

如果你想看到其他应用程序创建的对象,使用代理dll,dll注入或类似技术劫持OpenGL api并拦截相关调用可能更容易。

答案 1 :(得分:2)

  

如何通过OpenGL编程访问显卡的视频内存,具体来说,是为了获取所有内存的视频内存?

与操作系统对话,而不是OpenGL。

答案 2 :(得分:-1)

目前尚不清楚为什么这样做,以及您的最终游戏是什么,但在我看来,您正试图访问由第三方应用程序生成的图形信息。

如果您正在尝试完成what FRAPS does,请记住它使用的技术与您尝试的方法完全不同(更简单的方法):它拦截对OpenGL和DirectX等图形库的调用