我正在编写一个 2D OpenGL 引擎,并且我最近包含了一个帧缓冲区包装类,用于在运行时生成纹理图集。在我在笔记本电脑的集成显卡上对其进行测试之前,它工作得非常好,性能也得到了很大的提升。
显然,在集成显卡上运行时 glCheckFramebufferStatus 返回零。不,它不会返回 GL_FRAMEBUFFER_UNSUPPORTED。它返回零。我真的不认为我的集成显卡不支持帧缓冲区,因为它们不是那么旧。我还尝试延迟帧缓冲区的初始化以在主 GLUT 循环中执行此操作,但它没有解决问题。我也尝试使用 framebufferEXT 而不是 framebuffer,但没有任何改变。如果我忽略该错误,当我尝试绘制帧缓冲区的纹理时它不会绘制任何内容。另外:如果视频卡不支持帧缓冲区并且我绝对需要它们,我应该回退什么?
这是我的帧缓冲区类的代码:
帧缓冲区.hpp:
#pragma once
#include "sprite.hpp"
namespace core
{
class framebuffer
{
public:
framebuffer();
virtual ~framebuffer();
bool initialized();
void initialize(int width, int height);
int width();
int height();
sprite *getframe();
void begin();
void end();
protected:
GLubyte *pixels;
int w, h;
GLuint id, tex;
sprite frame;
};
}
帧缓冲区.cpp:
#include "framebuffer.hpp"
#include <iostream>
#include <cmath>
namespace core
{
framebuffer::framebuffer()
: pixels(NULL), w(0), h(0)
{
// empty
}
framebuffer::~framebuffer()
{
glDeleteFramebuffers(1, &id);
if (pixels)
{
// TODO: convert to smart pointer once everything works ok
delete [] pixels;
pixels = NULL;
}
}
bool framebuffer::initialized()
{
return w != 0 && h != 0;
}
void framebuffer::initialize(int width, int height)
{
w = width;
h = height;
//std::cout << "framebuffer.initialize: w = " << w << "\nh = " << h << std::endl;
}
int framebuffer::width()
{
return w;
}
int framebuffer::height()
{
return h;
}
sprite *framebuffer::getframe()
{
GLuint oldtex;
glBindFramebuffer(GL_FRAMEBUFFER, id);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGetIntegerv(GL_TEXTURE_RECTANGLE_ARB, reinterpret_cast<GLint *>(&oldtex)); // store old bound texture
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex); // bind framebuffer texture
glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // get framebuffer pixels
frame.fromtexture(tex, GL_RGBA, w, h, GL_RGBA, pixels); // create a sprite object from raw pixels
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldtex); // re-bind the old texture
glDisable(GL_TEXTURE_RECTANGLE_ARB);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return &frame;
}
void framebuffer::begin() // call this to start drawing to the framebuffer
{
if (!pixels)
{
GLenum result;
// initialize the frame buffer if it isn't already
glGenTextures(1, &tex); // generate the texture that will store the frame
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
// reserve video memory for the framebuffer image
pixels = new GLubyte[w * h * 4];
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenFramebuffers(1, &id); // create frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, id);
// assign the texture to the framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (result != GL_FRAMEBUFFER_COMPLETE)
{
if (result == GL_FRAMEBUFFER_UNSUPPORTED)
{
// todo: handle errors as exceptions and cleanup everything gracefully
std::cout << "framebuffer.begin: your video card doesn't seem to support framebuffers" << std::endl;
exit(0);
}
std::cout << "framebuffer.begin: failed to initialize framebuffer | error " << result << std::endl;
exit(0);
}
glDisable(GL_TEXTURE_RECTANGLE_ARB);
}
glBindFramebuffer(GL_FRAMEBUFFER, id); // bind the framebuffer
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
glViewport(0, 0, w, h); // adjust viewport to the fbo's size
glLoadIdentity(); // reset modelview matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix(); // store the non-flipped matrix
glLoadIdentity();
glOrtho(0, w, 0, h, -1, 1); // stupid fbo's flipping stuff upside down
glMatrixMode(GL_MODELVIEW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void framebuffer::end() // call this to stop drawing to the framebuffer
{
glPopAttrib();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glMatrixMode(GL_PROJECTION);
glPopMatrix(); // restore old matrix
glMatrixMode(GL_MODELVIEW);
}
}