From 7951b5f3e7ff7ef95ca32a1e163d00519e8a5125 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 29 Jun 2003 08:13:18 +0000 Subject: [PATCH] Add helpers: RageDisplay::CreateSurfaceFromPixfmt, RageDisplay::FindPixelFormat. UpdateTexture can now take any image format; it doesn't have to match the original format, or even be a standard pixel format. This is because we can often do the conversion much more efficiently within UpdateTexture than we can in the caller. With D3D, we can convert any source format as we copy, preventing an extra blit. OpenGL can do it on the fly if it happens to be a known texture format. We can figure out the pixel format from the image itself, so there's no need to pass pixfmt to UpdateTexture. Add BGR8, for movies with OpenGL. --- stepmania/src/RageDisplay.cpp | 33 +++++++++++++++++++ stepmania/src/RageDisplay.h | 8 +++-- stepmania/src/RageDisplay_D3D.cpp | 44 +++++++++++++++++++++++-- stepmania/src/RageDisplay_D3D.h | 3 +- stepmania/src/RageDisplay_OGL.cpp | 54 ++++++++++++++++++++++++++++--- stepmania/src/RageDisplay_OGL.h | 3 +- 6 files changed, 131 insertions(+), 14 deletions(-) diff --git a/stepmania/src/RageDisplay.cpp b/stepmania/src/RageDisplay.cpp index a7f3caedfa..8393ccdb39 100644 --- a/stepmania/src/RageDisplay.cpp +++ b/stepmania/src/RageDisplay.cpp @@ -17,6 +17,7 @@ #include "RageMath.h" #include "RageUtil.h" #include "GameConstantsAndTypes.h" +#include "SDL_utils.h" // // Statistics stuff @@ -566,3 +567,35 @@ RageMatrix RageDisplay::GetPerspectiveMatrix(float fovy, float aspect, float zNe return GetFrustrumMatrix(xmin, xmax, ymin, ymax, zNear, zFar); } + +SDL_Surface *RageDisplay::CreateSurfaceFromPixfmt( PixelFormat pixfmt, + void *pixels, int width, int height, int pitch ) +{ + const PixelFormatDesc *tpf = GetPixelFormatDesc(pixfmt); + + SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( + pixels, width, height, tpf->bpp, pitch, + tpf->masks[0], tpf->masks[1], tpf->masks[2], tpf->masks[3]); + + return surf; +} + +PixelFormat RageDisplay::FindPixelFormat( + int bpp, int Rmask, int Gmask, int Bmask, int Amask ) +{ + PixelFormatDesc tmp = { bpp, Rmask, Gmask, Bmask, Amask }; + + int pixfmt; + for(pixfmt = 0; pixfmt < NUM_PIX_FORMATS; ++pixfmt) + { + const PixelFormatDesc *pf = GetPixelFormatDesc(PixelFormat(pixfmt)); + if(!SupportsTextureFormat( PixelFormat(pixfmt) )) + continue; + + if(memcmp(pf, &tmp, sizeof(tmp))) + continue; + return PixelFormat(pixfmt); + } + + return NUM_PIX_FORMATS; +} diff --git a/stepmania/src/RageDisplay.h b/stepmania/src/RageDisplay.h index 114c3fde64..de807fdbfc 100644 --- a/stepmania/src/RageDisplay.h +++ b/stepmania/src/RageDisplay.h @@ -43,6 +43,8 @@ enum PixelFormat { FMT_RGB5A1, FMT_RGB5, FMT_RGB8, + /* This may not be as well-supported as RGBA; it's used to speed up DirectShow. */ + FMT_BGR8, FMT_PAL, NUM_PIX_FORMATS }; @@ -128,8 +130,7 @@ public: ) = 0; virtual void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) = 0; virtual void DeleteTexture( unsigned uTexHandle ) = 0; @@ -229,6 +230,9 @@ public: float zfar ); RageMatrix GetPerspectiveMatrix(float fovy, float aspect, float zNear, float zFar); + SDL_Surface *CreateSurfaceFromPixfmt( PixelFormat pixfmt, void *pixels, int width, int height, int pitch ); + PixelFormat FindPixelFormat( int bpp, int Rmask, int Gmask, int Bmask, int Amask ); + protected: const RageMatrix* GetProjection(); const RageMatrix* GetModelViewTop(); diff --git a/stepmania/src/RageDisplay_D3D.cpp b/stepmania/src/RageDisplay_D3D.cpp index bcedfc6f8b..5a2d50ec75 100644 --- a/stepmania/src/RageDisplay_D3D.cpp +++ b/stepmania/src/RageDisplay_D3D.cpp @@ -95,6 +95,7 @@ static void SetPalette( unsigned TexResource ) // Cards that don't support palettes with alpha will crash unless // all entires have full alpha. + // XXX: Since we disable FMT_PAL in SupportsTextureFormat, can we remove this? -glenn if( ! (g_DeviceCaps.TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) ) for(int j=0; j<256; j++) pal.p[j].peFlags = 255; @@ -165,6 +166,9 @@ static const PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { 0x00FF00, 0x0000FF, 0x000000 } + }, { + /* BGRA (N/A; OpenGL only) */ + 0, { 0,0,0,0 } }, { /* Paletted */ 8, @@ -183,6 +187,7 @@ static D3DFORMAT D3DFORMATS[NUM_PIX_FORMATS] = #else D3DFMT_A8R8G8B8, #endif + D3DFMT_UNKNOWN, /* no BGR */ D3DFMT_P8 }; @@ -555,6 +560,9 @@ bool RageDisplay_D3D::SupportsTextureFormat( PixelFormat pixfmt ) if( pixfmt == FMT_PAL && !(g_DeviceCaps.TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) ) return false; + if( D3DFORMATS[pixfmt] == D3DFMT_UNKNOWN ) + return false; + D3DFORMAT d3dfmt = D3DFORMATS[pixfmt]; HRESULT hr = g_pd3d->CheckDeviceFormat( D3DADAPTER_DEFAULT, @@ -563,6 +571,8 @@ bool RageDisplay_D3D::SupportsTextureFormat( PixelFormat pixfmt ) 0, D3DRTYPE_TEXTURE, d3dfmt); + if(FAILED(hr)) + LOG->Trace("format %i not supported", pixfmt); return SUCCEEDED( hr ); } @@ -910,20 +920,24 @@ unsigned RageDisplay_D3D::CreateTexture( g_TexResourceToTexturePalette[uTexHandle] = pal; } - UpdateTexture( uTexHandle, pixfmt, img, 0, 0, img->w, img->h ); + UpdateTexture( uTexHandle, img, 0, 0, img->w, img->h ); return uTexHandle; } void RageDisplay_D3D::UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) { IDirect3DTexture8* pTex = (IDirect3DTexture8*)uTexHandle; ASSERT( pTex != NULL ); + /* Make sure that the pixel format of the image is legit. We don't actually + * care, but the OpenGL renderer does, so make sure people coding in the D3D + * renderer don't accidentally break the OpenGL one. */ + FindPixelFormat( img->format->BitsPerPixel, img->format->Rmask, img->format->Gmask, img->format->Bmask, img->format->Amask ); + RECT rect; rect.left = xoffset; rect.top = yoffset; @@ -933,6 +947,29 @@ void RageDisplay_D3D::UpdateTexture( D3DLOCKED_RECT lr; pTex->LockRect( 0, &lr, &rect, 0 ); + D3DSURFACE_DESC desc; + pTex->GetLevelDesc(0, &desc); + ASSERT( xoffset+width <= int(desc.Width) ); + ASSERT( yoffset+height <= int(desc.Height) ); + + int texpixfmt; + for(texpixfmt = 0; texpixfmt < NUM_PIX_FORMATS; ++texpixfmt) + if(D3DFORMATS[texpixfmt] == desc.Format) break; + ASSERT( texpixfmt != NUM_PIX_FORMATS ); + + SDL_Surface *Texture = CreateSurfaceFromPixfmt(PixelFormat(texpixfmt), lr.pBits, width, height, lr.Pitch); + SDL_Rect area; + area.x = area.y = 0; + area.w = (Uint16) width; + area.h = (Uint16) height; + SDL_SetAlpha( img, 0, SDL_ALPHA_OPAQUE ); +// SDL_SetColorKey( img, 0, 0 ); +// SDL_BlitSurface( img, &area, Texture, &area ); + mySDL_BlitSurface( img, Texture, width, height, false ); + + SDL_FreeSurface( Texture ); + +#if 0 // copy each row int bytes_per_pixel = img->format->BytesPerPixel; for( int y=rect.top; yUnlockRect( 0 ); } diff --git a/stepmania/src/RageDisplay_D3D.h b/stepmania/src/RageDisplay_D3D.h index 5452c15238..a694f9188d 100644 --- a/stepmania/src/RageDisplay_D3D.h +++ b/stepmania/src/RageDisplay_D3D.h @@ -24,8 +24,7 @@ public: unsigned CreateTexture( PixelFormat pixfmt, SDL_Surface*& img ); void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ); void DeleteTexture( unsigned uTexHandle ); diff --git a/stepmania/src/RageDisplay_OGL.cpp b/stepmania/src/RageDisplay_OGL.cpp index 9479b6cfa0..ab3f93df22 100644 --- a/stepmania/src/RageDisplay_OGL.cpp +++ b/stepmania/src/RageDisplay_OGL.cpp @@ -73,7 +73,9 @@ namespace GLExt { PWSWAPINTERVALEXTPROC GLExt::wglSwapIntervalEXT = NULL; PFNGLCOLORTABLEPROC GLExt::glColorTableEXT = NULL; PFNGLCOLORTABLEPARAMETERIVPROC GLExt::glGetColorTableParameterivEXT = NULL; -bool g_bEXT_texture_env_combine = true; +bool g_bEXT_texture_env_combine = true; +bool g_bGL_EXT_bgra = true; + /* OpenGL system information that generally doesn't change at runtime. */ /* Range and granularity of points and lines: */ @@ -98,7 +100,7 @@ LowLevelWindow *wind; static PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { { - /* B8G8R8A8 */ + /* R8G8B8A8 */ 32, { 0xFF000000, 0x00FF0000, @@ -132,6 +134,13 @@ static PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { 0x00FF00, 0x0000FF, 0x000000 } + }, { + /* B8G8R8A8 */ + 24, + { 0x0000FF, + 0x00FF00, + 0xFF0000, + 0x000000 } }, { /* Paletted */ 8, @@ -148,7 +157,7 @@ struct GLPixFmtInfo_t { * is not, but all SDL masks are affected by endianness, so GL_UNSIGNED_BYTE * is reversed. This isn't endian-safe. */ { - /* B8G8R8A8 */ + /* R8G8B8A8 */ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, @@ -172,6 +181,11 @@ struct GLPixFmtInfo_t { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, + }, { + /* B8G8R8 */ + GL_RGB8, + GL_BGR, + GL_UNSIGNED_BYTE, }, { /* Paletted */ GL_COLOR_INDEX8_EXT, @@ -367,6 +381,7 @@ void SetupExtensions() GLExt::glColorTableEXT = (PFNGLCOLORTABLEPROC) wind->GetProcAddress("glColorTableEXT"); GLExt::glGetColorTableParameterivEXT = (PFNGLCOLORTABLEPARAMETERIVPROC) wind->GetProcAddress("glGetColorTableParameterivEXT"); g_bEXT_texture_env_combine = HasExtension("GL_EXT_texture_env_combine"); + g_bGL_EXT_bgra = HasExtension("GL_EXT_bgra"); CheckPalettedTextures(); // Checks for known bad drivers @@ -515,6 +530,8 @@ bool RageDisplay_OGL::SupportsTextureFormat( PixelFormat pixfmt ) { case FMT_PAL: return GLExt::glColorTableEXT && GLExt::glGetColorTableParameterivEXT; + case FMT_BGR8: + return g_bGL_EXT_bgra; default: return true; // No way to query this in OGL. You pass it a format and hope it doesn't have to convert. } @@ -983,14 +1000,38 @@ unsigned RageDisplay_OGL::CreateTexture( void RageDisplay_OGL::UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) { glBindTexture( GL_TEXTURE_2D, uTexHandle ); glPixelStorei(GL_UNPACK_ROW_LENGTH, img->pitch / img->format->BytesPerPixel); + PixelFormat pixfmt = FindPixelFormat( img->format->BitsPerPixel, img->format->Rmask, img->format->Gmask, img->format->Bmask, img->format->Amask ); + SDL_Surface *imgconv = NULL; + + if( pixfmt == NUM_PIX_FORMATS ) + { + LOG->Trace("guh"); + /* The source isn't in a supported, known pixel format. We need to convert + * it ourself. Just convert it to RGBA8, and let OpenGL convert it back + * down to whatever the actual pixel format is. This is a very slow code + * path, which should almost never be used. */ + pixfmt = FMT_RGBA8; + const PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt); + + SDL_SetAlpha( img, 0, SDL_ALPHA_OPAQUE ); + + SDL_Rect area; + area.x = area.y = 0; + area.w = short(width); + area.h = short(height); + imgconv = SDL_CreateRGBSurfaceSane(SDL_SWSURFACE, width, height, + pfd->bpp, pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3]); + SDL_BlitSurface(img, &area, imgconv, &area); + img = imgconv; + } + // GLenum glTexFormat = GL_PIXFMT_INFO[pixfmt].internalfmt; GLenum glImageFormat = GL_PIXFMT_INFO[pixfmt].format; GLenum glImageType = GL_PIXFMT_INFO[pixfmt].type; @@ -1003,6 +1044,9 @@ void RageDisplay_OGL::UpdateTexture( /* Must unset PixelStore when we're done! */ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glFlush(); + + if( imgconv ) + SDL_FreeSurface( imgconv ); } CString RageDisplay_OGL::GetTextureDiagnostics( unsigned id ) const diff --git a/stepmania/src/RageDisplay_OGL.h b/stepmania/src/RageDisplay_OGL.h index 4811643aec..30d8102f5e 100644 --- a/stepmania/src/RageDisplay_OGL.h +++ b/stepmania/src/RageDisplay_OGL.h @@ -20,8 +20,7 @@ public: unsigned CreateTexture( PixelFormat pixfmt, SDL_Surface*& img ); void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ); void DeleteTexture( unsigned uTexHandle );