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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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; y<rect.bottom; y++ )
|
||||
@@ -941,6 +978,7 @@ void RageDisplay_D3D::UpdateTexture(
|
||||
char* dst = (char*)lr.pBits + y*lr.Pitch + rect.left*bytes_per_pixel;
|
||||
memcpy( dst, src, (rect.right-rect.left)*bytes_per_pixel );
|
||||
}
|
||||
#endif
|
||||
pTex->UnlockRect( 0 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user