wined3d: Rework shader mode selection.

- currently half the shader selection code (GLSL vs ARB) is in
fillGLcaps. The parts that check for software shaders are in
GetDeviceCaps. That placement, will work, but is definitely not optimal.
FillGLcaps should detect support - it should not make decision as to
what's used, because that's not what the purpose of the function is.
GetDeviceCaps should report support as it has already been selected.
Instead, select shader mode in its own function, called in the
appropriate places.

- unifying pixel and vertex shaders into a single selection is a
mistake. A software vertex shader can be coupled with a hardware arb or
glsl pixel shader, or no shader at all. Split them back into two and add
a SHADER_NONE variant.

- drawprim is doing support checks for ARB_PROGRAM, and making shader
decisions based on that - that's wrong, support has already been
checked, and decided upon, and shaders can be implemented via software,
ARB_PROGRAm or GLSL, so that support check isn't valid.

- Store the shader selected mode into the shader itself. Different types
of shaders can be combined, so this is an improvement. In fact, storing
the mode into the settings globally is a mistake as well - it should be
done per device, since different cards have different capabilities.
This commit is contained in:
Ivan Gyurdiev 2006-07-04 01:21:53 -06:00 committed by Alexandre Julliard
parent 010f5729dd
commit 771623692e
7 changed files with 108 additions and 69 deletions

View File

