Я пишу 2D движок OpenGL, и недавно я включил класс-оболочку фреймбуфера, который я использую для генерации атласа текстуры во время выполнения. Он работал довольно хорошо и много улучшал производительность, пока я не протестировал его на интегрированной графике моего ноутбука.
Видимо, при работе на интегрированной графике glCheckFramebufferStatus возвращает ноль. Нет, он не возвращает GL_FRAMEBUFFER_UNSUPPORTED. Возвращает ноль. Я действительно не думаю, что моя интегрированная графика не поддерживает кадровые буферы, так как они не такие старые.
Я также попытался отложить инициализацию кадрового буфера, чтобы сделать это внутри основного цикла GLUT, но это не решило проблему. Я также попытался использовать framebufferEXT вместо framebuffer, но ничего не изменилось.
Если я игнорирую ошибку, она ничего не рисует, когда я пытаюсь нарисовать текстуру кадрового буфера.
Кроме того: к чему я должен прибегнуть, если видеокарта не поддерживает кадровые буферы и они мне абсолютно необходимы?
Вот код моего класса кадрового буфера:
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;
};
}
framebuffer.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);
}
}
Из официальной документации:
«Возвращаемое значение — GL_FRAMEBUFFER_COMPLETE, если кадровый буфер, связанный с целью, завершен. В противном случае возвращаемое значение определяется следующим образом:
…
Кроме того, если возникает ошибка, возвращается ноль. «
Итак, вот оно, произошла ошибка. Возможно, у glGetError есть дополнительная информация.
Если кадровые буферы не поддерживаются и вы хотите использовать их для рендеринга в текстуру, вы можете увидеть, поддерживаются ли pbuffers, в противном случае glReadPixels?
Я предполагаю, что целевая видеокарта может не поддерживать GL_TEXTURE_RECTANGLE_ARB. В этом случае вам, возможно, придется переключиться на степень 2 текстуры.