Make the video display use OpenGL display lists, slightly simplifying the code and reducing the amount of state explicitly tracked.

Originally committed to SVN as r4247.
This commit is contained in:
Thomas Goyne 2010-04-30 03:00:04 +00:00
parent 5f82c5bb02
commit b90fdcc111
2 changed files with 75 additions and 78 deletions

View file

@ -66,30 +66,11 @@ struct VideoOutGL::TextureInfo {
int dataOffset;
int sourceH;
int sourceW;
float destX1;
float destY1;
float destX2;
float destY2;
float texTop;
float texBottom;
float texLeft;
float texRight;
TextureInfo()
: textureID(0)
, dataOffset(0)
, sourceH(0)
, sourceW(0)
, destX1(0)
, destY1(0)
, destX2(0)
, destY2(0)
, texTop(0)
, texBottom(1.0f)
, texLeft(0)
, texRight(1.0f)
{ }
};
@ -147,6 +128,8 @@ void VideoOutGL::DetectOpenGLCapabilities() {
/// @param format The frame's format
/// @param bpp The frame's bytes per pixel
void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, bool flipped) {
using namespace std;
frameFlipped = flipped;
// Do nothing if the frame size and format are unchanged
if (width == frameWidth && height == frameHeight && format == frameFormat) return;
@ -168,9 +151,12 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
int textureArea = maxTextureSize - 2;
textureRows = (int)ceil(double(height) / textureArea);
textureCols = (int)ceil(double(width) / textureArea);
textureIdList.resize(textureRows * textureCols);
textureList.resize(textureRows * textureCols);
textureCount = textureRows * textureCols;
textureIdList.resize(textureCount);
textureList.resize(textureCount);
CHECK_INIT_ERROR(glGenTextures(textureIdList.size(), &textureIdList[0]));
vector<pair<int, int> > textureSizes;
textureSizes.reserve(textureCount);
/* Unfortunately, we can't simply use one of the two standard ways to do
* tiled textures to work around texture size limits in OpenGL, due to our
@ -195,6 +181,30 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
* Width behaves in the same way with respect to left/right edges
*/
// Set up the display list
dl = glGenLists(1);
glNewList(dl, GL_COMPILE);
CHECK_ERROR(glClearColor(0,0,0,0));
CHECK_ERROR(glClearStencil(0));
CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
CHECK_ERROR(glShadeModel(GL_FLAT));
CHECK_ERROR(glDisable(GL_BLEND));
// Switch to video coordinates
CHECK_ERROR(glMatrixMode(GL_PROJECTION));
CHECK_ERROR(glLoadIdentity());
CHECK_ERROR(glPushMatrix());
if (frameFlipped) {
CHECK_ERROR(glOrtho(0.0f, frameWidth, 0.0f, frameHeight, -1000.0f, 1000.0f));
}
else {
CHECK_ERROR(glOrtho(0.0f, frameWidth, frameHeight, 0.0f, -1000.0f, 1000.0f));
}
CHECK_ERROR(glEnable(GL_TEXTURE_2D));
// Calculate the position information for each texture
int lastRow = textureRows - 1;
int lastCol = textureCols - 1;
@ -221,33 +231,51 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
// Location where this texture is placed
// X2/Y2 will be offscreen unless the video frame happens to
// exactly use all of the texture
ti.destX1 = sourceX + (col != 0);
ti.destY1 = sourceY + (row != 0);
ti.destX2 = sourceX + textureWidth - (col != lastCol);
ti.destY2 = sourceY + textureHeight - (row != lastRow);
float x1 = sourceX + (col != 0);
float y1 = sourceY + (row != 0);
float x2 = sourceX + textureWidth - (col != lastCol);
float y2 = sourceY + textureHeight - (row != lastRow);
// Portion of the texture actually used
ti.texTop = row == 0 ? 0 : 1.0f / textureHeight;
ti.texLeft = col == 0 ? 0 : 1.0f / textureWidth;
ti.texBottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight;
ti.texRight = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth;
float top = row == 0 ? 0 : 1.0f / textureHeight;
float left = col == 0 ? 0 : 1.0f / textureWidth;
float bottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight;
float right = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth;
// Store the stuff needed later
ti.textureID = textureIdList[row * textureCols + col];
textureSizes.push_back(make_pair(textureWidth, textureHeight));
CreateTexture(textureWidth, textureHeight, ti, format);
}
}
}
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
void VideoOutGL::CreateTexture(int w, int h, const TextureInfo& ti, GLenum format) {
CHECK_INIT_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL));
wxLogDebug(L"VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h);
// Place the texture
glBegin(GL_QUADS);
glTexCoord2f(left, top); glVertex2f(x1, y1);
glTexCoord2f(right, top); glVertex2f(x2, y1);
glTexCoord2f(right, bottom); glVertex2f(x2, y2);
glTexCoord2f(left, bottom); glVertex2f(x1, y2);
glEnd();
if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err);
}
}
CHECK_ERROR(glDisable(GL_TEXTURE_2D));
CHECK_ERROR(glPopMatrix());
glEndList();
// Create the textures outside of the display list as there's no need to
// remake them on every frame
for (int i = 0; i < textureCount; ++i) {
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, textureIdList[i]));
CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureSizes[i].first, textureSizes[i].second, 0, format, GL_UNSIGNED_BYTE, NULL));
wxLogDebug(L"VideoOutGL::InitTextures: Using texture size: %dx%d\n", textureSizes[i].first, textureSizes[i].second);
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
}
}
void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) {
if (frame.h == 0 || frame.w == 0) return;
@ -273,52 +301,20 @@ void VideoOutGL::SetViewport(int x, int y, int width, int height) {
}
void VideoOutGL::Render(int sw, int sh) {
// Clear the frame buffer
CHECK_ERROR(glClearColor(0,0,0,0));
CHECK_ERROR(glClearStencil(0));
CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
glCallList(dl);
CHECK_ERROR(glShadeModel(GL_FLAT));
CHECK_ERROR(glDisable(GL_BLEND));
CHECK_ERROR(glMatrixMode(GL_PROJECTION));
CHECK_ERROR(glLoadIdentity());
CHECK_ERROR(glPushMatrix());
if (frameFlipped) {
CHECK_ERROR(glOrtho(0.0f, frameWidth, 0.0f, frameHeight, -1000.0f, 1000.0f));
}
else {
CHECK_ERROR(glOrtho(0.0f, frameWidth, frameHeight, 0.0f, -1000.0f, 1000.0f));
}
// Render the current frame
CHECK_ERROR(glEnable(GL_TEXTURE_2D));
for (unsigned i = 0; i < textureList.size(); i++) {
TextureInfo& ti = textureList[i];
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
glBegin(GL_QUADS);
glTexCoord2f(ti.texLeft, ti.texTop); glVertex2f(ti.destX1, ti.destY1);
glTexCoord2f(ti.texRight, ti.texTop); glVertex2f(ti.destX2, ti.destY1);
glTexCoord2f(ti.texRight, ti.texBottom); glVertex2f(ti.destX2, ti.destY2);
glTexCoord2f(ti.texLeft, ti.texBottom); glVertex2f(ti.destX1, ti.destY2);
glEnd();
if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err);
}
CHECK_ERROR(glDisable(GL_TEXTURE_2D));
CHECK_ERROR(glPopMatrix());
// Switch to script coordinates
// This isn't really the right place to do this, but there isn't really
// anywhere better right now
CHECK_ERROR(glOrtho(0.0f, sw, sh, 0.0f, -1000.0f, 1000.0f));
CHECK_ERROR(glMatrixMode(GL_MODELVIEW));
CHECK_ERROR(glLoadIdentity());
}
VideoOutGL::~VideoOutGL() {
if (textureIdList.size() > 0) {
glDeleteTextures(textureIdList.size(), &textureIdList[0]);
glDeleteLists(dl, 1);
}
}

View file

@ -69,6 +69,8 @@ private:
std::vector<GLuint> textureIdList;
/// List of precalculated texture display information
std::vector<TextureInfo> textureList;
/// OpenGL display list which draws the frames
GLuint dl;
/// The total texture count
int textureCount;
/// The number of rows of textures
@ -78,7 +80,6 @@ private:
void DetectOpenGLCapabilities();
void InitTextures(int width, int height, GLenum format, int bpp, bool flipped);
void CreateTexture(int w, int h, const TextureInfo& ti, GLenum format);
VideoOutGL(const VideoOutGL &);
VideoOutGL& operator=(const VideoOutGL&);