From b90fdcc1116b67bbccbe31ac8ee38e7f4a4e1fb5 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Fri, 30 Apr 2010 03:00:04 +0000 Subject: [PATCH] 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. --- aegisub/src/video_out_gl.cpp | 150 +++++++++++++++++------------------ aegisub/src/video_out_gl.h | 3 +- 2 files changed, 75 insertions(+), 78 deletions(-) diff --git a/aegisub/src/video_out_gl.cpp b/aegisub/src/video_out_gl.cpp index 9c922093f..419fcfabc 100644 --- a/aegisub/src/video_out_gl.cpp +++ b/aegisub/src/video_out_gl.cpp @@ -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 > 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,32 +231,50 @@ 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)); + + // 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) { - 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); - 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)); + 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) { @@ -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); } } diff --git a/aegisub/src/video_out_gl.h b/aegisub/src/video_out_gl.h index 625f70caf..698810431 100644 --- a/aegisub/src/video_out_gl.h +++ b/aegisub/src/video_out_gl.h @@ -69,6 +69,8 @@ private: std::vector textureIdList; /// List of precalculated texture display information std::vector 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&);