Module: wine
Branch: master
Commit: 134aa67ec9fc9f761e6da15a816f770d8a30c455
URL: http://source.winehq.org/git/wine.git/?a=commit;h=134aa67ec9fc9f761e6da15a8…
Author: Roderick Colenbrander <thunderbird2k(a)gmx.net>
Date: Thu Oct 11 23:11:37 2007 +0200
wined3d: Use a fragment shader to do P8 palette conversion in hardware.
---
dlls/wined3d/device.c | 5 +++
dlls/wined3d/surface.c | 64 ++++++++++++++++++++++++++++++++++++---
dlls/wined3d/wined3d_private.h | 1 +
3 files changed, 65 insertions(+), 5 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 3857ebd..a7a586d 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -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);
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index bbf51c7..fc1b10d 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -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;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 431160d..446f2a9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -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;
Module: wine
Branch: master
Commit: 5749dd40518aed6fff7abea8f5283fe324c55e1a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5749dd40518aed6fff7abea8f…
Author: Roderick Colenbrander <thunderbird2k(a)gmx.net>
Date: Thu Oct 11 22:04:48 2007 +0200
wined3d: Fix inverse palette lookup for P8 surfaces.
The previous method didn't take into account duplicate entries for the same color.
---
dlls/wined3d/surface.c | 76 ++++++++++++++++++++++++++++++++++--------------
1 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 938df0d..bbf51c7 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -487,24 +487,32 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v
{
case WINED3DFMT_P8:
{
- /* GL can't return palettized data, so read ARGB pixels into a
- * separate block of memory and convert them into palettized format
- * in software. Slow, but if the app means to use palettized render
- * targets and locks it...
- *
- * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
- * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
- * for the color channels when palettizing the colors.
- */
- fmt = GL_RGB;
- type = GL_UNSIGNED_BYTE;
- pitch *= 3;
- mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
- if(!mem) {
- ERR("Out of memory\n");
- return;
+ if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
+ /* In case of P8 render targets the index is stored in the alpha component */
+ fmt = GL_ALPHA;
+ type = GL_UNSIGNED_BYTE;
+ mem = dest;
+ bpp = This->bytesPerPixel;
+ } else {
+ /* GL can't return palettized data, so read ARGB pixels into a
+ * separate block of memory and convert them into palettized format
+ * in software. Slow, but if the app means to use palettized render
+ * targets and locks it...
+ *
+ * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
+ * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
+ * for the color channels when palettizing the colors.
+ */
+ fmt = GL_RGB;
+ type = GL_UNSIGNED_BYTE;
+ pitch *= 3;
+ mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
+ if(!mem) {
+ ERR("Out of memory\n");
+ return;
+ }
+ bpp = This->bytesPerPixel * 3;
}
- bpp = This->bytesPerPixel * 3;
}
break;
@@ -576,7 +584,12 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v
}
}
- if(This->resource.format == WINED3DFMT_P8) {
+ /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
+ * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
+ * the same color but we have no choice.
+ * In case of render targets, the index is stored in the alpha component so no conversion is needed.
+ */
+ if((This->resource.format == WINED3DFMT_P8) && !(This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
PALETTEENTRY *pal;
DWORD width = pitch / 3;
int x, y, c;
@@ -1892,18 +1905,33 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN
static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE (*table)[4], BOOL colorkey) {
IWineD3DPaletteImpl* pal = This->palette;
+ IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+ BOOL index_in_alpha = FALSE;
int i;
+ /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
+ * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
+ * is slow. Further RGB->P8 conversion is not possible because palettes can have
+ * duplicate entries. Store the color key in the unused alpha component to speed the
+ * download up and to make conversion unneeded. */
+ if (device->render_targets && device->render_targets[0]) {
+ IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
+
+ if(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
+ index_in_alpha = TRUE;
+ }
+
if (pal == NULL) {
/* Still no palette? Use the device's palette */
/* Get the surface's palette */
for (i = 0; i < 256; i++) {
- IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
-
table[i][0] = device->palettes[device->currentPalette][i].peRed;
table[i][1] = device->palettes[device->currentPalette][i].peGreen;
table[i][2] = device->palettes[device->currentPalette][i].peBlue;
- if (colorkey &&
+
+ if(index_in_alpha) {
+ table[i][3] = i;
+ } else if (colorkey &&
(i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
(i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
/* We should maybe here put a more 'neutral' color than the standard bright purple
@@ -1921,7 +1949,11 @@ static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE (*table)[4],
table[i][0] = pal->palents[i].peRed;
table[i][1] = pal->palents[i].peGreen;
table[i][2] = pal->palents[i].peBlue;
- if (colorkey &&
+
+ if(index_in_alpha) {
+ table[i][3] = i;
+ }
+ else if (colorkey &&
(i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
(i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
/* We should maybe here put a more 'neutral' color than the standard bright purple