wined3d: Use a fragment shader to do P8 palette conversion in hardware.

This commit is contained in:
Roderick Colenbrander 2007-10-11 23:11:37 +02:00 committed by Alexandre Julliard
parent 5749dd4051
commit 134aa67ec9
3 changed files with 65 additions and 5 deletions

View File

@ -2117,6 +2117,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D
}
}
/* Delete the palette conversion shader if it is around */
if(This->paletteConversionShader) {
GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
}
/* Delete the pbuffer context if there is any */
if(This->pbufferContext) DestroyContext(This, This->pbufferContext);

View File

@ -1413,7 +1413,7 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_
/* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
* for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
*/
if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
if( !(GL_SUPPORT(EXT_PALETTED_TEXTURE) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
*format = GL_RGBA;
*internal = GL_RGBA;
*type = GL_UNSIGNED_BYTE;
@ -1424,6 +1424,12 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_
*convert = CONVERT_PALETTED;
}
}
else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
*format = GL_RED;
*internal = GL_RGBA;
*type = GL_UNSIGNED_BYTE;
*target_bpp = 1;
}
break;
@ -1969,16 +1975,64 @@ static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE (*table)[4],
}
}
const char *fragment_palette_conversion =
"!!ARBfp1.0\n"
"TEMP index;\n"
"PARAM constants = { 0.996, 0.00195, 0, 0 };\n" /* { 255/256, 0.5/255*255/256, 0, 0 } */
"TEX index.x, fragment.texcoord[0], texture[0], 2D;\n" /* store the red-component of the current pixel */
"MUL index.x, index.x, constants.x;\n" /* Scale the index by 255/256 */
"ADD index.x, index.x, constants.y;\n" /* Add a bias of '0.5' in order to sample in the middle */
"TEX result.color, index, texture[1], 1D;\n" /* use the red-component as a index in the palette to get the final color */
"END";
/* This function is used in case of 8bit paletted textures to upload the palette.
For now it only supports GL_EXT_paletted_texture extension but support for other
extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
It supports GL_EXT_paletted_texture and GL_ARB_fragment_program, support for other
extensions like ATI_fragment_shaders is possible.
*/
static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
BYTE table[256][4];
IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
/* Try to use the paletted texture extension */
if(GL_SUPPORT(EXT_PALETTED_TEXTURE))
{
TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
}
else
{
/* Let a fragment shader do the color conversion by uploading the palette to a 1D texture.
* The 8bit pixel data will be used as an index in this palette texture to retrieve the final color. */
TRACE("Using fragment shaders for emulating 8-bit paletted texture support\n");
/* Create the fragment program if we don't have it */
if(!device->paletteConversionShader)
{
glEnable(GL_FRAGMENT_PROGRAM_ARB);
GL_EXTCALL(glGenProgramsARB(1, &device->paletteConversionShader));
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader));
GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragment_palette_conversion), (const GLbyte *)fragment_palette_conversion));
glDisable(GL_FRAGMENT_PROGRAM_ARB);
}
glEnable(GL_FRAGMENT_PROGRAM_ARB);
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader));
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1));
glEnable(GL_TEXTURE_1D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /* Make sure we have discrete color levels. */
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, table); /* Upload the palette */
/* Switch back to unit 0 in which the 2D texture will be stored. */
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0));
}
}
static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
@ -2150,7 +2204,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BO
d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
This->Flags |= SFLAG_CONVERTED;
} else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
} else if( (This->resource.format == WINED3DFMT_P8) && (GL_SUPPORT(EXT_PALETTED_TEXTURE) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) ) {
d3dfmt_p8_upload_palette(iface, convert);
This->Flags &= ~SFLAG_CONVERTED;
mem = This->resource.allocatedMemory;

View File

@ -699,6 +699,7 @@ struct IWineD3DDeviceImpl
/* palettes texture management */
PALETTEENTRY palettes[MAX_PALETTES][256];
UINT currentPalette;
UINT paletteConversionShader;
/* For rendering to a texture using glCopyTexImage */
BOOL render_offscreen;