wined3d: Recompile glsl pixelshaders if the sampler format changes.

This commit is contained in:
Stefan Dösinger 2007-09-21 23:47:40 +02:00 committed by Alexandre Julliard
parent 10f25e0104
commit 1c4a15d2cd
6 changed files with 135 additions and 18 deletions

View File

@ -846,6 +846,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U
HRESULT hr; HRESULT hr;
unsigned int pow2Width; unsigned int pow2Width;
unsigned int pow2Height; unsigned int pow2Height;
const GlPixelFormatDesc *glDesc;
getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage); TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
@ -928,6 +930,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U
tmpW = max(1, tmpW >> 1); tmpW = max(1, tmpW >> 1);
tmpH = max(1, tmpH >> 1); tmpH = max(1, tmpH >> 1);
} }
object->baseTexture.shader_conversion_group = glDesc->conversion_group;
TRACE("(%p) : Created texture %p\n", This, object); TRACE("(%p) : Created texture %p\n", This, object);
return WINED3D_OK; return WINED3D_OK;
@ -947,6 +950,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa
UINT tmpW; UINT tmpW;
UINT tmpH; UINT tmpH;
UINT tmpD; UINT tmpD;
const GlPixelFormatDesc *glDesc;
getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
/* TODO: It should only be possible to create textures for formats /* TODO: It should only be possible to create textures for formats
that are reported as supported */ that are reported as supported */
@ -1017,6 +1022,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa
tmpH = max(1, tmpH >> 1); tmpH = max(1, tmpH >> 1);
tmpD = max(1, tmpD >> 1); tmpD = max(1, tmpD >> 1);
} }
object->baseTexture.shader_conversion_group = glDesc->conversion_group;
*ppVolumeTexture = (IWineD3DVolumeTexture *) object; *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
TRACE("(%p) : Created volume texture %p\n", This, object); TRACE("(%p) : Created volume texture %p\n", This, object);
@ -1066,6 +1072,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface
UINT tmpW; UINT tmpW;
HRESULT hr; HRESULT hr;
unsigned int pow2EdgeLength = EdgeLength; unsigned int pow2EdgeLength = EdgeLength;
const GlPixelFormatDesc *glDesc;
getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
/* TODO: It should only be possible to create textures for formats /* TODO: It should only be possible to create textures for formats
that are reported as supported */ that are reported as supported */
@ -1149,6 +1157,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface
} }
tmpW = max(1, tmpW >> 1); tmpW = max(1, tmpW >> 1);
} }
object->baseTexture.shader_conversion_group = glDesc->conversion_group;
TRACE("(%p) : Created Cube Texture %p\n", This, object); TRACE("(%p) : Created Cube Texture %p\n", This, object);
*ppCubeTexture = (IWineD3DCubeTexture *) object; *ppCubeTexture = (IWineD3DCubeTexture *) object;

View File

