wined3d: Store GLSL programs in a hash table rather than a linked list.
This commit is contained in:
parent
2a82ed89b1
commit
2c85e5e8a3
|
@ -32,7 +32,6 @@
|
|||
#include "wined3d_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
|
||||
#define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
|
||||
|
||||
/* Define the default light parameters as specified by MSDN */
|
||||
|
@ -99,6 +98,7 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_
|
|||
object->parent = parent; \
|
||||
object->ref = 1; \
|
||||
object->baseShader.device = (IWineD3DDevice*) This; \
|
||||
list_init(&object->baseShader.linked_programs); \
|
||||
*pp##type = (IWineD3D##type *) object; \
|
||||
}
|
||||
|
||||
|
@ -148,76 +148,6 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_
|
|||
**********************************************************/
|
||||
const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
|
||||
|
||||
/**********************************************************
|
||||
* GLSL helper functions follow
|
||||
**********************************************************/
|
||||
|
||||
/** Detach the GLSL pixel or vertex shader object from the shader program */
|
||||
static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
|
||||
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
|
||||
if (shaderObj != 0 && programId != 0) {
|
||||
TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
|
||||
GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
|
||||
checkGLcall("glDetachObjectARB");
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete a GLSL shader program */
|
||||
static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
|
||||
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
|
||||
if (obj != 0) {
|
||||
TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
|
||||
GL_EXTCALL(glDeleteObjectARB(obj));
|
||||
checkGLcall("glDeleteObjectARB");
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete the list of linked programs this shader is associated with.
|
||||
* Also at this point, check to see if there are any objects left attached
|
||||
* to each GLSL program. If not, delete the GLSL program object.
|
||||
* This will be run when a device is released. */
|
||||
static void delete_glsl_shader_list(IWineD3DDevice* iface) {
|
||||
|
||||
struct list *ptr = NULL;
|
||||
struct glsl_shader_prog_link *curLink = NULL;
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
|
||||
int numAttached = 0;
|
||||
int i;
|
||||
GLhandleARB objList[2]; /* There should never be more than 2 objects attached
|
||||
(one pixel shader and one vertex shader at most) */
|
||||
|
||||
ptr = list_head( &This->glsl_shader_progs );
|
||||
while (ptr) {
|
||||
/* First, get the current item,
|
||||
* save the link to the next pointer,
|
||||
* detach and delete shader objects,
|
||||
* then de-allocate the list item's memory */
|
||||
curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
|
||||
ptr = list_next( &This->glsl_shader_progs, ptr );
|
||||
|
||||
/* See if this object is still attached to the program - it may have been detached already */
|
||||
GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
|
||||
TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
|
||||
for (i = 0; i < numAttached; i++) {
|
||||
detach_glsl_shader(iface, objList[i], curLink->programId);
|
||||
}
|
||||
|
||||
delete_glsl_shader_program(iface, curLink->programId);
|
||||
|
||||
/* Free the uniform locations */
|
||||
HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
|
||||
HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
|
||||
|
||||
/* Free the memory for this list item */
|
||||
HeapFree(GetProcessHeap(), 0, curLink);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* IUnknown parts follows
|
||||
**********************************************************/
|
||||
|
@ -261,15 +191,12 @@ static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
|
|||
|
||||
HeapFree(GetProcessHeap(), 0, This->draw_buffers);
|
||||
|
||||
if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
|
||||
|
||||
/* TODO: Clean up all the surfaces and textures! */
|
||||
/* NOTE: You must release the parent if the object was created via a callback
|
||||
** ***************************/
|
||||
|
||||
/* Delete any GLSL shader programs that may exist */
|
||||
if (This->vs_selected_mode == SHADER_GLSL ||
|
||||
This->ps_selected_mode == SHADER_GLSL)
|
||||
delete_glsl_shader_list(iface);
|
||||
|
||||
/* Release the update stateblock */
|
||||
if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
|
||||
if(This->updateStateBlock != This->stateBlock)
|
||||
|
@ -1764,9 +1691,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR
|
|||
IWineD3DImpl_CheckGraphicsMemory();
|
||||
#endif
|
||||
|
||||
/* Initialize our list of GLSL programs */
|
||||
list_init(&This->glsl_shader_progs);
|
||||
|
||||
{ /* Set a default viewport */
|
||||
WINED3DVIEWPORT vp;
|
||||
vp.X = 0;
|
||||
|
|
|
@ -2386,6 +2386,26 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
|
|||
return WINED3D_OK;
|
||||
}
|
||||
|
||||
static unsigned int glsl_program_key_hash(void *key) {
|
||||
glsl_program_key_t *k = (glsl_program_key_t *)key;
|
||||
|
||||
unsigned int hash = k->vshader | k->pshader << 16;
|
||||
hash += ~(hash << 15);
|
||||
hash ^= (hash >> 10);
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 6);
|
||||
hash += ~(hash << 11);
|
||||
hash ^= (hash >> 16);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static BOOL glsl_program_key_compare(void *keya, void *keyb) {
|
||||
glsl_program_key_t *ka = (glsl_program_key_t *)keya;
|
||||
glsl_program_key_t *kb = (glsl_program_key_t *)keyb;
|
||||
|
||||
return ka->vshader == kb->vshader && ka->pshader == kb->pshader;
|
||||
}
|
||||
|
||||
/* Note due to structure differences between dx8 and dx9 D3DPRESENT_PARAMETERS,
|
||||
and fields being inserted in the middle, a new structure is used in place */
|
||||
|
@ -2456,6 +2476,7 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter,
|
|||
select_shader_mode(&This->gl_info, DeviceType, &object->ps_selected_mode, &object->vs_selected_mode);
|
||||
if (object->ps_selected_mode == SHADER_GLSL || object->vs_selected_mode == SHADER_GLSL) {
|
||||
object->shader_backend = &glsl_shader_backend;
|
||||
object->glsl_program_lookup = hash_table_create(&glsl_program_key_hash, &glsl_program_key_compare);
|
||||
} else if (object->ps_selected_mode == SHADER_ARB || object->vs_selected_mode == SHADER_ARB) {
|
||||
object->shader_backend = &arb_program_shader_backend;
|
||||
} else {
|
||||
|
|
|
@ -1994,16 +1994,42 @@ void vshader_glsl_output_unpack(
|
|||
}
|
||||
}
|
||||
|
||||
/** Attach a GLSL pixel or vertex shader object to the shader program */
|
||||
static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
|
||||
static void add_glsl_program_entry(IWineD3DDeviceImpl *device, struct glsl_shader_prog_link *entry) {
|
||||
glsl_program_key_t *key;
|
||||
|
||||
key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));
|
||||
key->vshader = entry->vshader;
|
||||
key->pshader = entry->pshader;
|
||||
|
||||
hash_table_put(device->glsl_program_lookup, key, entry);
|
||||
}
|
||||
|
||||
static struct glsl_shader_prog_link *get_glsl_program_entry(IWineD3DDeviceImpl *device,
|
||||
GLhandleARB vshader, GLhandleARB pshader) {
|
||||
glsl_program_key_t key;
|
||||
|
||||
key.vshader = vshader;
|
||||
key.pshader = pshader;
|
||||
|
||||
return (struct glsl_shader_prog_link *)hash_table_get(device->glsl_program_lookup, &key);
|
||||
}
|
||||
|
||||
void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_link *entry) {
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
|
||||
GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
|
||||
if (This->stateBlock->glsl_program && shaderObj != 0) {
|
||||
TRACE("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
|
||||
GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
|
||||
checkGLcall("glAttachObjectARB");
|
||||
}
|
||||
glsl_program_key_t *key;
|
||||
|
||||
key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));
|
||||
key->vshader = entry->vshader;
|
||||
key->pshader = entry->pshader;
|
||||
hash_table_remove(This->glsl_program_lookup, key);
|
||||
|
||||
GL_EXTCALL(glDeleteObjectARB(entry->programId));
|
||||
if (entry->vshader) list_remove(&entry->vshader_entry);
|
||||
if (entry->pshader) list_remove(&entry->pshader_entry);
|
||||
HeapFree(GetProcessHeap(), 0, entry->vuniformF_locations);
|
||||
HeapFree(GetProcessHeap(), 0, entry->puniformF_locations);
|
||||
HeapFree(GetProcessHeap(), 0, entry);
|
||||
}
|
||||
|
||||
/** Sets the GLSL program ID for the given pixel and vertex shader combination.
|
||||
|
@ -2011,61 +2037,50 @@ static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader
|
|||
* inside of the DrawPrimitive() part of the render loop).
|
||||
*
|
||||
* If a program for the given combination does not exist, create one, and store
|
||||
* the program in the list. If it creates a program, it will link the given
|
||||
* objects, too.
|
||||
*
|
||||
* We keep the shader programs around on a list because linking
|
||||
* shader objects together is an expensive operation. It's much
|
||||
* faster to loop through a list of pre-compiled & linked programs
|
||||
* each time that the application sets a new pixel or vertex shader
|
||||
* than it is to re-link them together at that time.
|
||||
*
|
||||
* The list will be deleted in IWineD3DDevice::Release().
|
||||
* the program in the hash table. If it creates a program, it will link the
|
||||
* given objects, too.
|
||||
*/
|
||||
static void set_glsl_shader_program(IWineD3DDevice *iface) {
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
|
||||
IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
|
||||
IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
|
||||
struct glsl_shader_prog_link *curLink = NULL;
|
||||
struct glsl_shader_prog_link *newLink = NULL;
|
||||
struct list *ptr = NULL;
|
||||
struct glsl_shader_prog_link *entry = NULL;
|
||||
GLhandleARB programId = 0;
|
||||
int i;
|
||||
char glsl_name[8];
|
||||
|
||||
ptr = list_head( &This->glsl_shader_progs );
|
||||
while (ptr) {
|
||||
/* At least one program exists - see if it matches our ps/vs combination */
|
||||
curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
|
||||
if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
|
||||
/* Existing Program found, use it */
|
||||
TRACE("Found existing program (%u) for this vertex/pixel shader combination\n",
|
||||
curLink->programId);
|
||||
This->stateBlock->glsl_program = curLink;
|
||||
GLhandleARB vshader_id = (vshader && This->vs_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0;
|
||||
GLhandleARB pshader_id = (pshader && This->ps_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0;
|
||||
entry = get_glsl_program_entry(This, vshader_id, pshader_id);
|
||||
if (entry) {
|
||||
This->stateBlock->glsl_program = entry;
|
||||
return;
|
||||
}
|
||||
/* This isn't the entry we need - try the next one */
|
||||
ptr = list_next( &This->glsl_shader_progs, ptr );
|
||||
}
|
||||
|
||||
/* If we get to this point, then no matching program exists, so we create one */
|
||||
programId = GL_EXTCALL(glCreateProgramObjectARB());
|
||||
TRACE("Created new GLSL shader program %u\n", programId);
|
||||
|
||||
/* Allocate a new link for the list of programs */
|
||||
newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
|
||||
newLink->programId = programId;
|
||||
This->stateBlock->glsl_program = newLink;
|
||||
/* Create the entry */
|
||||
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
|
||||
entry->programId = programId;
|
||||
entry->vshader = vshader_id;
|
||||
entry->pshader = pshader_id;
|
||||
/* Add the hash table entry */
|
||||
add_glsl_program_entry(This, entry);
|
||||
|
||||
/* Set the current program */
|
||||
This->stateBlock->glsl_program = entry;
|
||||
|
||||
/* Attach GLSL vshader */
|
||||
if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
|
||||
int i;
|
||||
if (vshader_id) {
|
||||
int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
|
||||
char tmp_name[10];
|
||||
|
||||
TRACE("Attaching vertex shader to GLSL program\n");
|
||||
attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
|
||||
TRACE("Attaching GLSL shader object %u to program %u\n", vshader_id, programId);
|
||||
GL_EXTCALL(glAttachObjectARB(programId, vshader_id));
|
||||
checkGLcall("glAttachObjectARB");
|
||||
|
||||
/* Bind vertex attributes to a corresponding index number to match
|
||||
* the same index numbers as ARB_vertex_programs (makes loading
|
||||
|
@ -2081,34 +2096,34 @@ static void set_glsl_shader_program(IWineD3DDevice *iface) {
|
|||
GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
|
||||
}
|
||||
checkGLcall("glBindAttribLocationARB");
|
||||
newLink->vertexShader = vshader;
|
||||
|
||||
list_add_head(&((IWineD3DBaseShaderImpl *)vshader)->baseShader.linked_programs, &entry->vshader_entry);
|
||||
}
|
||||
|
||||
/* Attach GLSL pshader */
|
||||
if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
|
||||
TRACE("Attaching pixel shader to GLSL program\n");
|
||||
attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
|
||||
newLink->pixelShader = pshader;
|
||||
if (pshader_id) {
|
||||
TRACE("Attaching GLSL shader object %u to program %u\n", pshader_id, programId);
|
||||
GL_EXTCALL(glAttachObjectARB(programId, pshader_id));
|
||||
checkGLcall("glAttachObjectARB");
|
||||
|
||||
list_add_head(&((IWineD3DBaseShaderImpl *)pshader)->baseShader.linked_programs, &entry->pshader_entry);
|
||||
}
|
||||
|
||||
/* Link the program */
|
||||
TRACE("Linking GLSL shader program %u\n", programId);
|
||||
GL_EXTCALL(glLinkProgramARB(programId));
|
||||
print_glsl_info_log(&GLINFO_LOCATION, programId);
|
||||
list_add_head( &This->glsl_shader_progs, &newLink->entry);
|
||||
|
||||
newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
|
||||
entry->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
|
||||
for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
|
||||
snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
|
||||
newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
|
||||
entry->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
|
||||
}
|
||||
newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
|
||||
entry->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
|
||||
for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
|
||||
snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
|
||||
newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
|
||||
entry->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static GLhandleARB create_glsl_blt_shader(WineD3D_GL_Info *gl_info) {
|
||||
|
|
|
@ -74,7 +74,16 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface)
|
|||
ref = InterlockedDecrement(&This->ref);
|
||||
if (ref == 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 */
|
||||
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");
|
||||
|
|
|
@ -1113,7 +1113,16 @@ static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface
|
|||
ref = InterlockedDecrement(&This->ref);
|
||||
if (ref == 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 */
|
||||
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, vshader_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");
|
||||
|
|
|
@ -628,6 +628,7 @@ struct IWineD3DDeviceImpl
|
|||
int vs_selected_mode;
|
||||
int ps_selected_mode;
|
||||
const shader_backend_t *shader_backend;
|
||||
hash_table_t *glsl_program_lookup;
|
||||
|
||||
/* To store */
|
||||
BOOL view_ident; /* true iff view matrix is identity */
|
||||
|
@ -701,10 +702,6 @@ struct IWineD3DDeviceImpl
|
|||
WINED3DFORMAT ddraw_format;
|
||||
BOOL ddraw_fullscreen;
|
||||
|
||||
/* List of GLSL shader programs and their associated vertex & pixel shaders */
|
||||
struct list glsl_shader_progs;
|
||||
|
||||
|
||||
/* Final position fixup constant */
|
||||
float posFixup[4];
|
||||
|
||||
|
@ -1463,14 +1460,20 @@ typedef void (*SHADER_HANDLER) (struct SHADER_OPCODE_ARG*);
|
|||
* vertex shaders. A list of this type is maintained on the DeviceImpl, and is only
|
||||
* used if the user is using GLSL shaders. */
|
||||
struct glsl_shader_prog_link {
|
||||
struct list entry;
|
||||
struct list vshader_entry;
|
||||
struct list pshader_entry;
|
||||
GLhandleARB programId;
|
||||
GLhandleARB *vuniformF_locations;
|
||||
GLhandleARB *puniformF_locations;
|
||||
IWineD3DVertexShader* vertexShader;
|
||||
IWineD3DPixelShader* pixelShader;
|
||||
GLhandleARB vshader;
|
||||
GLhandleARB pshader;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GLhandleARB vshader;
|
||||
GLhandleARB pshader;
|
||||
} glsl_program_key_t;
|
||||
|
||||
/* TODO: Make this dynamic, based on shader limits ? */
|
||||
#define MAX_REG_ADDR 1
|
||||
#define MAX_REG_TEMP 32
|
||||
|
@ -1600,6 +1603,8 @@ extern const SHADER_OPCODE* shader_get_opcode(
|
|||
extern void shader_delete_constant_list(
|
||||
struct list* clist);
|
||||
|
||||
void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_link *entry);
|
||||
|
||||
/* Vertex shader utility functions */
|
||||
extern BOOL vshader_get_input(
|
||||
IWineD3DVertexShader* iface,
|
||||
|
@ -1727,6 +1732,9 @@ typedef struct IWineD3DBaseShaderClass
|
|||
/* Type of shader backend */
|
||||
int shader_mode;
|
||||
|
||||
/* Programs this shader is linked with */
|
||||
struct list linked_programs;
|
||||
|
||||
/* Immediate constants (override global ones) */
|
||||
struct list constantsB;
|
||||
struct list constantsF;
|
||||
|
|
Loading…
Reference in New Issue