2003-11-14 04:50:35 +01:00
/*
* shaders implementation
*
* Copyright 2002 - 2003 Jason Edmeades
2005-08-17 11:54:54 +02:00
* Copyright 2002 - 2003 Raphael Junqueira
2006-07-17 20:35:14 +02:00
* Copyright 2004 Christian Costa
2005-08-17 11:54:54 +02:00
* Copyright 2005 Oliver Stieber
2006-05-17 08:04:30 +02:00
* Copyright 2006 Ivan Gyurdiev
2003-11-14 04:50:35 +01:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
2006-05-18 14:49:52 +02:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2003-11-14 04:50:35 +01:00
*/
# include "config.h"
# include <math.h>
2005-08-17 13:34:03 +02:00
# include <stdio.h>
2003-11-14 04:50:35 +01:00
# include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL ( d3d_shader ) ;
2007-06-09 14:27:41 +02:00
# define GLINFO_LOCATION ((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info
2005-08-17 13:34:03 +02:00
2003-11-14 04:50:35 +01:00
/* Shader debugging - Change the following line to enable debugging of software
vertex shaders */
#if 0 /* Musxt not be 1 in cvs version */
# define VSTRACE(A) TRACE A
# define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
2005-07-13 16:15:54 +02:00
# else
# define VSTRACE(A)
2003-11-14 04:50:35 +01:00
# define TRACE_VSVECTOR(name)
# endif
/**
* DirectX9 SDK download
* http : //msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp
*
* Exploring D3DX
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx07162002.asp
*
* Using Vertex Shaders
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx02192001.asp
*
* Dx9 New
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/whatsnew.asp
*
* Dx9 Shaders
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/VertexShader2_0.asp
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/Instructions/Instructions.asp
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexDeclaration/VertexDeclaration.asp
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader3_0/VertexShader3_0.asp
*
* Dx9 D3DX
* http : //msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/VertexPipe/matrixstack/matrixstack.asp
*
* FVF
* http : //msdn.microsoft.com/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexFormats/vformats.asp
*
* NVIDIA : DX8 Vertex Shader to NV Vertex Program
* http : //developer.nvidia.com/view.asp?IO=vstovp
*
* NVIDIA : Memory Management with VAR
2005-07-13 16:15:54 +02:00
* http : //developer.nvidia.com/view.asp?IO=var_memory_management
2003-11-14 04:50:35 +01:00
*/
2005-08-17 13:34:03 +02:00
/* TODO: Vertex and Pixel shaders are almost identicle, the only exception being the way that some of the data is looked up or the availablity of some of the data i.e. some instructions are only valid for pshaders and some for vshaders
because of this the bulk of the software pipeline can be shared between pixel and vertex shaders . . . and it wouldn ' t supprise me if the programes can be cross compiled using a large body body shared code */
# define GLNAME_REQUIRE_GLSL ((const char *)1)
2006-03-28 21:10:44 +02:00
CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins [ ] = {
2006-10-30 20:27:01 +01:00
/* This table is not order or position dependent. */
2007-03-06 22:35:23 +01:00
/* Arithmetic */
{ WINED3DSIO_NOP , " nop " , " NOP " , 0 , 0 , vshader_hw_map2gl , NULL , 0 , 0 } ,
{ WINED3DSIO_MOV , " mov " , " MOV " , 1 , 2 , vshader_hw_map2gl , shader_glsl_mov , 0 , 0 } ,
{ WINED3DSIO_MOVA , " mova " , NULL , 1 , 2 , vshader_hw_map2gl , shader_glsl_mov , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_ADD , " add " , " ADD " , 1 , 3 , vshader_hw_map2gl , shader_glsl_arith , 0 , 0 } ,
{ WINED3DSIO_SUB , " sub " , " SUB " , 1 , 3 , vshader_hw_map2gl , shader_glsl_arith , 0 , 0 } ,
{ WINED3DSIO_MAD , " mad " , " MAD " , 1 , 4 , vshader_hw_map2gl , shader_glsl_mad , 0 , 0 } ,
{ WINED3DSIO_MUL , " mul " , " MUL " , 1 , 3 , vshader_hw_map2gl , shader_glsl_arith , 0 , 0 } ,
{ WINED3DSIO_RCP , " rcp " , " RCP " , 1 , 2 , vshader_hw_rsq_rcp , shader_glsl_rcp , 0 , 0 } ,
2007-07-02 22:40:06 +02:00
{ WINED3DSIO_RSQ , " rsq " , " RSQ " , 1 , 2 , vshader_hw_rsq_rcp , shader_glsl_rsq , 0 , 0 } ,
2007-03-06 22:35:23 +01:00
{ WINED3DSIO_DP3 , " dp3 " , " DP3 " , 1 , 3 , vshader_hw_map2gl , shader_glsl_dot , 0 , 0 } ,
{ WINED3DSIO_DP4 , " dp4 " , " DP4 " , 1 , 3 , vshader_hw_map2gl , shader_glsl_dot , 0 , 0 } ,
{ WINED3DSIO_MIN , " min " , " MIN " , 1 , 3 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_MAX , " max " , " MAX " , 1 , 3 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_SLT , " slt " , " SLT " , 1 , 3 , vshader_hw_map2gl , shader_glsl_compare , 0 , 0 } ,
{ WINED3DSIO_SGE , " sge " , " SGE " , 1 , 3 , vshader_hw_map2gl , shader_glsl_compare , 0 , 0 } ,
{ WINED3DSIO_ABS , " abs " , " ABS " , 1 , 2 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_EXP , " exp " , " EX2 " , 1 , 2 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_LOG , " log " , " LG2 " , 1 , 2 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_EXPP , " expp " , " EXP " , 1 , 2 , vshader_hw_map2gl , shader_glsl_expp , 0 , 0 } ,
{ WINED3DSIO_LOGP , " logp " , " LOG " , 1 , 2 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
{ WINED3DSIO_LIT , " lit " , " LIT " , 1 , 2 , vshader_hw_map2gl , shader_glsl_lit , 0 , 0 } ,
{ WINED3DSIO_DST , " dst " , " DST " , 1 , 3 , vshader_hw_map2gl , shader_glsl_dst , 0 , 0 } ,
{ WINED3DSIO_LRP , " lrp " , " LRP " , 1 , 4 , NULL , shader_glsl_lrp , 0 , 0 } ,
{ WINED3DSIO_FRC , " frc " , " FRC " , 1 , 2 , vshader_hw_map2gl , shader_glsl_map2gl , 0 , 0 } ,
2007-09-05 16:27:10 +02:00
{ WINED3DSIO_POW , " pow " , " POW " , 1 , 3 , vshader_hw_map2gl , shader_glsl_pow , 0 , 0 } ,
{ WINED3DSIO_CRS , " crs " , " XPD " , 1 , 3 , vshader_hw_map2gl , shader_glsl_cross , 0 , 0 } ,
2006-05-10 00:05:26 +02:00
/* TODO: sng can possibly be performed a s
2005-08-17 13:34:03 +02:00
RCP tmp , vec
MUL out , tmp , vec */
2007-03-06 22:35:23 +01:00
{ WINED3DSIO_SGN , " sgn " , NULL , 1 , 2 , NULL , shader_glsl_map2gl , 0 , 0 } ,
2007-09-05 20:09:06 +02:00
{ WINED3DSIO_NRM , " nrm " , NULL , 1 , 2 , shader_hw_nrm , shader_glsl_map2gl , 0 , 0 } ,
2007-09-26 22:09:59 +02:00
{ WINED3DSIO_SINCOS , " sincos " , NULL , 1 , 4 , shader_hw_sincos , shader_glsl_sincos , WINED3DVS_VERSION ( 2 , 0 ) , WINED3DVS_VERSION ( 2 , 1 ) } ,
{ WINED3DSIO_SINCOS , " sincos " , " SCS " , 1 , 2 , shader_hw_sincos , shader_glsl_sincos , WINED3DVS_VERSION ( 3 , 0 ) , - 1 } ,
2006-05-10 00:05:26 +02:00
/* Matrix */
2007-09-05 20:01:53 +02:00
{ WINED3DSIO_M4x4 , " m4x4 " , " undefined " , 1 , 3 , shader_hw_mnxn , shader_glsl_mnxn , 0 , 0 } ,
{ WINED3DSIO_M4x3 , " m4x3 " , " undefined " , 1 , 3 , shader_hw_mnxn , shader_glsl_mnxn , 0 , 0 } ,
{ WINED3DSIO_M3x4 , " m3x4 " , " undefined " , 1 , 3 , shader_hw_mnxn , shader_glsl_mnxn , 0 , 0 } ,
{ WINED3DSIO_M3x3 , " m3x3 " , " undefined " , 1 , 3 , shader_hw_mnxn , shader_glsl_mnxn , 0 , 0 } ,
{ WINED3DSIO_M3x2 , " m3x2 " , " undefined " , 1 , 3 , shader_hw_mnxn , shader_glsl_mnxn , 0 , 0 } ,
2006-05-10 00:05:26 +02:00
/* Declare registers */
2007-03-06 22:35:23 +01:00
{ WINED3DSIO_DCL , " dcl " , NULL , 0 , 2 , NULL , NULL , 0 , 0 } ,
2006-05-10 00:05:26 +02:00
/* Constant definitions */
2007-03-06 22:35:23 +01:00
{ WINED3DSIO_DEF , " def " , NULL , 1 , 5 , NULL , NULL , 0 , 0 } ,
{ WINED3DSIO_DEFB , " defb " , GLNAME_REQUIRE_GLSL , 1 , 2 , NULL , NULL , 0 , 0 } ,
{ WINED3DSIO_DEFI , " defi " , GLNAME_REQUIRE_GLSL , 1 , 5 , NULL , NULL , 0 , 0 } ,
2006-04-16 11:25:15 +02:00
/* Flow control - requires GLSL or software shaders */
2007-03-06 22:35:23 +01:00
{ WINED3DSIO_REP , " rep " , NULL , 0 , 1 , NULL , shader_glsl_rep , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_ENDREP , " endrep " , NULL , 0 , 0 , NULL , shader_glsl_end , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_IF , " if " , NULL , 0 , 1 , NULL , shader_glsl_if , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_IFC , " ifc " , NULL , 0 , 2 , NULL , shader_glsl_ifc , WINED3DVS_VERSION ( 2 , 1 ) , - 1 } ,
{ WINED3DSIO_ELSE , " else " , NULL , 0 , 0 , NULL , shader_glsl_else , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_ENDIF , " endif " , NULL , 0 , 0 , NULL , shader_glsl_end , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_BREAK , " break " , NULL , 0 , 0 , NULL , shader_glsl_break , WINED3DVS_VERSION ( 2 , 1 ) , - 1 } ,
{ WINED3DSIO_BREAKC , " breakc " , NULL , 0 , 2 , NULL , shader_glsl_breakc , WINED3DVS_VERSION ( 2 , 1 ) , - 1 } ,
{ WINED3DSIO_BREAKP , " breakp " , GLNAME_REQUIRE_GLSL , 0 , 1 , NULL , NULL , 0 , 0 } ,
{ WINED3DSIO_CALL , " call " , NULL , 0 , 1 , NULL , shader_glsl_call , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_CALLNZ , " callnz " , NULL , 0 , 2 , NULL , shader_glsl_callnz , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_LOOP , " loop " , NULL , 0 , 2 , NULL , shader_glsl_loop , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_RET , " ret " , NULL , 0 , 0 , NULL , NULL , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_ENDLOOP , " endloop " , NULL , 0 , 0 , NULL , shader_glsl_end , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_LABEL , " label " , NULL , 0 , 1 , NULL , shader_glsl_label , WINED3DVS_VERSION ( 2 , 0 ) , - 1 } ,
{ WINED3DSIO_SETP , " setp " , GLNAME_REQUIRE_GLSL , 1 , 3 , NULL , NULL , 0 , 0 } ,
2007-06-27 23:46:53 +02:00
{ WINED3DSIO_TEXLDL , " texldl " , NULL , 1 , 3 , NULL , shader_glsl_texldl , WINED3DVS_VERSION ( 3 , 0 ) , - 1 } ,
2007-03-06 22:35:23 +01:00
{ 0 , NULL , NULL , 0 , 0 , NULL , NULL , 0 , 0 }
2003-11-14 04:50:35 +01:00
} ;
2006-06-12 08:54:30 +02:00
static void vshader_set_limits (
IWineD3DVertexShaderImpl * This ) {
2006-05-08 23:09:21 +02:00
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . texcoord = 0 ;
2006-05-26 17:52:33 +02:00
This - > baseShader . limits . attributes = 16 ;
2006-06-12 08:57:07 +02:00
This - > baseShader . limits . packed_input = 0 ;
2006-05-08 23:09:21 +02:00
/* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
2006-07-19 06:06:07 +02:00
This - > baseShader . limits . constant_float = GL_LIMITS ( vshader_constantsF ) ;
2006-05-08 23:09:21 +02:00
2006-06-12 08:54:30 +02:00
switch ( This - > baseShader . hex_version ) {
2006-10-13 05:36:41 +02:00
case WINED3DVS_VERSION ( 1 , 0 ) :
case WINED3DVS_VERSION ( 1 , 1 ) :
2006-06-12 08:54:30 +02:00
This - > baseShader . limits . temporary = 12 ;
2006-05-08 23:09:21 +02:00
This - > baseShader . limits . constant_bool = 0 ;
This - > baseShader . limits . constant_int = 0 ;
This - > baseShader . limits . address = 1 ;
2006-06-12 08:57:07 +02:00
This - > baseShader . limits . packed_output = 0 ;
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . sampler = 0 ;
2006-07-10 12:35:15 +02:00
This - > baseShader . limits . label = 0 ;
2006-05-08 23:09:21 +02:00
break ;
2006-10-13 05:36:41 +02:00
case WINED3DVS_VERSION ( 2 , 0 ) :
case WINED3DVS_VERSION ( 2 , 1 ) :
2006-06-12 08:54:30 +02:00
This - > baseShader . limits . temporary = 12 ;
2006-05-08 23:09:21 +02:00
This - > baseShader . limits . constant_bool = 16 ;
This - > baseShader . limits . constant_int = 16 ;
This - > baseShader . limits . address = 1 ;
2006-06-12 08:57:07 +02:00
This - > baseShader . limits . packed_output = 0 ;
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . sampler = 0 ;
2006-07-10 12:35:15 +02:00
This - > baseShader . limits . label = 16 ;
2006-05-08 23:09:21 +02:00
break ;
2006-10-13 05:36:41 +02:00
case WINED3DVS_VERSION ( 3 , 0 ) :
2006-06-12 08:54:30 +02:00
This - > baseShader . limits . temporary = 32 ;
2006-05-08 23:09:21 +02:00
This - > baseShader . limits . constant_bool = 32 ;
This - > baseShader . limits . constant_int = 32 ;
This - > baseShader . limits . address = 1 ;
2006-06-12 08:57:07 +02:00
This - > baseShader . limits . packed_output = 12 ;
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . sampler = 4 ;
2006-07-10 12:35:15 +02:00
This - > baseShader . limits . label = 16 ; /* FIXME: 2048 */
2006-05-08 23:09:21 +02:00
break ;
default : This - > baseShader . limits . temporary = 12 ;
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . constant_bool = 16 ;
This - > baseShader . limits . constant_int = 16 ;
2006-05-08 23:09:21 +02:00
This - > baseShader . limits . address = 1 ;
2006-06-12 08:57:07 +02:00
This - > baseShader . limits . packed_output = 0 ;
2006-06-12 08:59:16 +02:00
This - > baseShader . limits . sampler = 0 ;
2006-07-10 12:35:15 +02:00
This - > baseShader . limits . label = 16 ;
2006-10-01 05:20:10 +02:00
FIXME ( " Unrecognized vertex shader version %#x \n " ,
2006-06-12 08:54:30 +02:00
This - > baseShader . hex_version ) ;
2006-05-08 23:09:21 +02:00
}
}
2006-07-07 08:28:30 +02:00
/* This is an internal function,
* used to create fake semantics for shaders
* that don ' t have them - d3d8 shaders where the declaration
* stores the register for each input
*/
static void vshader_set_input (
IWineD3DVertexShaderImpl * This ,
unsigned int regnum ,
BYTE usage , BYTE usage_idx ) {
/* Fake usage: set reserved bit, usage, usage_idx */
DWORD usage_token = ( 0x1 < < 31 ) |
2006-10-10 01:46:35 +02:00
( usage < < WINED3DSP_DCL_USAGE_SHIFT ) | ( usage_idx < < WINED3DSP_DCL_USAGEINDEX_SHIFT ) ;
2006-07-07 08:28:30 +02:00
/* Fake register; set reserved bit, regnum, type: input, wmask: all */
DWORD reg_token = ( 0x1 < < 31 ) |
2006-10-10 01:48:12 +02:00
WINED3DSP_WRITEMASK_ALL | ( WINED3DSPR_INPUT < < WINED3DSP_REGTYPE_SHIFT ) | regnum ;
2006-07-07 08:28:30 +02:00
This - > semantics_in [ regnum ] . usage = usage_token ;
This - > semantics_in [ regnum ] . reg = reg_token ;
}
2007-02-27 20:51:18 +01:00
static BOOL match_usage ( BYTE usage1 , BYTE usage_idx1 , BYTE usage2 , BYTE usage_idx2 ) {
if ( usage_idx1 ! = usage_idx2 ) return FALSE ;
if ( usage1 = = usage2 ) return TRUE ;
if ( usage1 = = WINED3DDECLUSAGE_POSITION & & usage2 = = WINED3DDECLUSAGE_POSITIONT ) return TRUE ;
if ( usage2 = = WINED3DDECLUSAGE_POSITION & & usage1 = = WINED3DDECLUSAGE_POSITIONT ) return TRUE ;
return FALSE ;
}
2006-07-07 08:27:38 +02:00
BOOL vshader_get_input (
IWineD3DVertexShader * iface ,
BYTE usage_req , BYTE usage_idx_req ,
unsigned int * regnum ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
int i ;
for ( i = 0 ; i < MAX_ATTRIBS ; i + + ) {
DWORD usage_token = This - > semantics_in [ i ] . usage ;
2006-10-10 01:46:35 +02:00
DWORD usage = ( usage_token & WINED3DSP_DCL_USAGE_MASK ) > > WINED3DSP_DCL_USAGE_SHIFT ;
DWORD usage_idx = ( usage_token & WINED3DSP_DCL_USAGEINDEX_MASK ) > > WINED3DSP_DCL_USAGEINDEX_SHIFT ;
2006-07-07 08:27:38 +02:00
2007-02-27 20:51:18 +01:00
if ( usage_token & & match_usage ( usage , usage_idx , usage_req , usage_idx_req ) ) {
2006-07-07 08:27:38 +02:00
* regnum = i ;
return TRUE ;
}
}
return FALSE ;
}
BOOL vshader_input_is_color (
IWineD3DVertexShader * iface ,
unsigned int regnum ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2006-09-27 13:14:46 +02:00
IWineD3DDeviceImpl * deviceImpl = ( IWineD3DDeviceImpl * ) This - > baseShader . device ;
2007-02-13 23:12:29 +01:00
IWineD3DVertexDeclarationImpl * vertexDeclaration = ( IWineD3DVertexDeclarationImpl * ) deviceImpl - > stateBlock - > vertexDecl ;
2006-09-27 13:14:46 +02:00
2006-07-07 08:27:38 +02:00
DWORD usage_token = This - > semantics_in [ regnum ] . usage ;
2006-10-10 01:46:35 +02:00
DWORD usage = ( usage_token & WINED3DSP_DCL_USAGE_MASK ) > > WINED3DSP_DCL_USAGE_SHIFT ;
DWORD usage_idx = ( usage_token & WINED3DSP_DCL_USAGEINDEX_MASK ) > > WINED3DSP_DCL_USAGEINDEX_SHIFT ;
2006-08-05 18:15:42 +02:00
if ( vertexDeclaration ) {
int i ;
/* Find the declaration element that matches our register, then check
* if it has D3DCOLOR as it ' s type . This works for both d3d8 and d3d9 . */
for ( i = 0 ; i < vertexDeclaration - > declarationWNumElements - 1 ; + + i ) {
WINED3DVERTEXELEMENT * element = vertexDeclaration - > pDeclarationWine + i ;
2007-02-27 20:51:18 +01:00
if ( match_usage ( element - > Usage , element - > UsageIndex , usage , usage_idx ) ) {
2006-08-05 18:15:42 +02:00
return element - > Type = = WINED3DDECLTYPE_D3DCOLOR ;
}
}
}
ERR ( " Either no vertexdeclaration present, or register not matched. This should never happen. \n " ) ;
return FALSE ;
2006-07-07 08:27:38 +02:00
}
2006-05-10 04:33:24 +02:00
/** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
or GLSL and send it to the card */
2006-07-04 10:01:46 +02:00
static VOID IWineD3DVertexShaderImpl_GenerateShader (
2006-05-10 04:33:24 +02:00
IWineD3DVertexShader * iface ,
2006-07-04 10:01:46 +02:00
shader_reg_maps * reg_maps ,
2006-05-10 04:33:24 +02:00
CONST DWORD * pFunction ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
SHADER_BUFFER buffer ;
#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur . . . */
if ( This - > device - > fixupVertexBufferSize < SHADER_PGMSIZE ) {
HeapFree ( GetProcessHeap ( ) , 0 , This - > fixupVertexBuffer ) ;
This - > fixupVertexBuffer = HeapAlloc ( GetProcessHeap ( ) , 0 , SHADER_PGMSIZE ) ;
This - > fixupVertexBufferSize = PGMSIZE ;
This - > fixupVertexBuffer [ 0 ] = 0 ;
}
buffer . buffer = This - > device - > fixupVertexBuffer ;
# else
buffer . buffer = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , SHADER_PGMSIZE ) ;
# endif
buffer . bsize = 0 ;
buffer . lineNo = 0 ;
2007-01-15 19:30:41 +01:00
buffer . newline = TRUE ;
2006-05-10 04:33:24 +02:00
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.
2006-07-04 09:21:53 +02:00
if ( This - > baseShader . shader_mode = = SHADER_GLSL ) {
2006-05-26 17:52:33 +02:00
/* Create the hw GLSL shader program and assign it as the baseShader.prgId */
GLhandleARB shader_obj = GL_EXTCALL ( glCreateShaderObjectARB ( GL_VERTEX_SHADER_ARB ) ) ;
2006-06-12 08:55:30 +02:00
/* Base Declarations */
2006-07-19 06:06:07 +02:00
shader_generate_glsl_declarations ( ( IWineD3DBaseShader * ) This , reg_maps , & buffer , & GLINFO_LOCATION ) ;
2006-06-12 08:55:30 +02:00
2006-06-12 08:53:32 +02:00
/* Base Shader Body */
2006-07-04 10:01:46 +02:00
shader_generate_main ( ( IWineD3DBaseShader * ) This , & buffer , reg_maps , pFunction ) ;
2006-05-26 17:52:33 +02:00
2006-06-12 08:57:07 +02:00
/* Unpack 3.0 outputs */
2006-10-13 05:36:41 +02:00
if ( This - > baseShader . hex_version > = WINED3DVS_VERSION ( 3 , 0 ) )
2006-07-04 10:01:46 +02:00
vshader_glsl_output_unpack ( & buffer , This - > semantics_out ) ;
2006-06-12 08:57:07 +02:00
2007-03-22 17:34:57 +01:00
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
2007-04-20 21:49:21 +02:00
if ( ! reg_maps - > fog )
2007-03-22 17:34:57 +01:00
shader_addline ( & buffer , " gl_FogFragCoord = gl_Position.z; \n " ) ;
2006-07-27 04:13:32 +02:00
/* Write the final position.
2006-08-28 23:46:00 +02:00
*
* OpenGL coordinates specify the center of the pixel while d3d coords specify
2006-09-23 19:09:06 +02:00
* the corner . The offsets are stored in z and w in the 2 nd row of the projection
* matrix to avoid wasting a free shader constant . Add them to the w and z coord
* of the 2 nd row
2006-08-28 23:46:00 +02:00
*/
2006-09-23 19:09:06 +02:00
shader_addline ( & buffer , " gl_Position.x = gl_Position.x + posFixup[2]; \n " ) ;
shader_addline ( & buffer , " gl_Position.y = gl_Position.y + posFixup[3]; \n " ) ;
2006-08-28 23:46:00 +02:00
/* Account for any inverted textures (render to texture case) by reversing the y coordinate
* ( this is handled in drawPrim ( ) when it sets the MODELVIEW and PROJECTION matrices )
*/
2006-09-23 19:09:06 +02:00
shader_addline ( & buffer , " gl_Position.y = gl_Position.y * posFixup[1]; \n " ) ;
2007-08-31 20:32:52 +02:00
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
*
* Basically we want ( in homogenous coordinates ) z = z * 2 - 1. However , shaders are run
* before the homogenous divide , so we have to take the w into account : z = ( ( z / w ) * 2 - 1 ) * w ,
* which is the same as z = z / 2 - w .
*/
shader_addline ( & buffer , " gl_Position.z = gl_Position.z * 2.0 - gl_Position.w; \n " ) ;
2006-07-17 07:41:53 +02:00
2006-10-15 17:06:44 +02:00
shader_addline ( & buffer , " } \n " ) ;
2006-05-26 17:52:33 +02:00
TRACE ( " Compiling shader object %u \n " , shader_obj ) ;
GL_EXTCALL ( glShaderSourceARB ( shader_obj , 1 , ( const char * * ) & buffer . buffer , NULL ) ) ;
GL_EXTCALL ( glCompileShaderARB ( shader_obj ) ) ;
print_glsl_info_log ( & GLINFO_LOCATION , shader_obj ) ;
/* Store the shader object */
This - > baseShader . prgId = shader_obj ;
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.
2006-07-04 09:21:53 +02:00
} else if ( This - > baseShader . shader_mode = = SHADER_ARB ) {
2006-05-26 17:52:33 +02:00
2006-05-10 04:33:24 +02:00
/* Create the hw ARB shader */
shader_addline ( & buffer , " !!ARBvp1.0 \n " ) ;
2007-08-31 20:32:52 +02:00
shader_addline ( & buffer , " PARAM zfixup = { 2.0, -1.0, 0.0, 0.0 }; \n " ) ;
2006-05-10 04:33:24 +02:00
/* Mesa supports only 95 constants */
if ( GL_VEND ( MESA ) | | GL_VEND ( WINE ) )
This - > baseShader . limits . constant_float =
min ( 95 , This - > baseShader . limits . constant_float ) ;
2007-09-05 20:09:06 +02:00
/* Some instructions need a temporary register. Add it if needed, but only if it is really needed */
if ( reg_maps - > usesnrm ) {
shader_addline ( & buffer , " TEMP TMP; \n " ) ;
}
2006-06-12 08:55:30 +02:00
/* Base Declarations */
2006-07-19 06:06:07 +02:00
shader_generate_arb_declarations ( ( IWineD3DBaseShader * ) This , reg_maps , & buffer , & GLINFO_LOCATION ) ;
2006-09-23 19:09:06 +02:00
/* We need a constant to fixup the final position */
shader_addline ( & buffer , " PARAM posFixup = program.env[%d]; \n " , ARB_SHADER_PRIVCONST_POS ) ;
2006-06-12 08:55:30 +02:00
2006-06-12 08:53:32 +02:00
/* Base Shader Body */
2006-07-04 10:01:46 +02:00
shader_generate_main ( ( IWineD3DBaseShader * ) This , & buffer , reg_maps , pFunction ) ;
2006-05-10 04:33:24 +02:00
2007-03-22 17:34:57 +01:00
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
2007-04-20 21:49:21 +02:00
if ( ! reg_maps - > fog )
2007-03-22 17:34:57 +01:00
shader_addline ( & buffer , " MOV result.fogcoord, TMP_OUT.z; \n " ) ;
2006-07-17 07:41:53 +02:00
2006-08-28 23:46:00 +02:00
/* Write the final position.
*
* OpenGL coordinates specify the center of the pixel while d3d coords specify
2006-09-23 19:09:06 +02:00
* the corner . The offsets are stored in the 2 nd row of the projection matrix ,
* the x offset in z and the y offset in w . Add them to the resulting position
2006-08-28 23:46:00 +02:00
*/
2006-09-26 20:31:36 +02:00
shader_addline ( & buffer , " ADD TMP_OUT.x, TMP_OUT.x, posFixup.z; \n " ) ;
shader_addline ( & buffer , " ADD TMP_OUT.y, TMP_OUT.y, posFixup.w; \n " ) ;
2006-08-28 23:46:00 +02:00
/* Account for any inverted textures (render to texture case) by reversing the y coordinate
* ( this is handled in drawPrim ( ) when it sets the MODELVIEW and PROJECTION matrices )
*/
2006-09-26 20:31:36 +02:00
shader_addline ( & buffer , " MUL TMP_OUT.y, TMP_OUT.y, posFixup.y; \n " ) ;
2007-08-31 20:32:52 +02:00
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
* and the glsl equivalent
*/
shader_addline ( & buffer , " MAD TMP_OUT.z, TMP_OUT.z, zfixup.x, -TMP_OUT.w; \n " ) ;
2006-09-26 20:31:36 +02:00
shader_addline ( & buffer , " MOV result.position, TMP_OUT; \n " ) ;
2006-07-27 04:13:32 +02:00
2006-10-15 17:06:44 +02:00
shader_addline ( & buffer , " END \n " ) ;
2006-05-10 04:33:24 +02:00
/* TODO: change to resource.glObjectHandle or something like that */
GL_EXTCALL ( glGenProgramsARB ( 1 , & This - > baseShader . prgId ) ) ;
TRACE ( " Creating a hw vertex shader, prg=%d \n " , This - > baseShader . prgId ) ;
GL_EXTCALL ( glBindProgramARB ( GL_VERTEX_PROGRAM_ARB , This - > baseShader . prgId ) ) ;
TRACE ( " Created hw vertex shader, prg=%d \n " , This - > baseShader . prgId ) ;
/* Create the program and check for errors */
GL_EXTCALL ( glProgramStringARB ( GL_VERTEX_PROGRAM_ARB , GL_PROGRAM_FORMAT_ASCII_ARB ,
buffer . bsize , buffer . buffer ) ) ;
if ( glGetError ( ) = = GL_INVALID_OPERATION ) {
GLint errPos ;
glGetIntegerv ( GL_PROGRAM_ERROR_POSITION_ARB , & errPos ) ;
FIXME ( " HW VertexShader Error at position %d: %s \n " ,
errPos , debugstr_a ( ( const char * ) glGetString ( GL_PROGRAM_ERROR_STRING_ARB ) ) ) ;
This - > baseShader . prgId = - 1 ;
}
}
# if 1 /* if were using the data buffer of device then we don't need to free it */
HeapFree ( GetProcessHeap ( ) , 0 , buffer . buffer ) ;
# endif
}
2005-03-02 13:16:10 +01:00
/* *******************************************
IWineD3DVertexShader IUnknown parts follow
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-06-10 13:15:32 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface ( IWineD3DVertexShader * iface , REFIID riid , LPVOID * ppobj )
2005-03-02 13:16:10 +01:00
{
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2005-08-17 11:54:54 +02:00
TRACE ( " (%p)->(%s,%p) \n " , This , debugstr_guid ( riid ) , ppobj ) ;
if ( IsEqualGUID ( riid , & IID_IUnknown )
2006-02-06 11:32:41 +01:00
| | IsEqualGUID ( riid , & IID_IWineD3DBase )
2006-03-28 21:10:51 +02:00
| | IsEqualGUID ( riid , & IID_IWineD3DBaseShader )
2005-08-17 11:54:54 +02:00
| | IsEqualGUID ( riid , & IID_IWineD3DVertexShader ) ) {
IUnknown_AddRef ( iface ) ;
* ppobj = This ;
2006-04-25 23:59:12 +02:00
return S_OK ;
2005-08-17 11:54:54 +02:00
}
2006-04-25 23:59:12 +02:00
* ppobj = NULL ;
2005-03-02 13:16:10 +01:00
return E_NOINTERFACE ;
}
2006-06-10 13:15:32 +02:00
static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef ( IWineD3DVertexShader * iface ) {
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2006-10-01 05:20:10 +02:00
TRACE ( " (%p) : AddRef increasing from %d \n " , This , This - > ref ) ;
2005-03-02 13:16:10 +01:00
return InterlockedIncrement ( & This - > ref ) ;
}
2006-06-10 13:15:32 +02:00
static ULONG WINAPI IWineD3DVertexShaderImpl_Release ( IWineD3DVertexShader * iface ) {
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
ULONG ref ;
2006-10-01 05:20:10 +02:00
TRACE ( " (%p) : Releasing from %d \n " , This , This - > ref ) ;
2005-03-02 13:16:10 +01:00
ref = InterlockedDecrement ( & This - > ref ) ;
2005-07-13 16:15:54 +02:00
if ( ref = = 0 ) {
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.
2006-07-04 09:21:53 +02:00
if ( This - > baseShader . shader_mode = = SHADER_GLSL & & This - > baseShader . prgId ! = 0 ) {
2007-02-27 20:51:53 +01:00
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 ) ;
}
}
2006-06-09 09:36:16 +02:00
TRACE ( " Deleting shader object %u \n " , This - > baseShader . prgId ) ;
GL_EXTCALL ( glDeleteObjectARB ( This - > baseShader . prgId ) ) ;
checkGLcall ( " glDeleteObjectARB " ) ;
}
2006-07-10 06:51:03 +02:00
shader_delete_constant_list ( & This - > baseShader . constantsF ) ;
shader_delete_constant_list ( & This - > baseShader . constantsB ) ;
shader_delete_constant_list ( & This - > baseShader . constantsI ) ;
HeapFree ( GetProcessHeap ( ) , 0 , This ) ;
2005-03-02 13:16:10 +01:00
}
return ref ;
}
/* *******************************************
IWineD3DVertexShader IWineD3DVertexShader parts follow
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-06-10 13:15:32 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent ( IWineD3DVertexShader * iface , IUnknown * * parent ) {
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2005-08-19 12:05:00 +02:00
2005-12-03 18:10:56 +01:00
* parent = This - > parent ;
2005-03-02 13:16:10 +01:00
IUnknown_AddRef ( * parent ) ;
TRACE ( " (%p) : returning %p \n " , This , * parent ) ;
2006-04-07 12:51:12 +02:00
return WINED3D_OK ;
2005-03-02 13:16:10 +01:00
}
2005-07-13 16:15:54 +02:00
2006-06-10 13:15:32 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice ( IWineD3DVertexShader * iface , IWineD3DDevice * * pDevice ) {
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2006-09-27 13:14:46 +02:00
IWineD3DDevice_AddRef ( This - > baseShader . device ) ;
* pDevice = This - > baseShader . device ;
2005-07-13 16:15:54 +02:00
TRACE ( " (%p) returning %p \n " , This , * pDevice ) ;
2006-04-07 12:51:12 +02:00
return WINED3D_OK ;
2005-03-02 13:16:10 +01:00
}
2006-06-10 13:15:32 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction ( IWineD3DVertexShader * impl , VOID * pData , UINT * pSizeOfData ) {
2005-08-17 11:54:54 +02:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) impl ;
2006-06-09 23:46:38 +02:00
TRACE ( " (%p) : pData(%p), pSizeOfData(%p) \n " , This , pData , pSizeOfData ) ;
2005-03-02 13:16:10 +01:00
2005-08-17 11:54:54 +02:00
if ( NULL = = pData ) {
2006-03-30 19:14:31 +02:00
* pSizeOfData = This - > baseShader . functionLength ;
2006-04-07 12:51:12 +02:00
return WINED3D_OK ;
2005-08-17 11:54:54 +02:00
}
2006-03-30 19:14:31 +02:00
if ( * pSizeOfData < This - > baseShader . functionLength ) {
2007-03-08 01:16:09 +01:00
/* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
* than the required size we should write the required size and
* return D3DERR_MOREDATA . That ' s not actually true . */
return WINED3DERR_INVALIDCALL ;
2005-08-17 11:54:54 +02:00
}
2006-03-30 19:14:31 +02:00
if ( NULL = = This - > baseShader . function ) { /* no function defined */
2005-08-17 11:54:54 +02:00
TRACE ( " (%p) : GetFunction no User Function defined using NULL to %p \n " , This , pData ) ;
( * ( DWORD * * ) pData ) = NULL ;
} else {
2006-03-30 19:14:31 +02:00
if ( This - > baseShader . functionLength = = 0 ) {
2005-07-13 16:15:54 +02:00
2005-08-17 11:54:54 +02:00
}
TRACE ( " (%p) : GetFunction copying to %p \n " , This , pData ) ;
2006-03-30 19:14:31 +02:00
memcpy ( pData , This - > baseShader . function , This - > baseShader . functionLength ) ;
2005-03-02 13:16:10 +01:00
}
2006-04-07 12:51:12 +02:00
return WINED3D_OK ;
2005-03-02 13:16:10 +01:00
}
2006-08-05 18:15:35 +02:00
/* Note that for vertex shaders CompileShader isn't called until the
* shader is first used . The reason for this is that we need the vertex
* declaration the shader will be used with in order to determine if
* the data in a register is of type D3DCOLOR , and needs swizzling . */
2006-06-10 13:15:32 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction ( IWineD3DVertexShader * iface , CONST DWORD * pFunction ) {
2006-06-06 08:40:08 +02:00
2006-06-12 08:54:30 +02:00
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
2006-09-27 13:14:46 +02:00
IWineD3DDeviceImpl * deviceImpl = ( IWineD3DDeviceImpl * ) This - > baseShader . device ;
2006-07-10 06:51:03 +02:00
HRESULT hr ;
2006-08-05 18:15:35 +02:00
shader_reg_maps * reg_maps = & This - > baseShader . reg_maps ;
2006-05-17 08:04:30 +02:00
2006-07-25 00:51:03 +02:00
TRACE ( " (%p) : pFunction %p \n " , iface , pFunction ) ;
2006-07-04 10:01:46 +02:00
/* First pass: trace shader */
2006-06-12 08:54:30 +02:00
shader_trace_init ( ( IWineD3DBaseShader * ) This , pFunction ) ;
vshader_set_limits ( This ) ;
2005-03-02 13:16:10 +01:00
2006-07-10 06:51:03 +02:00
/* Initialize immediate constant lists */
list_init ( & This - > baseShader . constantsF ) ;
list_init ( & This - > baseShader . constantsB ) ;
list_init ( & This - > baseShader . constantsI ) ;
2006-07-04 10:01:46 +02:00
/* Second pass: figure out registers used, semantics, etc.. */
2006-08-05 18:15:35 +02:00
memset ( reg_maps , 0 , sizeof ( shader_reg_maps ) ) ;
hr = shader_get_registers_used ( ( IWineD3DBaseShader * ) This , reg_maps ,
2007-06-07 23:52:43 +02:00
This - > semantics_in , This - > semantics_out , pFunction , NULL ) ;
2006-07-10 06:51:03 +02:00
if ( hr ! = WINED3D_OK ) return hr ;
2006-07-04 10:01:46 +02:00
2006-10-08 05:25:01 +02:00
This - > baseShader . shader_mode = deviceImpl - > vs_selected_mode ;
2005-08-17 13:34:03 +02:00
/* copy the function ... because it will certainly be released by application */
if ( NULL ! = pFunction ) {
2006-11-24 15:15:16 +01:00
void * function ;
function = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , This - > baseShader . functionLength ) ;
if ( ! function ) return E_OUTOFMEMORY ;
memcpy ( function , pFunction , This - > baseShader . functionLength ) ;
This - > baseShader . function = function ;
2005-08-17 13:34:03 +02:00
} else {
2006-03-30 19:14:31 +02:00
This - > baseShader . function = NULL ;
2005-08-17 13:34:03 +02:00
}
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.
2006-07-04 09:21:53 +02:00
2006-04-07 12:51:12 +02:00
return WINED3D_OK ;
2005-08-17 13:34:03 +02:00
}
2005-03-02 13:16:10 +01:00
2007-02-13 23:12:29 +01:00
/* Preload semantics for d3d8 shaders */
static void WINAPI IWineD3DVertexShaderImpl_FakeSemantics ( IWineD3DVertexShader * iface , IWineD3DVertexDeclaration * vertex_declaration ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
IWineD3DVertexDeclarationImpl * vdecl = ( IWineD3DVertexDeclarationImpl * ) vertex_declaration ;
int i ;
for ( i = 0 ; i < vdecl - > declarationWNumElements - 1 ; + + i ) {
WINED3DVERTEXELEMENT * element = vdecl - > pDeclarationWine + i ;
vshader_set_input ( This , element - > Reg , element - > Usage , element - > UsageIndex ) ;
}
}
2007-02-13 23:12:40 +01:00
/* Set local constants for d3d8 shaders */
static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF ( IWineD3DVertexShader * iface ,
UINT start_idx , const float * src_data , UINT count ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
UINT i , end_idx ;
TRACE ( " (%p) : start_idx %u, src_data %p, count %u \n " , This , start_idx , src_data , count ) ;
end_idx = start_idx + count ;
if ( end_idx > GL_LIMITS ( vshader_constantsF ) ) {
WARN ( " end_idx %u > float constants limit %u \n " , end_idx , GL_LIMITS ( vshader_constantsF ) ) ;
end_idx = GL_LIMITS ( vshader_constantsF ) ;
}
for ( i = start_idx ; i < end_idx ; + + i ) {
local_constant * lconst = HeapAlloc ( GetProcessHeap ( ) , 0 , sizeof ( local_constant ) ) ;
if ( ! lconst ) return E_OUTOFMEMORY ;
lconst - > idx = i ;
2007-06-16 11:44:08 +02:00
memcpy ( lconst - > value , src_data + ( i - start_idx ) * 4 /* 4 components */ , 4 * sizeof ( float ) ) ;
2007-02-13 23:12:40 +01:00
list_add_head ( & This - > baseShader . constantsF , & lconst - > entry ) ;
}
2007-02-14 23:30:40 +01:00
return WINED3D_OK ;
2007-02-13 23:12:40 +01:00
}
2006-08-05 18:15:35 +02:00
static HRESULT WINAPI IWineD3DVertexShaderImpl_CompileShader ( IWineD3DVertexShader * iface ) {
IWineD3DVertexShaderImpl * This = ( IWineD3DVertexShaderImpl * ) iface ;
CONST DWORD * function = This - > baseShader . function ;
TRACE ( " (%p) : function %p \n " , iface , function ) ;
/* We're already compiled. */
if ( This - > baseShader . is_compiled ) return WINED3D_OK ;
/* We don't need to compile */
2007-03-06 22:35:23 +01:00
if ( ! function ) {
2006-08-05 18:15:35 +02:00
This - > baseShader . is_compiled = TRUE ;
return WINED3D_OK ;
}
/* Generate the HW shader */
TRACE ( " (%p) : Generating hardware program \n " , This ) ;
IWineD3DVertexShaderImpl_GenerateShader ( iface , & This - > baseShader . reg_maps , function ) ;
This - > baseShader . is_compiled = TRUE ;
return WINED3D_OK ;
}
2005-06-06 21:50:35 +02:00
const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
2005-03-02 13:16:10 +01:00
{
/*** IUnknown methods ***/
IWineD3DVertexShaderImpl_QueryInterface ,
IWineD3DVertexShaderImpl_AddRef ,
IWineD3DVertexShaderImpl_Release ,
2006-03-28 21:10:51 +02:00
/*** IWineD3DBase methods ***/
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl_GetParent ,
2006-03-28 21:10:51 +02:00
/*** IWineD3DBaseShader methods ***/
IWineD3DVertexShaderImpl_SetFunction ,
2006-08-05 18:15:35 +02:00
IWineD3DVertexShaderImpl_CompileShader ,
2006-03-28 21:10:51 +02:00
/*** IWineD3DVertexShader methods ***/
2005-03-02 13:16:10 +01:00
IWineD3DVertexShaderImpl_GetDevice ,
2007-02-13 23:12:29 +01:00
IWineD3DVertexShaderImpl_GetFunction ,
2007-02-13 23:12:40 +01:00
IWineD3DVertexShaderImpl_FakeSemantics ,
IWIneD3DVertexShaderImpl_SetLocalConstantsF
2005-03-02 13:16:10 +01:00
} ;