@ -976,14 +976,34 @@ static void shader_glsl_add_color_correction(SHADER_OPCODE_ARG* arg, DWORD sampl
glsl_dst_param_t dst_param; glsl_dst_param_t dst_param;
glsl_dst_param_t dst_param2; glsl_dst_param_t dst_param2;
WINED3DFORMAT fmt; WINED3DFORMAT fmt;
WINED3DFORMAT conversion_group;
IWineD3DBaseTextureImpl *texture; IWineD3DBaseTextureImpl *texture;
DWORD mask, mask_size; DWORD mask, mask_size;
UINT i;
BOOL recorded = FALSE;
texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx]; texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx];
if(texture) { if(texture) {
fmt = texture->resource.format; fmt = texture->resource.format;
conversion_group = texture->baseTexture.shader_conversion_group;
} else { } else {
fmt = WINED3DFMT_UNKNOWN; fmt = WINED3DFMT_UNKNOWN;
conversion_group = WINED3DFMT_UNKNOWN;
}
/* before doing anything, record the sampler with the format in the format conversion list,
* but check if it's not there already
*/
for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) {
if(shader->baseShader.sampled_samplers[i] == sampler_idx) {
recorded = TRUE;
break;
}
}
if(!recorded) {
shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
shader->baseShader.num_sampled_samplers++;
shader->baseShader.sampled_format[sampler_idx] = conversion_group;
} }
switch(fmt) { switch(fmt) {

View File

@ -67,6 +67,22 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_AddRef(IWineD3DPixelShader *iface)
return InterlockedIncrement(&This->ref); return InterlockedIncrement(&This->ref);
} }
static void destroy_glsl_pshader(IWineD3DPixelShaderImpl *This) {
struct list *linked_programs = &This->baseShader.linked_programs;
TRACE("Deleting linked programs\n");
if (linked_programs->next) {
struct glsl_shader_prog_link *entry, *entry2;
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, pshader_entry) {
delete_glsl_program_entry(This->baseShader.device, entry);
}
}
TRACE("Deleting shader object %u\n", This->baseShader.prgId);
GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId));
checkGLcall("glDeleteObjectARB");
}
static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface) { static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface) {
IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
ULONG ref; ULONG ref;
@ -74,19 +90,7 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface)
ref = InterlockedDecrement(&This->ref); ref = InterlockedDecrement(&This->ref);
if (ref == 0) { if (ref == 0) {
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
struct list *linked_programs = &This->baseShader.linked_programs; destroy_glsl_pshader(This);
TRACE("Deleting linked programs\n");
if (linked_programs->next) {
struct glsl_shader_prog_link *entry, *entry2;
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, pshader_entry) {
delete_glsl_program_entry(This->baseShader.device, entry);
}
}
TRACE("Deleting shader object %u\n", This->baseShader.prgId);
GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId));
checkGLcall("glDeleteObjectARB");
} }
shader_delete_constant_list(&This->baseShader.constantsF); shader_delete_constant_list(&This->baseShader.constantsF);
shader_delete_constant_list(&This->baseShader.constantsB); shader_delete_constant_list(&This->baseShader.constantsB);
@ -523,11 +527,43 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader
IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface; IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface;
IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
CONST DWORD *function = This->baseShader.function; CONST DWORD *function = This->baseShader.function;
UINT i, sampler;
IWineD3DBaseTextureImpl *texture;
TRACE("(%p) : function %p\n", iface, function); TRACE("(%p) : function %p\n", iface, function);
/* We're already compiled. */ /* We're already compiled, but check if any of the hardcoded stateblock assumptions
if (This->baseShader.is_compiled) return WINED3D_OK; * changed.
*/
if (This->baseShader.is_compiled) {
for(i = 0; i < This->baseShader.num_sampled_samplers; i++) {
sampler = This->baseShader.sampled_samplers[i];
texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler];
if(texture && texture->baseTexture.shader_conversion_group != This->baseShader.sampled_format[sampler]) {
WARN("Recompiling shader %p due to format change on sampler %d\n", This, sampler);
WARN("Old format group %s, new is %s\n",
debug_d3dformat(This->baseShader.sampled_format[sampler]),
debug_d3dformat(texture->baseTexture.shader_conversion_group));
goto recompile;
}
}
/* TODO: Check projected textures */
/* TODO: Check texture types(2D, Cube, 3D) */
return WINED3D_OK;
recompile:
if(This->baseShader.recompile_count > 50) {
FIXME("Shader %p recompiled more than 50 times\n", This);
} else {
This->baseShader.recompile_count++;
}
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
destroy_glsl_pshader(This);
}
}
/* We don't need to compile */ /* We don't need to compile */
if (!function) { if (!function) {
@ -547,6 +583,9 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader
/* FIXME: validate reg_maps against OpenGL */ /* FIXME: validate reg_maps against OpenGL */
} }
/* Reset fields tracking stateblock values beeing hardcoded in the shader */
This->baseShader.num_sampled_samplers = 0;
/* Generate the HW shader */ /* Generate the HW shader */
TRACE("(%p) : Generating hardware program\n", This); TRACE("(%p) : Generating hardware program\n", This);
IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function); IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);

View File