@ -747,9 +747,14 @@ void shader_generate_main(
/* Read opcode */
opcode_token = *pToken++;
curOpcode = shader_get_opcode(iface, opcode_token);
hw_fct = (curOpcode == NULL)? NULL:
(wined3d_settings.shader_mode == SHADER_GLSL)?
curOpcode->hw_glsl_fct : curOpcode->hw_fct;
/* Select handler */
if (curOpcode == NULL)
hw_fct = NULL;
else if (This->baseShader.shader_mode == SHADER_GLSL)
hw_fct = curOpcode->hw_glsl_fct;
else if (This->baseShader.shader_mode == SHADER_ARB)
hw_fct = curOpcode->hw_fct;
/* Unknown opcode and its parameters */
if (NULL == curOpcode) {
@ -802,7 +807,7 @@ void shader_generate_main(
hw_fct(&hw_arg);
/* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
if (wined3d_settings.shader_mode == SHADER_GLSL)
if (This->baseShader.shader_mode == SHADER_GLSL)
shader_glsl_add_instruction_modifiers(&hw_arg);
/* Unhandled opcode */

View File

@ -567,9 +567,9 @@ static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
** ***************************/
/* Delete any GLSL shader programs that may exist */
if (wined3d_settings.shader_mode == SHADER_GLSL) {
if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
wined3d_settings.ps_selected_mode == SHADER_GLSL)
delete_glsl_shader_list(iface);
}
/* Release the update stateblock */
if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){

View File

@ -199,6 +199,43 @@ static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) {
return ref;
}
/* Set the shader type for this device, depending on the given capabilities,
* the device type, and the user preferences in wined3d_settings */
static void select_shader_mode(
WineD3D_GL_Info *gl_info,
WINED3DDEVTYPE DeviceType,
int* ps_selected,
int* vs_selected) {
/* Give priority to user disable/emulation request.
* Then respect REF device for software.
* Then check capabilities for hardware, and fallback to software */
if (wined3d_settings.vs_mode == VS_NONE)
*vs_selected = SHADER_NONE;
else if (DeviceType == WINED3DDEVTYPE_REF || wined3d_settings.vs_mode == VS_SW)
*vs_selected = SHADER_SW;
else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested)
*vs_selected = SHADER_GLSL;
else if (gl_info->supported[ARB_VERTEX_PROGRAM])
*vs_selected = SHADER_ARB;
else
*vs_selected = SHADER_SW;
/* Fallback to SHADER_NONE where software pixel shaders should be used */
if (wined3d_settings.ps_mode == PS_NONE)
*ps_selected = SHADER_NONE;
else if (DeviceType == WINED3DDEVTYPE_REF)
*ps_selected = SHADER_NONE;
else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested)
*ps_selected = SHADER_GLSL;
else if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
*ps_selected = SHADER_ARB;
else
*ps_selected = SHADER_NONE;
}
/**********************************************************
* IWineD3D parts follows
**********************************************************/
@ -752,17 +789,6 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info, Display* display) {
GLX_EXT_FUNCS_GEN;
#undef USE_GL_FUNC
/* Determine shader mode to use based on GL caps */
if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested
&& (wined3d_settings.vs_mode == VS_HW || wined3d_settings.ps_mode == PS_HW))
wined3d_settings.shader_mode = SHADER_GLSL;
else if ((gl_info->supported[ARB_VERTEX_PROGRAM] && wined3d_settings.vs_mode == VS_HW) ||
(gl_info->supported[ARB_FRAGMENT_PROGRAM] && wined3d_settings.ps_mode == PS_HW))
wined3d_settings.shader_mode = SHADER_ARB;
else
wined3d_settings.shader_mode = SHADER_SW;
/* If we created a dummy context, throw it away */
if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx);
@ -1467,6 +1493,8 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
return WINED3DERR_INVALIDCALL;
}
/* FIXME: both the gl_info and the shader_mode should be made per adapter */
/* If we don't know the device settings, go query them now */
if (This->isGLInfoValid == FALSE) {
/* use the desktop window to fill gl caps */
@ -1474,8 +1502,9 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
/* We are running off a real context, save the values */
if (rc) This->isGLInfoValid = TRUE;
}
select_shader_mode(&This->gl_info, DeviceType,
&wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
/* ------------------------------------------------
The following fields apply to both d3d8 and d3d9
@ -1718,19 +1747,16 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
*pCaps->MaxStreams = MAX_STREAMS;
*pCaps->MaxStreamStride = 1024;
if (wined3d_settings.vs_mode == VS_HW && wined3d_settings.shader_mode == SHADER_GLSL
&& DeviceType != WINED3DDEVTYPE_REF) {
/* FIXME: the shader mode should be per adapter */
if (wined3d_settings.vs_selected_mode == SHADER_GLSL) {
*pCaps->VertexShaderVersion = D3DVS_VERSION(3,0);
TRACE_(d3d_caps)("Hardware vertex shader versions 2.0+ enabled\n");
} else if (wined3d_settings.vs_mode == VS_HW
&& wined3d_settings.shader_mode == SHADER_ARB
&& DeviceType != WINED3DDEVTYPE_REF) {
TRACE_(d3d_caps)("Hardware vertex shader version 3.0 enabled (GLSL)\n");
} else if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
*pCaps->VertexShaderVersion = D3DVS_VERSION(1,1);
TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled\n");
} else if (wined3d_settings.vs_mode == VS_SW || DeviceType == WINED3DDEVTYPE_REF) {
/* FIXME: Change the following line (when needed) to reflect the reported software vertex shader version implemented */
*pCaps->VertexShaderVersion = D3DVS_VERSION(1,1);
TRACE_(d3d_caps)("Software vertex shader version 1.1 enabled\n");
TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n");
} else if (wined3d_settings.vs_selected_mode == SHADER_SW) {
*pCaps->VertexShaderVersion = D3DVS_VERSION(3,0);
TRACE_(d3d_caps)("Software vertex shader version 3.0 enabled\n");
} else {
*pCaps->VertexShaderVersion = 0;
TRACE_(d3d_caps)("Vertex shader functionality not available\n");
@ -1742,23 +1768,21 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
*pCaps->MaxVertexShaderConst = WINED3D_VSHADER_MAX_CONSTANTS;
}
if (wined3d_settings.ps_mode == PS_HW && wined3d_settings.shader_mode == SHADER_GLSL
&& DeviceType != WINED3DDEVTYPE_REF) {
/* FIXME: the shader ode should be per adapter */
if (wined3d_settings.ps_selected_mode == SHADER_GLSL) {
*pCaps->PixelShaderVersion = D3DPS_VERSION(3,0);
/* FIXME: The following line is card dependent. -1.0 to 1.0 is a safe default clamp range for now */
*pCaps->PixelShader1xMaxValue = 1.0;
TRACE_(d3d_caps)("Hardware pixel shader versions 2.0+ enabled\n");
} else if (wined3d_settings.ps_mode == PS_HW
&& wined3d_settings.shader_mode == SHADER_ARB
&& DeviceType != WINED3DDEVTYPE_REF) {
TRACE_(d3d_caps)("Hardware pixel shader version 3.0 enabled (GLSL)\n");
} else if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
*pCaps->PixelShaderVersion = D3DPS_VERSION(1,4);
*pCaps->PixelShader1xMaxValue = 1.0;
TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled\n");
/* FIXME: Uncomment this when there is support for software Pixel Shader 1.4 and PS_SW is defined
} else if (wined3d_settings.ps_mode == PS_SW || DeviceType == WINED3DDEVTYPE_REF) {
*pCaps->PixelShaderVersion = D3DPS_VERSION(1,4);
TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n");
/* FIXME: Uncomment this when there is support for software Pixel Shader 3.0 and PS_SW is defined
} else if (wined3d_settings.ps_selected_mode = SHADER_SW) {
*pCaps->PixelShaderVersion = D3DPS_VERSION(3,0);
*pCaps->PixelShader1xMaxValue = 1.0;
TRACE_(d3d_caps)("Software pixel shader version 1.4 enabled\n"); */
TRACE_(d3d_caps)("Software pixel shader version 3.0 enabled\n"); */
} else {
*pCaps->PixelShaderVersion = 0;
*pCaps->PixelShader1xMaxValue = 0.0;
@ -1865,8 +1889,11 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter,
/* Setup some defaults for creating the implicit swapchain */
ENTER_GL();
/* FIXME: both of those should be made per adapter */
IWineD3DImpl_FillGLCaps(&This->gl_info, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
LEAVE_GL();
select_shader_mode(&This->gl_info, DeviceType,
&wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
/* set the state of the device to valid */
object->state = WINED3D_OK;

View File

@ -1962,7 +1962,9 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx
TRACE("Loaded arrays\n");
/* Bind the correct GLSL shader program based on the currently set vertex & pixel shaders. */
if (wined3d_settings.shader_mode == SHADER_GLSL) {
if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
wined3d_settings.ps_selected_mode == SHADER_GLSL) {
set_glsl_shader_program(iface);
/* Start using this program ID (if it's 0, there is no shader program to use, so
* glUseProgramObjectARB(0) will disable the use of any shaders) */
@ -1977,7 +1979,7 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx
TRACE("Using vertex shader\n");
if (wined3d_settings.shader_mode == SHADER_ARB) {
if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
/* Bind the vertex program */
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
@ -1995,7 +1997,7 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx
TRACE("Using pixel shader\n");
if (wined3d_settings.shader_mode == SHADER_ARB) {
if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
/* Bind the fragment program */
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
@ -2008,12 +2010,12 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx
This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
}
}
/* Load any global constants/uniforms that may have been set by the application */
if (wined3d_settings.shader_mode == SHADER_GLSL)
shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
else if (wined3d_settings.shader_mode == SHADER_ARB)
shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL)
shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB)
shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
/* DirectX colours are in a different format to opengl colours
@ -2046,12 +2048,12 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx
checkGLcall("glDisableVertexAttribArrayARB(reg);");
}
if (wined3d_settings.shader_mode == SHADER_ARB)
if (wined3d_settings.vs_selected_mode == SHADER_ARB)
glDisable(GL_VERTEX_PROGRAM_ARB);
}
/* Cleanup fragment program */
if (usePixelShaderFunction && wined3d_settings.shader_mode == SHADER_ARB) {
if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB) {
glDisable(GL_FRAGMENT_PROGRAM_ARB);
}
}
@ -2278,19 +2280,15 @@ void drawPrimitive(IWineD3DDevice *iface,
int useHW = FALSE, i;
BOOL fixup = FALSE;
if (This->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE
&&((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL
&& GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
/* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
* here simply check whether a shader was set, or the user disabled shaders */
if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
useVertexShaderFunction = TRUE;
} else {
useVertexShaderFunction = FALSE;
}
if (wined3d_settings.ps_mode != PS_NONE && GL_SUPPORT(ARB_FRAGMENT_PROGRAM)
&& This->stateBlock->pixelShader
&& ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) {
if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
usePixelShaderFunction = TRUE;
}
if (This->stateBlock->vertexDecl == NULL) {
/* Work out what the FVF should look like */

View File

@ -73,7 +73,7 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface)
ref = InterlockedDecrement(&This->ref);
if (ref == 0) {
HeapFree(GetProcessHeap(), 0, This);
if (wined3d_settings.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
/* If this shader is still attached to a program, GL will perform a lazy delete */
TRACE("Deleting shader object %u\n", This->baseShader.prgId);
GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId));
@ -829,7 +829,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateShader(
buffer.bsize = 0;
buffer.lineNo = 0;
if (wined3d_settings.shader_mode == SHADER_GLSL) {
if (This->baseShader.shader_mode == SHADER_GLSL) {
/* Create the hw GLSL shader object and assign it as the baseShader.prgId */
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
@ -857,7 +857,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateShader(
/* Store the shader object */
This->baseShader.prgId = shader_obj;
} else if (wined3d_settings.shader_mode == SHADER_ARB) {
} else if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
/* Create the hw ARB shader */
shader_addline(&buffer, "!!ARBfp1.0\n");
@ -913,7 +913,8 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
pshader_set_limits(This);
/* Generate HW shader in needed */
if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW) {
This->baseShader.shader_mode = wined3d_settings.ps_selected_mode;
if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW) {
TRACE("(%p) : Generating hardware program\n", This);
IWineD3DPixelShaderImpl_GenerateShader(iface, pFunction);
}

View File

@ -644,7 +644,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateShader(
buffer.bsize = 0;
buffer.lineNo = 0;
if (wined3d_settings.shader_mode == SHADER_GLSL) {
if (This->baseShader.shader_mode == SHADER_GLSL) {
/* Create the hw GLSL shader program and assign it as the baseShader.prgId */
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
@ -669,7 +669,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* Store the shader object */
This->baseShader.prgId = shader_obj;
} else if (wined3d_settings.shader_mode == SHADER_ARB) {
} else if (This->baseShader.shader_mode == SHADER_ARB) {
/* Create the hw ARB shader */
shader_addline(&buffer, "!!ARBvp1.0\n");
@ -990,7 +990,7 @@ static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface
ref = InterlockedDecrement(&This->ref);
if (ref == 0) {
if (This->vertexDeclaration) IWineD3DVertexDeclaration_Release(This->vertexDeclaration);
if (wined3d_settings.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
/* If this shader is still attached to a program, GL will perform a lazy delete */
TRACE("Deleting shader object %u\n", This->baseShader.prgId);
GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId));
@ -1055,7 +1055,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
vshader_set_limits(This);
/* Generate HW shader in needed */
if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW)
This->baseShader.shader_mode = wined3d_settings.vs_selected_mode;
if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW)
IWineD3DVertexShaderImpl_GenerateShader(iface, pFunction);
/* copy the function ... because it will certainly be released by application */
@ -1065,6 +1066,7 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
} else {
This->baseShader.function = NULL;
}
return WINED3D_OK;
}

View File

@ -136,6 +136,7 @@ WINED3DGLTYPE static const glTypeLookup[D3DDECLTYPE_UNUSED] = {
#define SHADER_SW 0
#define SHADER_ARB 1
#define SHADER_GLSL 2
#define SHADER_NONE 3
typedef struct wined3d_settings_s {
/* vertex and pixel shader modes */
@ -146,7 +147,8 @@ typedef struct wined3d_settings_s {
we should use it. However, until it's fully implemented, we'll leave it as a registry
setting for developers. */
BOOL glslRequested;
int shader_mode;
int vs_selected_mode;
int ps_selected_mode;
/* nonpower 2 function */
int nonpower2_mode;
} wined3d_settings_t;
@ -1460,6 +1462,10 @@ typedef struct IWineD3DBaseShaderClass
CONST DWORD *function;
UINT functionLength;
GLuint prgId;
/* Type of shader backend */
int shader_mode;
} IWineD3DBaseShaderClass;
typedef struct IWineD3DBaseShaderImpl {