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 dataOffset;
int sourceH; int sourceH;
int sourceW; int sourceW;
float destX1;
float destY1;
float destX2;
float destY2;
float texTop;
float texBottom;
float texLeft;
float texRight;
TextureInfo() TextureInfo()
: textureID(0) : textureID(0)
, dataOffset(0) , dataOffset(0)
, sourceH(0) , sourceH(0)
, sourceW(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 format The frame's format
/// @param bpp The frame's bytes per pixel /// @param bpp The frame's bytes per pixel
void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, bool flipped) { void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, bool flipped) {
using namespace std;
frameFlipped = flipped; frameFlipped = flipped;
// Do nothing if the frame size and format are unchanged // Do nothing if the frame size and format are unchanged
if (width == frameWidth && height == frameHeight && format == frameFormat) return; 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; int textureArea = maxTextureSize - 2;
textureRows = (int)ceil(double(height) / textureArea); textureRows = (int)ceil(double(height) / textureArea);
textureCols = (int)ceil(double(width) / textureArea); textureCols = (int)ceil(double(width) / textureArea);
textureIdList.resize(textureRows * textureCols); textureCount = textureRows * textureCols;
textureList.resize(textureRows * textureCols); textureIdList.resize(textureCount);
textureList.resize(textureCount);
CHECK_INIT_ERROR(glGenTextures(textureIdList.size(), &textureIdList[0])); 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 /* 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 * 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 * 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 // Calculate the position information for each texture
int lastRow = textureRows - 1; int lastRow = textureRows - 1;
int lastCol = textureCols - 1; int lastCol = textureCols - 1;
@ -221,32 +231,50 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
// Location where this texture is placed // Location where this texture is placed
// X2/Y2 will be offscreen unless the video frame happens to // X2/Y2 will be offscreen unless the video frame happens to
// exactly use all of the texture // exactly use all of the texture
ti.destX1 = sourceX + (col != 0); float x1 = sourceX + (col != 0);
ti.destY1 = sourceY + (row != 0); float y1 = sourceY + (row != 0);
ti.destX2 = sourceX + textureWidth - (col != lastCol); float x2 = sourceX + textureWidth - (col != lastCol);
ti.destY2 = sourceY + textureHeight - (row != lastRow); float y2 = sourceY + textureHeight - (row != lastRow);
// Portion of the texture actually used // Portion of the texture actually used
ti.texTop = row == 0 ? 0 : 1.0f / textureHeight; float top = row == 0 ? 0 : 1.0f / textureHeight;
ti.texLeft = col == 0 ? 0 : 1.0f / textureWidth; float left = col == 0 ? 0 : 1.0f / textureWidth;
ti.texBottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight; float bottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight;
ti.texRight = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth; float right = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth;
// Store the stuff needed later
ti.textureID = textureIdList[row * textureCols + col]; 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));
// 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());
void VideoOutGL::CreateTexture(int w, int h, const TextureInfo& ti, GLenum format) { glEndList();
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)); // Create the textures outside of the display list as there's no need to
wxLogDebug(L"VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h); // remake them on every frame
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); for (int i = 0; i < textureCount; ++i) {
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, textureIdList[i]));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureSizes[i].first, textureSizes[i].second, 0, format, GL_UNSIGNED_BYTE, NULL));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); 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) { void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) {
@ -273,52 +301,20 @@ void VideoOutGL::SetViewport(int x, int y, int width, int height) {
} }
void VideoOutGL::Render(int sw, int sh) { void VideoOutGL::Render(int sw, int sh) {
// Clear the frame buffer glCallList(dl);
CHECK_ERROR(glClearColor(0,0,0,0));
CHECK_ERROR(glClearStencil(0));
CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
// Switch to script coordinates
CHECK_ERROR(glShadeModel(GL_FLAT)); // This isn't really the right place to do this, but there isn't really
CHECK_ERROR(glDisable(GL_BLEND)); // anywhere better right now
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());
CHECK_ERROR(glOrtho(0.0f, sw, sh, 0.0f, -1000.0f, 1000.0f)); CHECK_ERROR(glOrtho(0.0f, sw, sh, 0.0f, -1000.0f, 1000.0f));
CHECK_ERROR(glMatrixMode(GL_MODELVIEW)); CHECK_ERROR(glMatrixMode(GL_MODELVIEW));
CHECK_ERROR(glLoadIdentity()); CHECK_ERROR(glLoadIdentity());
} }
VideoOutGL::~VideoOutGL() { VideoOutGL::~VideoOutGL() {
if (textureIdList.size() > 0) { if (textureIdList.size() > 0) {
glDeleteTextures(textureIdList.size(), &textureIdList[0]); glDeleteTextures(textureIdList.size(), &textureIdList[0]);
glDeleteLists(dl, 1);
} }
} }

View file

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