@ -27,8 +27,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DEFAULT_DEBUG_CHANNEL(d3d);
#define GLINFO_LOCATION This->adapter->gl_info
/***************************************************************************** /*****************************************************************************
* Pixel format array * Pixel format array
*/ */
@ -210,9 +208,11 @@ static inline int getFmtIdx(WINED3DFORMAT fmt) {
return -1; return -1;
} }
#define GLINFO_LOCATION (*gl_info)
BOOL initPixelFormats(WineD3D_GL_Info *gl_info) BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
{ {
unsigned int src; unsigned int src;
int dst;
gl_info->gl_formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, gl_info->gl_formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(formats) / sizeof(formats[0]) * sizeof(gl_info->gl_formats[0])); sizeof(formats) / sizeof(formats[0]) * sizeof(gl_info->gl_formats[0]));
@ -222,15 +222,51 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
* after this loop * after this loop
*/ */
for(src = 0; src < sizeof(gl_formats_template) / sizeof(gl_formats_template[0]); src++) { for(src = 0; src < sizeof(gl_formats_template) / sizeof(gl_formats_template[0]); src++) {
int dst = getFmtIdx(gl_formats_template[src].fmt); dst = getFmtIdx(gl_formats_template[src].fmt);
gl_info->gl_formats[dst].glInternal = gl_formats_template[src].glInternal; gl_info->gl_formats[dst].glInternal = gl_formats_template[src].glInternal;
gl_info->gl_formats[dst].glGammaInternal = gl_formats_template[src].glGammaInternal; gl_info->gl_formats[dst].glGammaInternal = gl_formats_template[src].glGammaInternal;
gl_info->gl_formats[dst].glFormat = gl_formats_template[src].glFormat; gl_info->gl_formats[dst].glFormat = gl_formats_template[src].glFormat;
gl_info->gl_formats[dst].glType = gl_formats_template[src].glType; gl_info->gl_formats[dst].glType = gl_formats_template[src].glType;
gl_info->gl_formats[dst].conversion_group= WINED3DFMT_UNKNOWN;
}
/* V8U8 and V16U16 are always tidied up in the pixel shader - blue is set to 1.0.
* They can't be switched with other formats, but they can be switched with each other,
* except if GL_ATI_envmap_bumpmap is supported. In this case, V8U8 uses the gl native format,
* but V16U16 is converted.
*/
dst = getFmtIdx(WINED3DFMT_V8U8);
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8;
dst = getFmtIdx(WINED3DFMT_V16U16);
if(!GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8;
} else {
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V16U16;
}
if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
/* If GL_NV_texture_shader is not supported, those formats are converted, incompatibly
* with each other
*/
dst = getFmtIdx(WINED3DFMT_L6V5U5);
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_L6V5U5;
dst = getFmtIdx(WINED3DFMT_X8L8V8U8);
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_X8L8V8U8;
dst = getFmtIdx(WINED3DFMT_Q8W8V8U8);
gl_info->gl_formats[dst].conversion_group = WINED3DFMT_Q8W8V8U8;
} else {
/* If GL_NV_texture_shader is supported, WINED3DFMT_L6V5U5 and WINED3DFMT_X8L8V8U8
* are converted at surface loading time, but they do not need any modification in
* the shader, thus they are compatible with all WINED3DFMT_UNKNOWN group formats.
* WINED3DFMT_Q8W8V8U8 doesn't even need load-time conversion
*/
} }
return TRUE; return TRUE;
} }
#undef GLINFO_LOCATION
#define GLINFO_LOCATION This->adapter->gl_info
const StaticPixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt, WineD3D_GL_Info *gl_info, const GlPixelFormatDesc **glDesc) const StaticPixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt, WineD3D_GL_Info *gl_info, const GlPixelFormatDesc **glDesc)
{ {

View File

@ -932,6 +932,7 @@ typedef struct IWineD3DBaseTextureClass
DWORD sampler; DWORD sampler;
BOOL is_srgb; BOOL is_srgb;
UINT srgb_mode_change_count; UINT srgb_mode_change_count;
WINED3DFORMAT shader_conversion_group;
} IWineD3DBaseTextureClass; } IWineD3DBaseTextureClass;
typedef struct IWineD3DBaseTextureImpl typedef struct IWineD3DBaseTextureImpl
@ -1898,6 +1899,17 @@ typedef struct IWineD3DBaseShaderClass
struct list constantsI; struct list constantsI;
shader_reg_maps reg_maps; shader_reg_maps reg_maps;
/* Pixel formats of sampled textures, for format conversion. This
* represents the formats found during compilation, it is not initialized
* on the first parser pass. It is needed to check if the shader
* needs recompilation to adjust the format conversion
*/
WINED3DFORMAT sampled_format[MAX_COMBINED_SAMPLERS];
UINT sampled_samplers[MAX_COMBINED_SAMPLERS];
UINT num_sampled_samplers;
UINT recompile_count;
/* Pointer to the parent device */ /* Pointer to the parent device */
IWineD3DDevice *device; IWineD3DDevice *device;

View File

@ -3691,6 +3691,7 @@ typedef BOOL (WINAPI * WINED3D_PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer,
typedef struct { typedef struct {
GLint glInternal, glGammaInternal, glFormat, glType; GLint glInternal, glGammaInternal, glFormat, glType;
WINED3DFORMAT conversion_group;
} GlPixelFormatDesc; } GlPixelFormatDesc;
#define USE_GL_FUNC(type, pfn) type pfn; #define USE_GL_FUNC(type, pfn) type pfn;