Commit 8dcd5128 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

WineD3D: Put vertex shader duplication infrastructure in place.

parent ad880ba0
...@@ -510,7 +510,7 @@ static void vshader_program_add_param(const SHADER_OPCODE_ARG *arg, const DWORD ...@@ -510,7 +510,7 @@ static void vshader_program_add_param(const SHADER_OPCODE_ARG *arg, const DWORD
break; break;
case WINED3DSPR_INPUT: case WINED3DSPR_INPUT:
if (This->swizzle_map & (1 << reg)) is_color = TRUE; if (This->cur_args->swizzle_map & (1 << reg)) is_color = TRUE;
sprintf(tmpReg, "vertex.attrib[%u]", reg); sprintf(tmpReg, "vertex.attrib[%u]", reg);
strcat(hwLine, tmpReg); strcat(hwLine, tmpReg);
...@@ -1745,14 +1745,15 @@ static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) { ...@@ -1745,14 +1745,15 @@ static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
const WineD3D_GL_Info *gl_info = &This->adapter->gl_info; const WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
if (useVS) { if (useVS) {
TRACE("Using vertex shader\n"); struct vs_compile_args compile_args;
IWineD3DVertexShaderImpl_CompileShader(This->stateBlock->vertexShader);
priv->current_vprogram_id = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->prgId; TRACE("Using vertex shader\n");
find_vs_compile_args((IWineD3DVertexShaderImpl *) This->stateBlock->vertexShader, This->stateBlock, &compile_args);
priv->current_vprogram_id = find_gl_vshader((IWineD3DVertexShaderImpl *) This->stateBlock->vertexShader, &compile_args);
/* Bind the vertex program */ /* Bind the vertex program */
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id)); GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id));
checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);"); checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id);");
/* Enable OpenGL vertex programs */ /* Enable OpenGL vertex programs */
glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_VERTEX_PROGRAM_ARB);
...@@ -1773,7 +1774,7 @@ static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) { ...@@ -1773,7 +1774,7 @@ static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
/* Bind the fragment program */ /* Bind the fragment program */
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id)); GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id));
checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);"); checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id);");
if(!priv->use_arbfp_fixed_func) { if(!priv->use_arbfp_fixed_func) {
/* Enable OpenGL fragment programs */ /* Enable OpenGL fragment programs */
...@@ -1860,14 +1861,19 @@ static void shader_arb_destroy(IWineD3DBaseShader *iface) { ...@@ -1860,14 +1861,19 @@ static void shader_arb_destroy(IWineD3DBaseShader *iface) {
This->shader_array_size = 0; This->shader_array_size = 0;
} else { } else {
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *) iface; IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *) iface;
UINT i;
ENTER_GL(); ENTER_GL();
GL_EXTCALL(glDeleteProgramsARB(1, &This->prgId)); for(i = 0; i < This->num_gl_shaders; i++) {
checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &This->prgId))"); GL_EXTCALL(glDeleteProgramsARB(1, &This->gl_shaders[i].prgId));
((IWineD3DVertexShaderImpl *) This)->prgId = 0; checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &This->gl_shaders[i].prgId))");
}
LEAVE_GL(); LEAVE_GL();
HeapFree(GetProcessHeap(), 0, This->gl_shaders);
This->gl_shaders = NULL;
This->num_gl_shaders = 0;
This->shader_array_size = 0;
} }
baseShader->baseShader.is_compiled = FALSE;
} }
static HRESULT shader_arb_alloc(IWineD3DDevice *iface) { static HRESULT shader_arb_alloc(IWineD3DDevice *iface) {
...@@ -2008,13 +2014,14 @@ static GLuint shader_arb_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUF ...@@ -2008,13 +2014,14 @@ static GLuint shader_arb_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUF
return retval; return retval;
} }
static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) { static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer, const struct vs_compile_args *args) {
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
const shader_reg_maps *reg_maps = &This->baseShader.reg_maps; const shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
CONST DWORD *function = This->baseShader.function; CONST DWORD *function = This->baseShader.function;
IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)This->baseShader.device; IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)This->baseShader.device;
const WineD3D_GL_Info *gl_info = &device->adapter->gl_info; const WineD3D_GL_Info *gl_info = &device->adapter->gl_info;
const local_constant *lconst; const local_constant *lconst;
GLuint ret;
/* Create the hw ARB shader */ /* Create the hw ARB shader */
shader_addline(buffer, "!!ARBvp1.0\n"); shader_addline(buffer, "!!ARBvp1.0\n");
...@@ -2086,12 +2093,12 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF ...@@ -2086,12 +2093,12 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF
shader_addline(buffer, "END\n"); shader_addline(buffer, "END\n");
/* TODO: change to resource.glObjectHandle or something like that */ /* TODO: change to resource.glObjectHandle or something like that */
GL_EXTCALL(glGenProgramsARB(1, &This->prgId)); GL_EXTCALL(glGenProgramsARB(1, &ret));
TRACE("Creating a hw vertex shader, prg=%d\n", This->prgId); TRACE("Creating a hw vertex shader, prg=%d\n", ret);
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->prgId)); GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ret));
TRACE("Created hw vertex shader, prg=%d\n", This->prgId); TRACE("Created hw vertex shader, prg=%d\n", ret);
/* Create the program and check for errors */ /* Create the program and check for errors */
GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
buffer->bsize, buffer->buffer)); buffer->bsize, buffer->buffer));
...@@ -2101,9 +2108,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF ...@@ -2101,9 +2108,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
FIXME("HW VertexShader Error at position %d: %s\n", FIXME("HW VertexShader Error at position %d: %s\n",
errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
This->prgId = -1; ret = -1;
} } else {
/* Load immediate constants */ /* Load immediate constants */
if(!This->baseShader.load_local_constsF) { if(!This->baseShader.load_local_constsF) {
LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
...@@ -2111,6 +2117,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF ...@@ -2111,6 +2117,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, lconst->idx, value)); GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, lconst->idx, value));
} }
} }
}
return ret;
} }
static void shader_arb_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *pCaps) static void shader_arb_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *pCaps)
......
...@@ -1133,8 +1133,9 @@ static GLuint shader_none_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU ...@@ -1133,8 +1133,9 @@ static GLuint shader_none_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU
FIXME("NONE shader backend asked to generate a pixel shader\n"); FIXME("NONE shader backend asked to generate a pixel shader\n");
return 0; return 0;
} }
static void shader_none_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) { static GLuint shader_none_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer, const struct vs_compile_args *args) {
FIXME("NONE shader backend asked to generate a vertex shader\n"); FIXME("NONE shader backend asked to generate a vertex shader\n");
return 0;
} }
#define GLINFO_LOCATION (*gl_info) #define GLINFO_LOCATION (*gl_info)
......
...@@ -101,16 +101,18 @@ struct glsl_shader_prog_link { ...@@ -101,16 +101,18 @@ struct glsl_shader_prog_link {
GLhandleARB luminanceoffset_location[MAX_TEXTURES]; GLhandleARB luminanceoffset_location[MAX_TEXTURES];
GLhandleARB ycorrection_location; GLhandleARB ycorrection_location;
GLenum vertex_color_clamp; GLenum vertex_color_clamp;
GLhandleARB vshader; IWineD3DVertexShader *vshader;
IWineD3DPixelShader *pshader; IWineD3DPixelShader *pshader;
struct vs_compile_args vs_args;
struct ps_compile_args ps_args; struct ps_compile_args ps_args;
UINT constant_version; UINT constant_version;
}; };
typedef struct { typedef struct {
GLhandleARB vshader; IWineD3DVertexShader *vshader;
IWineD3DPixelShader *pshader; IWineD3DPixelShader *pshader;
struct ps_compile_args ps_args; struct ps_compile_args ps_args;
struct vs_compile_args vs_args;
} glsl_program_key_t; } glsl_program_key_t;
...@@ -1030,7 +1032,7 @@ static void shader_glsl_get_register_name(const DWORD param, const DWORD addr_to ...@@ -1030,7 +1032,7 @@ static void shader_glsl_get_register_name(const DWORD param, const DWORD addr_to
strcpy(tmpStr, "gl_SecondaryColor"); strcpy(tmpStr, "gl_SecondaryColor");
} }
} else { } else {
if (((IWineD3DVertexShaderImpl *)This)->swizzle_map & (1 << reg)) *is_color = TRUE; if (((IWineD3DVertexShaderImpl *)This)->cur_args->swizzle_map & (1 << reg)) *is_color = TRUE;
sprintf(tmpStr, "attrib%u", reg); sprintf(tmpStr, "attrib%u", reg);
} }
break; break;
...@@ -2918,17 +2920,20 @@ static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_sh ...@@ -2918,17 +2920,20 @@ static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_sh
key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t)); key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));
key->vshader = entry->vshader; key->vshader = entry->vshader;
key->pshader = entry->pshader; key->pshader = entry->pshader;
key->vs_args = entry->vs_args;
key->ps_args = entry->ps_args; key->ps_args = entry->ps_args;
hash_table_put(priv->glsl_program_lookup, key, entry); hash_table_put(priv->glsl_program_lookup, key, entry);
} }
static struct glsl_shader_prog_link *get_glsl_program_entry(struct shader_glsl_priv *priv, static struct glsl_shader_prog_link *get_glsl_program_entry(struct shader_glsl_priv *priv,
GLhandleARB vshader, IWineD3DPixelShader *pshader, struct ps_compile_args *ps_args) { IWineD3DVertexShader *vshader, IWineD3DPixelShader *pshader, struct vs_compile_args *vs_args,
struct ps_compile_args *ps_args) {
glsl_program_key_t key; glsl_program_key_t key;
key.vshader = vshader; key.vshader = vshader;
key.pshader = pshader; key.pshader = pshader;
key.vs_args = *vs_args;
key.ps_args = *ps_args; key.ps_args = *ps_args;
return hash_table_get(priv->glsl_program_lookup, &key); return hash_table_get(priv->glsl_program_lookup, &key);
...@@ -2942,6 +2947,7 @@ static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const WineD ...@@ -2942,6 +2947,7 @@ static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const WineD
key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t)); key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));
key->vshader = entry->vshader; key->vshader = entry->vshader;
key->pshader = entry->pshader; key->pshader = entry->pshader;
key->vs_args = entry->vs_args;
key->ps_args = entry->ps_args; key->ps_args = entry->ps_args;
hash_table_remove(priv->glsl_program_lookup, key); hash_table_remove(priv->glsl_program_lookup, key);
...@@ -3293,21 +3299,22 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use ...@@ -3293,21 +3299,22 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
int i; int i;
char glsl_name[8]; char glsl_name[8];
GLhandleARB vshader_id, pshader_id; GLhandleARB vshader_id, pshader_id;
struct ps_compile_args compile_args; struct ps_compile_args ps_compile_args;
struct vs_compile_args vs_compile_args;
if(use_vs) { if(use_vs) {
IWineD3DVertexShaderImpl_CompileShader(vshader); find_vs_compile_args((IWineD3DVertexShaderImpl*)This->stateBlock->vertexShader, This->stateBlock, &vs_compile_args);
vshader_id = ((IWineD3DVertexShaderImpl*)vshader)->prgId;
} else { } else {
vshader_id = 0; /* FIXME: Do we really have to spend CPU cycles to generate a few zeroed bytes? */
memset(&vs_compile_args, 0, sizeof(vs_compile_args));
} }
if(use_ps) { if(use_ps) {
find_ps_compile_args((IWineD3DPixelShaderImpl*)This->stateBlock->pixelShader, This->stateBlock, &compile_args); find_ps_compile_args((IWineD3DPixelShaderImpl*)This->stateBlock->pixelShader, This->stateBlock, &ps_compile_args);
} else { } else {
/* FIXME: Do we really have to spend CPU cycles to generate a few zeroed bytes? */ /* FIXME: Do we really have to spend CPU cycles to generate a few zeroed bytes? */
memset(&compile_args, 0, sizeof(compile_args)); memset(&ps_compile_args, 0, sizeof(ps_compile_args));
} }
entry = get_glsl_program_entry(priv, vshader_id, pshader, &compile_args); entry = get_glsl_program_entry(priv, vshader, pshader, &vs_compile_args, &ps_compile_args);
if (entry) { if (entry) {
priv->glsl_program = entry; priv->glsl_program = entry;
return; return;
...@@ -3320,9 +3327,10 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use ...@@ -3320,9 +3327,10 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
/* Create the entry */ /* Create the entry */
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link)); entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
entry->programId = programId; entry->programId = programId;
entry->vshader = vshader_id; entry->vshader = vshader;
entry->pshader = pshader; entry->pshader = pshader;
entry->ps_args = compile_args; entry->vs_args = vs_compile_args;
entry->ps_args = ps_compile_args;
entry->constant_version = 0; entry->constant_version = 0;
/* Add the hash table entry */ /* Add the hash table entry */
add_glsl_program_entry(priv, entry); add_glsl_program_entry(priv, entry);
...@@ -3330,6 +3338,12 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use ...@@ -3330,6 +3338,12 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
/* Set the current program */ /* Set the current program */
priv->glsl_program = entry; priv->glsl_program = entry;
if(use_vs) {
vshader_id = find_gl_vshader((IWineD3DVertexShaderImpl *) vshader, &vs_compile_args);
} else {
vshader_id = 0;
}
/* Attach GLSL vshader */ /* Attach GLSL vshader */
if (vshader_id) { if (vshader_id) {
int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */ int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
...@@ -3369,7 +3383,7 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use ...@@ -3369,7 +3383,7 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
} }
if(use_ps) { if(use_ps) {
pshader_id = find_gl_pshader((IWineD3DPixelShaderImpl *) pshader, &compile_args); pshader_id = find_gl_pshader((IWineD3DPixelShaderImpl *) pshader, &ps_compile_args);
} else { } else {
pshader_id = 0; pshader_id = 0;
} }
...@@ -3619,7 +3633,7 @@ static void shader_glsl_destroy(IWineD3DBaseShader *iface) { ...@@ -3619,7 +3633,7 @@ static void shader_glsl_destroy(IWineD3DBaseShader *iface) {
if(ps->num_gl_shaders == 0) return; if(ps->num_gl_shaders == 0) return;
} else { } else {
vs = (IWineD3DVertexShaderImpl *) This; vs = (IWineD3DVertexShaderImpl *) This;
if(vs->prgId == 0) return; if(vs->num_gl_shaders == 0) return;
} }
linked_programs = &This->baseShader.linked_programs; linked_programs = &This->baseShader.linked_programs;
...@@ -3654,13 +3668,19 @@ static void shader_glsl_destroy(IWineD3DBaseShader *iface) { ...@@ -3654,13 +3668,19 @@ static void shader_glsl_destroy(IWineD3DBaseShader *iface) {
ps->num_gl_shaders = 0; ps->num_gl_shaders = 0;
ps->shader_array_size = 0; ps->shader_array_size = 0;
} else { } else {
TRACE("Deleting shader object %u\n", vs->prgId); UINT i;
ENTER_GL(); ENTER_GL();
GL_EXTCALL(glDeleteObjectARB(vs->prgId)); for(i = 0; i < vs->num_gl_shaders; i++) {
TRACE("deleting vshader %u\n", vs->gl_shaders[i].prgId);
GL_EXTCALL(glDeleteObjectARB(vs->gl_shaders[i].prgId));
checkGLcall("glDeleteObjectARB"); checkGLcall("glDeleteObjectARB");
}
LEAVE_GL(); LEAVE_GL();
vs->prgId = 0; HeapFree(GetProcessHeap(), 0, vs->gl_shaders);
vs->baseShader.is_compiled = FALSE; vs->gl_shaders = NULL;
vs->num_gl_shaders = 0;
vs->shader_array_size = 0;
} }
} }
...@@ -3668,7 +3688,7 @@ static unsigned int glsl_program_key_hash(const void *key) ...@@ -3668,7 +3688,7 @@ static unsigned int glsl_program_key_hash(const void *key)
{ {
const glsl_program_key_t *k = key; const glsl_program_key_t *k = key;
unsigned int hash = k->vshader | ((DWORD_PTR) k->pshader) << 16; unsigned int hash = ((DWORD_PTR) k->vshader) | ((DWORD_PTR) k->pshader) << 16;
hash += ~(hash << 15); hash += ~(hash << 15);
hash ^= (hash >> 10); hash ^= (hash >> 10);
hash += (hash << 3); hash += (hash << 3);
...@@ -3685,7 +3705,8 @@ static BOOL glsl_program_key_compare(const void *keya, const void *keyb) ...@@ -3685,7 +3705,8 @@ static BOOL glsl_program_key_compare(const void *keya, const void *keyb)
const glsl_program_key_t *kb = keyb; const glsl_program_key_t *kb = keyb;
return ka->vshader == kb->vshader && ka->pshader == kb->pshader && return ka->vshader == kb->vshader && ka->pshader == kb->pshader &&
(memcmp(&ka->ps_args, &kb->ps_args, sizeof(kb->ps_args)) == 0); (memcmp(&ka->ps_args, &kb->ps_args, sizeof(kb->ps_args)) == 0) &&
(memcmp(&ka->vs_args, &kb->vs_args, sizeof(kb->vs_args)) == 0);
} }
static BOOL constant_heap_init(struct constant_heap *heap, unsigned int constant_count) static BOOL constant_heap_init(struct constant_heap *heap, unsigned int constant_count)
...@@ -3870,7 +3891,7 @@ static GLuint shader_glsl_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU ...@@ -3870,7 +3891,7 @@ static GLuint shader_glsl_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU
return shader_obj; return shader_obj;
} }
static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) { static GLuint shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer, const struct vs_compile_args *args) {
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
const struct shader_reg_maps *reg_maps = &This->baseShader.reg_maps; const struct shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
CONST DWORD *function = This->baseShader.function; CONST DWORD *function = This->baseShader.function;
...@@ -3920,8 +3941,7 @@ static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUF ...@@ -3920,8 +3941,7 @@ static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUF
GL_EXTCALL(glCompileShaderARB(shader_obj)); GL_EXTCALL(glCompileShaderARB(shader_obj));
print_glsl_info_log(&GLINFO_LOCATION, shader_obj); print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
/* Store the shader object */ return shader_obj;
This->prgId = shader_obj;
} }
static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *pCaps) static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *pCaps)
......
...@@ -216,21 +216,6 @@ BOOL vshader_get_input( ...@@ -216,21 +216,6 @@ BOOL vshader_get_input(
return FALSE; return FALSE;
} }
/** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
or GLSL and send it to the card */
static void IWineD3DVertexShaderImpl_GenerateShader(IWineD3DVertexShader *iface,
const struct shader_reg_maps* reg_maps, const DWORD *pFunction)
{
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
SHADER_BUFFER buffer;
This->swizzle_map = ((IWineD3DDeviceImpl *)This->baseShader.device)->strided_streams.swizzle_map;
shader_buffer_init(&buffer);
((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
shader_buffer_free(&buffer);
}
/* ******************************************* /* *******************************************
IWineD3DVertexShader IUnknown parts follow IWineD3DVertexShader IUnknown parts follow
******************************************* */ ******************************************* */
...@@ -416,40 +401,20 @@ static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertex ...@@ -416,40 +401,20 @@ static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertex
return WINED3D_OK; return WINED3D_OK;
} }
HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) { static GLuint vertexshader_compile(IWineD3DVertexShaderImpl *This, const struct vs_compile_args *args) {
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
CONST DWORD *function = This->baseShader.function;
IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device; IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
SHADER_BUFFER buffer;
TRACE("(%p) : function %p\n", iface, function); GLuint ret;
/* We're already compiled. */
if (This->baseShader.is_compiled) {
if ((This->swizzle_map & deviceImpl->strided_streams.use_map) != deviceImpl->strided_streams.swizzle_map)
{
WARN("Recompiling vertex shader %p due to D3DCOLOR input changes\n", This);
goto recompile;
}
return WINED3D_OK;
recompile:
if(This->recompile_count < 50) {
This->recompile_count++;
} else {
FIXME("Vertexshader %p recompiled more than 50 times\n", This);
}
deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader *) iface);
}
/* Generate the HW shader */ /* Generate the HW shader */
TRACE("(%p) : Generating hardware program\n", This); TRACE("(%p) : Generating hardware program\n", This);
IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function); shader_buffer_init(&buffer);
This->cur_args = args;
This->baseShader.is_compiled = TRUE; ret = deviceImpl->shader_backend->shader_generate_vshader((IWineD3DVertexShader *)This, &buffer, args);
This->cur_args = NULL;
shader_buffer_free(&buffer);
return WINED3D_OK; return ret;
} }
const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl = const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
...@@ -468,3 +433,56 @@ const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl = ...@@ -468,3 +433,56 @@ const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
IWineD3DVertexShaderImpl_FakeSemantics, IWineD3DVertexShaderImpl_FakeSemantics,
IWIneD3DVertexShaderImpl_SetLocalConstantsF IWIneD3DVertexShaderImpl_SetLocalConstantsF
}; };
void find_vs_compile_args(IWineD3DVertexShaderImpl *shader, IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args) {
args->fog_src = stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE ? VS_FOG_COORD : VS_FOG_Z;
args->swizzle_map = ((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.swizzle_map;
}
static inline BOOL vs_args_equal(const struct vs_compile_args *stored, const struct vs_compile_args *new,
const DWORD use_map) {
if((stored->swizzle_map & use_map) != new->swizzle_map) return FALSE;
return stored->fog_src == new->fog_src;
}
GLuint find_gl_vshader(IWineD3DVertexShaderImpl *shader, const struct vs_compile_args *args)
{
UINT i;
DWORD new_size = shader->shader_array_size;
struct vs_compiled_shader *new_array;
DWORD use_map = ((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.use_map;
/* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2),
* so a linear search is more performant than a hashmap or a binary search
* (cache coherency etc)
*/
for(i = 0; i < shader->num_gl_shaders; i++) {
if(vs_args_equal(&shader->gl_shaders[i].args, args, use_map)) {
return shader->gl_shaders[i].prgId;
}
}
TRACE("No matching GL shader found, compiling a new shader\n");
if(shader->shader_array_size == shader->num_gl_shaders) {
if(shader->gl_shaders) {
new_size = shader->shader_array_size + max(1, shader->shader_array_size / 2);
new_array = HeapReAlloc(GetProcessHeap(), 0, shader->gl_shaders,
new_size * sizeof(*shader->gl_shaders));
} else {
new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*shader->gl_shaders));
new_size = 1;
}
if(!new_array) {
ERR("Out of memory\n");
return 0;
}
shader->gl_shaders = new_array;
shader->shader_array_size = new_size;
}
shader->gl_shaders[shader->num_gl_shaders].args = *args;
shader->gl_shaders[shader->num_gl_shaders].prgId = vertexshader_compile(shader, args);
return shader->gl_shaders[shader->num_gl_shaders++].prgId;
}
...@@ -459,6 +459,18 @@ struct ps_compile_args { ...@@ -459,6 +459,18 @@ struct ps_compile_args {
/* Texture types(2D, Cube, 3D) in ps 1.x */ /* Texture types(2D, Cube, 3D) in ps 1.x */
}; };
#define MAX_ATTRIBS 16
enum fog_src_type {
VS_FOG_Z = 0,
VS_FOG_COORD = 1
};
struct vs_compile_args {
WORD fog_src;
WORD swizzle_map; /* MAX_ATTRIBS, 16 */
};
typedef struct { typedef struct {
const SHADER_HANDLER *shader_instruction_handler_table; const SHADER_HANDLER *shader_instruction_handler_table;
void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS); void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS);
...@@ -473,7 +485,7 @@ typedef struct { ...@@ -473,7 +485,7 @@ typedef struct {
void (*shader_free_private)(IWineD3DDevice *iface); void (*shader_free_private)(IWineD3DDevice *iface);
BOOL (*shader_dirtifyable_constants)(IWineD3DDevice *iface); BOOL (*shader_dirtifyable_constants)(IWineD3DDevice *iface);
GLuint (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer, const struct ps_compile_args *args); GLuint (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer, const struct ps_compile_args *args);
void (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer); GLuint (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer, const struct vs_compile_args *args);
void (*shader_get_caps)(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *caps); void (*shader_get_caps)(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *caps);
BOOL (*shader_color_fixup_supported)(struct color_fixup_desc fixup); BOOL (*shader_color_fixup_supported)(struct color_fixup_desc fixup);
} shader_backend_t; } shader_backend_t;
...@@ -2207,7 +2219,6 @@ typedef struct IWineD3DBaseShaderClass ...@@ -2207,7 +2219,6 @@ typedef struct IWineD3DBaseShaderClass
CONST SHADER_OPCODE *shader_ins; CONST SHADER_OPCODE *shader_ins;
DWORD *function; DWORD *function;
UINT functionLength; UINT functionLength;
BOOL is_compiled;
UINT cur_loop_depth, cur_loop_regno; UINT cur_loop_depth, cur_loop_regno;
BOOL load_local_constsF; BOOL load_local_constsF;
BOOL uses_bool_consts, uses_int_consts; BOOL uses_bool_consts, uses_int_consts;
...@@ -2323,8 +2334,14 @@ static inline BOOL shader_constant_is_local(IWineD3DBaseShaderImpl* This, DWORD ...@@ -2323,8 +2334,14 @@ static inline BOOL shader_constant_is_local(IWineD3DBaseShaderImpl* This, DWORD
} }
/***************************************************************************** /*****************************************************************************
* IDirect3DVertexShader implementation structure * IDirect3DVertexShader implementation structures
*/ */
struct vs_compiled_shader {
struct vs_compile_args args;
GLuint prgId;
};
typedef struct IWineD3DVertexShaderImpl { typedef struct IWineD3DVertexShaderImpl {
/* IUnknown parts*/ /* IUnknown parts*/
const IWineD3DVertexShaderVtbl *lpVtbl; const IWineD3DVertexShaderVtbl *lpVtbl;
...@@ -2338,22 +2355,25 @@ typedef struct IWineD3DVertexShaderImpl { ...@@ -2338,22 +2355,25 @@ typedef struct IWineD3DVertexShaderImpl {
DWORD usage; DWORD usage;
/* The GL shader */ /* The GL shader */
GLuint prgId; struct vs_compiled_shader *gl_shaders;
UINT num_gl_shaders, shader_array_size;
/* Vertex shader input and output semantics */ /* Vertex shader input and output semantics */
semantic semantics_in [MAX_ATTRIBS]; semantic semantics_in [MAX_ATTRIBS];
semantic semantics_out [MAX_REG_OUTPUT]; semantic semantics_out [MAX_REG_OUTPUT];
WORD swizzle_map; /* MAX_ATTRIBS, 16 */
UINT min_rel_offset, max_rel_offset; UINT min_rel_offset, max_rel_offset;
UINT rel_offset; UINT rel_offset;
UINT recompile_count; UINT recompile_count;
const struct vs_compile_args *cur_args;
} IWineD3DVertexShaderImpl; } IWineD3DVertexShaderImpl;
extern const SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[]; extern const SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[];
extern const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl; extern const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl;
HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface);
void find_vs_compile_args(IWineD3DVertexShaderImpl *shader, IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args);
GLuint find_gl_vshader(IWineD3DVertexShaderImpl *shader, const struct vs_compile_args *args);
/***************************************************************************** /*****************************************************************************
* IDirect3DPixelShader implementation structure * IDirect3DPixelShader implementation structure
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment