From dc25a86cc5a34e89f65135482dc966ed5c85b00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Wed, 23 Jul 2008 10:33:10 -0500 Subject: [PATCH] wined3d: Support ATI's D3DFMT_ATI2N format. This is an ATI specific format designed for compressed normal maps, and quite a few games check for its existence. While it is an ATI-specific "extension" in d3d9, it is a core part of D3D10(DXGI_FORMAT_BC5), and supported on Geforce 8 cards. --- dlls/wined3d/arb_program_shader.c | 17 +++++++++++++++++ dlls/wined3d/device.c | 3 ++- dlls/wined3d/directx.c | 10 ++++++++++ dlls/wined3d/glsl_shader.c | 20 ++++++++++++++++++++ dlls/wined3d/surface.c | 12 ++++++++---- dlls/wined3d/utils.c | 13 +++++++++++++ include/wine/wined3d_gl.h | 6 ++++++ include/wine/wined3d_types.h | 2 ++ 8 files changed, 78 insertions(+), 5 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 83a7ed8aa7b..9f074ada14b 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -816,6 +816,23 @@ static void shader_arb_color_correction(SHADER_OPCODE_ARG* arg) { } break; + case WINED3DFMT_ATI2N: + /* GL_ATI_texture_compression_3dc returns the two channels as luminance-alpha, + * which means the first one is replicated accross .rgb, and the 2nd one is in + * .a. We need the 2nd in .g + */ + if(strlen(writemask) == 5) { + /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */ + shader_addline(arg->buffer, "MOV %s.%c, %s.%c;\n", + reg, writemask[2], reg, writemask[4]); + } else if(strlen(writemask) == 2) { + /* Nothing to do */ + } else { + /* This is bad: We have VL, but we need VU */ + FIXME("2 or 3 components sampled from a converted ATI2N texture\n"); + } + break; + /* stupid compiler */ default: break; diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b3db3b740c7..0a6bd2b7ba4 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -641,7 +641,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, U Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1; } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 || - Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { + Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 || + Format == WINED3DFMT_ATI2N) { Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)); } else { /* The pitch is a multiple of 4 bytes */ diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index f3537394838..f4bc0ee8f1e 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -59,6 +59,7 @@ static const struct { {"GL_ATI_texture_mirror_once", ATI_TEXTURE_MIRROR_ONCE, 0 }, {"GL_ATI_envmap_bumpmap", ATI_ENVMAP_BUMPMAP, 0 }, {"GL_ATI_fragment_shader", ATI_FRAGMENT_SHADER, 0 }, + {"GL_ATI_texture_compression_3dc", ATI_TEXTURE_COMPRESSION_3DC, 0 }, /* ARB */ {"GL_ARB_color_buffer_float", ARB_COLOR_BUFFER_FLOAT, 0 }, @@ -2371,6 +2372,15 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) TRACE_(d3d_caps)("[FAILED]\n"); return FALSE; + /* Vendor specific formats */ + case WINED3DFMT_ATI2N: + if(GL_SUPPORT(ATI_TEXTURE_COMPRESSION_3DC)) { + TRACE_(d3d_caps)("[OK]\n"); + return TRUE; + } + TRACE_(d3d_caps)("[FAILED]\n"); + return FALSE; + case WINED3DFMT_UNKNOWN: return FALSE; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index da13d1d99a0..7a20ae175b1 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1344,6 +1344,26 @@ static void shader_glsl_color_correction(SHADER_OPCODE_ARG* arg) { } break; + case WINED3DFMT_ATI2N: + /* GL_ATI_texture_compression_3dc returns the two channels as luminance-alpha, + * which means the first one is replicated accross .rgb, and the 2nd one is in + * .a. We need the 2nd in .g + */ + mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param); + mask_size = shader_glsl_get_write_mask_size(mask); + if(mask_size == 4) { + /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */ + shader_addline(arg->buffer, "%s.%c = %s.%c;\n", + dst_param.reg_name, dst_param.mask_str[2], + dst_param.reg_name, dst_param.mask_str[4]); + } else if(mask_size == 1) { + /* Nothing to do */ + } else { + FIXME("%u components sampled from a converted ATI2N texture\n", mask_size); + /* This is bad: We have .r[gb], but we need .ra */ + } + break; + /* stupid compiler */ default: break; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index cd312bcad4c..2227243aadc 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -93,7 +93,8 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { if (This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || - This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5 || + This->resource.format == WINED3DFMT_ATI2N) { if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */ FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This); } else { @@ -232,7 +233,8 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) { if (This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || - This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5 || + This->resource.format == WINED3DFMT_ATI2N) { if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { FIXME("Using DXT1/3/5 without advertized support\n"); } else { @@ -296,7 +298,8 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, if (This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || - This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5 || + This->resource.format == WINED3DFMT_ATI2N) { /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */ TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n"); @@ -3771,7 +3774,8 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { WINED3DFORMAT Format = This->resource.format; /** TODO: add support for non power two compressed textures **/ if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 - || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { + || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 + || This->resource.format == WINED3DFMT_ATI2N) { FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n", This, This->currentDesc.Width, This->currentDesc.Height); return WINED3DERR_NOTAVAILABLE; diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index dd18b274243..370f50ba23c 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -112,6 +112,8 @@ static const StaticPixelFormatDesc formats[] = { {WINED3DFMT_INDEX16 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, {WINED3DFMT_INDEX32 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, {WINED3DFMT_Q16W16V16U16,0x0 ,0x0 ,0x0 ,0x0 ,8 ,0 ,0 ,FALSE }, + /* Vendor-specific formats */ + {WINED3DFMT_ATI2N ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, }; typedef struct { @@ -260,6 +262,9 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { {WINED3DFMT_INDEX32 ,0 ,0 , 0, 0 ,0 ,0 }, {WINED3DFMT_Q16W16V16U16 ,GL_COLOR_INDEX ,GL_COLOR_INDEX , 0, GL_COLOR_INDEX ,GL_UNSIGNED_SHORT + ,0 }, + /* Vendor-specific formats */ + {WINED3DFMT_ATI2N ,0 ,0 , 0, GL_LUMINANCE_ALPHA ,GL_UNSIGNED_BYTE ,0 } }; @@ -390,6 +395,13 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info) */ } + if(GL_SUPPORT(ATI_TEXTURE_COMPRESSION_3DC)) { + dst = getFmtIdx(WINED3DFMT_ATI2N); + gl_info->gl_formats[dst].glInternal = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; + gl_info->gl_formats[dst].glGammaInternal = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; + gl_info->gl_formats[dst].conversion_group= WINED3DFMT_ATI2N; + } + return TRUE; } @@ -519,6 +531,7 @@ const char* debug_d3dformat(WINED3DFORMAT fmt) { FMT_TO_STR(WINED3DFMT_G32R32F); FMT_TO_STR(WINED3DFMT_A32B32G32R32F); FMT_TO_STR(WINED3DFMT_CxV8U8); + FMT_TO_STR(WINED3DFMT_ATI2N); #undef FMT_TO_STR default: { diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h index 04471df737b..533c991ca7f 100644 --- a/include/wine/wined3d_gl.h +++ b/include/wine/wined3d_gl.h @@ -2991,6 +2991,11 @@ typedef void (WINE_GLAPI *PGLFNSETFRAGMENTSHADERCONSTANTATI) (GLuint dst, const #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 #endif +/* GL_ATI_texture_compression_3dc */ +#ifndef GL_ATI_texture_compression_3dc +#define GL_ATI_texture_compression_3dc +#define GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI 0x8837 +#endif /* GL_VERSION_2_0 */ #ifndef GL_VERSION_2_0 @@ -3357,6 +3362,7 @@ typedef enum _GL_SupportedExt { EXT_VERTEX_SHADER, ATI_ENVMAP_BUMPMAP, ATI_FRAGMENT_SHADER, + ATI_TEXTURE_COMPRESSION_3DC, /* APPLE */ APPLE_FENCE, APPLE_CLIENT_STORAGE, diff --git a/include/wine/wined3d_types.h b/include/wine/wined3d_types.h index 45a947d0da4..c67c3116280 100644 --- a/include/wine/wined3d_types.h +++ b/include/wine/wined3d_types.h @@ -303,6 +303,8 @@ typedef enum _WINED3DFORMAT { WINED3DFMT_CxV8U8 = 117, + /* Vendor specific formats */ + WINED3DFMT_ATI2N = WINEMAKEFOURCC('A', 'T', 'I', '2'), WINED3DFMT_FORCE_DWORD = 0xFFFFFFFF } WINED3DFORMAT;