2 * Pixel and vertex shaders implementation using ARB_vertex_program
3 * and ARB_fragment_program GL extensions.
5 * Copyright 2002-2003 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Ivan Gyurdiev
10 * Copyright 2006 Jason Green
11 * Copyright 2006 Henri Verbeet
12 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "wined3d_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader
);
38 WINE_DECLARE_DEBUG_CHANNEL(d3d_constants
);
39 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps
);
40 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
42 #define GLINFO_LOCATION (*gl_info)
44 /* GL locking for state handlers is done by the caller. */
45 static BOOL
need_mova_const(IWineD3DBaseShader
*shader
, const struct wined3d_gl_info
*gl_info
)
47 IWineD3DBaseShaderImpl
*This
= (IWineD3DBaseShaderImpl
*) shader
;
48 if(!This
->baseShader
.reg_maps
.usesmova
) return FALSE
;
49 return !gl_info
->supported
[NV_VERTEX_PROGRAM2_OPTION
];
52 /* Returns TRUE if result.clip from GL_NV_vertex_program2 should be used and FALSE otherwise */
53 static inline BOOL
use_nv_clip(const struct wined3d_gl_info
*gl_info
)
55 return gl_info
->supported
[NV_VERTEX_PROGRAM2_OPTION
]
56 && !(gl_info
->quirks
& WINED3D_QUIRK_NV_CLIP_BROKEN
);
59 static BOOL
need_helper_const(const struct wined3d_gl_info
*gl_info
)
61 if (!gl_info
->supported
[NV_VERTEX_PROGRAM
] /* Need to init colors. */
62 || gl_info
->quirks
& WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT
/* Load the immval offset. */
63 || gl_info
->quirks
& WINED3D_QUIRK_SET_TEXCOORD_W
/* Have to init texcoords. */
64 || (!use_nv_clip(gl_info
)) /* Init the clip texcoord */)
71 static unsigned int reserved_vs_const(IWineD3DBaseShader
*shader
, const struct wined3d_gl_info
*gl_info
)
74 /* We use one PARAM for the pos fixup, and in some cases one to load
75 * some immediate values into the shader
77 if(need_helper_const(gl_info
)) ret
++;
78 if(need_mova_const(shader
, gl_info
)) ret
++;
82 static inline BOOL
ffp_clip_emul(IWineD3DStateBlockImpl
*stateblock
)
84 return stateblock
->lowest_disabled_stage
< 7;
87 /* ARB_program_shader private data */
106 struct wined3d_shader_loop_control loop_control
;
110 struct arb_ps_np2fixup_info
112 struct ps_np2fixup_info super
;
113 /* For ARB we need a offset value:
114 * With both GLSL and ARB mode the NP2 fixup information (the texture dimensions) are stored in a
115 * consecutive way (GLSL uses a uniform array). Since ARB doesn't know the notion of a "standalone"
116 * array we need an offset to the index inside the program local parameter array. */
120 struct arb_ps_compile_args
122 struct ps_compile_args super
;
124 WORD clip
; /* only a boolean, use a WORD for alignment */
125 unsigned char loop_ctrl
[MAX_CONST_I
][3];
128 struct stb_const_desc
130 unsigned char texunit
;
134 struct arb_ps_compiled_shader
136 struct arb_ps_compile_args args
;
137 struct arb_ps_np2fixup_info np2fixup_info
;
138 struct stb_const_desc bumpenvmatconst
[MAX_TEXTURES
];
139 struct stb_const_desc luminanceconst
[MAX_TEXTURES
];
140 UINT int_consts
[MAX_CONST_I
];
143 unsigned char numbumpenvmatconsts
;
147 struct arb_vs_compile_args
149 struct vs_compile_args super
;
158 DWORD boolclip_compare
;
163 unsigned char samplers
[4];
164 DWORD samplers_compare
;
166 unsigned char loop_ctrl
[MAX_CONST_I
][3];
169 struct arb_vs_compiled_shader
171 struct arb_vs_compile_args args
;
173 UINT int_consts
[MAX_CONST_I
];
175 char need_color_unclamp
;
179 struct recorded_instruction
181 struct wined3d_shader_instruction ins
;
185 struct shader_arb_ctx_priv
190 /* plain GL_ARB_vertex_program or GL_ARB_fragment_program */
192 /* GL_NV_vertex_progam2_option or GL_NV_fragment_program_option */
194 /* GL_NV_vertex_program3 or GL_NV_fragment_program2 */
198 const struct arb_vs_compile_args
*cur_vs_args
;
199 const struct arb_ps_compile_args
*cur_ps_args
;
200 const struct arb_ps_compiled_shader
*compiled_fprog
;
201 const struct arb_vs_compiled_shader
*compiled_vprog
;
202 struct arb_ps_np2fixup_info
*cur_np2fixup_info
;
203 struct list control_frames
;
207 unsigned int num_loops
, loop_depth
, num_ifcs
;
210 unsigned int vs_clipplanes
;
214 /* For 3.0 vertex shaders */
215 const char *vs_output
[MAX_REG_OUTPUT
];
216 /* For 2.x and earlier vertex shaders */
217 const char *texcrd_output
[8], *color_output
[2], *fog_output
;
219 /* 3.0 pshader input for compatibility with fixed function */
220 const char *ps_input
[MAX_REG_INPUT
];
225 struct wined3d_shader_signature_element
*sig
;
227 struct wine_rb_entry entry
;
230 struct arb_pshader_private
{
231 struct arb_ps_compiled_shader
*gl_shaders
;
232 UINT num_gl_shaders
, shader_array_size
;
233 BOOL has_signature_idx
;
234 DWORD input_signature_idx
;
235 DWORD clipplane_emulation
;
239 struct arb_vshader_private
{
240 struct arb_vs_compiled_shader
*gl_shaders
;
241 UINT num_gl_shaders
, shader_array_size
;
244 struct shader_arb_priv
246 GLuint current_vprogram_id
;
247 GLuint current_fprogram_id
;
248 const struct arb_ps_compiled_shader
*compiled_fprog
;
249 const struct arb_vs_compiled_shader
*compiled_vprog
;
250 GLuint depth_blt_vprogram_id
;
251 GLuint depth_blt_fprogram_id
[tex_type_count
];
252 BOOL use_arbfp_fixed_func
;
253 struct wine_rb_tree fragment_shaders
;
254 BOOL last_ps_const_clamped
;
255 BOOL last_vs_color_unclamp
;
257 struct wine_rb_tree signature_tree
;
261 /********************************************************
262 * ARB_[vertex/fragment]_program helper functions follow
263 ********************************************************/
265 /* Loads floating point constants into the currently set ARB_vertex/fragment_program.
266 * When constant_list == NULL, it will load all the constants.
268 * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
269 * or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
271 /* GL locking is done by the caller */
272 static unsigned int shader_arb_load_constantsF(IWineD3DBaseShaderImpl
*This
, const struct wined3d_gl_info
*gl_info
,
273 GLuint target_type
, unsigned int max_constants
, const float *constants
, char *dirty_consts
)
275 local_constant
* lconst
;
279 if (TRACE_ON(d3d_constants
))
281 for(i
= 0; i
< max_constants
; i
++) {
282 if(!dirty_consts
[i
]) continue;
283 TRACE_(d3d_constants
)("Loading constants %i: %f, %f, %f, %f\n", i
,
284 constants
[i
* 4 + 0], constants
[i
* 4 + 1],
285 constants
[i
* 4 + 2], constants
[i
* 4 + 3]);
291 /* In 1.X pixel shaders constants are implicitly clamped in the range [-1;1] */
292 if (target_type
== GL_FRAGMENT_PROGRAM_ARB
&& This
->baseShader
.reg_maps
.shader_version
.major
== 1)
295 /* ps 1.x supports only 8 constants, clamp only those. When switching between 1.x and higher
296 * shaders, the first 8 constants are marked dirty for reload
298 for(; i
< min(8, max_constants
); i
++) {
299 if(!dirty_consts
[i
]) continue;
303 if (constants
[j
+ 0] > 1.0f
) lcl_const
[0] = 1.0f
;
304 else if (constants
[j
+ 0] < -1.0f
) lcl_const
[0] = -1.0f
;
305 else lcl_const
[0] = constants
[j
+ 0];
307 if (constants
[j
+ 1] > 1.0f
) lcl_const
[1] = 1.0f
;
308 else if (constants
[j
+ 1] < -1.0f
) lcl_const
[1] = -1.0f
;
309 else lcl_const
[1] = constants
[j
+ 1];
311 if (constants
[j
+ 2] > 1.0f
) lcl_const
[2] = 1.0f
;
312 else if (constants
[j
+ 2] < -1.0f
) lcl_const
[2] = -1.0f
;
313 else lcl_const
[2] = constants
[j
+ 2];
315 if (constants
[j
+ 3] > 1.0f
) lcl_const
[3] = 1.0f
;
316 else if (constants
[j
+ 3] < -1.0f
) lcl_const
[3] = -1.0f
;
317 else lcl_const
[3] = constants
[j
+ 3];
319 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type
, i
, lcl_const
));
322 /* If further constants are dirty, reload them without clamping.
324 * The alternative is not to touch them, but then we cannot reset the dirty constant count
325 * to zero. That's bad for apps that only use PS 1.x shaders, because in that case the code
326 * above would always re-check the first 8 constants since max_constant remains at the init
331 if (gl_info
->supported
[EXT_GPU_PROGRAM_PARAMETERS
])
333 /* TODO: Benchmark if we're better of with finding the dirty constants ourselves,
334 * or just reloading *all* constants at once
336 GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, i, max_constants, constants + (i * 4)));
338 for(; i
< max_constants
; i
++) {
339 if(!dirty_consts
[i
]) continue;
341 /* Find the next block of dirty constants */
344 for(i
++; (i
< max_constants
) && dirty_consts
[i
]; i
++) {
348 GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type
, j
, i
- j
, constants
+ (j
* 4)));
351 for(; i
< max_constants
; i
++) {
352 if(dirty_consts
[i
]) {
354 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type
, i
, constants
+ (i
* 4)));
358 checkGLcall("glProgramEnvParameter4fvARB()");
360 /* Load immediate constants */
361 if(This
->baseShader
.load_local_constsF
) {
362 if (TRACE_ON(d3d_shader
)) {
363 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
364 GLfloat
* values
= (GLfloat
*)lconst
->value
;
365 TRACE_(d3d_constants
)("Loading local constants %i: %f, %f, %f, %f\n", lconst
->idx
,
366 values
[0], values
[1], values
[2], values
[3]);
369 /* Immediate constants are clamped for 1.X shaders at loading times */
371 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
372 dirty_consts
[lconst
->idx
] = 1; /* Dirtify so the non-immediate constant overwrites it next time */
373 ret
= max(ret
, lconst
->idx
+ 1);
374 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type
, lconst
->idx
, (GLfloat
*)lconst
->value
));
376 checkGLcall("glProgramEnvParameter4fvARB()");
377 return ret
; /* The loaded immediate constants need reloading for the next shader */
379 return 0; /* No constants are dirty now */
384 * Loads the texture dimensions for NP2 fixup into the currently set ARB_[vertex/fragment]_programs.
386 static void shader_arb_load_np2fixup_constants(
387 IWineD3DDevice
* device
,
389 char useVertexShader
) {
391 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) device
;
392 const struct shader_arb_priv
* const priv
= (const struct shader_arb_priv
*) deviceImpl
->shader_priv
;
393 IWineD3DStateBlockImpl
* stateBlock
= deviceImpl
->stateBlock
;
394 const struct wined3d_gl_info
*gl_info
= &deviceImpl
->adapter
->gl_info
;
396 if (!usePixelShader
) {
397 /* NP2 texcoord fixup is (currently) only done for pixelshaders. */
401 if (priv
->compiled_fprog
&& priv
->compiled_fprog
->np2fixup_info
.super
.active
) {
402 const struct arb_ps_np2fixup_info
* const fixup
= &priv
->compiled_fprog
->np2fixup_info
;
404 WORD active
= fixup
->super
.active
;
405 GLfloat np2fixup_constants
[4 * MAX_FRAGMENT_SAMPLERS
];
407 for (i
= 0; active
; active
>>= 1, ++i
) {
408 const unsigned char idx
= fixup
->super
.idx
[i
];
409 const IWineD3DTextureImpl
* const tex
= (const IWineD3DTextureImpl
*) stateBlock
->textures
[i
];
410 GLfloat
* tex_dim
= &np2fixup_constants
[(idx
>> 1) * 4];
412 if (!(active
& 1)) continue;
415 FIXME("Nonexistent texture is flagged for NP2 texcoord fixup\n");
420 tex_dim
[2] = tex
->baseTexture
.pow2Matrix
[0]; tex_dim
[3] = tex
->baseTexture
.pow2Matrix
[5];
422 tex_dim
[0] = tex
->baseTexture
.pow2Matrix
[0]; tex_dim
[1] = tex
->baseTexture
.pow2Matrix
[5];
426 for (i
= 0; i
< fixup
->super
.num_consts
; ++i
) {
427 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
,
428 fixup
->offset
+ i
, &np2fixup_constants
[i
* 4]));
433 /* GL locking is done by the caller. */
434 static inline void shader_arb_ps_local_constants(IWineD3DDeviceImpl
* deviceImpl
)
436 const struct wined3d_context
*context
= context_get_current();
437 IWineD3DStateBlockImpl
* stateBlock
= deviceImpl
->stateBlock
;
438 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
440 struct shader_arb_priv
*priv
= deviceImpl
->shader_priv
;
441 const struct arb_ps_compiled_shader
*gl_shader
= priv
->compiled_fprog
;
443 for(i
= 0; i
< gl_shader
->numbumpenvmatconsts
; i
++)
445 int texunit
= gl_shader
->bumpenvmatconst
[i
].texunit
;
447 /* The state manager takes care that this function is always called if the bump env matrix changes */
448 const float *data
= (const float *)&stateBlock
->textureState
[texunit
][WINED3DTSS_BUMPENVMAT00
];
449 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, gl_shader
->bumpenvmatconst
[i
].const_num
, data
));
451 if (gl_shader
->luminanceconst
[i
].const_num
!= WINED3D_CONST_NUM_UNUSED
)
453 /* WINED3DTSS_BUMPENVLSCALE and WINED3DTSS_BUMPENVLOFFSET are next to each other.
454 * point gl to the scale, and load 4 floats. x = scale, y = offset, z and w are junk, we
455 * don't care about them. The pointers are valid for sure because the stateblock is bigger.
456 * (they're WINED3DTSS_TEXTURETRANSFORMFLAGS and WINED3DTSS_ADDRESSW, so most likely 0 or NaN
458 const float *scale
= (const float *)&stateBlock
->textureState
[texunit
][WINED3DTSS_BUMPENVLSCALE
];
459 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, gl_shader
->luminanceconst
[i
].const_num
, scale
));
462 checkGLcall("Load bumpmap consts");
464 if(gl_shader
->ycorrection
!= WINED3D_CONST_NUM_UNUSED
)
466 /* ycorrection.x: Backbuffer height(onscreen) or 0(offscreen).
467 * ycorrection.y: -1.0(onscreen), 1.0(offscreen)
472 val
[0] = context
->render_offscreen
? 0.0f
473 : ((IWineD3DSurfaceImpl
*) deviceImpl
->render_targets
[0])->currentDesc
.Height
;
474 val
[1] = context
->render_offscreen
? 1.0f
: -1.0f
;
477 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, gl_shader
->ycorrection
, val
));
478 checkGLcall("y correction loading");
481 if(gl_shader
->num_int_consts
== 0) return;
483 for(i
= 0; i
< MAX_CONST_I
; i
++)
485 if(gl_shader
->int_consts
[i
] != WINED3D_CONST_NUM_UNUSED
)
488 val
[0] = stateBlock
->pixelShaderConstantI
[4 * i
];
489 val
[1] = stateBlock
->pixelShaderConstantI
[4 * i
+ 1];
490 val
[2] = stateBlock
->pixelShaderConstantI
[4 * i
+ 2];
493 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, gl_shader
->int_consts
[i
], val
));
496 checkGLcall("Load ps int consts");
499 /* GL locking is done by the caller. */
500 static inline void shader_arb_vs_local_constants(IWineD3DDeviceImpl
* deviceImpl
)
502 IWineD3DStateBlockImpl
* stateBlock
;
503 const struct wined3d_gl_info
*gl_info
= &deviceImpl
->adapter
->gl_info
;
505 struct shader_arb_priv
*priv
= deviceImpl
->shader_priv
;
506 const struct arb_vs_compiled_shader
*gl_shader
= priv
->compiled_vprog
;
508 /* Upload the position fixup */
509 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB
, gl_shader
->pos_fixup
, deviceImpl
->posFixup
));
511 if(gl_shader
->num_int_consts
== 0) return;
513 stateBlock
= deviceImpl
->stateBlock
;
515 for(i
= 0; i
< MAX_CONST_I
; i
++)
517 if(gl_shader
->int_consts
[i
] != WINED3D_CONST_NUM_UNUSED
)
520 val
[0] = stateBlock
->vertexShaderConstantI
[4 * i
];
521 val
[1] = stateBlock
->vertexShaderConstantI
[4 * i
+ 1];
522 val
[2] = stateBlock
->vertexShaderConstantI
[4 * i
+ 2];
525 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB
, gl_shader
->int_consts
[i
], val
));
528 checkGLcall("Load vs int consts");
532 * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
534 * We only support float constants in ARB at the moment, so don't
535 * worry about the Integers or Booleans
537 /* GL locking is done by the caller (state handler) */
538 static void shader_arb_load_constants(const struct wined3d_context
*context
, char usePixelShader
, char useVertexShader
)
540 IWineD3DDeviceImpl
*device
= ((IWineD3DSurfaceImpl
*)context
->surface
)->resource
.device
;
541 IWineD3DStateBlockImpl
* stateBlock
= device
->stateBlock
;
542 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
544 if (useVertexShader
) {
545 IWineD3DBaseShaderImpl
* vshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->vertexShader
;
547 /* Load DirectX 9 float constants for vertex shader */
548 device
->highest_dirty_vs_const
= shader_arb_load_constantsF(vshader
, gl_info
, GL_VERTEX_PROGRAM_ARB
,
549 device
->highest_dirty_vs_const
, stateBlock
->vertexShaderConstantF
, context
->vshader_const_dirty
);
550 shader_arb_vs_local_constants(device
);
553 if (usePixelShader
) {
554 IWineD3DBaseShaderImpl
* pshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->pixelShader
;
556 /* Load DirectX 9 float constants for pixel shader */
557 device
->highest_dirty_ps_const
= shader_arb_load_constantsF(pshader
, gl_info
, GL_FRAGMENT_PROGRAM_ARB
,
558 device
->highest_dirty_ps_const
, stateBlock
->pixelShaderConstantF
, context
->pshader_const_dirty
);
559 shader_arb_ps_local_constants(device
);
563 static void shader_arb_update_float_vertex_constants(IWineD3DDevice
*iface
, UINT start
, UINT count
)
565 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
566 struct wined3d_context
*context
= context_get_current();
568 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
569 * context. On a context switch the old context will be fully dirtified */
570 if (!context
|| ((IWineD3DSurfaceImpl
*)context
->surface
)->resource
.device
!= This
) return;
572 memset(context
->vshader_const_dirty
+ start
, 1, sizeof(*context
->vshader_const_dirty
) * count
);
573 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+ count
);
576 static void shader_arb_update_float_pixel_constants(IWineD3DDevice
*iface
, UINT start
, UINT count
)
578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
579 struct wined3d_context
*context
= context_get_current();
581 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
582 * context. On a context switch the old context will be fully dirtified */
583 if (!context
|| ((IWineD3DSurfaceImpl
*)context
->surface
)->resource
.device
!= This
) return;
585 memset(context
->pshader_const_dirty
+ start
, 1, sizeof(*context
->pshader_const_dirty
) * count
);
586 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+ count
);
589 static DWORD
*local_const_mapping(IWineD3DBaseShaderImpl
*This
)
593 const local_constant
*lconst
;
595 if(This
->baseShader
.load_local_constsF
|| list_empty(&This
->baseShader
.constantsF
)) return NULL
;
597 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD
) * This
->baseShader
.limits
.constant_float
);
599 ERR("Out of memory\n");
603 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
604 ret
[lconst
->idx
] = idx
++;
609 /* Generate the variable & register declarations for the ARB_vertex_program output target */
610 static DWORD
shader_generate_arb_declarations(IWineD3DBaseShader
*iface
, const shader_reg_maps
*reg_maps
,
611 struct wined3d_shader_buffer
*buffer
, const struct wined3d_gl_info
*gl_info
, DWORD
*lconst_map
,
612 DWORD
*num_clipplanes
, struct shader_arb_ctx_priv
*ctx
)
614 IWineD3DBaseShaderImpl
* This
= (IWineD3DBaseShaderImpl
*) iface
;
615 DWORD i
, next_local
= 0;
616 char pshader
= shader_is_pshader_version(reg_maps
->shader_version
.type
);
617 unsigned max_constantsF
;
618 const local_constant
*lconst
;
621 /* In pixel shaders, all private constants are program local, we don't need anything
622 * from program.env. Thus we can advertise the full set of constants in pixel shaders.
623 * If we need a private constant the GL implementation will squeeze it in somewhere
625 * With vertex shaders we need the posFixup and on some GL implementations 4 helper
626 * immediate values. The posFixup is loaded using program.env for now, so always
627 * subtract one from the number of constants. If the shader uses indirect addressing,
628 * account for the helper const too because we have to declare all availabke d3d constants
629 * and don't know which are actually used.
633 max_constantsF
= gl_info
->limits
.arb_ps_native_constants
;
637 if(This
->baseShader
.reg_maps
.usesrelconstF
) {
638 DWORD highest_constf
= 0, clip_limit
;
639 max_constantsF
= gl_info
->limits
.arb_vs_native_constants
- reserved_vs_const(iface
, gl_info
);
640 max_constantsF
-= count_bits(This
->baseShader
.reg_maps
.integer_constants
);
642 for(i
= 0; i
< This
->baseShader
.limits
.constant_float
; i
++)
645 DWORD shift
= i
& 0x1f;
646 if(reg_maps
->constf
[idx
] & (1 << shift
)) highest_constf
= i
;
649 if(use_nv_clip(gl_info
) && ctx
->target_version
>= NV2
)
651 if(ctx
->cur_vs_args
->super
.clip_enabled
)
652 clip_limit
= gl_info
->limits
.clipplanes
;
658 unsigned int mask
= ctx
->cur_vs_args
->clip
.boolclip
.clipplane_mask
;
659 clip_limit
= min(count_bits(mask
), 4);
661 *num_clipplanes
= min(clip_limit
, max_constantsF
- highest_constf
- 1);
662 max_constantsF
-= *num_clipplanes
;
663 if(*num_clipplanes
< clip_limit
)
665 WARN("Only %u clipplanes out of %u enabled\n", *num_clipplanes
, gl_info
->limits
.clipplanes
);
670 if (ctx
->target_version
>= NV2
) *num_clipplanes
= gl_info
->limits
.clipplanes
;
671 else *num_clipplanes
= min(gl_info
->limits
.clipplanes
, 4);
672 max_constantsF
= gl_info
->limits
.arb_vs_native_constants
;
676 for (i
= 0, map
= reg_maps
->temporary
; map
; map
>>= 1, ++i
)
678 if (map
& 1) shader_addline(buffer
, "TEMP R%u;\n", i
);
681 for (i
= 0, map
= reg_maps
->address
; map
; map
>>= 1, ++i
)
683 if (map
& 1) shader_addline(buffer
, "ADDRESS A%u;\n", i
);
686 if (pshader
&& reg_maps
->shader_version
.major
== 1 && reg_maps
->shader_version
.minor
<= 3)
688 for (i
= 0, map
= reg_maps
->texcoord
; map
; map
>>= 1, ++i
)
690 if (map
& 1) shader_addline(buffer
, "TEMP T%u;\n", i
);
694 /* Load local constants using the program-local space,
695 * this avoids reloading them each time the shader is used
698 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
699 shader_addline(buffer
, "PARAM C%u = program.local[%u];\n", lconst
->idx
,
700 lconst_map
[lconst
->idx
]);
701 next_local
= max(next_local
, lconst_map
[lconst
->idx
] + 1);
705 /* After subtracting privately used constants from the hardware limit(they are loaded as
706 * local constants), make sure the shader doesn't violate the env constant limit
710 max_constantsF
= min(max_constantsF
, gl_info
->limits
.arb_ps_float_constants
);
714 max_constantsF
= min(max_constantsF
, gl_info
->limits
.arb_vs_float_constants
);
717 /* Avoid declaring more constants than needed */
718 max_constantsF
= min(max_constantsF
, This
->baseShader
.limits
.constant_float
);
720 /* we use the array-based constants array if the local constants are marked for loading,
721 * because then we use indirect addressing, or when the local constant list is empty,
722 * because then we don't know if we're using indirect addressing or not. If we're hardcoding
723 * local constants do not declare the loaded constants as an array because ARB compilers usually
724 * do not optimize unused constants away
726 if(This
->baseShader
.reg_maps
.usesrelconstF
) {
727 /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
728 shader_addline(buffer
, "PARAM C[%d] = { program.env[0..%d] };\n",
729 max_constantsF
, max_constantsF
- 1);
731 for(i
= 0; i
< max_constantsF
; i
++) {
734 mask
= 1 << (i
& 0x1f);
735 if(!shader_constant_is_local(This
, i
) && (This
->baseShader
.reg_maps
.constf
[idx
] & mask
)) {
736 shader_addline(buffer
, "PARAM C%d = program.env[%d];\n",i
, i
);
744 static const char * const shift_tab
[] = {
745 "dummy", /* 0 (none) */
746 "coefmul.x", /* 1 (x2) */
747 "coefmul.y", /* 2 (x4) */
748 "coefmul.z", /* 3 (x8) */
749 "coefmul.w", /* 4 (x16) */
750 "dummy", /* 5 (x32) */
751 "dummy", /* 6 (x64) */
752 "dummy", /* 7 (x128) */
753 "dummy", /* 8 (d256) */
754 "dummy", /* 9 (d128) */
755 "dummy", /* 10 (d64) */
756 "dummy", /* 11 (d32) */
757 "coefdiv.w", /* 12 (d16) */
758 "coefdiv.z", /* 13 (d8) */
759 "coefdiv.y", /* 14 (d4) */
760 "coefdiv.x" /* 15 (d2) */
763 static void shader_arb_get_write_mask(const struct wined3d_shader_instruction
*ins
,
764 const struct wined3d_shader_dst_param
*dst
, char *write_mask
)
766 char *ptr
= write_mask
;
768 if (dst
->write_mask
!= WINED3DSP_WRITEMASK_ALL
)
771 if (dst
->write_mask
& WINED3DSP_WRITEMASK_0
) *ptr
++ = 'x';
772 if (dst
->write_mask
& WINED3DSP_WRITEMASK_1
) *ptr
++ = 'y';
773 if (dst
->write_mask
& WINED3DSP_WRITEMASK_2
) *ptr
++ = 'z';
774 if (dst
->write_mask
& WINED3DSP_WRITEMASK_3
) *ptr
++ = 'w';
780 static void shader_arb_get_swizzle(const struct wined3d_shader_src_param
*param
, BOOL fixup
, char *swizzle_str
)
782 /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra",
783 * but addressed as "rgba". To fix this we need to swap the register's x
784 * and z components. */
785 const char *swizzle_chars
= fixup
? "zyxw" : "xyzw";
786 char *ptr
= swizzle_str
;
788 /* swizzle bits fields: wwzzyyxx */
789 DWORD swizzle
= param
->swizzle
;
790 DWORD swizzle_x
= swizzle
& 0x03;
791 DWORD swizzle_y
= (swizzle
>> 2) & 0x03;
792 DWORD swizzle_z
= (swizzle
>> 4) & 0x03;
793 DWORD swizzle_w
= (swizzle
>> 6) & 0x03;
795 /* If the swizzle is the default swizzle (ie, "xyzw"), we don't need to
796 * generate a swizzle string. Unless we need to our own swizzling. */
797 if (swizzle
!= WINED3DSP_NOSWIZZLE
|| fixup
)
800 if (swizzle_x
== swizzle_y
&& swizzle_x
== swizzle_z
&& swizzle_x
== swizzle_w
) {
801 *ptr
++ = swizzle_chars
[swizzle_x
];
803 *ptr
++ = swizzle_chars
[swizzle_x
];
804 *ptr
++ = swizzle_chars
[swizzle_y
];
805 *ptr
++ = swizzle_chars
[swizzle_z
];
806 *ptr
++ = swizzle_chars
[swizzle_w
];
813 static void shader_arb_request_a0(const struct wined3d_shader_instruction
*ins
, const char *src
)
815 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
816 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
818 if(strcmp(priv
->addr_reg
, src
) == 0) return;
820 strcpy(priv
->addr_reg
, src
);
821 shader_addline(buffer
, "ARL A0.x, %s;\n", src
);
824 static void shader_arb_get_src_param(const struct wined3d_shader_instruction
*ins
,
825 const struct wined3d_shader_src_param
*src
, unsigned int tmpreg
, char *outregstr
);
827 static void shader_arb_get_register_name(const struct wined3d_shader_instruction
*ins
,
828 const struct wined3d_shader_register
*reg
, char *register_name
, BOOL
*is_color
)
830 /* oPos, oFog and oPts in D3D */
831 static const char * const rastout_reg_names
[] = {"TMP_OUT", "result.fogcoord", "result.pointsize"};
832 IWineD3DBaseShaderImpl
*This
= (IWineD3DBaseShaderImpl
*)ins
->ctx
->shader
;
833 BOOL pshader
= shader_is_pshader_version(This
->baseShader
.reg_maps
.shader_version
.type
);
834 struct shader_arb_ctx_priv
*ctx
= ins
->ctx
->backend_data
;
840 case WINED3DSPR_TEMP
:
841 sprintf(register_name
, "R%u", reg
->idx
);
844 case WINED3DSPR_INPUT
:
847 if(This
->baseShader
.reg_maps
.shader_version
.major
< 3)
849 if (reg
->idx
== 0) strcpy(register_name
, "fragment.color.primary");
850 else strcpy(register_name
, "fragment.color.secondary");
857 shader_arb_get_src_param(ins
, reg
->rel_addr
, 0, rel_reg
);
859 if(strcmp(rel_reg
, "**aL_emul**") == 0)
861 DWORD idx
= ctx
->aL
+ reg
->idx
;
862 if(idx
< MAX_REG_INPUT
)
864 strcpy(register_name
, ctx
->ps_input
[idx
]);
868 ERR("Pixel shader input register out of bounds: %u\n", idx
);
869 sprintf(register_name
, "out_of_bounds_%u", idx
);
872 else if(This
->baseShader
.reg_maps
.input_registers
& 0x0300)
874 /* There are two ways basically:
876 * 1) Use the unrolling code that is used for loop emulation and unroll the loop.
877 * That means trouble if the loop also contains a breakc or if the control values
878 * aren't local constants.
879 * 2) Generate an if block that checks if aL.y < 8, == 8 or == 9 and selects the
880 * source dynamically. The trouble is that we cannot simply read aL.y because it
881 * is an ADDRESS register. We could however push it, load .zw with a value and use
882 * ADAC to load the condition code register and pop it again afterwards
884 FIXME("Relative input register addressing with more than 8 registers\n");
886 /* This is better than nothing for now */
887 sprintf(register_name
, "fragment.texcoord[%s + %u]", rel_reg
, reg
->idx
);
889 else if(ctx
->cur_ps_args
->super
.vp_mode
!= vertexshader
)
891 /* This is problematic because we'd have to consult the ctx->ps_input strings
892 * for where to find the varying. Some may be "0.0", others can be texcoords or
893 * colors. This needs either a pipeline replacement to make the vertex shader feed
894 * proper varyings, or loop unrolling
896 * For now use the texcoords and hope for the best
898 FIXME("Non-vertex shader varying input with indirect addressing\n");
899 sprintf(register_name
, "fragment.texcoord[%s + %u]", rel_reg
, reg
->idx
);
903 /* D3D supports indirect addressing only with aL in loop registers. The loop instruction
904 * pulls GL_NV_fragment_program2 in
906 sprintf(register_name
, "fragment.texcoord[%s + %u]", rel_reg
, reg
->idx
);
911 if(reg
->idx
< MAX_REG_INPUT
)
913 strcpy(register_name
, ctx
->ps_input
[reg
->idx
]);
917 ERR("Pixel shader input register out of bounds: %u\n", reg
->idx
);
918 sprintf(register_name
, "out_of_bounds_%u", reg
->idx
);
925 if (ctx
->cur_vs_args
->super
.swizzle_map
& (1 << reg
->idx
)) *is_color
= TRUE
;
926 sprintf(register_name
, "vertex.attrib[%u]", reg
->idx
);
930 case WINED3DSPR_CONST
:
931 if (!pshader
&& reg
->rel_addr
)
935 UINT rel_offset
= ((IWineD3DVertexShaderImpl
*)This
)->rel_offset
;
936 if(This
->baseShader
.reg_maps
.shader_version
.major
< 2) {
937 sprintf(rel_reg
, "A0.x");
939 shader_arb_get_src_param(ins
, reg
->rel_addr
, 0, rel_reg
);
940 if(ctx
->target_version
== ARB
) {
941 if(strcmp(rel_reg
, "**aL_emul**") == 0) {
944 shader_arb_request_a0(ins
, rel_reg
);
945 sprintf(rel_reg
, "A0.x");
950 sprintf(register_name
, "C[%u]", ctx
->aL
+ reg
->idx
);
951 else if (reg
->idx
>= rel_offset
)
952 sprintf(register_name
, "C[%s + %u]", rel_reg
, reg
->idx
- rel_offset
);
954 sprintf(register_name
, "C[%s - %u]", rel_reg
, -reg
->idx
+ rel_offset
);
958 if (This
->baseShader
.reg_maps
.usesrelconstF
)
959 sprintf(register_name
, "C[%u]", reg
->idx
);
961 sprintf(register_name
, "C%u", reg
->idx
);
965 case WINED3DSPR_TEXTURE
: /* case WINED3DSPR_ADDR: */
967 if(This
->baseShader
.reg_maps
.shader_version
.major
== 1 &&
968 This
->baseShader
.reg_maps
.shader_version
.minor
<= 3) {
969 /* In ps <= 1.3, Tx is a temporary register as destination to all instructions,
970 * and as source to most instructions. For some instructions it is the texcoord
971 * input. Those instructions know about the special use
973 sprintf(register_name
, "T%u", reg
->idx
);
975 /* in ps 1.4 and 2.x Tx is always a (read-only) varying */
976 sprintf(register_name
, "fragment.texcoord[%u]", reg
->idx
);
981 if(This
->baseShader
.reg_maps
.shader_version
.major
== 1 || ctx
->target_version
>= NV2
)
983 sprintf(register_name
, "A%u", reg
->idx
);
987 sprintf(register_name
, "A%u_SHADOW", reg
->idx
);
992 case WINED3DSPR_COLOROUT
:
993 if(ctx
->cur_ps_args
->super
.srgb_correction
&& reg
->idx
== 0)
995 strcpy(register_name
, "TMP_COLOR");
999 if(ctx
->cur_ps_args
->super
.srgb_correction
) FIXME("sRGB correction on higher render targets\n");
1000 if(This
->baseShader
.reg_maps
.highest_render_target
> 0)
1002 sprintf(register_name
, "result.color[%u]", reg
->idx
);
1006 strcpy(register_name
, "result.color");
1011 case WINED3DSPR_RASTOUT
:
1012 if(reg
->idx
== 1) sprintf(register_name
, "%s", ctx
->fog_output
);
1013 else sprintf(register_name
, "%s", rastout_reg_names
[reg
->idx
]);
1016 case WINED3DSPR_DEPTHOUT
:
1017 strcpy(register_name
, "result.depth");
1020 case WINED3DSPR_ATTROUT
:
1021 /* case WINED3DSPR_OUTPUT: */
1022 if (pshader
) sprintf(register_name
, "oD[%u]", reg
->idx
);
1023 else strcpy(register_name
, ctx
->color_output
[reg
->idx
]);
1026 case WINED3DSPR_TEXCRDOUT
:
1029 sprintf(register_name
, "oT[%u]", reg
->idx
);
1033 if(This
->baseShader
.reg_maps
.shader_version
.major
< 3)
1035 strcpy(register_name
, ctx
->texcrd_output
[reg
->idx
]);
1039 strcpy(register_name
, ctx
->vs_output
[reg
->idx
]);
1044 case WINED3DSPR_LOOP
:
1045 if(ctx
->target_version
>= NV2
)
1047 /* Pshader has an implicitly declared loop index counter A0.x that cannot be renamed */
1048 if(pshader
) sprintf(register_name
, "A0.x");
1049 else sprintf(register_name
, "aL.y");
1053 /* Unfortunately this code cannot return the value of ctx->aL here. An immediate value
1054 * would be valid, but if aL is used for indexing(its only use), there's likely an offset,
1055 * thus the result would be something like C[15 + 30], which is not valid in the ARB program
1056 * grammar. So return a marker for the emulated aL and intercept it in constant and varying
1059 sprintf(register_name
, "**aL_emul**");
1064 case WINED3DSPR_CONSTINT
:
1065 sprintf(register_name
, "I%u", reg
->idx
);
1068 case WINED3DSPR_MISCTYPE
:
1071 sprintf(register_name
, "vpos");
1073 else if(reg
->idx
== 1)
1075 sprintf(register_name
, "fragment.facing.x");
1079 FIXME("Unknown MISCTYPE register index %u\n", reg
->idx
);
1084 FIXME("Unhandled register type %#x[%u]\n", reg
->type
, reg
->idx
);
1085 sprintf(register_name
, "unrecognized_register[%u]", reg
->idx
);
1090 static void shader_arb_get_dst_param(const struct wined3d_shader_instruction
*ins
,
1091 const struct wined3d_shader_dst_param
*wined3d_dst
, char *str
)
1093 char register_name
[255];
1097 shader_arb_get_register_name(ins
, &wined3d_dst
->reg
, register_name
, &is_color
);
1098 strcpy(str
, register_name
);
1100 shader_arb_get_write_mask(ins
, wined3d_dst
, write_mask
);
1101 strcat(str
, write_mask
);
1104 static const char *shader_arb_get_fixup_swizzle(enum fixup_channel_source channel_source
)
1106 switch(channel_source
)
1108 case CHANNEL_SOURCE_ZERO
: return "0";
1109 case CHANNEL_SOURCE_ONE
: return "1";
1110 case CHANNEL_SOURCE_X
: return "x";
1111 case CHANNEL_SOURCE_Y
: return "y";
1112 case CHANNEL_SOURCE_Z
: return "z";
1113 case CHANNEL_SOURCE_W
: return "w";
1115 FIXME("Unhandled channel source %#x\n", channel_source
);
1120 static void gen_color_correction(struct wined3d_shader_buffer
*buffer
, const char *reg
,
1121 DWORD dst_mask
, const char *one
, const char *two
, struct color_fixup_desc fixup
)
1125 if (is_yuv_fixup(fixup
))
1127 enum yuv_fixup yuv_fixup
= get_yuv_fixup(fixup
);
1128 FIXME("YUV fixup (%#x) not supported\n", yuv_fixup
);
1133 if (fixup
.x_source
!= CHANNEL_SOURCE_X
) mask
|= WINED3DSP_WRITEMASK_0
;
1134 if (fixup
.y_source
!= CHANNEL_SOURCE_Y
) mask
|= WINED3DSP_WRITEMASK_1
;
1135 if (fixup
.z_source
!= CHANNEL_SOURCE_Z
) mask
|= WINED3DSP_WRITEMASK_2
;
1136 if (fixup
.w_source
!= CHANNEL_SOURCE_W
) mask
|= WINED3DSP_WRITEMASK_3
;
1141 shader_addline(buffer
, "SWZ %s, %s, %s, %s, %s, %s;\n", reg
, reg
,
1142 shader_arb_get_fixup_swizzle(fixup
.x_source
), shader_arb_get_fixup_swizzle(fixup
.y_source
),
1143 shader_arb_get_fixup_swizzle(fixup
.z_source
), shader_arb_get_fixup_swizzle(fixup
.w_source
));
1147 if (fixup
.x_sign_fixup
) mask
|= WINED3DSP_WRITEMASK_0
;
1148 if (fixup
.y_sign_fixup
) mask
|= WINED3DSP_WRITEMASK_1
;
1149 if (fixup
.z_sign_fixup
) mask
|= WINED3DSP_WRITEMASK_2
;
1150 if (fixup
.w_sign_fixup
) mask
|= WINED3DSP_WRITEMASK_3
;
1156 char *ptr
= reg_mask
;
1158 if (mask
!= WINED3DSP_WRITEMASK_ALL
)
1161 if (mask
& WINED3DSP_WRITEMASK_0
) *ptr
++ = 'x';
1162 if (mask
& WINED3DSP_WRITEMASK_1
) *ptr
++ = 'y';
1163 if (mask
& WINED3DSP_WRITEMASK_2
) *ptr
++ = 'z';
1164 if (mask
& WINED3DSP_WRITEMASK_3
) *ptr
++ = 'w';
1168 shader_addline(buffer
, "MAD %s%s, %s, %s, -%s;\n", reg
, reg_mask
, reg
, two
, one
);
1172 static const char *shader_arb_get_modifier(const struct wined3d_shader_instruction
*ins
)
1175 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
1176 if (!ins
->dst_count
) return "";
1178 mod
= ins
->dst
[0].modifiers
;
1180 /* Silently ignore PARTIALPRECISION if its not supported */
1181 if(priv
->target_version
== ARB
) mod
&= ~WINED3DSPDM_PARTIALPRECISION
;
1183 if(mod
& WINED3DSPDM_MSAMPCENTROID
)
1185 FIXME("Unhandled modifier WINED3DSPDM_MSAMPCENTROID\n");
1186 mod
&= ~WINED3DSPDM_MSAMPCENTROID
;
1191 case WINED3DSPDM_SATURATE
| WINED3DSPDM_PARTIALPRECISION
:
1194 case WINED3DSPDM_SATURATE
:
1197 case WINED3DSPDM_PARTIALPRECISION
:
1204 FIXME("Unknown modifiers 0x%08x\n", mod
);
1209 #define TEX_PROJ 0x1
1210 #define TEX_BIAS 0x2
1212 #define TEX_DERIV 0x10
1214 static void shader_hw_sample(const struct wined3d_shader_instruction
*ins
, DWORD sampler_idx
,
1215 const char *dst_str
, const char *coord_reg
, WORD flags
, const char *dsx
, const char *dsy
)
1217 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1218 DWORD sampler_type
= ins
->ctx
->reg_maps
->sampler_type
[sampler_idx
];
1219 const char *tex_type
;
1220 BOOL np2_fixup
= FALSE
;
1221 IWineD3DBaseShaderImpl
*This
= (IWineD3DBaseShaderImpl
*)ins
->ctx
->shader
;
1222 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
1223 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
1225 BOOL pshader
= shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
1227 /* D3D vertex shader sampler IDs are vertex samplers(0-3), not global d3d samplers */
1228 if(!pshader
) sampler_idx
+= MAX_FRAGMENT_SAMPLERS
;
1230 switch(sampler_type
) {
1236 if(device
->stateBlock
->textures
[sampler_idx
] &&
1237 IWineD3DBaseTexture_GetTextureDimensions(device
->stateBlock
->textures
[sampler_idx
]) == GL_TEXTURE_RECTANGLE_ARB
) {
1242 if (shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
))
1244 if (priv
->cur_np2fixup_info
->super
.active
& (1 << sampler_idx
))
1246 if (flags
) FIXME("Only ordinary sampling from NP2 textures is supported.\n");
1247 else np2_fixup
= TRUE
;
1252 case WINED3DSTT_VOLUME
:
1256 case WINED3DSTT_CUBE
:
1261 ERR("Unexpected texture type %d\n", sampler_type
);
1265 /* TEX, TXL, TXD and TXP do not support the "H" modifier,
1266 * so don't use shader_arb_get_modifier
1268 if(ins
->dst
[0].modifiers
& WINED3DSPDM_SATURATE
) mod
= "_SAT";
1271 /* Fragment samplers always have indentity mapping */
1272 if(sampler_idx
>= MAX_FRAGMENT_SAMPLERS
)
1274 sampler_idx
= priv
->cur_vs_args
->vertex
.samplers
[sampler_idx
- MAX_FRAGMENT_SAMPLERS
];
1277 if (flags
& TEX_DERIV
)
1279 if(flags
& TEX_PROJ
) FIXME("Projected texture sampling with custom derivatives\n");
1280 if(flags
& TEX_BIAS
) FIXME("Biased texture sampling with custom derivatives\n");
1281 shader_addline(buffer
, "TXD%s %s, %s, %s, %s, texture[%u], %s;\n", mod
, dst_str
, coord_reg
,
1282 dsx
, dsy
,sampler_idx
, tex_type
);
1284 else if(flags
& TEX_LOD
)
1286 if(flags
& TEX_PROJ
) FIXME("Projected texture sampling with explicit lod\n");
1287 if(flags
& TEX_BIAS
) FIXME("Biased texture sampling with explicit lod\n");
1288 shader_addline(buffer
, "TXL%s %s, %s, texture[%u], %s;\n", mod
, dst_str
, coord_reg
,
1289 sampler_idx
, tex_type
);
1291 else if (flags
& TEX_BIAS
)
1293 /* Shouldn't be possible, but let's check for it */
1294 if(flags
& TEX_PROJ
) FIXME("Biased and Projected texture sampling\n");
1295 /* TXB takes the 4th component of the source vector automatically, as d3d. Nothing more to do */
1296 shader_addline(buffer
, "TXB%s %s, %s, texture[%u], %s;\n", mod
, dst_str
, coord_reg
, sampler_idx
, tex_type
);
1298 else if (flags
& TEX_PROJ
)
1300 shader_addline(buffer
, "TXP%s %s, %s, texture[%u], %s;\n", mod
, dst_str
, coord_reg
, sampler_idx
, tex_type
);
1306 const unsigned char idx
= priv
->cur_np2fixup_info
->super
.idx
[sampler_idx
];
1307 shader_addline(buffer
, "MUL TA, np2fixup[%u].%s, %s;\n", idx
>> 1,
1308 (idx
% 2) ? "zwxy" : "xyzw", coord_reg
);
1310 shader_addline(buffer
, "TEX%s %s, TA, texture[%u], %s;\n", mod
, dst_str
, sampler_idx
, tex_type
);
1313 shader_addline(buffer
, "TEX%s %s, %s, texture[%u], %s;\n", mod
, dst_str
, coord_reg
, sampler_idx
, tex_type
);
1318 gen_color_correction(buffer
, dst_str
, ins
->dst
[0].write_mask
,
1319 "one", "coefmul.x", priv
->cur_ps_args
->super
.color_fixup
[sampler_idx
]);
1323 static void shader_arb_get_src_param(const struct wined3d_shader_instruction
*ins
,
1324 const struct wined3d_shader_src_param
*src
, unsigned int tmpreg
, char *outregstr
)
1326 /* Generate a line that does the input modifier computation and return the input register to use */
1327 BOOL is_color
= FALSE
;
1331 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1332 struct shader_arb_ctx_priv
*ctx
= ins
->ctx
->backend_data
;
1334 /* Assume a new line will be added */
1337 /* Get register name */
1338 shader_arb_get_register_name(ins
, &src
->reg
, regstr
, &is_color
);
1339 shader_arb_get_swizzle(src
, is_color
, swzstr
);
1341 switch (src
->modifiers
)
1343 case WINED3DSPSM_NONE
:
1344 sprintf(outregstr
, "%s%s", regstr
, swzstr
);
1347 case WINED3DSPSM_NEG
:
1348 sprintf(outregstr
, "-%s%s", regstr
, swzstr
);
1351 case WINED3DSPSM_BIAS
:
1352 shader_addline(buffer
, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg
, regstr
);
1354 case WINED3DSPSM_BIASNEG
:
1355 shader_addline(buffer
, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg
, regstr
);
1357 case WINED3DSPSM_SIGN
:
1358 shader_addline(buffer
, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg
, regstr
);
1360 case WINED3DSPSM_SIGNNEG
:
1361 shader_addline(buffer
, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg
, regstr
);
1363 case WINED3DSPSM_COMP
:
1364 shader_addline(buffer
, "SUB T%c, one.x, %s;\n", 'A' + tmpreg
, regstr
);
1366 case WINED3DSPSM_X2
:
1367 shader_addline(buffer
, "ADD T%c, %s, %s;\n", 'A' + tmpreg
, regstr
, regstr
);
1369 case WINED3DSPSM_X2NEG
:
1370 shader_addline(buffer
, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg
, regstr
, regstr
);
1372 case WINED3DSPSM_DZ
:
1373 shader_addline(buffer
, "RCP T%c, %s.z;\n", 'A' + tmpreg
, regstr
);
1374 shader_addline(buffer
, "MUL T%c, %s, T%c;\n", 'A' + tmpreg
, regstr
, 'A' + tmpreg
);
1376 case WINED3DSPSM_DW
:
1377 shader_addline(buffer
, "RCP T%c, %s.w;\n", 'A' + tmpreg
, regstr
);
1378 shader_addline(buffer
, "MUL T%c, %s, T%c;\n", 'A' + tmpreg
, regstr
, 'A' + tmpreg
);
1380 case WINED3DSPSM_ABS
:
1381 if(ctx
->target_version
>= NV2
) {
1382 sprintf(outregstr
, "|%s%s|", regstr
, swzstr
);
1385 shader_addline(buffer
, "ABS T%c, %s;\n", 'A' + tmpreg
, regstr
);
1388 case WINED3DSPSM_ABSNEG
:
1389 if(ctx
->target_version
>= NV2
) {
1390 sprintf(outregstr
, "-|%s%s|", regstr
, swzstr
);
1392 shader_addline(buffer
, "ABS T%c, %s;\n", 'A' + tmpreg
, regstr
);
1393 sprintf(outregstr
, "-T%c%s", 'A' + tmpreg
, swzstr
);
1398 sprintf(outregstr
, "%s%s", regstr
, swzstr
);
1402 /* Return modified or original register, with swizzle */
1404 sprintf(outregstr
, "T%c%s", 'A' + tmpreg
, swzstr
);
1407 static void pshader_hw_bem(const struct wined3d_shader_instruction
*ins
)
1409 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1410 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1412 char src_name
[2][50];
1413 DWORD sampler_code
= dst
->reg
.idx
;
1415 shader_arb_get_dst_param(ins
, dst
, dst_name
);
1417 /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed
1419 * Keep in mind that src_name[1] can be "TB" and src_name[0] can be "TA" because modifiers like _x2 are valid
1420 * with bem. So delay loading the first parameter until after the perturbation calculation which needs two
1423 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
1424 shader_addline(buffer
, "SWZ TA, bumpenvmat%d, x, z, 0, 0;\n", sampler_code
);
1425 shader_addline(buffer
, "DP3 TC.r, TA, %s;\n", src_name
[1]);
1426 shader_addline(buffer
, "SWZ TA, bumpenvmat%d, y, w, 0, 0;\n", sampler_code
);
1427 shader_addline(buffer
, "DP3 TC.g, TA, %s;\n", src_name
[1]);
1429 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
[0]);
1430 shader_addline(buffer
, "ADD %s, %s, TC;\n", dst_name
, src_name
[0]);
1433 static DWORD
negate_modifiers(DWORD mod
, char *extra_char
)
1438 case WINED3DSPSM_NONE
: return WINED3DSPSM_NEG
;
1439 case WINED3DSPSM_NEG
: return WINED3DSPSM_NONE
;
1440 case WINED3DSPSM_BIAS
: return WINED3DSPSM_BIASNEG
;
1441 case WINED3DSPSM_BIASNEG
: return WINED3DSPSM_BIAS
;
1442 case WINED3DSPSM_SIGN
: return WINED3DSPSM_SIGNNEG
;
1443 case WINED3DSPSM_SIGNNEG
: return WINED3DSPSM_SIGN
;
1444 case WINED3DSPSM_COMP
: *extra_char
= '-'; return WINED3DSPSM_COMP
;
1445 case WINED3DSPSM_X2
: return WINED3DSPSM_X2NEG
;
1446 case WINED3DSPSM_X2NEG
: return WINED3DSPSM_X2
;
1447 case WINED3DSPSM_DZ
: *extra_char
= '-'; return WINED3DSPSM_DZ
;
1448 case WINED3DSPSM_DW
: *extra_char
= '-'; return WINED3DSPSM_DW
;
1449 case WINED3DSPSM_ABS
: return WINED3DSPSM_ABSNEG
;
1450 case WINED3DSPSM_ABSNEG
: return WINED3DSPSM_ABS
;
1452 FIXME("Unknown modifier %u\n", mod
);
1456 static void pshader_hw_cnd(const struct wined3d_shader_instruction
*ins
)
1458 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1459 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1461 char src_name
[3][50];
1462 DWORD shader_version
= WINED3D_SHADER_VERSION(ins
->ctx
->reg_maps
->shader_version
.major
,
1463 ins
->ctx
->reg_maps
->shader_version
.minor
);
1466 shader_arb_get_dst_param(ins
, dst
, dst_name
);
1467 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
1469 /* The coissue flag changes the semantic of the cnd instruction in <= 1.3 shaders */
1470 if (shader_version
<= WINED3D_SHADER_VERSION(1, 3) && ins
->coissue
)
1472 shader_addline(buffer
, "MOV%s %s, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name
[1]);
1474 struct wined3d_shader_src_param src0_copy
= ins
->src
[0];
1477 /* src0 may have a negate srcmod set, so we can't blindly add "-" to the name */
1478 src0_copy
.modifiers
= negate_modifiers(src0_copy
.modifiers
, &extra_neg
);
1480 shader_arb_get_src_param(ins
, &src0_copy
, 0, src_name
[0]);
1481 shader_arb_get_src_param(ins
, &ins
->src
[2], 2, src_name
[2]);
1482 shader_addline(buffer
, "ADD TA, %c%s, coefdiv.x;\n", extra_neg
, src_name
[0]);
1483 /* No modifiers supported on CMP */
1484 shader_addline(buffer
, "CMP %s, TA, %s, %s;\n", dst_name
, src_name
[1], src_name
[2]);
1486 /* _SAT on CMP doesn't make much sense, but it is not a pure NOP */
1487 if(ins
->dst
[0].modifiers
& WINED3DSPDM_SATURATE
)
1489 shader_arb_get_register_name(ins
, &dst
->reg
, src_name
[0], &is_color
);
1490 shader_addline(buffer
, "MOV_SAT %s, %s;\n", dst_name
, dst_name
);
1495 static void pshader_hw_cmp(const struct wined3d_shader_instruction
*ins
)
1497 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1498 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1500 char src_name
[3][50];
1503 shader_arb_get_dst_param(ins
, dst
, dst_name
);
1505 /* Generate input register names (with modifiers) */
1506 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
[0]);
1507 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
1508 shader_arb_get_src_param(ins
, &ins
->src
[2], 2, src_name
[2]);
1510 /* No modifiers are supported on CMP */
1511 shader_addline(buffer
, "CMP %s, %s, %s, %s;\n", dst_name
,
1512 src_name
[0], src_name
[2], src_name
[1]);
1514 if(ins
->dst
[0].modifiers
& WINED3DSPDM_SATURATE
)
1516 shader_arb_get_register_name(ins
, &dst
->reg
, src_name
[0], &is_color
);
1517 shader_addline(buffer
, "MOV_SAT %s, %s;\n", dst_name
, src_name
[0]);
1521 /** Process the WINED3DSIO_DP2ADD instruction in ARB.
1522 * dst = dot2(src0, src1) + src2 */
1523 static void pshader_hw_dp2add(const struct wined3d_shader_instruction
*ins
)
1525 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1526 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1528 char src_name
[3][50];
1529 struct shader_arb_ctx_priv
*ctx
= ins
->ctx
->backend_data
;
1531 shader_arb_get_dst_param(ins
, dst
, dst_name
);
1532 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
[0]);
1533 shader_arb_get_src_param(ins
, &ins
->src
[2], 2, src_name
[2]);
1535 if(ctx
->target_version
>= NV3
)
1537 /* GL_NV_fragment_program2 has a 1:1 matching instruction */
1538 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
1539 shader_addline(buffer
, "DP2A%s %s, %s, %s, %s;\n", shader_arb_get_modifier(ins
),
1540 dst_name
, src_name
[0], src_name
[1], src_name
[2]);
1542 else if(ctx
->target_version
>= NV2
)
1544 /* dst.x = src2.?, src0.x, src1.x + src0.y * src1.y
1545 * dst.y = src2.?, src0.x, src1.z + src0.y * src1.w
1546 * dst.z = src2.?, src0.x, src1.x + src0.y * src1.y
1547 * dst.z = src2.?, src0.x, src1.z + src0.y * src1.w
1549 * Make sure that src1.zw = src1.xy, then we get a classic dp2add
1551 * .xyxy and other swizzles that we could get with this are not valid in
1552 * plain ARBfp, but luckily the NV extension grammar lifts this limitation.
1554 struct wined3d_shader_src_param tmp_param
= ins
->src
[1];
1555 DWORD swizzle
= tmp_param
.swizzle
& 0xf; /* Selects .xy */
1556 tmp_param
.swizzle
= swizzle
| (swizzle
<< 4); /* Creates .xyxy */
1558 shader_arb_get_src_param(ins
, &tmp_param
, 1, src_name
[1]);
1560 shader_addline(buffer
, "X2D%s %s, %s, %s, %s;\n", shader_arb_get_modifier(ins
),
1561 dst_name
, src_name
[2], src_name
[0], src_name
[1]);
1565 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
1566 /* Emulate a DP2 with a DP3 and 0.0. Don't use the dest as temp register, it could be src[1] or src[2]
1567 * src_name[0] can be TA, but TA is a private temp for modifiers, so it is save to overwrite
1569 shader_addline(buffer
, "MOV TA, %s;\n", src_name
[0]);
1570 shader_addline(buffer
, "MOV TA.z, 0.0;\n");
1571 shader_addline(buffer
, "DP3 TA, TA, %s;\n", src_name
[1]);
1572 shader_addline(buffer
, "ADD%s %s, TA, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name
[2]);
1576 /* Map the opcode 1-to-1 to the GL code */
1577 static void shader_hw_map2gl(const struct wined3d_shader_instruction
*ins
)
1579 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1580 const char *instruction
;
1581 char arguments
[256], dst_str
[50];
1583 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1585 switch (ins
->handler_idx
)
1587 case WINED3DSIH_ABS
: instruction
= "ABS"; break;
1588 case WINED3DSIH_ADD
: instruction
= "ADD"; break;
1589 case WINED3DSIH_CRS
: instruction
= "XPD"; break;
1590 case WINED3DSIH_DP3
: instruction
= "DP3"; break;
1591 case WINED3DSIH_DP4
: instruction
= "DP4"; break;
1592 case WINED3DSIH_DST
: instruction
= "DST"; break;
1593 case WINED3DSIH_FRC
: instruction
= "FRC"; break;
1594 case WINED3DSIH_LIT
: instruction
= "LIT"; break;
1595 case WINED3DSIH_LRP
: instruction
= "LRP"; break;
1596 case WINED3DSIH_MAD
: instruction
= "MAD"; break;
1597 case WINED3DSIH_MAX
: instruction
= "MAX"; break;
1598 case WINED3DSIH_MIN
: instruction
= "MIN"; break;
1599 case WINED3DSIH_MOV
: instruction
= "MOV"; break;
1600 case WINED3DSIH_MUL
: instruction
= "MUL"; break;
1601 case WINED3DSIH_SGE
: instruction
= "SGE"; break;
1602 case WINED3DSIH_SLT
: instruction
= "SLT"; break;
1603 case WINED3DSIH_SUB
: instruction
= "SUB"; break;
1604 case WINED3DSIH_MOVA
:instruction
= "ARR"; break;
1605 case WINED3DSIH_DSX
: instruction
= "DDX"; break;
1606 default: instruction
= "";
1607 FIXME("Unhandled opcode %#x\n", ins
->handler_idx
);
1611 /* Note that shader_arb_add_dst_param() adds spaces. */
1612 arguments
[0] = '\0';
1613 shader_arb_get_dst_param(ins
, dst
, dst_str
);
1614 for (i
= 0; i
< ins
->src_count
; ++i
)
1617 strcat(arguments
, ", ");
1618 shader_arb_get_src_param(ins
, &ins
->src
[i
], i
, operand
);
1619 strcat(arguments
, operand
);
1621 shader_addline(buffer
, "%s%s %s%s;\n", instruction
, shader_arb_get_modifier(ins
), dst_str
, arguments
);
1624 static void shader_hw_nop(const struct wined3d_shader_instruction
*ins
)
1626 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1627 shader_addline(buffer
, "NOP;\n");
1630 static void shader_hw_mov(const struct wined3d_shader_instruction
*ins
)
1632 IWineD3DBaseShaderImpl
*shader
= (IWineD3DBaseShaderImpl
*)ins
->ctx
->shader
;
1633 BOOL pshader
= shader_is_pshader_version(shader
->baseShader
.reg_maps
.shader_version
.type
);
1634 struct shader_arb_ctx_priv
*ctx
= ins
->ctx
->backend_data
;
1636 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1637 char src0_param
[256];
1639 if(ins
->handler_idx
== WINED3DSIH_MOVA
) {
1642 if(ctx
->target_version
>= NV2
) {
1643 shader_hw_map2gl(ins
);
1646 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_param
);
1647 shader_arb_get_write_mask(ins
, &ins
->dst
[0], write_mask
);
1649 /* This implements the mova formula used in GLSL. The first two instructions
1650 * prepare the sign() part. Note that it is fine to have my_sign(0.0) = 1.0
1654 * A0.x = arl(floor(abs(0.0) + 0.5) * 1.0) = floor(0.5) = 0.0 since arl does a floor
1656 * The ARL is performed when A0 is used - the requested component is read from A0_SHADOW into
1657 * A0.x. We can use the overwritten component of A0_shadow as temporary storage for the sign.
1659 shader_addline(buffer
, "SGE A0_SHADOW%s, %s, mova_const.y;\n", write_mask
, src0_param
);
1660 shader_addline(buffer
, "MAD A0_SHADOW%s, A0_SHADOW, mova_const.z, -mova_const.w;\n", write_mask
);
1662 shader_addline(buffer
, "ABS TA%s, %s;\n", write_mask
, src0_param
);
1663 shader_addline(buffer
, "ADD TA%s, TA, mova_const.x;\n", write_mask
);
1664 shader_addline(buffer
, "FLR TA%s, TA;\n", write_mask
);
1665 if (((IWineD3DVertexShaderImpl
*)shader
)->rel_offset
)
1667 shader_addline(buffer
, "ADD TA%s, TA, helper_const.z;\n", write_mask
);
1669 shader_addline(buffer
, "MUL A0_SHADOW%s, TA, A0_SHADOW;\n", write_mask
);
1671 ((struct shader_arb_ctx_priv
*)ins
->ctx
->backend_data
)->addr_reg
[0] = '\0';
1672 } else if (ins
->ctx
->reg_maps
->shader_version
.major
== 1
1673 && !shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
)
1674 && ins
->dst
[0].reg
.type
== WINED3DSPR_ADDR
)
1676 src0_param
[0] = '\0';
1677 if (((IWineD3DVertexShaderImpl
*)shader
)->rel_offset
)
1679 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_param
);
1680 shader_addline(buffer
, "ADD TA.x, %s, helper_const.z;\n", src0_param
);
1681 shader_addline(buffer
, "ARL A0.x, TA.x;\n");
1685 /* Apple's ARB_vertex_program implementation does not accept an ARL source argument
1686 * with more than one component. Thus replicate the first source argument over all
1687 * 4 components. For example, .xyzw -> .x (or better: .xxxx), .zwxy -> .z, etc) */
1688 struct wined3d_shader_src_param tmp_src
= ins
->src
[0];
1689 tmp_src
.swizzle
= (tmp_src
.swizzle
& 0x3) * 0x55;
1690 shader_arb_get_src_param(ins
, &tmp_src
, 0, src0_param
);
1691 shader_addline(buffer
, "ARL A0.x, %s;\n", src0_param
);
1694 else if(ins
->dst
[0].reg
.type
== WINED3DSPR_COLOROUT
&& ins
->dst
[0].reg
.idx
== 0 && pshader
)
1696 IWineD3DPixelShaderImpl
*ps
= (IWineD3DPixelShaderImpl
*) shader
;
1697 if(ctx
->cur_ps_args
->super
.srgb_correction
&& ps
->color0_mov
)
1699 shader_addline(buffer
, "#mov handled in srgb write code\n");
1702 shader_hw_map2gl(ins
);
1706 shader_hw_map2gl(ins
);
1710 static void pshader_hw_texkill(const struct wined3d_shader_instruction
*ins
)
1712 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1713 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1716 /* No swizzles are allowed in d3d's texkill. PS 1.x ignores the 4th component as documented,
1717 * but >= 2.0 honors it(undocumented, but tested by the d3d9 testsuit)
1719 shader_arb_get_dst_param(ins
, dst
, reg_dest
);
1721 if (ins
->ctx
->reg_maps
->shader_version
.major
>= 2)
1723 const char *kilsrc
= "TA";
1726 shader_arb_get_register_name(ins
, &dst
->reg
, reg_dest
, &is_color
);
1727 if(dst
->write_mask
== WINED3DSP_WRITEMASK_ALL
)
1733 /* Sigh. KIL doesn't support swizzles/writemasks. KIL passes a writemask, but ".xy" for example
1734 * is not valid as a swizzle in ARB (needs ".xyyy"). Use SWZ to load the register properly, and set
1735 * masked out components to 0(won't kill)
1737 char x
= '0', y
= '0', z
= '0', w
= '0';
1738 if(dst
->write_mask
& WINED3DSP_WRITEMASK_0
) x
= 'x';
1739 if(dst
->write_mask
& WINED3DSP_WRITEMASK_1
) y
= 'y';
1740 if(dst
->write_mask
& WINED3DSP_WRITEMASK_2
) z
= 'z';
1741 if(dst
->write_mask
& WINED3DSP_WRITEMASK_3
) w
= 'w';
1742 shader_addline(buffer
, "SWZ TA, %s, %c, %c, %c, %c;\n", reg_dest
, x
, y
, z
, w
);
1744 shader_addline(buffer
, "KIL %s;\n", kilsrc
);
1746 /* ARB fp doesn't like swizzles on the parameter of the KIL instruction. To mask the 4th component,
1747 * copy the register into our general purpose TMP variable, overwrite .w and pass TMP to KIL
1749 * ps_1_3 shaders use the texcoord incarnation of the Tx register. ps_1_4 shaders can use the same,
1750 * or pass in any temporary register(in shader phase 2)
1752 if(ins
->ctx
->reg_maps
->shader_version
.minor
<= 3) {
1753 sprintf(reg_dest
, "fragment.texcoord[%u]", dst
->reg
.idx
);
1755 shader_arb_get_dst_param(ins
, dst
, reg_dest
);
1757 shader_addline(buffer
, "SWZ TA, %s, x, y, z, 1;\n", reg_dest
);
1758 shader_addline(buffer
, "KIL TA;\n");
1762 static void pshader_hw_tex(const struct wined3d_shader_instruction
*ins
)
1764 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
1765 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
1766 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1767 DWORD shader_version
= WINED3D_SHADER_VERSION(ins
->ctx
->reg_maps
->shader_version
.major
,
1768 ins
->ctx
->reg_maps
->shader_version
.minor
);
1769 struct wined3d_shader_src_param src
;
1773 DWORD reg_sampler_code
;
1776 /* All versions have a destination register */
1777 shader_arb_get_dst_param(ins
, dst
, reg_dest
);
1779 /* 1.0-1.4: Use destination register number as texture code.
1780 2.0+: Use provided sampler number as texure code. */
1781 if (shader_version
< WINED3D_SHADER_VERSION(2,0))
1782 reg_sampler_code
= dst
->reg
.idx
;
1784 reg_sampler_code
= ins
->src
[1].reg
.idx
;
1786 /* 1.0-1.3: Use the texcoord varying.
1787 1.4+: Use provided coordinate source register. */
1788 if (shader_version
< WINED3D_SHADER_VERSION(1,4))
1789 sprintf(reg_coord
, "fragment.texcoord[%u]", reg_sampler_code
);
1791 /* TEX is the only instruction that can handle DW and DZ natively */
1793 if(src
.modifiers
== WINED3DSPSM_DW
) src
.modifiers
= WINED3DSPSM_NONE
;
1794 if(src
.modifiers
== WINED3DSPSM_DZ
) src
.modifiers
= WINED3DSPSM_NONE
;
1795 shader_arb_get_src_param(ins
, &src
, 0, reg_coord
);
1799 * 1.1, 1.2, 1.3: Use WINED3DTSS_TEXTURETRANSFORMFLAGS
1800 * 1.4: Use WINED3DSPSM_DZ or WINED3DSPSM_DW on src[0]
1801 * 2.0+: Use WINED3DSI_TEXLD_PROJECT on the opcode
1803 if (shader_version
< WINED3D_SHADER_VERSION(1,4))
1806 if(reg_sampler_code
< MAX_TEXTURES
) {
1807 flags
= deviceImpl
->stateBlock
->textureState
[reg_sampler_code
][WINED3DTSS_TEXTURETRANSFORMFLAGS
];
1809 if (flags
& WINED3DTTFF_PROJECTED
) {
1810 myflags
|= TEX_PROJ
;
1813 else if (shader_version
< WINED3D_SHADER_VERSION(2,0))
1815 DWORD src_mod
= ins
->src
[0].modifiers
;
1816 if (src_mod
== WINED3DSPSM_DZ
) {
1817 /* TXP cannot handle DZ natively, so move the z coordinate to .w. reg_coord is a read-only
1818 * varying register, so we need a temp reg
1820 shader_addline(ins
->ctx
->buffer
, "SWZ TA, %s, x, y, z, z;\n", reg_coord
);
1821 strcpy(reg_coord
, "TA");
1822 myflags
|= TEX_PROJ
;
1823 } else if(src_mod
== WINED3DSPSM_DW
) {
1824 myflags
|= TEX_PROJ
;
1827 if (ins
->flags
& WINED3DSI_TEXLD_PROJECT
) myflags
|= TEX_PROJ
;
1828 if (ins
->flags
& WINED3DSI_TEXLD_BIAS
) myflags
|= TEX_BIAS
;
1830 shader_hw_sample(ins
, reg_sampler_code
, reg_dest
, reg_coord
, myflags
, NULL
, NULL
);
1833 static void pshader_hw_texcoord(const struct wined3d_shader_instruction
*ins
)
1835 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1836 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1837 DWORD shader_version
= WINED3D_SHADER_VERSION(ins
->ctx
->reg_maps
->shader_version
.major
,
1838 ins
->ctx
->reg_maps
->shader_version
.minor
);
1841 if (shader_version
< WINED3D_SHADER_VERSION(1,4))
1843 DWORD reg
= dst
->reg
.idx
;
1845 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1846 shader_addline(buffer
, "MOV_SAT %s, fragment.texcoord[%u];\n", dst_str
, reg
);
1850 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, reg_src
);
1851 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1852 shader_addline(buffer
, "MOV %s, %s;\n", dst_str
, reg_src
);
1856 static void pshader_hw_texreg2ar(const struct wined3d_shader_instruction
*ins
)
1858 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1859 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
1860 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
1863 DWORD reg1
= ins
->dst
[0].reg
.idx
;
1867 /* Note that texreg2ar treats Tx as a temporary register, not as a varying */
1868 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1869 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_str
);
1870 /* Move .x first in case src_str is "TA" */
1871 shader_addline(buffer
, "MOV TA.y, %s.x;\n", src_str
);
1872 shader_addline(buffer
, "MOV TA.x, %s.w;\n", src_str
);
1873 flags
= reg1
< MAX_TEXTURES
? deviceImpl
->stateBlock
->textureState
[reg1
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] : 0;
1874 shader_hw_sample(ins
, reg1
, dst_str
, "TA", flags
& WINED3DTTFF_PROJECTED
? TEX_PROJ
: 0, NULL
, NULL
);
1877 static void pshader_hw_texreg2gb(const struct wined3d_shader_instruction
*ins
)
1879 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1881 DWORD reg1
= ins
->dst
[0].reg
.idx
;
1885 /* Note that texreg2gb treats Tx as a temporary register, not as a varying */
1886 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1887 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_str
);
1888 shader_addline(buffer
, "MOV TA.x, %s.y;\n", src_str
);
1889 shader_addline(buffer
, "MOV TA.y, %s.z;\n", src_str
);
1890 shader_hw_sample(ins
, reg1
, dst_str
, "TA", 0, NULL
, NULL
);
1893 static void pshader_hw_texreg2rgb(const struct wined3d_shader_instruction
*ins
)
1895 DWORD reg1
= ins
->dst
[0].reg
.idx
;
1899 /* Note that texreg2rg treats Tx as a temporary register, not as a varying */
1900 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1901 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_str
);
1902 shader_hw_sample(ins
, reg1
, dst_str
, src_str
, 0, NULL
, NULL
);
1905 static void pshader_hw_texbem(const struct wined3d_shader_instruction
*ins
)
1907 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
1908 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
1909 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1910 char reg_coord
[40], dst_reg
[50], src_reg
[50];
1911 DWORD reg_dest_code
;
1913 /* All versions have a destination register. The Tx where the texture coordinates come
1914 * from is the varying incarnation of the texture register
1916 reg_dest_code
= dst
->reg
.idx
;
1917 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_reg
);
1918 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_reg
);
1919 sprintf(reg_coord
, "fragment.texcoord[%u]", reg_dest_code
);
1921 /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed
1922 * The Tx in which the perturbation map is stored is the tempreg incarnation of the texture register
1924 * GL_NV_fragment_program_option could handle this in one instruction via X2D:
1925 * X2D TA.xy, fragment.texcoord, T%u, bumpenvmat%u.xzyw
1927 * However, the NV extensions are never enabled for <= 2.0 shaders because of the performance penalty that
1928 * comes with it, and texbem is an 1.x only instruction. No 1.x instruction forces us to enable the NV
1931 shader_addline(buffer
, "SWZ TB, bumpenvmat%d, x, z, 0, 0;\n", reg_dest_code
);
1932 shader_addline(buffer
, "DP3 TA.x, TB, %s;\n", src_reg
);
1933 shader_addline(buffer
, "SWZ TB, bumpenvmat%d, y, w, 0, 0;\n", reg_dest_code
);
1934 shader_addline(buffer
, "DP3 TA.y, TB, %s;\n", src_reg
);
1936 /* with projective textures, texbem only divides the static texture coord, not the displacement,
1937 * so we can't let the GL handle this.
1939 if (((IWineD3DDeviceImpl
*) This
->baseShader
.device
)->stateBlock
->textureState
[reg_dest_code
][WINED3DTSS_TEXTURETRANSFORMFLAGS
]
1940 & WINED3DTTFF_PROJECTED
) {
1941 shader_addline(buffer
, "RCP TB.w, %s.w;\n", reg_coord
);
1942 shader_addline(buffer
, "MUL TB.xy, %s, TB.w;\n", reg_coord
);
1943 shader_addline(buffer
, "ADD TA.xy, TA, TB;\n");
1945 shader_addline(buffer
, "ADD TA.xy, TA, %s;\n", reg_coord
);
1948 shader_hw_sample(ins
, reg_dest_code
, dst_reg
, "TA", 0, NULL
, NULL
);
1950 if (ins
->handler_idx
== WINED3DSIH_TEXBEML
)
1952 /* No src swizzles are allowed, so this is ok */
1953 shader_addline(buffer
, "MAD TA, %s.z, luminance%d.x, luminance%d.y;\n",
1954 src_reg
, reg_dest_code
, reg_dest_code
);
1955 shader_addline(buffer
, "MUL %s, %s, TA;\n", dst_reg
, dst_reg
);
1959 static void pshader_hw_texm3x2pad(const struct wined3d_shader_instruction
*ins
)
1961 DWORD reg
= ins
->dst
[0].reg
.idx
;
1962 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1963 char src0_name
[50], dst_name
[50];
1965 struct wined3d_shader_register tmp_reg
= ins
->dst
[0].reg
;
1967 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
1968 /* The next instruction will be a texm3x2tex or texm3x2depth that writes to the uninitialized
1969 * T<reg+1> register. Use this register to store the calculated vector
1971 tmp_reg
.idx
= reg
+ 1;
1972 shader_arb_get_register_name(ins
, &tmp_reg
, dst_name
, &is_color
);
1973 shader_addline(buffer
, "DP3 %s.x, fragment.texcoord[%u], %s;\n", dst_name
, reg
, src0_name
);
1976 static void pshader_hw_texm3x2tex(const struct wined3d_shader_instruction
*ins
)
1978 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
1979 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
1981 DWORD reg
= ins
->dst
[0].reg
.idx
;
1982 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
1988 /* We know that we're writing to the uninitialized T<reg> register, so use it for temporary storage */
1989 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_reg
, &is_color
);
1991 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
1992 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
1993 shader_addline(buffer
, "DP3 %s.y, fragment.texcoord[%u], %s;\n", dst_reg
, reg
, src0_name
);
1994 flags
= reg
< MAX_TEXTURES
? deviceImpl
->stateBlock
->textureState
[reg
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] : 0;
1995 shader_hw_sample(ins
, reg
, dst_str
, dst_reg
, flags
& WINED3DTTFF_PROJECTED
? TEX_PROJ
: 0, NULL
, NULL
);
1998 static void pshader_hw_texm3x3pad(const struct wined3d_shader_instruction
*ins
)
2000 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
2001 DWORD reg
= ins
->dst
[0].reg
.idx
;
2002 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2003 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
2004 char src0_name
[50], dst_name
[50];
2005 struct wined3d_shader_register tmp_reg
= ins
->dst
[0].reg
;
2008 /* There are always 2 texm3x3pad instructions followed by one texm3x3[tex,vspec, ...] instruction, with
2009 * incrementing ins->dst[0].register_idx numbers. So the pad instruction already knows the final destination
2010 * register, and this register is uninitialized(otherwise the assembler complains that it is 'redeclared')
2012 tmp_reg
.idx
= reg
+ 2 - current_state
->current_row
;
2013 shader_arb_get_register_name(ins
, &tmp_reg
, dst_name
, &is_color
);
2015 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
2016 shader_addline(buffer
, "DP3 %s.%c, fragment.texcoord[%u], %s;\n",
2017 dst_name
, 'x' + current_state
->current_row
, reg
, src0_name
);
2018 current_state
->texcoord_w
[current_state
->current_row
++] = reg
;
2021 static void pshader_hw_texm3x3tex(const struct wined3d_shader_instruction
*ins
)
2023 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
2024 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
2026 DWORD reg
= ins
->dst
[0].reg
.idx
;
2027 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2028 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
2030 char src0_name
[50], dst_name
[50];
2033 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_name
, &is_color
);
2034 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
2035 shader_addline(buffer
, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_name
, reg
, src0_name
);
2037 /* Sample the texture using the calculated coordinates */
2038 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
2039 flags
= reg
< MAX_TEXTURES
? deviceImpl
->stateBlock
->textureState
[reg
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] : 0;
2040 shader_hw_sample(ins
, reg
, dst_str
, dst_name
, flags
& WINED3DTTFF_PROJECTED
? TEX_PROJ
: 0, NULL
, NULL
);
2041 current_state
->current_row
= 0;
2044 static void pshader_hw_texm3x3vspec(const struct wined3d_shader_instruction
*ins
)
2046 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
2047 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
2049 DWORD reg
= ins
->dst
[0].reg
.idx
;
2050 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2051 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
2057 /* Get the dst reg without writemask strings. We know this register is uninitialized, so we can use all
2058 * components for temporary data storage
2060 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_reg
, &is_color
);
2061 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
2062 shader_addline(buffer
, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_reg
, reg
, src0_name
);
2064 /* Construct the eye-ray vector from w coordinates */
2065 shader_addline(buffer
, "MOV TB.x, fragment.texcoord[%u].w;\n", current_state
->texcoord_w
[0]);
2066 shader_addline(buffer
, "MOV TB.y, fragment.texcoord[%u].w;\n", current_state
->texcoord_w
[1]);
2067 shader_addline(buffer
, "MOV TB.z, fragment.texcoord[%u].w;\n", reg
);
2069 /* Calculate reflection vector
2071 shader_addline(buffer
, "DP3 %s.w, %s, TB;\n", dst_reg
, dst_reg
);
2072 /* The .w is ignored when sampling, so I can use TB.w to calculate dot(N, N) */
2073 shader_addline(buffer
, "DP3 TB.w, %s, %s;\n", dst_reg
, dst_reg
);
2074 shader_addline(buffer
, "RCP TB.w, TB.w;\n");
2075 shader_addline(buffer
, "MUL %s.w, %s.w, TB.w;\n", dst_reg
, dst_reg
);
2076 shader_addline(buffer
, "MUL %s, %s.w, %s;\n", dst_reg
, dst_reg
, dst_reg
);
2077 shader_addline(buffer
, "MAD %s, coefmul.x, %s, -TB;\n", dst_reg
, dst_reg
);
2079 /* Sample the texture using the calculated coordinates */
2080 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
2081 flags
= reg
< MAX_TEXTURES
? deviceImpl
->stateBlock
->textureState
[reg
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] : 0;
2082 shader_hw_sample(ins
, reg
, dst_str
, dst_reg
, flags
& WINED3DTTFF_PROJECTED
? TEX_PROJ
: 0, NULL
, NULL
);
2083 current_state
->current_row
= 0;
2086 static void pshader_hw_texm3x3spec(const struct wined3d_shader_instruction
*ins
)
2088 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*)ins
->ctx
->shader
;
2089 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
2091 DWORD reg
= ins
->dst
[0].reg
.idx
;
2092 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
2093 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2100 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0_name
);
2101 shader_arb_get_src_param(ins
, &ins
->src
[0], 1, src1_name
);
2102 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_reg
, &is_color
);
2103 /* Note: dst_reg.xy is input here, generated by two texm3x3pad instructions */
2104 shader_addline(buffer
, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_reg
, reg
, src0_name
);
2106 /* Calculate reflection vector.
2109 * dst_reg.xyz = 2 * --------- * N - E
2112 * Which normalizes the normal vector
2114 shader_addline(buffer
, "DP3 %s.w, %s, %s;\n", dst_reg
, dst_reg
, src1_name
);
2115 shader_addline(buffer
, "DP3 TC.w, %s, %s;\n", dst_reg
, dst_reg
);
2116 shader_addline(buffer
, "RCP TC.w, TC.w;\n");
2117 shader_addline(buffer
, "MUL %s.w, %s.w, TC.w;\n", dst_reg
, dst_reg
);
2118 shader_addline(buffer
, "MUL %s, %s.w, %s;\n", dst_reg
, dst_reg
, dst_reg
);
2119 shader_addline(buffer
, "MAD %s, coefmul.x, %s, -%s;\n", dst_reg
, dst_reg
, src1_name
);
2121 /* Sample the texture using the calculated coordinates */
2122 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
2123 flags
= reg
< MAX_TEXTURES
? deviceImpl
->stateBlock
->textureState
[reg
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] : 0;
2124 shader_hw_sample(ins
, reg
, dst_str
, dst_reg
, flags
& WINED3DTTFF_PROJECTED
? TEX_PROJ
: 0, NULL
, NULL
);
2125 current_state
->current_row
= 0;
2128 static void pshader_hw_texdepth(const struct wined3d_shader_instruction
*ins
)
2130 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
2131 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2134 /* texdepth has an implicit destination, the fragment depth value. It's only parameter,
2135 * which is essentially an input, is the destination register because it is the first
2136 * parameter. According to the msdn, this must be register r5, but let's keep it more flexible
2137 * here(writemasks/swizzles are not valid on texdepth)
2139 shader_arb_get_dst_param(ins
, dst
, dst_name
);
2141 /* According to the msdn, the source register(must be r5) is unusable after
2142 * the texdepth instruction, so we're free to modify it
2144 shader_addline(buffer
, "MIN %s.y, %s.y, one.y;\n", dst_name
, dst_name
);
2146 /* How to deal with the special case dst_name.g == 0? if r != 0, then
2147 * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct
2148 * result. But if r = 0.0, then 0 * inf = 0, which is incorrect.
2150 shader_addline(buffer
, "RCP %s.y, %s.y;\n", dst_name
, dst_name
);
2151 shader_addline(buffer
, "MUL TA.x, %s.x, %s.y;\n", dst_name
, dst_name
);
2152 shader_addline(buffer
, "MIN TA.x, TA.x, one.x;\n");
2153 shader_addline(buffer
, "MAX result.depth, TA.x, 0.0;\n");
2156 /** Process the WINED3DSIO_TEXDP3TEX instruction in ARB:
2157 * Take a 3-component dot product of the TexCoord[dstreg] and src,
2158 * then perform a 1D texture lookup from stage dstregnum, place into dst. */
2159 static void pshader_hw_texdp3tex(const struct wined3d_shader_instruction
*ins
)
2161 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2162 DWORD sampler_idx
= ins
->dst
[0].reg
.idx
;
2166 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0
);
2167 shader_addline(buffer
, "MOV TB, 0.0;\n");
2168 shader_addline(buffer
, "DP3 TB.x, fragment.texcoord[%u], %s;\n", sampler_idx
, src0
);
2170 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_str
);
2171 shader_hw_sample(ins
, sampler_idx
, dst_str
, "TB", 0 /* Only one coord, can't be projected */, NULL
, NULL
);
2174 /** Process the WINED3DSIO_TEXDP3 instruction in ARB:
2175 * Take a 3-component dot product of the TexCoord[dstreg] and src. */
2176 static void pshader_hw_texdp3(const struct wined3d_shader_instruction
*ins
)
2178 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
2181 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2183 /* Handle output register */
2184 shader_arb_get_dst_param(ins
, dst
, dst_str
);
2185 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0
);
2186 shader_addline(buffer
, "DP3 %s, fragment.texcoord[%u], %s;\n", dst_str
, dst
->reg
.idx
, src0
);
2189 /** Process the WINED3DSIO_TEXM3X3 instruction in ARB
2190 * Perform the 3rd row of a 3x3 matrix multiply */
2191 static void pshader_hw_texm3x3(const struct wined3d_shader_instruction
*ins
)
2193 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
2194 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2195 char dst_str
[50], dst_name
[50];
2199 shader_arb_get_dst_param(ins
, dst
, dst_str
);
2200 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0
);
2201 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_name
, &is_color
);
2202 shader_addline(buffer
, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_name
, dst
->reg
.idx
, src0
);
2203 shader_addline(buffer
, "MOV %s, %s;\n", dst_str
, dst_name
);
2206 /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in ARB:
2207 * Last row of a 3x2 matrix multiply, use the result to calculate the depth:
2208 * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated)
2209 * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y
2211 static void pshader_hw_texm3x2depth(const struct wined3d_shader_instruction
*ins
)
2213 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2214 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
2215 char src0
[50], dst_name
[50];
2218 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src0
);
2219 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_name
, &is_color
);
2220 shader_addline(buffer
, "DP3 %s.y, fragment.texcoord[%u], %s;\n", dst_name
, dst
->reg
.idx
, src0
);
2222 /* How to deal with the special case dst_name.g == 0? if r != 0, then
2223 * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct
2224 * result. But if r = 0.0, then 0 * inf = 0, which is incorrect.
2226 shader_addline(buffer
, "RCP %s.y, %s.y;\n", dst_name
, dst_name
);
2227 shader_addline(buffer
, "MUL %s.x, %s.x, %s.y;\n", dst_name
, dst_name
, dst_name
);
2228 shader_addline(buffer
, "MIN %s.x, %s.x, one.x;\n", dst_name
, dst_name
);
2229 shader_addline(buffer
, "MAX result.depth, %s.x, 0.0;\n", dst_name
);
2232 /** Handles transforming all WINED3DSIO_M?x? opcodes for
2233 Vertex/Pixel shaders to ARB_vertex_program codes */
2234 static void shader_hw_mnxn(const struct wined3d_shader_instruction
*ins
)
2237 int nComponents
= 0;
2238 struct wined3d_shader_dst_param tmp_dst
= {{0}};
2239 struct wined3d_shader_src_param tmp_src
[2] = {{{0}}};
2240 struct wined3d_shader_instruction tmp_ins
;
2242 memset(&tmp_ins
, 0, sizeof(tmp_ins
));
2244 /* Set constants for the temporary argument */
2245 tmp_ins
.ctx
= ins
->ctx
;
2246 tmp_ins
.dst_count
= 1;
2247 tmp_ins
.dst
= &tmp_dst
;
2248 tmp_ins
.src_count
= 2;
2249 tmp_ins
.src
= tmp_src
;
2251 switch(ins
->handler_idx
)
2253 case WINED3DSIH_M4x4
:
2255 tmp_ins
.handler_idx
= WINED3DSIH_DP4
;
2257 case WINED3DSIH_M4x3
:
2259 tmp_ins
.handler_idx
= WINED3DSIH_DP4
;
2261 case WINED3DSIH_M3x4
:
2263 tmp_ins
.handler_idx
= WINED3DSIH_DP3
;
2265 case WINED3DSIH_M3x3
:
2267 tmp_ins
.handler_idx
= WINED3DSIH_DP3
;
2269 case WINED3DSIH_M3x2
:
2271 tmp_ins
.handler_idx
= WINED3DSIH_DP3
;
2274 FIXME("Unhandled opcode %#x\n", ins
->handler_idx
);
2278 tmp_dst
= ins
->dst
[0];
2279 tmp_src
[0] = ins
->src
[0];
2280 tmp_src
[1] = ins
->src
[1];
2281 for (i
= 0; i
< nComponents
; i
++) {
2282 tmp_dst
.write_mask
= WINED3DSP_WRITEMASK_0
<< i
;
2283 shader_hw_map2gl(&tmp_ins
);
2284 ++tmp_src
[1].reg
.idx
;
2288 static void shader_hw_scalar_op(const struct wined3d_shader_instruction
*ins
)
2290 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2291 const char *instruction
;
2296 switch(ins
->handler_idx
)
2298 case WINED3DSIH_RSQ
: instruction
= "RSQ"; break;
2299 case WINED3DSIH_RCP
: instruction
= "RCP"; break;
2300 case WINED3DSIH_EXP
: instruction
= "EX2"; break;
2301 case WINED3DSIH_EXPP
: instruction
= "EXP"; break;
2302 default: instruction
= "";
2303 FIXME("Unhandled opcode %#x\n", ins
->handler_idx
);
2307 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst
); /* Destination */
2308 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src
);
2309 if (ins
->src
[0].swizzle
== WINED3DSP_NOSWIZZLE
)
2311 /* Dx sdk says .x is used if no swizzle is given, but our test shows that
2317 shader_addline(buffer
, "%s%s %s, %s;\n", instruction
, shader_arb_get_modifier(ins
), dst
, src
);
2320 static void shader_hw_nrm(const struct wined3d_shader_instruction
*ins
)
2322 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2325 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2326 BOOL pshader
= shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2328 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_name
);
2329 shader_arb_get_src_param(ins
, &ins
->src
[0], 1 /* Use TB */, src_name
);
2331 if(pshader
&& priv
->target_version
>= NV3
)
2333 shader_addline(buffer
, "NRM%s %s, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name
);
2337 shader_addline(buffer
, "DP3 TA, %s, %s;\n", src_name
, src_name
);
2338 shader_addline(buffer
, "RSQ TA, TA.x;\n");
2339 /* dst.w = src[0].w * 1 / (src.x^2 + src.y^2 + src.z^2)^(1/2) according to msdn*/
2340 shader_addline(buffer
, "MUL%s %s, %s, TA;\n", shader_arb_get_modifier(ins
), dst_name
,
2345 static void shader_hw_lrp(const struct wined3d_shader_instruction
*ins
)
2347 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2349 char src_name
[3][50];
2351 /* ARB_fragment_program has a convenient LRP instruction */
2352 if(shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
)) {
2353 shader_hw_map2gl(ins
);
2357 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_name
);
2358 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
[0]);
2359 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name
[1]);
2360 shader_arb_get_src_param(ins
, &ins
->src
[2], 2, src_name
[2]);
2362 shader_addline(buffer
, "SUB TA, %s, %s;\n", src_name
[1], src_name
[2]);
2363 shader_addline(buffer
, "MAD%s %s, %s, TA, %s;\n", shader_arb_get_modifier(ins
),
2364 dst_name
, src_name
[0], src_name
[2]);
2367 static void shader_hw_sincos(const struct wined3d_shader_instruction
*ins
)
2369 /* This instruction exists in ARB, but the d3d instruction takes two extra parameters which
2370 * must contain fixed constants. So we need a separate function to filter those constants and
2373 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2374 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2375 const struct wined3d_shader_dst_param
*dst
= &ins
->dst
[0];
2377 char src_name0
[50], src_name1
[50], src_name2
[50];
2380 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name0
);
2381 if(shader_is_pshader_version(ins
->ctx
->reg_maps
->shader_version
.type
)) {
2382 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_name
);
2383 /* No modifiers are supported on SCS */
2384 shader_addline(buffer
, "SCS %s, %s;\n", dst_name
, src_name0
);
2386 if(ins
->dst
[0].modifiers
& WINED3DSPDM_SATURATE
)
2388 shader_arb_get_register_name(ins
, &dst
->reg
, src_name0
, &is_color
);
2389 shader_addline(buffer
, "MOV_SAT %s, %s;\n", dst_name
, src_name0
);
2391 } else if(priv
->target_version
>= NV2
) {
2392 shader_arb_get_register_name(ins
, &dst
->reg
, dst_name
, &is_color
);
2394 /* Sincos writemask must be .x, .y or .xy */
2395 if(dst
->write_mask
& WINED3DSP_WRITEMASK_0
)
2396 shader_addline(buffer
, "COS%s %s.x, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name0
);
2397 if(dst
->write_mask
& WINED3DSP_WRITEMASK_1
)
2398 shader_addline(buffer
, "SIN%s %s.y, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name0
);
2400 /* Approximate sine and cosine with a taylor series, as per math textbook. The application passes 8
2401 * helper constants(D3DSINCOSCONST1 and D3DSINCOSCONST2) in src1 and src2.
2403 * sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
2404 * cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + ...
2406 * The constants we get are:
2408 * +1 +1, -1 -1 +1 +1 -1 -1
2409 * ---- , ---- , ---- , ----- , ----- , ----- , ------
2410 * 1!*2 2!*4 3!*8 4!*16 5!*32 6!*64 7!*128
2412 * If used with x^2, x^3, x^4 etc they calculate sin(x/2) and cos(x/2):
2416 * (x/2)^4 = x^4 / 16
2417 * (x/2)^5 = x^5 / 32
2420 * To get the final result:
2421 * sin(x) = 2 * sin(x/2) * cos(x/2)
2422 * cos(x) = cos(x/2)^2 - sin(x/2)^2
2423 * (from sin(x+y) and cos(x+y) rules)
2425 * As per MSDN, dst.z is undefined after the operation, and so is
2426 * dst.x and dst.y if they're masked out by the writemask. Ie
2427 * sincos dst.y, src1, c0, c1
2428 * returns the sine in dst.y. dst.x and dst.z are undefined, dst.w is not touched. The assembler
2429 * vsa.exe also stops with an error if the dest register is the same register as the source
2430 * register. This means we can use dest.xyz as temporary storage. The assembler vsa.exe output also
2431 * indicates that sincos consumes 8 instruction slots in vs_2_0(and, strangely, in vs_3_0).
2433 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name1
);
2434 shader_arb_get_src_param(ins
, &ins
->src
[2], 2, src_name2
);
2435 shader_arb_get_register_name(ins
, &dst
->reg
, dst_name
, &is_color
);
2437 shader_addline(buffer
, "MUL %s.x, %s, %s;\n", dst_name
, src_name0
, src_name0
); /* x ^ 2 */
2438 shader_addline(buffer
, "MUL TA.y, %s.x, %s;\n", dst_name
, src_name0
); /* x ^ 3 */
2439 shader_addline(buffer
, "MUL %s.y, TA.y, %s;\n", dst_name
, src_name0
); /* x ^ 4 */
2440 shader_addline(buffer
, "MUL TA.z, %s.y, %s;\n", dst_name
, src_name0
); /* x ^ 5 */
2441 shader_addline(buffer
, "MUL %s.z, TA.z, %s;\n", dst_name
, src_name0
); /* x ^ 6 */
2442 shader_addline(buffer
, "MUL TA.w, %s.z, %s;\n", dst_name
, src_name0
); /* x ^ 7 */
2446 * Unfortunately we don't get the constants in a DP4-capable form. Is there a way to
2447 * properly merge that with MULs in the code above?
2448 * The swizzles .yz and xw however fit into the .yzxw swizzle added to ps_2_0. Maybe
2449 * we can merge the sine and cosine MAD rows to calculate them together.
2451 shader_addline(buffer
, "MUL TA.x, %s, %s.w;\n", src_name0
, src_name2
); /* x^1, +1/(1!*2) */
2452 shader_addline(buffer
, "MAD TA.x, TA.y, %s.x, TA.x;\n", src_name2
); /* -1/(3!*8) */
2453 shader_addline(buffer
, "MAD TA.x, TA.z, %s.w, TA.x;\n", src_name1
); /* +1/(5!*32) */
2454 shader_addline(buffer
, "MAD TA.x, TA.w, %s.x, TA.x;\n", src_name1
); /* -1/(7!*128) */
2457 shader_addline(buffer
, "MAD TA.y, %s.x, %s.y, %s.z;\n", dst_name
, src_name2
, src_name2
); /* -1/(2!*4), +1.0 */
2458 shader_addline(buffer
, "MAD TA.y, %s.y, %s.z, TA.y;\n", dst_name
, src_name1
); /* +1/(4!*16) */
2459 shader_addline(buffer
, "MAD TA.y, %s.z, %s.y, TA.y;\n", dst_name
, src_name1
); /* -1/(6!*64) */
2461 if(dst
->write_mask
& WINED3DSP_WRITEMASK_0
) {
2463 shader_addline(buffer
, "MUL TA.z, TA.y, TA.y;\n");
2464 shader_addline(buffer
, "MAD %s.x, -TA.x, TA.x, TA.z;\n", dst_name
);
2466 if(dst
->write_mask
& WINED3DSP_WRITEMASK_1
) {
2468 shader_addline(buffer
, "MUL %s.y, TA.x, TA.y;\n", dst_name
);
2469 shader_addline(buffer
, "ADD %s.y, %s.y, %s.y;\n", dst_name
, dst_name
, dst_name
);
2474 static void shader_hw_sgn(const struct wined3d_shader_instruction
*ins
)
2476 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2479 struct shader_arb_ctx_priv
*ctx
= ins
->ctx
->backend_data
;
2481 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst_name
);
2482 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
);
2484 /* SGN is only valid in vertex shaders */
2485 if(ctx
->target_version
>= NV2
) {
2486 shader_addline(buffer
, "SSG%s %s, %s;\n", shader_arb_get_modifier(ins
), dst_name
, src_name
);
2490 /* If SRC > 0.0, -SRC < SRC = TRUE, otherwise false.
2491 * if SRC < 0.0, SRC < -SRC = TRUE. If neither is true, src = 0.0
2493 if(ins
->dst
[0].modifiers
& WINED3DSPDM_SATURATE
) {
2494 shader_addline(buffer
, "SLT %s, -%s, %s;\n", dst_name
, src_name
, src_name
);
2496 /* src contains TA? Write to the dest first. This won't overwrite our destination.
2497 * Then use TA, and calculate the final result
2499 * Not reading from TA? Store the first result in TA to avoid overwriting the
2500 * destination if src reg = dst reg
2502 if(strstr(src_name
, "TA"))
2504 shader_addline(buffer
, "SLT %s, %s, -%s;\n", dst_name
, src_name
, src_name
);
2505 shader_addline(buffer
, "SLT TA, -%s, %s;\n", src_name
, src_name
);
2506 shader_addline(buffer
, "ADD %s, %s, -TA;\n", dst_name
, dst_name
);
2510 shader_addline(buffer
, "SLT TA, -%s, %s;\n", src_name
, src_name
);
2511 shader_addline(buffer
, "SLT %s, %s, -%s;\n", dst_name
, src_name
, src_name
);
2512 shader_addline(buffer
, "ADD %s, TA, -%s;\n", dst_name
, dst_name
);
2517 static void shader_hw_dsy(const struct wined3d_shader_instruction
*ins
)
2519 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2525 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst
);
2526 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src
);
2527 shader_arb_get_register_name(ins
, &ins
->dst
[0].reg
, dst_name
, &is_color
);
2529 shader_addline(buffer
, "DDY %s, %s;\n", dst
, src
);
2530 shader_addline(buffer
, "MUL%s %s, %s, ycorrection.y;\n", shader_arb_get_modifier(ins
), dst
, dst_name
);
2533 static DWORD
abs_modifier(DWORD mod
, BOOL
*need_abs
)
2539 case WINED3DSPSM_NONE
: return WINED3DSPSM_ABS
;
2540 case WINED3DSPSM_NEG
: return WINED3DSPSM_ABS
;
2541 case WINED3DSPSM_BIAS
: *need_abs
= TRUE
; return WINED3DSPSM_BIAS
;
2542 case WINED3DSPSM_BIASNEG
: *need_abs
= TRUE
; return WINED3DSPSM_BIASNEG
;
2543 case WINED3DSPSM_SIGN
: *need_abs
= TRUE
; return WINED3DSPSM_SIGN
;
2544 case WINED3DSPSM_SIGNNEG
: *need_abs
= TRUE
; return WINED3DSPSM_SIGNNEG
;
2545 case WINED3DSPSM_COMP
: *need_abs
= TRUE
; return WINED3DSPSM_COMP
;
2546 case WINED3DSPSM_X2
: *need_abs
= TRUE
; return WINED3DSPSM_X2
;
2547 case WINED3DSPSM_X2NEG
: *need_abs
= TRUE
; return WINED3DSPSM_X2NEG
;
2548 case WINED3DSPSM_DZ
: *need_abs
= TRUE
; return WINED3DSPSM_DZ
;
2549 case WINED3DSPSM_DW
: *need_abs
= TRUE
; return WINED3DSPSM_DW
;
2550 case WINED3DSPSM_ABS
: return WINED3DSPSM_ABS
;
2551 case WINED3DSPSM_ABSNEG
: return WINED3DSPSM_ABS
;
2553 FIXME("Unknown modifier %u\n", mod
);
2557 static void shader_hw_log_pow(const struct wined3d_shader_instruction
*ins
)
2559 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2560 char src0
[50], src1
[50], dst
[50];
2561 struct wined3d_shader_src_param src0_copy
= ins
->src
[0];
2562 BOOL need_abs
= FALSE
;
2566 switch(ins
->handler_idx
)
2568 case WINED3DSIH_LOG
: instr
= "LG2"; break;
2569 case WINED3DSIH_LOGP
: instr
= "LOG"; break;
2570 case WINED3DSIH_POW
: instr
= "POW"; arg2
= TRUE
; break;
2572 ERR("Unexpected instruction %d\n", ins
->handler_idx
);
2576 /* LOG, LOGP and POW operate on the absolute value of the input */
2577 src0_copy
.modifiers
= abs_modifier(src0_copy
.modifiers
, &need_abs
);
2579 shader_arb_get_dst_param(ins
, &ins
->dst
[0], dst
);
2580 shader_arb_get_src_param(ins
, &src0_copy
, 0, src0
);
2581 if(arg2
) shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src1
);
2585 shader_addline(buffer
, "ABS TA, %s;\n", src0
);
2588 shader_addline(buffer
, "%s%s %s, TA, %s;\n", instr
, shader_arb_get_modifier(ins
), dst
, src1
);
2592 shader_addline(buffer
, "%s%s %s, TA;\n", instr
, shader_arb_get_modifier(ins
), dst
);
2597 shader_addline(buffer
, "%s%s %s, %s, %s;\n", instr
, shader_arb_get_modifier(ins
), dst
, src0
, src1
);
2601 shader_addline(buffer
, "%s%s %s, %s;\n", instr
, shader_arb_get_modifier(ins
), dst
, src0
);
2605 static void shader_hw_loop(const struct wined3d_shader_instruction
*ins
)
2607 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2609 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2612 shader_arb_get_src_param(ins
, &ins
->src
[1], 0, src_name
);
2616 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2617 struct list
*e
= list_head(&priv
->control_frames
);
2618 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2620 if(priv
->loop_depth
> 1) shader_addline(buffer
, "PUSHA aL;\n");
2621 /* The constant loader makes sure to load -1 into iX.w */
2622 shader_addline(buffer
, "ARLC aL, %s.xywz;\n", src_name
);
2623 shader_addline(buffer
, "BRA loop_%u_end (LE.x);\n", control_frame
->no
.loop
);
2624 shader_addline(buffer
, "loop_%u_start:\n", control_frame
->no
.loop
);
2628 shader_addline(buffer
, "LOOP %s;\n", src_name
);
2632 static void shader_hw_rep(const struct wined3d_shader_instruction
*ins
)
2634 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2636 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2638 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name
);
2640 /* The constant loader makes sure to load -1 into iX.w */
2643 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2644 struct list
*e
= list_head(&priv
->control_frames
);
2645 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2647 if(priv
->loop_depth
> 1) shader_addline(buffer
, "PUSHA aL;\n");
2649 shader_addline(buffer
, "ARLC aL, %s.xywz;\n", src_name
);
2650 shader_addline(buffer
, "BRA loop_%u_end (LE.x);\n", control_frame
->no
.loop
);
2651 shader_addline(buffer
, "loop_%u_start:\n", control_frame
->no
.loop
);
2655 shader_addline(buffer
, "REP %s;\n", src_name
);
2659 static void shader_hw_endloop(const struct wined3d_shader_instruction
*ins
)
2661 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2662 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2666 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2667 struct list
*e
= list_head(&priv
->control_frames
);
2668 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2670 shader_addline(buffer
, "ARAC aL.xy, aL;\n");
2671 shader_addline(buffer
, "BRA loop_%u_start (GT.x);\n", control_frame
->no
.loop
);
2672 shader_addline(buffer
, "loop_%u_end:\n", control_frame
->no
.loop
);
2674 if(priv
->loop_depth
> 1) shader_addline(buffer
, "POPA aL;\n");
2678 shader_addline(buffer
, "ENDLOOP;\n");
2682 static void shader_hw_endrep(const struct wined3d_shader_instruction
*ins
)
2684 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2685 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2689 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2690 struct list
*e
= list_head(&priv
->control_frames
);
2691 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2693 shader_addline(buffer
, "ARAC aL.xy, aL;\n");
2694 shader_addline(buffer
, "BRA loop_%u_start (GT.x);\n", control_frame
->no
.loop
);
2695 shader_addline(buffer
, "loop_%u_end:\n", control_frame
->no
.loop
);
2697 if(priv
->loop_depth
> 1) shader_addline(buffer
, "POPA aL;\n");
2701 shader_addline(buffer
, "ENDREP;\n");
2705 static const struct control_frame
*find_last_loop(const struct shader_arb_ctx_priv
*priv
)
2707 struct control_frame
*control_frame
;
2709 LIST_FOR_EACH_ENTRY(control_frame
, &priv
->control_frames
, struct control_frame
, entry
)
2711 if(control_frame
->type
== LOOP
|| control_frame
->type
== REP
) return control_frame
;
2713 ERR("Could not find loop for break\n");
2717 static void shader_hw_break(const struct wined3d_shader_instruction
*ins
)
2719 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2720 const struct control_frame
*control_frame
= find_last_loop(ins
->ctx
->backend_data
);
2721 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2725 shader_addline(buffer
, "BRA loop_%u_end;\n", control_frame
->no
.loop
);
2729 shader_addline(buffer
, "BRK;\n");
2733 static const char *get_compare(COMPARISON_TYPE flags
)
2737 case COMPARISON_GT
: return "GT";
2738 case COMPARISON_EQ
: return "EQ";
2739 case COMPARISON_GE
: return "GE";
2740 case COMPARISON_LT
: return "LT";
2741 case COMPARISON_NE
: return "NE";
2742 case COMPARISON_LE
: return "LE";
2744 FIXME("Unrecognized comparison value: %u\n", flags
);
2749 static COMPARISON_TYPE
invert_compare(COMPARISON_TYPE flags
)
2753 case COMPARISON_GT
: return COMPARISON_LE
;
2754 case COMPARISON_EQ
: return COMPARISON_NE
;
2755 case COMPARISON_GE
: return COMPARISON_LT
;
2756 case COMPARISON_LT
: return COMPARISON_GE
;
2757 case COMPARISON_NE
: return COMPARISON_EQ
;
2758 case COMPARISON_LE
: return COMPARISON_GT
;
2760 FIXME("Unrecognized comparison value: %u\n", flags
);
2765 static void shader_hw_breakc(const struct wined3d_shader_instruction
*ins
)
2767 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2768 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2769 const struct control_frame
*control_frame
= find_last_loop(ins
->ctx
->backend_data
);
2772 const char *comp
= get_compare(ins
->flags
);
2774 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name0
);
2775 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name1
);
2779 /* SUBC CC, src0, src1" works only in pixel shaders, so use TA to throw
2780 * away the subtraction result
2782 shader_addline(buffer
, "SUBC TA, %s, %s;\n", src_name0
, src_name1
);
2783 shader_addline(buffer
, "BRA loop_%u_end (%s.x);\n", control_frame
->no
.loop
, comp
);
2787 shader_addline(buffer
, "SUBC TA, %s, %s;\n", src_name0
, src_name1
);
2788 shader_addline(buffer
, "BRK (%s.x);\n", comp
);
2792 static void shader_hw_ifc(const struct wined3d_shader_instruction
*ins
)
2794 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2795 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2796 struct list
*e
= list_head(&priv
->control_frames
);
2797 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2801 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2803 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, src_name0
);
2804 shader_arb_get_src_param(ins
, &ins
->src
[1], 1, src_name1
);
2808 /* Invert the flag. We jump to the else label if the condition is NOT true */
2809 comp
= get_compare(invert_compare(ins
->flags
));
2810 shader_addline(buffer
, "SUBC TA, %s, %s;\n", src_name0
, src_name1
);
2811 shader_addline(buffer
, "BRA ifc_%u_else (%s.x);\n", control_frame
->no
.ifc
, comp
);
2815 comp
= get_compare(ins
->flags
);
2816 shader_addline(buffer
, "SUBC TA, %s, %s;\n", src_name0
, src_name1
);
2817 shader_addline(buffer
, "IF %s.x;\n", comp
);
2821 static void shader_hw_else(const struct wined3d_shader_instruction
*ins
)
2823 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2824 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2825 struct list
*e
= list_head(&priv
->control_frames
);
2826 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2827 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2831 shader_addline(buffer
, "BRA ifc_%u_endif;\n", control_frame
->no
.ifc
);
2832 shader_addline(buffer
, "ifc_%u_else:\n", control_frame
->no
.ifc
);
2833 control_frame
->had_else
= TRUE
;
2837 shader_addline(buffer
, "ELSE;\n");
2841 static void shader_hw_endif(const struct wined3d_shader_instruction
*ins
)
2843 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2844 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2845 struct list
*e
= list_head(&priv
->control_frames
);
2846 struct control_frame
*control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
2847 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
2851 if(control_frame
->had_else
)
2853 shader_addline(buffer
, "ifc_%u_endif:\n", control_frame
->no
.ifc
);
2857 shader_addline(buffer
, "#No else branch. else is endif\n");
2858 shader_addline(buffer
, "ifc_%u_else:\n", control_frame
->no
.ifc
);
2863 shader_addline(buffer
, "ENDIF;\n");
2867 static void shader_hw_texldd(const struct wined3d_shader_instruction
*ins
)
2869 DWORD sampler_idx
= ins
->src
[1].reg
.idx
;
2871 char reg_src
[3][40];
2872 DWORD flags
= TEX_DERIV
;
2874 shader_arb_get_dst_param(ins
, &ins
->dst
[0], reg_dest
);
2875 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, reg_src
[0]);
2876 shader_arb_get_src_param(ins
, &ins
->src
[2], 1, reg_src
[1]);
2877 shader_arb_get_src_param(ins
, &ins
->src
[3], 2, reg_src
[2]);
2879 if (ins
->flags
& WINED3DSI_TEXLD_PROJECT
) flags
|= TEX_PROJ
;
2880 if (ins
->flags
& WINED3DSI_TEXLD_BIAS
) flags
|= TEX_BIAS
;
2882 shader_hw_sample(ins
, sampler_idx
, reg_dest
, reg_src
[0], flags
, reg_src
[1], reg_src
[2]);
2885 static void shader_hw_texldl(const struct wined3d_shader_instruction
*ins
)
2887 DWORD sampler_idx
= ins
->src
[1].reg
.idx
;
2890 DWORD flags
= TEX_LOD
;
2892 shader_arb_get_dst_param(ins
, &ins
->dst
[0], reg_dest
);
2893 shader_arb_get_src_param(ins
, &ins
->src
[0], 0, reg_coord
);
2895 if (ins
->flags
& WINED3DSI_TEXLD_PROJECT
) flags
|= TEX_PROJ
;
2896 if (ins
->flags
& WINED3DSI_TEXLD_BIAS
) flags
|= TEX_BIAS
;
2898 shader_hw_sample(ins
, sampler_idx
, reg_dest
, reg_coord
, flags
, NULL
, NULL
);
2901 static void shader_hw_label(const struct wined3d_shader_instruction
*ins
)
2903 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
2904 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
2906 priv
->in_main_func
= FALSE
;
2907 /* Call instructions activate the NV extensions, not labels and rets. If there is an uncalled
2908 * subroutine, don't generate a label that will make GL complain
2910 if(priv
->target_version
== ARB
) return;
2912 shader_addline(buffer
, "l%u:\n", ins
->src
[0].reg
.idx
);
2915 static void vshader_add_footer(IWineD3DVertexShaderImpl
*This
, struct wined3d_shader_buffer
*buffer
,
2916 const struct arb_vs_compile_args
*args
, struct shader_arb_ctx_priv
*priv_ctx
)
2918 const shader_reg_maps
*reg_maps
= &This
->baseShader
.reg_maps
;
2919 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)This
->baseShader
.device
;
2920 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2923 /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used
2924 * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE),
2925 * the fog frag coord is thrown away. If the fog frag coord is used, but not written by
2926 * the shader, it is set to 0.0(fully fogged, since start = 1.0, end = 0.0)
2928 if(args
->super
.fog_src
== VS_FOG_Z
) {
2929 shader_addline(buffer
, "MOV result.fogcoord, TMP_OUT.z;\n");
2930 } else if (!reg_maps
->fog
) {
2931 /* posFixup.x is always 1.0, so we can savely use it */
2932 shader_addline(buffer
, "ADD result.fogcoord, posFixup.x, -posFixup.x;\n");
2935 /* Write the final position.
2937 * OpenGL coordinates specify the center of the pixel while d3d coords specify
2938 * the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
2939 * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
2940 * contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that.
2942 shader_addline(buffer
, "MUL TA, posFixup, TMP_OUT.w;\n");
2943 shader_addline(buffer
, "ADD TMP_OUT.x, TMP_OUT.x, TA.z;\n");
2944 shader_addline(buffer
, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TA.w;\n");
2946 if(use_nv_clip(gl_info
) && priv_ctx
->target_version
>= NV2
)
2948 if(args
->super
.clip_enabled
)
2950 for(i
= 0; i
< priv_ctx
->vs_clipplanes
; i
++)
2952 shader_addline(buffer
, "DP4 result.clip[%u].x, TMP_OUT, state.clip[%u].plane;\n", i
, i
);
2956 else if(args
->clip
.boolclip
.clip_texcoord
)
2958 unsigned int cur_clip
= 0;
2959 char component
[4] = {'x', 'y', 'z', 'w'};
2961 for (i
= 0; i
< gl_info
->limits
.clipplanes
; ++i
)
2963 if(args
->clip
.boolclip
.clipplane_mask
& (1 << i
))
2965 shader_addline(buffer
, "DP4 TA.%c, TMP_OUT, state.clip[%u].plane;\n",
2966 component
[cur_clip
++], i
);
2972 shader_addline(buffer
, "MOV TA, -helper_const.w;\n");
2975 shader_addline(buffer
, "MOV TA.yzw, -helper_const.w;\n");
2978 shader_addline(buffer
, "MOV TA.zw, -helper_const.w;\n");
2981 shader_addline(buffer
, "MOV TA.w, -helper_const.w;\n");
2984 shader_addline(buffer
, "MOV result.texcoord[%u], TA;\n",
2985 args
->clip
.boolclip
.clip_texcoord
- 1);
2988 /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
2989 * and the glsl equivalent
2991 if(need_helper_const(gl_info
)) {
2992 shader_addline(buffer
, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n");
2994 shader_addline(buffer
, "ADD TMP_OUT.z, TMP_OUT.z, TMP_OUT.z;\n");
2995 shader_addline(buffer
, "ADD TMP_OUT.z, TMP_OUT.z, -TMP_OUT.w;\n");
2998 shader_addline(buffer
, "MOV result.position, TMP_OUT;\n");
3000 priv_ctx
->footer_written
= TRUE
;
3003 static void shader_hw_ret(const struct wined3d_shader_instruction
*ins
)
3005 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
3006 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
3007 IWineD3DBaseShaderImpl
*shader
= (IWineD3DBaseShaderImpl
*) ins
->ctx
->shader
;
3008 BOOL vshader
= shader_is_vshader_version(ins
->ctx
->reg_maps
->shader_version
.type
);
3010 if(priv
->target_version
== ARB
) return;
3014 if(priv
->in_main_func
) vshader_add_footer((IWineD3DVertexShaderImpl
*) shader
, buffer
, priv
->cur_vs_args
, priv
);
3017 shader_addline(buffer
, "RET;\n");
3020 static void shader_hw_call(const struct wined3d_shader_instruction
*ins
)
3022 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
3023 shader_addline(buffer
, "CAL l%u;\n", ins
->src
[0].reg
.idx
);
3026 /* GL locking is done by the caller */
3027 static GLuint
create_arb_blt_vertex_program(const struct wined3d_gl_info
*gl_info
)
3029 GLuint program_id
= 0;
3032 const char *blt_vprogram
=
3034 "PARAM c[1] = { { 1, 0.5 } };\n"
3035 "MOV result.position, vertex.position;\n"
3036 "MOV result.color, c[0].x;\n"
3037 "MOV result.texcoord[0], vertex.texcoord[0];\n"
3040 GL_EXTCALL(glGenProgramsARB(1, &program_id
));
3041 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, program_id
));
3042 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
3043 strlen(blt_vprogram
), blt_vprogram
));
3044 checkGLcall("glProgramStringARB()");
3046 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &pos
);
3049 FIXME("Vertex program error at position %d: %s\n", pos
,
3050 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
3056 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
3057 checkGLcall("glGetProgramivARB()");
3058 if (!native
) WARN("Program exceeds native resource limits.\n");
3064 /* GL locking is done by the caller */
3065 static GLuint
create_arb_blt_fragment_program(const struct wined3d_gl_info
*gl_info
, enum tex_types tex_type
)
3067 GLuint program_id
= 0;
3070 static const char * const blt_fprograms
[tex_type_count
] =
3077 "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n"
3078 "MOV result.depth.z, R0.x;\n"
3085 "TEX R0.x, fragment.texcoord[0], texture[0], CUBE;\n"
3086 "MOV result.depth.z, R0.x;\n"
3091 "TEX R0.x, fragment.texcoord[0], texture[0], RECT;\n"
3092 "MOV result.depth.z, R0.x;\n"
3096 if (!blt_fprograms
[tex_type
])
3098 FIXME("tex_type %#x not supported\n", tex_type
);
3102 GL_EXTCALL(glGenProgramsARB(1, &program_id
));
3103 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, program_id
));
3104 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
3105 strlen(blt_fprograms
[tex_type
]), blt_fprograms
[tex_type
]));
3106 checkGLcall("glProgramStringARB()");
3108 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &pos
);
3111 FIXME("Fragment program error at position %d: %s\n", pos
,
3112 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
3118 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
3119 checkGLcall("glGetProgramivARB()");
3120 if (!native
) WARN("Program exceeds native resource limits.\n");
3126 static void arbfp_add_sRGB_correction(struct wined3d_shader_buffer
*buffer
, const char *fragcolor
,
3127 const char *tmp1
, const char *tmp2
, const char *tmp3
, const char *tmp4
, BOOL condcode
)
3129 /* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */
3133 /* Sigh. MOVC CC doesn't work, so use one of the temps as dummy dest */
3134 shader_addline(buffer
, "SUBC %s, %s.x, srgb_consts1.y;\n", tmp1
, fragcolor
);
3135 /* Calculate the > 0.0031308 case */
3136 shader_addline(buffer
, "POW %s.x (GE), %s.x, srgb_consts1.z;\n", fragcolor
, fragcolor
);
3137 shader_addline(buffer
, "POW %s.y (GE), %s.y, srgb_consts1.z;\n", fragcolor
, fragcolor
);
3138 shader_addline(buffer
, "POW %s.z (GE), %s.z, srgb_consts1.z;\n", fragcolor
, fragcolor
);
3139 shader_addline(buffer
, "MUL %s.xyz (GE), %s, srgb_consts1.w;\n", fragcolor
, fragcolor
);
3140 shader_addline(buffer
, "SUB %s.xyz (GE), %s, srgb_consts2.x;\n", fragcolor
, fragcolor
);
3141 /* Calculate the < case */
3142 shader_addline(buffer
, "MUL %s.xyz (LT), srgb_consts1.x, %s;\n", fragcolor
, fragcolor
);
3146 /* Calculate the > 0.0031308 case */
3147 shader_addline(buffer
, "POW %s.x, %s.x, srgb_consts1.z;\n", tmp1
, fragcolor
);
3148 shader_addline(buffer
, "POW %s.y, %s.y, srgb_consts1.z;\n", tmp1
, fragcolor
);
3149 shader_addline(buffer
, "POW %s.z, %s.z, srgb_consts1.z;\n", tmp1
, fragcolor
);
3150 shader_addline(buffer
, "MUL %s, %s, srgb_consts1.w;\n", tmp1
, tmp1
);
3151 shader_addline(buffer
, "SUB %s, %s, srgb_consts2.x;\n", tmp1
, tmp1
);
3152 /* Calculate the < case */
3153 shader_addline(buffer
, "MUL %s, srgb_consts1.x, %s;\n", tmp2
, fragcolor
);
3154 /* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */
3155 shader_addline(buffer
, "SLT %s, srgb_consts1.y, %s;\n", tmp3
, fragcolor
);
3156 shader_addline(buffer
, "SGE %s, srgb_consts1.y, %s;\n", tmp4
, fragcolor
);
3157 /* Store the components > 0.0031308 in the destination */
3158 shader_addline(buffer
, "MUL %s.xyz, %s, %s;\n", fragcolor
, tmp1
, tmp3
);
3159 /* Add the components that are < 0.0031308 */
3160 shader_addline(buffer
, "MAD %s.xyz, %s, %s, %s;\n", fragcolor
, tmp2
, tmp4
, fragcolor
);
3161 /* Move everything into result.color at once. Nvidia hardware cannot handle partial
3162 * result.color writes(.rgb first, then .a), or handle overwriting already written
3163 * components. The assembler uses a temporary register in this case, which is usually
3164 * not allocated from one of our registers that were used earlier.
3167 /* [0.0;1.0] clamping. Not needed, this is done implicitly */
3170 static const DWORD
*find_loop_control_values(IWineD3DBaseShaderImpl
*This
, DWORD idx
)
3172 const local_constant
*constant
;
3174 LIST_FOR_EACH_ENTRY(constant
, &This
->baseShader
.constantsI
, local_constant
, entry
)
3176 if (constant
->idx
== idx
)
3178 return constant
->value
;
3184 static void init_ps_input(const IWineD3DPixelShaderImpl
*This
, const struct arb_ps_compile_args
*args
,
3185 struct shader_arb_ctx_priv
*priv
)
3187 const char *texcoords
[8] =
3189 "fragment.texcoord[0]", "fragment.texcoord[1]", "fragment.texcoord[2]", "fragment.texcoord[3]",
3190 "fragment.texcoord[4]", "fragment.texcoord[5]", "fragment.texcoord[6]", "fragment.texcoord[7]"
3193 const struct wined3d_shader_signature_element
*sig
= This
->baseShader
.input_signature
;
3194 const char *semantic_name
;
3197 switch(args
->super
.vp_mode
)
3199 case pretransformed
:
3201 /* The pixelshader has to collect the varyings on its own. In any case properly load
3202 * color0 and color1. In the case of pretransformed vertices also load texcoords. Set
3203 * other attribs to 0.0.
3205 * For fixedfunction this behavior is correct, according to the tests. For pretransformed
3206 * we'd either need a replacement shader that can load other attribs like BINORMAL, or
3207 * load the texcoord attrib pointers to match the pixel shader signature
3209 for(i
= 0; i
< MAX_REG_INPUT
; i
++)
3211 semantic_name
= sig
[i
].semantic_name
;
3212 semantic_idx
= sig
[i
].semantic_idx
;
3213 if(semantic_name
== NULL
) continue;
3215 if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_COLOR
))
3217 if(semantic_idx
== 0) priv
->ps_input
[i
] = "fragment.color.primary";
3218 else if(semantic_idx
== 1) priv
->ps_input
[i
] = "fragment.color.secondary";
3219 else priv
->ps_input
[i
] = "0.0";
3221 else if(args
->super
.vp_mode
== fixedfunction
)
3223 priv
->ps_input
[i
] = "0.0";
3225 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_TEXCOORD
))
3227 if(semantic_idx
< 8) priv
->ps_input
[i
] = texcoords
[semantic_idx
];
3228 else priv
->ps_input
[i
] = "0.0";
3230 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_FOG
))
3232 if(semantic_idx
== 0) priv
->ps_input
[i
] = "fragment.fogcoord";
3233 else priv
->ps_input
[i
] = "0.0";
3237 priv
->ps_input
[i
] = "0.0";
3240 TRACE("v%u, semantic %s%u is %s\n", i
, semantic_name
, semantic_idx
, priv
->ps_input
[i
]);
3245 /* That one is easy. The vertex shaders provide v0-v7 in fragment.texcoord and v8 and v9 in
3248 for(i
= 0; i
< 8; i
++)
3250 priv
->ps_input
[i
] = texcoords
[i
];
3252 priv
->ps_input
[8] = "fragment.color.primary";
3253 priv
->ps_input
[9] = "fragment.color.secondary";
3258 /* GL locking is done by the caller */
3259 static GLuint
shader_arb_generate_pshader(IWineD3DPixelShaderImpl
*This
, struct wined3d_shader_buffer
*buffer
,
3260 const struct arb_ps_compile_args
*args
, struct arb_ps_compiled_shader
*compiled
)
3262 const shader_reg_maps
* reg_maps
= &This
->baseShader
.reg_maps
;
3263 CONST DWORD
*function
= This
->baseShader
.function
;
3264 const struct wined3d_gl_info
*gl_info
= &((IWineD3DDeviceImpl
*)This
->baseShader
.device
)->adapter
->gl_info
;
3265 const local_constant
*lconst
;
3268 DWORD
*lconst_map
= local_const_mapping((IWineD3DBaseShaderImpl
*) This
), next_local
, cur
;
3269 struct shader_arb_ctx_priv priv_ctx
;
3270 BOOL dcl_tmp
= args
->super
.srgb_correction
, dcl_td
= FALSE
;
3271 BOOL want_nv_prog
= FALSE
;
3272 struct arb_pshader_private
*shader_priv
= This
->baseShader
.backend_data
;
3277 unsigned int i
, found
= 0;
3279 for (i
= 0, map
= reg_maps
->temporary
; map
; map
>>= 1, ++i
)
3282 || (This
->color0_mov
&& i
== This
->color0_reg
)
3283 || (reg_maps
->shader_version
.major
< 2 && i
== 0))
3286 sprintf(srgbtmp
[found
], "R%u", i
);
3288 if (found
== 4) break;
3292 case 4: dcl_tmp
= FALSE
; break;
3294 sprintf(srgbtmp
[0], "TA");
3295 sprintf(srgbtmp
[1], "TB");
3296 sprintf(srgbtmp
[2], "TC");
3297 sprintf(srgbtmp
[3], "TD");
3301 sprintf(srgbtmp
[1], "TA");
3302 sprintf(srgbtmp
[2], "TB");
3303 sprintf(srgbtmp
[3], "TC");
3306 sprintf(srgbtmp
[2], "TA");
3307 sprintf(srgbtmp
[3], "TB");
3310 sprintf(srgbtmp
[3], "TA");
3314 /* Create the hw ARB shader */
3315 memset(&priv_ctx
, 0, sizeof(priv_ctx
));
3316 priv_ctx
.cur_ps_args
= args
;
3317 priv_ctx
.compiled_fprog
= compiled
;
3318 priv_ctx
.cur_np2fixup_info
= &compiled
->np2fixup_info
;
3319 init_ps_input(This
, args
, &priv_ctx
);
3320 list_init(&priv_ctx
.control_frames
);
3322 /* Avoid enabling NV_fragment_program* if we do not need it.
3324 * Enabling GL_NV_fragment_program_option causes the driver to occupy a temporary register,
3325 * and it slows down the shader execution noticeably(about 5%). Usually our instruction emulation
3326 * is faster than what we gain from using higher native instructions. There are some things though
3327 * that cannot be emulated. In that case enable the extensions.
3328 * If the extension is enabled, instruction handlers that support both ways will use it.
3330 * Testing shows no performance difference between OPTION NV_fragment_program2 and NV_fragment_program.
3331 * So enable the best we can get.
3333 if(reg_maps
->usesdsx
|| reg_maps
->usesdsy
|| reg_maps
->loop_depth
> 0 || reg_maps
->usestexldd
||
3334 reg_maps
->usestexldl
|| reg_maps
->usesfacing
|| reg_maps
->usesifc
|| reg_maps
->usescall
)
3336 want_nv_prog
= TRUE
;
3339 shader_addline(buffer
, "!!ARBfp1.0\n");
3340 if (want_nv_prog
&& gl_info
->supported
[NV_FRAGMENT_PROGRAM2
])
3342 shader_addline(buffer
, "OPTION NV_fragment_program2;\n");
3343 priv_ctx
.target_version
= NV3
;
3345 else if (want_nv_prog
&& gl_info
->supported
[NV_FRAGMENT_PROGRAM_OPTION
])
3347 shader_addline(buffer
, "OPTION NV_fragment_program;\n");
3348 priv_ctx
.target_version
= NV2
;
3352 /* This is an error - either we're advertising the wrong shader version, or aren't enforcing some
3355 ERR("The shader requires instructions that are not available in plain GL_ARB_fragment_program\n");
3358 priv_ctx
.target_version
= ARB
;
3361 if(This
->baseShader
.reg_maps
.highest_render_target
> 0)
3363 shader_addline(buffer
, "OPTION ARB_draw_buffers;\n");
3366 if (reg_maps
->shader_version
.major
< 3)
3368 switch(args
->super
.fog
) {
3372 shader_addline(buffer
, "OPTION ARB_fog_linear;\n");
3375 shader_addline(buffer
, "OPTION ARB_fog_exp;\n");
3378 shader_addline(buffer
, "OPTION ARB_fog_exp2;\n");
3383 /* For now always declare the temps. At least the Nvidia assembler optimizes completely
3384 * unused temps away(but occupies them for the whole shader if they're used once). Always
3385 * declaring them avoids tricky bookkeeping work
3387 shader_addline(buffer
, "TEMP TA;\n"); /* Used for modifiers */
3388 shader_addline(buffer
, "TEMP TB;\n"); /* Used for modifiers */
3389 shader_addline(buffer
, "TEMP TC;\n"); /* Used for modifiers */
3390 if(dcl_td
) shader_addline(buffer
, "TEMP TD;\n"); /* Used for sRGB writing */
3391 shader_addline(buffer
, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
3392 shader_addline(buffer
, "PARAM coefmul = { 2, 4, 8, 16 };\n");
3393 shader_addline(buffer
, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
3395 if (reg_maps
->shader_version
.major
< 2)
3397 strcpy(fragcolor
, "R0");
3399 if(args
->super
.srgb_correction
) {
3400 if(This
->color0_mov
) {
3401 sprintf(fragcolor
, "R%u", This
->color0_reg
);
3403 shader_addline(buffer
, "TEMP TMP_COLOR;\n");
3404 strcpy(fragcolor
, "TMP_COLOR");
3407 strcpy(fragcolor
, "result.color");
3411 if(args
->super
.srgb_correction
) {
3412 shader_addline(buffer
, "PARAM srgb_consts1 = {%f, %f, %f, %f};\n",
3413 srgb_mul_low
, srgb_cmp
, srgb_pow
, srgb_mul_high
);
3414 shader_addline(buffer
, "PARAM srgb_consts2 = {%f, %f, %f, %f};\n",
3415 srgb_sub_high
, 0.0, 0.0, 0.0);
3418 /* Base Declarations */
3419 next_local
= shader_generate_arb_declarations((IWineD3DBaseShader
*)This
,
3420 reg_maps
, buffer
, gl_info
, lconst_map
, NULL
, &priv_ctx
);
3422 for (i
= 0, map
= reg_maps
->bumpmat
; map
; map
>>= 1, ++i
)
3424 if (!(map
& 1)) continue;
3426 cur
= compiled
->numbumpenvmatconsts
;
3427 compiled
->bumpenvmatconst
[cur
].const_num
= WINED3D_CONST_NUM_UNUSED
;
3428 compiled
->bumpenvmatconst
[cur
].texunit
= i
;
3429 compiled
->luminanceconst
[cur
].const_num
= WINED3D_CONST_NUM_UNUSED
;
3430 compiled
->luminanceconst
[cur
].texunit
= i
;
3432 /* We can fit the constants into the constant limit for sure because texbem, texbeml, bem and beml are only supported
3433 * in 1.x shaders, and GL_ARB_fragment_program has a constant limit of 24 constants. So in the worst case we're loading
3434 * 8 shader constants, 8 bump matrices and 8 luminance parameters and are perfectly fine. (No NP2 fixup on bumpmapped
3435 * textures due to conditional NP2 restrictions)
3437 * Use local constants to load the bump env parameters, not program.env. This avoids collisions with d3d constants of
3438 * shaders in newer shader models. Since the bump env parameters have to share their space with NP2 fixup constants,
3439 * their location is shader dependent anyway and they cannot be loaded globally.
3441 compiled
->bumpenvmatconst
[cur
].const_num
= next_local
++;
3442 shader_addline(buffer
, "PARAM bumpenvmat%d = program.local[%d];\n",
3443 i
, compiled
->bumpenvmatconst
[cur
].const_num
);
3444 compiled
->numbumpenvmatconsts
= cur
+ 1;
3446 if (!(reg_maps
->luminanceparams
& (1 << i
))) continue;
3448 compiled
->luminanceconst
[cur
].const_num
= next_local
++;
3449 shader_addline(buffer
, "PARAM luminance%d = program.local[%d];\n",
3450 i
, compiled
->luminanceconst
[cur
].const_num
);
3453 for(i
= 0; i
< MAX_CONST_I
; i
++)
3455 compiled
->int_consts
[i
] = WINED3D_CONST_NUM_UNUSED
;
3456 if (reg_maps
->integer_constants
& (1 << i
) && priv_ctx
.target_version
>= NV2
)
3458 const DWORD
*control_values
= find_loop_control_values((IWineD3DBaseShaderImpl
*) This
, i
);
3462 shader_addline(buffer
, "PARAM I%u = {%u, %u, %u, -1};\n", i
,
3463 control_values
[0], control_values
[1], control_values
[2]);
3467 compiled
->int_consts
[i
] = next_local
;
3468 compiled
->num_int_consts
++;
3469 shader_addline(buffer
, "PARAM I%u = program.local[%u];\n", i
, next_local
++);
3474 if(reg_maps
->vpos
|| reg_maps
->usesdsy
)
3476 compiled
->ycorrection
= next_local
;
3477 shader_addline(buffer
, "PARAM ycorrection = program.local[%u];\n", next_local
++);
3481 shader_addline(buffer
, "TEMP vpos;\n");
3482 /* ycorrection.x: Backbuffer height(onscreen) or 0(offscreen).
3483 * ycorrection.y: -1.0(onscreen), 1.0(offscreen)
3484 * ycorrection.z: 1.0
3485 * ycorrection.w: 0.0
3487 shader_addline(buffer
, "MAD vpos, fragment.position, ycorrection.zyww, ycorrection.wxww;\n");
3488 shader_addline(buffer
, "FLR vpos.xy, vpos;\n");
3493 compiled
->ycorrection
= WINED3D_CONST_NUM_UNUSED
;
3496 /* Load constants to fixup NP2 texcoords if there are still free constants left:
3497 * Constants (texture dimensions) for the NP2 fixup are loaded as local program parameters. This will consume
3498 * at most 8 (MAX_FRAGMENT_SAMPLERS / 2) parameters, which is highly unlikely, since the application had to
3499 * use 16 NP2 textures at the same time. In case that we run out of constants the fixup is simply not
3500 * applied / activated. This will probably result in wrong rendering of the texture, but will save us from
3501 * shader compilation errors and the subsequent errors when drawing with this shader. */
3502 if (priv_ctx
.cur_ps_args
->super
.np2_fixup
) {
3504 struct arb_ps_np2fixup_info
* const fixup
= priv_ctx
.cur_np2fixup_info
;
3505 const WORD map
= priv_ctx
.cur_ps_args
->super
.np2_fixup
;
3506 const UINT max_lconsts
= gl_info
->limits
.arb_ps_local_constants
;
3508 fixup
->offset
= next_local
;
3509 fixup
->super
.active
= 0;
3512 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3513 if (!(map
& (1 << i
))) continue;
3515 if (fixup
->offset
+ (cur
>> 1) < max_lconsts
) {
3516 fixup
->super
.active
|= (1 << i
);
3517 fixup
->super
.idx
[i
] = cur
++;
3519 FIXME("No free constant found to load NP2 fixup data into shader. "
3520 "Sampling from this texture will probably look wrong.\n");
3525 fixup
->super
.num_consts
= (cur
+ 1) >> 1;
3526 if (fixup
->super
.num_consts
) {
3527 shader_addline(buffer
, "PARAM np2fixup[%u] = { program.env[%u..%u] };\n",
3528 fixup
->super
.num_consts
, fixup
->offset
, fixup
->super
.num_consts
+ fixup
->offset
- 1);
3531 next_local
+= fixup
->super
.num_consts
;
3534 if (shader_priv
->clipplane_emulation
!= ~0U && args
->clip
)
3536 shader_addline(buffer
, "KIL fragment.texcoord[%u];\n", shader_priv
->clipplane_emulation
);
3539 /* Base Shader Body */
3540 shader_generate_main((IWineD3DBaseShader
*)This
, buffer
, reg_maps
, function
, &priv_ctx
);
3542 if(args
->super
.srgb_correction
) {
3543 arbfp_add_sRGB_correction(buffer
, fragcolor
, srgbtmp
[0], srgbtmp
[1], srgbtmp
[2], srgbtmp
[3],
3544 priv_ctx
.target_version
>= NV2
);
3547 if(strcmp(fragcolor
, "result.color")) {
3548 shader_addline(buffer
, "MOV result.color, %s;\n", fragcolor
);
3550 shader_addline(buffer
, "END\n");
3552 /* TODO: change to resource.glObjectHandle or something like that */
3553 GL_EXTCALL(glGenProgramsARB(1, &retval
));
3555 TRACE("Creating a hw pixel shader, prg=%d\n", retval
);
3556 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, retval
));
3558 TRACE("Created hw pixel shader, prg=%d\n", retval
);
3559 /* Create the program and check for errors */
3560 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
3561 buffer
->bsize
, buffer
->buffer
));
3562 checkGLcall("glProgramStringARB()");
3564 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errPos
);
3567 FIXME("HW PixelShader Error at position %d: %s\n",
3568 errPos
, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
3575 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
3576 checkGLcall("glGetProgramivARB()");
3577 if (!native
) WARN("Program exceeds native resource limits.\n");
3580 /* Load immediate constants */
3582 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
3583 const float *value
= (const float *)lconst
->value
;
3584 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, lconst_map
[lconst
->idx
], value
));
3585 checkGLcall("glProgramLocalParameter4fvARB");
3587 HeapFree(GetProcessHeap(), 0, lconst_map
);
3593 static int compare_sig(const struct wined3d_shader_signature_element
*sig1
, const struct wined3d_shader_signature_element
*sig2
)
3598 for(i
= 0; i
< MAX_REG_INPUT
; i
++)
3600 if(sig1
[i
].semantic_name
== NULL
|| sig2
[i
].semantic_name
== NULL
)
3602 /* Compare pointers, not contents. One string is NULL(element does not exist), the other one is not NULL */
3603 if(sig1
[i
].semantic_name
!= sig2
[i
].semantic_name
) return sig1
[i
].semantic_name
< sig2
[i
].semantic_name
? -1 : 1;
3607 ret
= strcmp(sig1
[i
].semantic_name
, sig2
[i
].semantic_name
);
3608 if(ret
!= 0) return ret
;
3609 if(sig1
[i
].semantic_idx
!= sig2
[i
].semantic_idx
) return sig1
[i
].semantic_idx
< sig2
[i
].semantic_idx
? -1 : 1;
3610 if(sig1
[i
].sysval_semantic
!= sig2
[i
].sysval_semantic
) return sig1
[i
].sysval_semantic
< sig2
[i
].sysval_semantic
? -1 : 1;
3611 if(sig1
[i
].component_type
!= sig2
[i
].component_type
) return sig1
[i
].sysval_semantic
< sig2
[i
].component_type
? -1 : 1;
3612 if(sig1
[i
].register_idx
!= sig2
[i
].register_idx
) return sig1
[i
].register_idx
< sig2
[i
].register_idx
? -1 : 1;
3613 if(sig1
[i
].mask
!= sig2
->mask
) return sig1
[i
].mask
< sig2
[i
].mask
? -1 : 1;
3618 static struct wined3d_shader_signature_element
*clone_sig(const struct wined3d_shader_signature_element
*sig
)
3620 struct wined3d_shader_signature_element
*new;
3624 new = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*new) * MAX_REG_INPUT
);
3625 for(i
= 0; i
< MAX_REG_INPUT
; i
++)
3627 if(sig
[i
].semantic_name
== NULL
)
3633 /* Clone the semantic string */
3634 name
= HeapAlloc(GetProcessHeap(), 0, strlen(sig
[i
].semantic_name
) + 1);
3635 strcpy(name
, sig
[i
].semantic_name
);
3636 new[i
].semantic_name
= name
;
3641 static DWORD
find_input_signature(struct shader_arb_priv
*priv
, const struct wined3d_shader_signature_element
*sig
)
3643 struct wine_rb_entry
*entry
= wine_rb_get(&priv
->signature_tree
, sig
);
3644 struct ps_signature
*found_sig
;
3648 found_sig
= WINE_RB_ENTRY_VALUE(entry
, struct ps_signature
, entry
);
3649 TRACE("Found existing signature %u\n", found_sig
->idx
);
3650 return found_sig
->idx
;
3652 found_sig
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*sig
));
3653 found_sig
->sig
= clone_sig(sig
);
3654 found_sig
->idx
= priv
->ps_sig_number
++;
3655 TRACE("New signature stored and assigned number %u\n", found_sig
->idx
);
3656 if(wine_rb_put(&priv
->signature_tree
, sig
, &found_sig
->entry
) == -1)
3658 ERR("Failed to insert program entry.\n");
3660 return found_sig
->idx
;
3663 static void init_output_registers(IWineD3DVertexShaderImpl
*shader
, DWORD sig_num
, struct shader_arb_ctx_priv
*priv_ctx
,
3664 struct arb_vs_compiled_shader
*compiled
)
3667 static const char *texcoords
[8] =
3669 "result.texcoord[0]", "result.texcoord[1]", "result.texcoord[2]", "result.texcoord[3]",
3670 "result.texcoord[4]", "result.texcoord[5]", "result.texcoord[6]", "result.texcoord[7]"
3672 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) shader
->baseShader
.device
;
3673 IWineD3DBaseShaderClass
*baseshader
= &shader
->baseShader
;
3674 const struct wined3d_shader_signature_element
*sig
;
3675 const char *semantic_name
;
3676 DWORD semantic_idx
, reg_idx
;
3678 /* Write generic input varyings 0 to 7 to result.texcoord[], varying 8 to result.color.primary
3679 * and varying 9 to result.color.secondary
3681 const char *decl_idx_to_string
[MAX_REG_INPUT
] =
3683 texcoords
[0], texcoords
[1], texcoords
[2], texcoords
[3],
3684 texcoords
[4], texcoords
[5], texcoords
[6], texcoords
[7],
3685 "result.color.primary", "result.color.secondary"
3690 TRACE("Pixel shader uses builtin varyings\n");
3691 /* Map builtins to builtins */
3692 for(i
= 0; i
< 8; i
++)
3694 priv_ctx
->texcrd_output
[i
] = texcoords
[i
];
3696 priv_ctx
->color_output
[0] = "result.color.primary";
3697 priv_ctx
->color_output
[1] = "result.color.secondary";
3698 priv_ctx
->fog_output
= "result.fogcoord";
3700 /* Map declared regs to builtins. Use "TA" to /dev/null unread output */
3701 for (i
= 0; i
< (sizeof(baseshader
->output_signature
) / sizeof(*baseshader
->output_signature
)); ++i
)
3703 semantic_name
= baseshader
->output_signature
[i
].semantic_name
;
3704 if(semantic_name
== NULL
) continue;
3706 if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_POSITION
))
3708 TRACE("o%u is TMP_OUT\n", i
);
3709 if (baseshader
->output_signature
[i
].semantic_idx
== 0) priv_ctx
->vs_output
[i
] = "TMP_OUT";
3710 else priv_ctx
->vs_output
[i
] = "TA";
3712 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_PSIZE
))
3714 TRACE("o%u is result.pointsize\n", i
);
3715 if (baseshader
->output_signature
[i
].semantic_idx
== 0) priv_ctx
->vs_output
[i
] = "result.pointsize";
3716 else priv_ctx
->vs_output
[i
] = "TA";
3718 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_COLOR
))
3720 TRACE("o%u is result.color.?, idx %u\n", i
, baseshader
->output_signature
[i
].semantic_idx
);
3721 if (baseshader
->output_signature
[i
].semantic_idx
== 0)
3722 priv_ctx
->vs_output
[i
] = "result.color.primary";
3723 else if (baseshader
->output_signature
[i
].semantic_idx
== 1)
3724 priv_ctx
->vs_output
[i
] = "result.color.secondary";
3725 else priv_ctx
->vs_output
[i
] = "TA";
3727 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_TEXCOORD
))
3729 TRACE("o%u is %s\n", i
, texcoords
[baseshader
->output_signature
[i
].semantic_idx
]);
3730 if (baseshader
->output_signature
[i
].semantic_idx
>= 8) priv_ctx
->vs_output
[i
] = "TA";
3731 else priv_ctx
->vs_output
[i
] = texcoords
[baseshader
->output_signature
[i
].semantic_idx
];
3733 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_FOG
))
3735 TRACE("o%u is result.fogcoord\n", i
);
3736 if (baseshader
->output_signature
[i
].semantic_idx
> 0) priv_ctx
->vs_output
[i
] = "TA";
3737 else priv_ctx
->vs_output
[i
] = "result.fogcoord";
3741 priv_ctx
->vs_output
[i
] = "TA";
3747 /* Instead of searching for the signature in the signature list, read the one from the current pixel shader.
3748 * Its maybe not the shader where the signature came from, but it is the same signature and faster to find
3750 sig
= ((IWineD3DPixelShaderImpl
*)device
->stateBlock
->pixelShader
)->baseShader
.input_signature
;
3751 TRACE("Pixel shader uses declared varyings\n");
3753 /* Map builtin to declared. /dev/null the results by default to the TA temp reg */
3754 for(i
= 0; i
< 8; i
++)
3756 priv_ctx
->texcrd_output
[i
] = "TA";
3758 priv_ctx
->color_output
[0] = "TA";
3759 priv_ctx
->color_output
[1] = "TA";
3760 priv_ctx
->fog_output
= "TA";
3762 for(i
= 0; i
< MAX_REG_INPUT
; i
++)
3764 semantic_name
= sig
[i
].semantic_name
;
3765 semantic_idx
= sig
[i
].semantic_idx
;
3766 reg_idx
= sig
[i
].register_idx
;
3767 if(semantic_name
== NULL
) continue;
3769 /* If a declared input register is not written by builtin arguments, don't write to it.
3770 * GL_NV_vertex_program makes sure the input defaults to 0.0, which is correct with D3D
3772 * Don't care about POSITION and PSIZE here - this is a builtin vertex shader, position goes
3773 * to TMP_OUT in any case
3775 if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_TEXCOORD
))
3777 if(semantic_idx
< 8) priv_ctx
->texcrd_output
[semantic_idx
] = decl_idx_to_string
[reg_idx
];
3779 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_COLOR
))
3781 if(semantic_idx
< 2) priv_ctx
->color_output
[semantic_idx
] = decl_idx_to_string
[reg_idx
];
3783 else if(shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_FOG
))
3785 if(semantic_idx
== 0) priv_ctx
->fog_output
= decl_idx_to_string
[reg_idx
];
3792 if(strcmp(decl_idx_to_string
[reg_idx
], "result.color.primary") == 0 ||
3793 strcmp(decl_idx_to_string
[reg_idx
], "result.color.secondary") == 0)
3795 compiled
->need_color_unclamp
= TRUE
;
3799 /* Map declared to declared */
3800 for (i
= 0; i
< (sizeof(baseshader
->output_signature
) / sizeof(*baseshader
->output_signature
)); ++i
)
3802 /* Write unread output to TA to throw them away */
3803 priv_ctx
->vs_output
[i
] = "TA";
3804 semantic_name
= baseshader
->output_signature
[i
].semantic_name
;
3805 if(semantic_name
== NULL
)
3810 if (shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_POSITION
)
3811 && baseshader
->output_signature
[i
].semantic_idx
== 0)
3813 priv_ctx
->vs_output
[i
] = "TMP_OUT";
3816 else if (shader_match_semantic(semantic_name
, WINED3DDECLUSAGE_PSIZE
)
3817 && baseshader
->output_signature
[i
].semantic_idx
== 0)
3819 priv_ctx
->vs_output
[i
] = "result.pointsize";
3823 for(j
= 0; j
< MAX_REG_INPUT
; j
++)
3825 if(sig
[j
].semantic_name
== NULL
)
3830 if (strcmp(sig
[j
].semantic_name
, semantic_name
) == 0
3831 && sig
[j
].semantic_idx
== baseshader
->output_signature
[i
].semantic_idx
)
3833 priv_ctx
->vs_output
[i
] = decl_idx_to_string
[sig
[j
].register_idx
];
3835 if(strcmp(priv_ctx
->vs_output
[i
], "result.color.primary") == 0 ||
3836 strcmp(priv_ctx
->vs_output
[i
], "result.color.secondary") == 0)
3838 compiled
->need_color_unclamp
= TRUE
;
3845 /* GL locking is done by the caller */
3846 static GLuint
shader_arb_generate_vshader(IWineD3DVertexShaderImpl
*This
, struct wined3d_shader_buffer
*buffer
,
3847 const struct arb_vs_compile_args
*args
, struct arb_vs_compiled_shader
*compiled
)
3849 const shader_reg_maps
*reg_maps
= &This
->baseShader
.reg_maps
;
3850 CONST DWORD
*function
= This
->baseShader
.function
;
3851 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)This
->baseShader
.device
;
3852 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3853 const local_constant
*lconst
;
3855 DWORD next_local
, *lconst_map
= local_const_mapping((IWineD3DBaseShaderImpl
*) This
);
3856 struct shader_arb_ctx_priv priv_ctx
;
3860 memset(&priv_ctx
, 0, sizeof(priv_ctx
));
3861 priv_ctx
.cur_vs_args
= args
;
3862 list_init(&priv_ctx
.control_frames
);
3863 init_output_registers(This
, args
->ps_signature
, &priv_ctx
, compiled
);
3865 /* Create the hw ARB shader */
3866 shader_addline(buffer
, "!!ARBvp1.0\n");
3868 /* Always enable the NV extension if available. Unlike fragment shaders, there is no
3869 * mesurable performance penalty, and we can always make use of it for clipplanes.
3871 if (gl_info
->supported
[NV_VERTEX_PROGRAM3
])
3873 shader_addline(buffer
, "OPTION NV_vertex_program3;\n");
3874 priv_ctx
.target_version
= NV3
;
3875 shader_addline(buffer
, "ADDRESS aL;\n");
3877 else if (gl_info
->supported
[NV_VERTEX_PROGRAM2_OPTION
])
3879 shader_addline(buffer
, "OPTION NV_vertex_program2;\n");
3880 priv_ctx
.target_version
= NV2
;
3881 shader_addline(buffer
, "ADDRESS aL;\n");
3883 priv_ctx
.target_version
= ARB
;
3886 shader_addline(buffer
, "TEMP TMP_OUT;\n");
3887 if(need_helper_const(gl_info
)) {
3888 shader_addline(buffer
, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This
->rel_offset
);
3890 if(need_mova_const((IWineD3DBaseShader
*) This
, gl_info
)) {
3891 shader_addline(buffer
, "PARAM mova_const = { 0.5, 0.0, 2.0, 1.0 };\n");
3892 shader_addline(buffer
, "TEMP A0_SHADOW;\n");
3895 shader_addline(buffer
, "TEMP TA;\n");
3897 /* Base Declarations */
3898 next_local
= shader_generate_arb_declarations((IWineD3DBaseShader
*)This
,
3899 reg_maps
, buffer
, gl_info
, lconst_map
, &priv_ctx
.vs_clipplanes
, &priv_ctx
);
3901 for(i
= 0; i
< MAX_CONST_I
; i
++)
3903 compiled
->int_consts
[i
] = WINED3D_CONST_NUM_UNUSED
;
3904 if(reg_maps
->integer_constants
& (1 << i
) && priv_ctx
.target_version
>= NV2
)
3906 const DWORD
*control_values
= find_loop_control_values((IWineD3DBaseShaderImpl
*) This
, i
);
3910 shader_addline(buffer
, "PARAM I%u = {%u, %u, %u, -1};\n", i
,
3911 control_values
[0], control_values
[1], control_values
[2]);
3915 compiled
->int_consts
[i
] = next_local
;
3916 compiled
->num_int_consts
++;
3917 shader_addline(buffer
, "PARAM I%u = program.local[%u];\n", i
, next_local
++);
3922 /* We need a constant to fixup the final position */
3923 shader_addline(buffer
, "PARAM posFixup = program.local[%u];\n", next_local
);
3924 compiled
->pos_fixup
= next_local
++;
3926 /* Initialize output parameters. GL_ARB_vertex_program does not require special initialization values
3927 * for output parameters. D3D in theory does not do that either, but some applications depend on a
3928 * proper initialization of the secondary color, and programs using the fixed function pipeline without
3929 * a replacement shader depend on the texcoord.w being set properly.
3931 * GL_NV_vertex_program defines that all output values are initialized to {0.0, 0.0, 0.0, 1.0}. This
3932 * assertion is in effect even when using GL_ARB_vertex_program without any NV specific additions. So
3933 * skip this if NV_vertex_program is supported. Otherwise, initialize the secondary color. For the tex-
3934 * coords, we have a flag in the opengl caps. Many cards do not require the texcoord being set, and
3935 * this can eat a number of instructions, so skip it unless this cap is set as well
3937 if (!gl_info
->supported
[NV_VERTEX_PROGRAM
])
3939 shader_addline(buffer
, "MOV result.color.secondary, -helper_const.wwwy;\n");
3941 if (gl_info
->quirks
& WINED3D_QUIRK_SET_TEXCOORD_W
&& !device
->frag_pipe
->ffp_proj_control
)
3944 for(i
= 0; i
< min(8, MAX_REG_TEXCRD
); i
++) {
3945 if(This
->baseShader
.reg_maps
.texcoord_mask
[i
] != 0 &&
3946 This
->baseShader
.reg_maps
.texcoord_mask
[i
] != WINED3DSP_WRITEMASK_ALL
) {
3947 shader_addline(buffer
, "MOV result.texcoord[%u].w, -helper_const.y;\n", i
);
3953 /* The shader starts with the main function */
3954 priv_ctx
.in_main_func
= TRUE
;
3955 /* Base Shader Body */
3956 shader_generate_main((IWineD3DBaseShader
*)This
, buffer
, reg_maps
, function
, &priv_ctx
);
3958 if(!priv_ctx
.footer_written
) vshader_add_footer(This
, buffer
, args
, &priv_ctx
);
3960 shader_addline(buffer
, "END\n");
3962 /* TODO: change to resource.glObjectHandle or something like that */
3963 GL_EXTCALL(glGenProgramsARB(1, &ret
));
3965 TRACE("Creating a hw vertex shader, prg=%d\n", ret
);
3966 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, ret
));
3968 TRACE("Created hw vertex shader, prg=%d\n", ret
);
3969 /* Create the program and check for errors */
3970 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
3971 buffer
->bsize
, buffer
->buffer
));
3972 checkGLcall("glProgramStringARB()");
3974 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errPos
);
3977 FIXME("HW VertexShader Error at position %d: %s\n",
3978 errPos
, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
3985 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
3986 checkGLcall("glGetProgramivARB()");
3987 if (!native
) WARN("Program exceeds native resource limits.\n");
3989 /* Load immediate constants */
3991 LIST_FOR_EACH_ENTRY(lconst
, &This
->baseShader
.constantsF
, local_constant
, entry
) {
3992 const float *value
= (const float *)lconst
->value
;
3993 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB
, lconst_map
[lconst
->idx
], value
));
3997 HeapFree(GetProcessHeap(), 0, lconst_map
);
4002 /* GL locking is done by the caller */
4003 static struct arb_ps_compiled_shader
*find_arb_pshader(IWineD3DPixelShaderImpl
*shader
, const struct arb_ps_compile_args
*args
)
4007 struct arb_ps_compiled_shader
*new_array
;
4008 struct wined3d_shader_buffer buffer
;
4009 struct arb_pshader_private
*shader_data
;
4012 if (!shader
->baseShader
.backend_data
)
4014 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) shader
->baseShader
.device
;
4015 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4016 struct shader_arb_priv
*priv
= device
->shader_priv
;
4018 shader
->baseShader
.backend_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*shader_data
));
4019 shader_data
= shader
->baseShader
.backend_data
;
4020 shader_data
->clamp_consts
= shader
->baseShader
.reg_maps
.shader_version
.major
== 1;
4022 if(shader
->baseShader
.reg_maps
.shader_version
.major
< 3) shader_data
->input_signature_idx
= ~0;
4023 else shader_data
->input_signature_idx
= find_input_signature(priv
, shader
->baseShader
.input_signature
);
4025 shader_data
->has_signature_idx
= TRUE
;
4026 TRACE("Shader got assigned input signature index %u\n", shader_data
->input_signature_idx
);
4028 if (!device
->vs_clipping
)
4029 shader_data
->clipplane_emulation
= shader_find_free_input_register(&shader
->baseShader
.reg_maps
,
4030 gl_info
->limits
.texture_stages
- 1);
4032 shader_data
->clipplane_emulation
= ~0U;
4034 shader_data
= shader
->baseShader
.backend_data
;
4036 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2),
4037 * so a linear search is more performant than a hashmap or a binary search
4038 * (cache coherency etc)
4040 for(i
= 0; i
< shader_data
->num_gl_shaders
; i
++) {
4041 if(memcmp(&shader_data
->gl_shaders
[i
].args
, args
, sizeof(*args
)) == 0) {
4042 return &shader_data
->gl_shaders
[i
];
4046 TRACE("No matching GL shader found, compiling a new shader\n");
4047 if(shader_data
->shader_array_size
== shader_data
->num_gl_shaders
) {
4048 if (shader_data
->num_gl_shaders
)
4050 new_size
= shader_data
->shader_array_size
+ max(1, shader_data
->shader_array_size
/ 2);
4051 new_array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, shader_data
->gl_shaders
,
4052 new_size
* sizeof(*shader_data
->gl_shaders
));
4054 new_array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*shader_data
->gl_shaders
));
4059 ERR("Out of memory\n");
4062 shader_data
->gl_shaders
= new_array
;
4063 shader_data
->shader_array_size
= new_size
;
4066 shader_data
->gl_shaders
[shader_data
->num_gl_shaders
].args
= *args
;
4068 pixelshader_update_samplers(&shader
->baseShader
.reg_maps
,
4069 ((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->stateBlock
->textures
);
4071 if (!shader_buffer_init(&buffer
))
4073 ERR("Failed to initialize shader buffer.\n");
4077 ret
= shader_arb_generate_pshader(shader
, &buffer
, args
,
4078 &shader_data
->gl_shaders
[shader_data
->num_gl_shaders
]);
4079 shader_buffer_free(&buffer
);
4080 shader_data
->gl_shaders
[shader_data
->num_gl_shaders
].prgId
= ret
;
4082 return &shader_data
->gl_shaders
[shader_data
->num_gl_shaders
++];
4085 static inline BOOL
vs_args_equal(const struct arb_vs_compile_args
*stored
, const struct arb_vs_compile_args
*new,
4086 const DWORD use_map
, BOOL skip_int
) {
4087 if((stored
->super
.swizzle_map
& use_map
) != new->super
.swizzle_map
) return FALSE
;
4088 if(stored
->super
.clip_enabled
!= new->super
.clip_enabled
) return FALSE
;
4089 if(stored
->super
.fog_src
!= new->super
.fog_src
) return FALSE
;
4090 if(stored
->clip
.boolclip_compare
!= new->clip
.boolclip_compare
) return FALSE
;
4091 if(stored
->ps_signature
!= new->ps_signature
) return FALSE
;
4092 if(stored
->vertex
.samplers_compare
!= new->vertex
.samplers_compare
) return FALSE
;
4093 if(skip_int
) return TRUE
;
4095 return memcmp(stored
->loop_ctrl
, new->loop_ctrl
, sizeof(stored
->loop_ctrl
)) == 0;
4098 static struct arb_vs_compiled_shader
*find_arb_vshader(IWineD3DVertexShaderImpl
*shader
, const struct arb_vs_compile_args
*args
)
4102 struct arb_vs_compiled_shader
*new_array
;
4103 DWORD use_map
= ((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->strided_streams
.use_map
;
4104 struct wined3d_shader_buffer buffer
;
4105 struct arb_vshader_private
*shader_data
;
4107 const struct wined3d_gl_info
*gl_info
= &((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->adapter
->gl_info
;
4109 if (!shader
->baseShader
.backend_data
)
4111 shader
->baseShader
.backend_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*shader_data
));
4113 shader_data
= shader
->baseShader
.backend_data
;
4115 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2),
4116 * so a linear search is more performant than a hashmap or a binary search
4117 * (cache coherency etc)
4119 for(i
= 0; i
< shader_data
->num_gl_shaders
; i
++) {
4120 if (vs_args_equal(&shader_data
->gl_shaders
[i
].args
, args
,
4121 use_map
, gl_info
->supported
[NV_VERTEX_PROGRAM2_OPTION
]))
4123 return &shader_data
->gl_shaders
[i
];
4127 TRACE("No matching GL shader found, compiling a new shader\n");
4129 if(shader_data
->shader_array_size
== shader_data
->num_gl_shaders
) {
4130 if (shader_data
->num_gl_shaders
)
4132 new_size
= shader_data
->shader_array_size
+ max(1, shader_data
->shader_array_size
/ 2);
4133 new_array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, shader_data
->gl_shaders
,
4134 new_size
* sizeof(*shader_data
->gl_shaders
));
4136 new_array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*shader_data
->gl_shaders
));
4141 ERR("Out of memory\n");
4144 shader_data
->gl_shaders
= new_array
;
4145 shader_data
->shader_array_size
= new_size
;
4148 shader_data
->gl_shaders
[shader_data
->num_gl_shaders
].args
= *args
;
4150 if (!shader_buffer_init(&buffer
))
4152 ERR("Failed to initialize shader buffer.\n");
4156 ret
= shader_arb_generate_vshader(shader
, &buffer
, args
,
4157 &shader_data
->gl_shaders
[shader_data
->num_gl_shaders
]);
4158 shader_buffer_free(&buffer
);
4159 shader_data
->gl_shaders
[shader_data
->num_gl_shaders
].prgId
= ret
;
4161 return &shader_data
->gl_shaders
[shader_data
->num_gl_shaders
++];
4164 static inline void find_arb_ps_compile_args(IWineD3DPixelShaderImpl
*shader
, IWineD3DStateBlockImpl
*stateblock
,
4165 struct arb_ps_compile_args
*args
)
4169 const struct wined3d_gl_info
*gl_info
= &((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->adapter
->gl_info
;
4170 find_ps_compile_args(shader
, stateblock
, &args
->super
);
4172 /* This forces all local boolean constants to 1 to make them stateblock independent */
4173 args
->bools
= shader
->baseShader
.reg_maps
.local_bool_consts
;
4175 for(i
= 0; i
< MAX_CONST_B
; i
++)
4177 if(stateblock
->pixelShaderConstantB
[i
]) args
->bools
|= ( 1 << i
);
4180 /* Only enable the clip plane emulation KIL if at least one clipplane is enabled. The KIL instruction
4181 * is quite expensive because it forces the driver to disable early Z discards. It is cheaper to
4182 * duplicate the shader than have a no-op KIL instruction in every shader
4184 if((!((IWineD3DDeviceImpl
*) shader
->baseShader
.device
)->vs_clipping
) && use_vs(stateblock
) &&
4185 stateblock
->renderState
[WINED3DRS_CLIPPING
] && stateblock
->renderState
[WINED3DRS_CLIPPLANEENABLE
])
4194 /* Skip if unused or local, or supported natively */
4195 int_skip
= ~shader
->baseShader
.reg_maps
.integer_constants
| shader
->baseShader
.reg_maps
.local_int_consts
;
4196 if (int_skip
== 0xffff || gl_info
->supported
[NV_FRAGMENT_PROGRAM_OPTION
])
4198 memset(&args
->loop_ctrl
, 0, sizeof(args
->loop_ctrl
));
4202 for(i
= 0; i
< MAX_CONST_I
; i
++)
4204 if(int_skip
& (1 << i
))
4206 args
->loop_ctrl
[i
][0] = 0;
4207 args
->loop_ctrl
[i
][1] = 0;
4208 args
->loop_ctrl
[i
][2] = 0;
4212 args
->loop_ctrl
[i
][0] = stateblock
->pixelShaderConstantI
[i
* 4];
4213 args
->loop_ctrl
[i
][1] = stateblock
->pixelShaderConstantI
[i
* 4 + 1];
4214 args
->loop_ctrl
[i
][2] = stateblock
->pixelShaderConstantI
[i
* 4 + 2];
4219 static inline void find_arb_vs_compile_args(IWineD3DVertexShaderImpl
*shader
, IWineD3DStateBlockImpl
*stateblock
,
4220 struct arb_vs_compile_args
*args
)
4224 IWineD3DDeviceImpl
*dev
= (IWineD3DDeviceImpl
*)shader
->baseShader
.device
;
4225 const struct wined3d_gl_info
*gl_info
= &dev
->adapter
->gl_info
;
4226 find_vs_compile_args(shader
, stateblock
, &args
->super
);
4228 args
->clip
.boolclip_compare
= 0;
4229 if(use_ps(stateblock
))
4231 IWineD3DPixelShaderImpl
*ps
= (IWineD3DPixelShaderImpl
*) stateblock
->pixelShader
;
4232 struct arb_pshader_private
*shader_priv
= ps
->baseShader
.backend_data
;
4233 args
->ps_signature
= shader_priv
->input_signature_idx
;
4235 args
->clip
.boolclip
.clip_texcoord
= shader_priv
->clipplane_emulation
+ 1;
4239 args
->ps_signature
= ~0;
4240 if(!dev
->vs_clipping
)
4242 args
->clip
.boolclip
.clip_texcoord
= ffp_clip_emul(stateblock
) ? gl_info
->limits
.texture_stages
: 0;
4244 /* Otherwise: Setting boolclip_compare set clip_texcoord to 0 */
4247 if(args
->clip
.boolclip
.clip_texcoord
)
4249 if(stateblock
->renderState
[WINED3DRS_CLIPPING
])
4251 args
->clip
.boolclip
.clipplane_mask
= stateblock
->renderState
[WINED3DRS_CLIPPLANEENABLE
];
4253 /* clipplane_mask was set to 0 by setting boolclip_compare to 0 */
4256 /* This forces all local boolean constants to 1 to make them stateblock independent */
4257 args
->clip
.boolclip
.bools
= shader
->baseShader
.reg_maps
.local_bool_consts
;
4258 /* TODO: Figure out if it would be better to store bool constants as bitmasks in the stateblock */
4259 for(i
= 0; i
< MAX_CONST_B
; i
++)
4261 if(stateblock
->vertexShaderConstantB
[i
]) args
->clip
.boolclip
.bools
|= ( 1 << i
);
4264 args
->vertex
.samplers
[0] = dev
->texUnitMap
[MAX_FRAGMENT_SAMPLERS
+ 0];
4265 args
->vertex
.samplers
[1] = dev
->texUnitMap
[MAX_FRAGMENT_SAMPLERS
+ 1];
4266 args
->vertex
.samplers
[2] = dev
->texUnitMap
[MAX_FRAGMENT_SAMPLERS
+ 2];
4267 args
->vertex
.samplers
[3] = 0;
4269 /* Skip if unused or local */
4270 int_skip
= ~shader
->baseShader
.reg_maps
.integer_constants
| shader
->baseShader
.reg_maps
.local_int_consts
;
4271 /* This is about flow control, not clipping. */
4272 if (int_skip
== 0xffff || gl_info
->supported
[NV_VERTEX_PROGRAM2_OPTION
])
4274 memset(&args
->loop_ctrl
, 0, sizeof(args
->loop_ctrl
));
4278 for(i
= 0; i
< MAX_CONST_I
; i
++)
4280 if(int_skip
& (1 << i
))
4282 args
->loop_ctrl
[i
][0] = 0;
4283 args
->loop_ctrl
[i
][1] = 0;
4284 args
->loop_ctrl
[i
][2] = 0;
4288 args
->loop_ctrl
[i
][0] = stateblock
->vertexShaderConstantI
[i
* 4];
4289 args
->loop_ctrl
[i
][1] = stateblock
->vertexShaderConstantI
[i
* 4 + 1];
4290 args
->loop_ctrl
[i
][2] = stateblock
->vertexShaderConstantI
[i
* 4 + 2];
4295 /* GL locking is done by the caller */
4296 static void shader_arb_select(const struct wined3d_context
*context
, BOOL usePS
, BOOL useVS
)
4298 IWineD3DDeviceImpl
*This
= ((IWineD3DSurfaceImpl
*)context
->surface
)->resource
.device
;
4299 struct shader_arb_priv
*priv
= This
->shader_priv
;
4300 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4303 /* Deal with pixel shaders first so the vertex shader arg function has the input signature ready */
4305 struct arb_ps_compile_args compile_args
;
4306 struct arb_ps_compiled_shader
*compiled
;
4307 IWineD3DPixelShaderImpl
*ps
= (IWineD3DPixelShaderImpl
*) This
->stateBlock
->pixelShader
;
4309 TRACE("Using pixel shader %p\n", This
->stateBlock
->pixelShader
);
4310 find_arb_ps_compile_args(ps
, This
->stateBlock
, &compile_args
);
4311 compiled
= find_arb_pshader(ps
, &compile_args
);
4312 priv
->current_fprogram_id
= compiled
->prgId
;
4313 priv
->compiled_fprog
= compiled
;
4315 /* Bind the fragment program */
4316 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, priv
->current_fprogram_id
));
4317 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id);");
4319 if(!priv
->use_arbfp_fixed_func
) {
4320 /* Enable OpenGL fragment programs */
4321 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
4322 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
4324 TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", This
, priv
->current_fprogram_id
);
4326 /* Pixel Shader 1.x constants are clamped to [-1;1], Pixel Shader 2.0 constants are not. If switching between
4327 * a 1.x and newer shader, reload the first 8 constants
4329 if(priv
->last_ps_const_clamped
!= ((struct arb_pshader_private
*)ps
->baseShader
.backend_data
)->clamp_consts
)
4331 priv
->last_ps_const_clamped
= ((struct arb_pshader_private
*)ps
->baseShader
.backend_data
)->clamp_consts
;
4332 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, 8);
4333 for(i
= 0; i
< 8; i
++)
4335 context
->pshader_const_dirty
[i
] = 1;
4337 /* Also takes care of loading local constants */
4338 shader_arb_load_constants(context
, TRUE
, FALSE
);
4342 shader_arb_ps_local_constants(This
);
4345 /* Force constant reloading for the NP2 fixup (see comment in shader_glsl_select for more info) */
4346 if (compiled
->np2fixup_info
.super
.active
)
4347 shader_arb_load_np2fixup_constants((IWineD3DDevice
*)This
, usePS
, useVS
);
4349 else if (gl_info
->supported
[ARB_FRAGMENT_PROGRAM
] && !priv
->use_arbfp_fixed_func
)
4351 /* Disable only if we're not using arbfp fixed function fragment processing. If this is used,
4352 * keep GL_FRAGMENT_PROGRAM_ARB enabled, and the fixed function pipeline will bind the fixed function
4353 * replacement shader
4355 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
4356 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
4357 priv
->current_fprogram_id
= 0;
4361 struct arb_vs_compile_args compile_args
;
4362 struct arb_vs_compiled_shader
*compiled
;
4363 IWineD3DVertexShaderImpl
*vs
= (IWineD3DVertexShaderImpl
*) This
->stateBlock
->vertexShader
;
4365 TRACE("Using vertex shader %p\n", This
->stateBlock
->vertexShader
);
4366 find_arb_vs_compile_args(vs
, This
->stateBlock
, &compile_args
);
4367 compiled
= find_arb_vshader(vs
, &compile_args
);
4368 priv
->current_vprogram_id
= compiled
->prgId
;
4369 priv
->compiled_vprog
= compiled
;
4371 /* Bind the vertex program */
4372 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, priv
->current_vprogram_id
));
4373 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id);");
4375 /* Enable OpenGL vertex programs */
4376 glEnable(GL_VERTEX_PROGRAM_ARB
);
4377 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
4378 TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", This
, priv
->current_vprogram_id
);
4379 shader_arb_vs_local_constants(This
);
4381 if(priv
->last_vs_color_unclamp
!= compiled
->need_color_unclamp
) {
4382 priv
->last_vs_color_unclamp
= compiled
->need_color_unclamp
;
4384 if (gl_info
->supported
[ARB_COLOR_BUFFER_FLOAT
])
4386 GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB
, !compiled
->need_color_unclamp
));
4387 checkGLcall("glClampColorARB");
4389 FIXME("vertex color clamp needs to be changed, but extension not supported.\n");
4393 else if (gl_info
->supported
[ARB_VERTEX_PROGRAM
])
4395 priv
->current_vprogram_id
= 0;
4396 glDisable(GL_VERTEX_PROGRAM_ARB
);
4397 checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)");
4401 /* GL locking is done by the caller */
4402 static void shader_arb_select_depth_blt(IWineD3DDevice
*iface
, enum tex_types tex_type
) {
4403 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4404 struct shader_arb_priv
*priv
= This
->shader_priv
;
4405 GLuint
*blt_fprogram
= &priv
->depth_blt_fprogram_id
[tex_type
];
4406 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4408 if (!priv
->depth_blt_vprogram_id
) priv
->depth_blt_vprogram_id
= create_arb_blt_vertex_program(gl_info
);
4409 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, priv
->depth_blt_vprogram_id
));
4410 glEnable(GL_VERTEX_PROGRAM_ARB
);
4412 if (!*blt_fprogram
) *blt_fprogram
= create_arb_blt_fragment_program(gl_info
, tex_type
);
4413 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, *blt_fprogram
));
4414 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
4417 /* GL locking is done by the caller */
4418 static void shader_arb_deselect_depth_blt(IWineD3DDevice
*iface
) {
4419 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4420 struct shader_arb_priv
*priv
= This
->shader_priv
;
4421 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4423 if (priv
->current_vprogram_id
) {
4424 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, priv
->current_vprogram_id
));
4425 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
4427 TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", This
, priv
->current_vprogram_id
);
4429 glDisable(GL_VERTEX_PROGRAM_ARB
);
4430 checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)");
4433 if (priv
->current_fprogram_id
) {
4434 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, priv
->current_fprogram_id
));
4435 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
4437 TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", This
, priv
->current_fprogram_id
);
4438 } else if(!priv
->use_arbfp_fixed_func
) {
4439 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
4440 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
4444 static void shader_arb_destroy(IWineD3DBaseShader
*iface
) {
4445 IWineD3DBaseShaderImpl
*baseShader
= (IWineD3DBaseShaderImpl
*) iface
;
4446 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)baseShader
->baseShader
.device
;
4447 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4449 if (shader_is_pshader_version(baseShader
->baseShader
.reg_maps
.shader_version
.type
))
4451 IWineD3DPixelShaderImpl
*This
= (IWineD3DPixelShaderImpl
*) iface
;
4452 struct arb_pshader_private
*shader_data
= This
->baseShader
.backend_data
;
4455 if(!shader_data
) return; /* This can happen if a shader was never compiled */
4457 if (shader_data
->num_gl_shaders
)
4459 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
4462 for (i
= 0; i
< shader_data
->num_gl_shaders
; ++i
)
4464 GL_EXTCALL(glDeleteProgramsARB(1, &shader_data
->gl_shaders
[i
].prgId
));
4465 checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId))");
4469 context_release(context
);
4472 HeapFree(GetProcessHeap(), 0, shader_data
->gl_shaders
);
4473 HeapFree(GetProcessHeap(), 0, shader_data
);
4474 This
->baseShader
.backend_data
= NULL
;
4476 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*) iface
;
4477 struct arb_vshader_private
*shader_data
= This
->baseShader
.backend_data
;
4480 if(!shader_data
) return; /* This can happen if a shader was never compiled */
4482 if (shader_data
->num_gl_shaders
)
4484 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
4487 for (i
= 0; i
< shader_data
->num_gl_shaders
; ++i
)
4489 GL_EXTCALL(glDeleteProgramsARB(1, &shader_data
->gl_shaders
[i
].prgId
));
4490 checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId))");
4494 context_release(context
);
4497 HeapFree(GetProcessHeap(), 0, shader_data
->gl_shaders
);
4498 HeapFree(GetProcessHeap(), 0, shader_data
);
4499 This
->baseShader
.backend_data
= NULL
;
4503 static int sig_tree_compare(const void *key
, const struct wine_rb_entry
*entry
)
4505 struct ps_signature
*e
= WINE_RB_ENTRY_VALUE(entry
, struct ps_signature
, entry
);
4506 return compare_sig(key
, e
->sig
);
4509 static const struct wine_rb_functions sig_tree_functions
=
4517 static HRESULT
shader_arb_alloc(IWineD3DDevice
*iface
) {
4518 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4519 struct shader_arb_priv
*priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*priv
));
4520 if(wine_rb_init(&priv
->signature_tree
, &sig_tree_functions
) == -1)
4522 ERR("RB tree init failed\n");
4523 HeapFree(GetProcessHeap(), 0, priv
);
4524 return E_OUTOFMEMORY
;
4526 This
->shader_priv
= priv
;
4530 static void release_signature(struct wine_rb_entry
*entry
, void *context
)
4532 struct ps_signature
*sig
= WINE_RB_ENTRY_VALUE(entry
, struct ps_signature
, entry
);
4534 for(i
= 0; i
< MAX_REG_INPUT
; i
++)
4536 HeapFree(GetProcessHeap(), 0, (char *) sig
->sig
[i
].semantic_name
);
4538 HeapFree(GetProcessHeap(), 0, sig
->sig
);
4539 HeapFree(GetProcessHeap(), 0, sig
);
4542 /* Context activation is done by the caller. */
4543 static void shader_arb_free(IWineD3DDevice
*iface
) {
4544 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4545 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4546 struct shader_arb_priv
*priv
= This
->shader_priv
;
4550 if(priv
->depth_blt_vprogram_id
) {
4551 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->depth_blt_vprogram_id
));
4553 for (i
= 0; i
< tex_type_count
; ++i
) {
4554 if (priv
->depth_blt_fprogram_id
[i
]) {
4555 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->depth_blt_fprogram_id
[i
]));
4560 wine_rb_destroy(&priv
->signature_tree
, release_signature
, NULL
);
4561 HeapFree(GetProcessHeap(), 0, This
->shader_priv
);
4564 static BOOL
shader_arb_dirty_const(IWineD3DDevice
*iface
) {
4568 static void shader_arb_get_caps(WINED3DDEVTYPE devtype
, const struct wined3d_gl_info
*gl_info
,
4569 struct shader_caps
*pCaps
)
4571 DWORD vs_consts
= min(gl_info
->limits
.arb_vs_float_constants
, gl_info
->limits
.arb_vs_native_constants
);
4572 DWORD ps_consts
= min(gl_info
->limits
.arb_ps_float_constants
, gl_info
->limits
.arb_ps_native_constants
);
4574 /* We don't have an ARB fixed function pipeline yet, so let the none backend set its caps,
4575 * then overwrite the shader specific ones
4577 none_shader_backend
.shader_get_caps(devtype
, gl_info
, pCaps
);
4579 if (gl_info
->supported
[ARB_VERTEX_PROGRAM
])
4581 if (gl_info
->supported
[NV_VERTEX_PROGRAM3
])
4583 pCaps
->VertexShaderVersion
= WINED3DVS_VERSION(3,0);
4584 TRACE_(d3d_caps
)("Hardware vertex shader version 3.0 enabled (NV_VERTEX_PROGRAM3)\n");
4586 else if (vs_consts
>= 256)
4588 /* Shader Model 2.0 requires at least 256 vertex shader constants */
4589 pCaps
->VertexShaderVersion
= WINED3DVS_VERSION(2,0);
4590 TRACE_(d3d_caps
)("Hardware vertex shader version 2.0 enabled (ARB_PROGRAM)\n");
4594 pCaps
->VertexShaderVersion
= WINED3DVS_VERSION(1,1);
4595 TRACE_(d3d_caps
)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n");
4597 pCaps
->MaxVertexShaderConst
= vs_consts
;
4600 if (gl_info
->supported
[ARB_FRAGMENT_PROGRAM
])
4602 if (gl_info
->supported
[NV_FRAGMENT_PROGRAM2
])
4604 pCaps
->PixelShaderVersion
= WINED3DPS_VERSION(3,0);
4605 TRACE_(d3d_caps
)("Hardware pixel shader version 3.0 enabled (NV_FRAGMENT_PROGRAM2)\n");
4607 else if (ps_consts
>= 32)
4609 /* Shader Model 2.0 requires at least 32 pixel shader constants */
4610 pCaps
->PixelShaderVersion
= WINED3DPS_VERSION(2,0);
4611 TRACE_(d3d_caps
)("Hardware pixel shader version 2.0 enabled (ARB_PROGRAM)\n");
4615 pCaps
->PixelShaderVersion
= WINED3DPS_VERSION(1,4);
4616 TRACE_(d3d_caps
)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n");
4618 pCaps
->PixelShader1xMaxValue
= 8.0f
;
4619 pCaps
->MaxPixelShaderConst
= ps_consts
;
4622 pCaps
->VSClipping
= use_nv_clip(gl_info
);
4625 static BOOL
shader_arb_color_fixup_supported(struct color_fixup_desc fixup
)
4627 if (TRACE_ON(d3d_shader
) && TRACE_ON(d3d
))
4629 TRACE("Checking support for color_fixup:\n");
4630 dump_color_fixup_desc(fixup
);
4633 /* We support everything except YUV conversions. */
4634 if (!is_yuv_fixup(fixup
))
4640 TRACE("[FAILED]\n");
4644 static void shader_arb_add_instruction_modifiers(const struct wined3d_shader_instruction
*ins
) {
4646 char write_mask
[20], regstr
[50];
4647 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
4648 BOOL is_color
= FALSE
;
4649 const struct wined3d_shader_dst_param
*dst
;
4651 if (!ins
->dst_count
) return;
4655 if(shift
== 0) return; /* Saturate alone is handled by the instructions */
4657 shader_arb_get_write_mask(ins
, dst
, write_mask
);
4658 shader_arb_get_register_name(ins
, &dst
->reg
, regstr
, &is_color
);
4660 /* Generate a line that does the output modifier computation
4661 * FIXME: _SAT vs shift? _SAT alone is already handled in the instructions, if this
4662 * maps problems in e.g. _d4_sat modify shader_arb_get_modifier
4664 shader_addline(buffer
, "MUL%s %s%s, %s, %s;\n", shader_arb_get_modifier(ins
),
4665 regstr
, write_mask
, regstr
, shift_tab
[shift
]);
4668 static const SHADER_HANDLER shader_arb_instruction_handler_table
[WINED3DSIH_TABLE_SIZE
] =
4670 /* WINED3DSIH_ABS */ shader_hw_map2gl
,
4671 /* WINED3DSIH_ADD */ shader_hw_map2gl
,
4672 /* WINED3DSIH_BEM */ pshader_hw_bem
,
4673 /* WINED3DSIH_BREAK */ shader_hw_break
,
4674 /* WINED3DSIH_BREAKC */ shader_hw_breakc
,
4675 /* WINED3DSIH_BREAKP */ NULL
,
4676 /* WINED3DSIH_CALL */ shader_hw_call
,
4677 /* WINED3DSIH_CALLNZ */ NULL
,
4678 /* WINED3DSIH_CMP */ pshader_hw_cmp
,
4679 /* WINED3DSIH_CND */ pshader_hw_cnd
,
4680 /* WINED3DSIH_CRS */ shader_hw_map2gl
,
4681 /* WINED3DSIH_CUT */ NULL
,
4682 /* WINED3DSIH_DCL */ NULL
,
4683 /* WINED3DSIH_DEF */ NULL
,
4684 /* WINED3DSIH_DEFB */ NULL
,
4685 /* WINED3DSIH_DEFI */ NULL
,
4686 /* WINED3DSIH_DP2ADD */ pshader_hw_dp2add
,
4687 /* WINED3DSIH_DP3 */ shader_hw_map2gl
,
4688 /* WINED3DSIH_DP4 */ shader_hw_map2gl
,
4689 /* WINED3DSIH_DST */ shader_hw_map2gl
,
4690 /* WINED3DSIH_DSX */ shader_hw_map2gl
,
4691 /* WINED3DSIH_DSY */ shader_hw_dsy
,
4692 /* WINED3DSIH_ELSE */ shader_hw_else
,
4693 /* WINED3DSIH_EMIT */ NULL
,
4694 /* WINED3DSIH_ENDIF */ shader_hw_endif
,
4695 /* WINED3DSIH_ENDLOOP */ shader_hw_endloop
,
4696 /* WINED3DSIH_ENDREP */ shader_hw_endrep
,
4697 /* WINED3DSIH_EXP */ shader_hw_scalar_op
,
4698 /* WINED3DSIH_EXPP */ shader_hw_scalar_op
,
4699 /* WINED3DSIH_FRC */ shader_hw_map2gl
,
4700 /* WINED3DSIH_IADD */ NULL
,
4701 /* WINED3DSIH_IF */ NULL
/* Hardcoded into the shader */,
4702 /* WINED3DSIH_IFC */ shader_hw_ifc
,
4703 /* WINED3DSIH_IGE */ NULL
,
4704 /* WINED3DSIH_LABEL */ shader_hw_label
,
4705 /* WINED3DSIH_LIT */ shader_hw_map2gl
,
4706 /* WINED3DSIH_LOG */ shader_hw_log_pow
,
4707 /* WINED3DSIH_LOGP */ shader_hw_log_pow
,
4708 /* WINED3DSIH_LOOP */ shader_hw_loop
,
4709 /* WINED3DSIH_LRP */ shader_hw_lrp
,
4710 /* WINED3DSIH_LT */ NULL
,
4711 /* WINED3DSIH_M3x2 */ shader_hw_mnxn
,
4712 /* WINED3DSIH_M3x3 */ shader_hw_mnxn
,
4713 /* WINED3DSIH_M3x4 */ shader_hw_mnxn
,
4714 /* WINED3DSIH_M4x3 */ shader_hw_mnxn
,
4715 /* WINED3DSIH_M4x4 */ shader_hw_mnxn
,
4716 /* WINED3DSIH_MAD */ shader_hw_map2gl
,
4717 /* WINED3DSIH_MAX */ shader_hw_map2gl
,
4718 /* WINED3DSIH_MIN */ shader_hw_map2gl
,
4719 /* WINED3DSIH_MOV */ shader_hw_mov
,
4720 /* WINED3DSIH_MOVA */ shader_hw_mov
,
4721 /* WINED3DSIH_MUL */ shader_hw_map2gl
,
4722 /* WINED3DSIH_NOP */ shader_hw_nop
,
4723 /* WINED3DSIH_NRM */ shader_hw_nrm
,
4724 /* WINED3DSIH_PHASE */ NULL
,
4725 /* WINED3DSIH_POW */ shader_hw_log_pow
,
4726 /* WINED3DSIH_RCP */ shader_hw_scalar_op
,
4727 /* WINED3DSIH_REP */ shader_hw_rep
,
4728 /* WINED3DSIH_RET */ shader_hw_ret
,
4729 /* WINED3DSIH_RSQ */ shader_hw_scalar_op
,
4730 /* WINED3DSIH_SETP */ NULL
,
4731 /* WINED3DSIH_SGE */ shader_hw_map2gl
,
4732 /* WINED3DSIH_SGN */ shader_hw_sgn
,
4733 /* WINED3DSIH_SINCOS */ shader_hw_sincos
,
4734 /* WINED3DSIH_SLT */ shader_hw_map2gl
,
4735 /* WINED3DSIH_SUB */ shader_hw_map2gl
,
4736 /* WINED3DSIH_TEX */ pshader_hw_tex
,
4737 /* WINED3DSIH_TEXBEM */ pshader_hw_texbem
,
4738 /* WINED3DSIH_TEXBEML */ pshader_hw_texbem
,
4739 /* WINED3DSIH_TEXCOORD */ pshader_hw_texcoord
,
4740 /* WINED3DSIH_TEXDEPTH */ pshader_hw_texdepth
,
4741 /* WINED3DSIH_TEXDP3 */ pshader_hw_texdp3
,
4742 /* WINED3DSIH_TEXDP3TEX */ pshader_hw_texdp3tex
,
4743 /* WINED3DSIH_TEXKILL */ pshader_hw_texkill
,
4744 /* WINED3DSIH_TEXLDD */ shader_hw_texldd
,
4745 /* WINED3DSIH_TEXLDL */ shader_hw_texldl
,
4746 /* WINED3DSIH_TEXM3x2DEPTH */ pshader_hw_texm3x2depth
,
4747 /* WINED3DSIH_TEXM3x2PAD */ pshader_hw_texm3x2pad
,
4748 /* WINED3DSIH_TEXM3x2TEX */ pshader_hw_texm3x2tex
,
4749 /* WINED3DSIH_TEXM3x3 */ pshader_hw_texm3x3
,
4750 /* WINED3DSIH_TEXM3x3DIFF */ NULL
,
4751 /* WINED3DSIH_TEXM3x3PAD */ pshader_hw_texm3x3pad
,
4752 /* WINED3DSIH_TEXM3x3SPEC */ pshader_hw_texm3x3spec
,
4753 /* WINED3DSIH_TEXM3x3TEX */ pshader_hw_texm3x3tex
,
4754 /* WINED3DSIH_TEXM3x3VSPEC */ pshader_hw_texm3x3vspec
,
4755 /* WINED3DSIH_TEXREG2AR */ pshader_hw_texreg2ar
,
4756 /* WINED3DSIH_TEXREG2GB */ pshader_hw_texreg2gb
,
4757 /* WINED3DSIH_TEXREG2RGB */ pshader_hw_texreg2rgb
,
4760 static inline BOOL
get_bool_const(const struct wined3d_shader_instruction
*ins
, IWineD3DBaseShaderImpl
*This
, DWORD idx
)
4762 BOOL vshader
= shader_is_vshader_version(This
->baseShader
.reg_maps
.shader_version
.type
);
4764 WORD flag
= (1 << idx
);
4765 const local_constant
*constant
;
4766 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
4768 if(This
->baseShader
.reg_maps
.local_bool_consts
& flag
)
4770 /* What good is a if(bool) with a hardcoded local constant? I don't know, but handle it */
4771 LIST_FOR_EACH_ENTRY(constant
, &This
->baseShader
.constantsB
, local_constant
, entry
)
4773 if (constant
->idx
== idx
)
4775 return constant
->value
[0];
4778 ERR("Local constant not found\n");
4783 if(vshader
) bools
= priv
->cur_vs_args
->clip
.boolclip
.bools
;
4784 else bools
= priv
->cur_ps_args
->bools
;
4785 return bools
& flag
;
4789 static void get_loop_control_const(const struct wined3d_shader_instruction
*ins
,
4790 IWineD3DBaseShaderImpl
*This
, UINT idx
, struct wined3d_shader_loop_control
*loop_control
)
4792 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
4794 /* Integer constants can either be a local constant, or they can be stored in the shader
4795 * type specific compile args. */
4796 if (This
->baseShader
.reg_maps
.local_int_consts
& (1 << idx
))
4798 const local_constant
*constant
;
4800 LIST_FOR_EACH_ENTRY(constant
, &This
->baseShader
.constantsI
, local_constant
, entry
)
4802 if (constant
->idx
== idx
)
4804 loop_control
->count
= constant
->value
[0];
4805 loop_control
->start
= constant
->value
[1];
4806 /* Step is signed. */
4807 loop_control
->step
= (int)constant
->value
[2];
4811 /* If this happens the flag was set incorrectly */
4812 ERR("Local constant not found\n");
4813 loop_control
->count
= 0;
4814 loop_control
->start
= 0;
4815 loop_control
->step
= 0;
4819 switch (This
->baseShader
.reg_maps
.shader_version
.type
)
4821 case WINED3D_SHADER_TYPE_VERTEX
:
4822 /* Count and aL start value are unsigned */
4823 loop_control
->count
= priv
->cur_vs_args
->loop_ctrl
[idx
][0];
4824 loop_control
->start
= priv
->cur_vs_args
->loop_ctrl
[idx
][1];
4825 /* Step is signed. */
4826 loop_control
->step
= ((char)priv
->cur_vs_args
->loop_ctrl
[idx
][2]);
4829 case WINED3D_SHADER_TYPE_PIXEL
:
4830 loop_control
->count
= priv
->cur_ps_args
->loop_ctrl
[idx
][0];
4831 loop_control
->start
= priv
->cur_ps_args
->loop_ctrl
[idx
][1];
4832 loop_control
->step
= ((char)priv
->cur_ps_args
->loop_ctrl
[idx
][2]);
4836 FIXME("Unhandled shader type %#x.\n", This
->baseShader
.reg_maps
.shader_version
.type
);
4841 static void record_instruction(struct list
*list
, const struct wined3d_shader_instruction
*ins
)
4844 struct wined3d_shader_dst_param
*dst_param
= NULL
;
4845 struct wined3d_shader_src_param
*src_param
= NULL
, *rel_addr
= NULL
;
4846 struct recorded_instruction
*rec
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*rec
));
4849 ERR("Out of memory\n");
4854 dst_param
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dst_param
));
4855 if(!dst_param
) goto free
;
4856 *dst_param
= *ins
->dst
;
4857 if(ins
->dst
->reg
.rel_addr
)
4859 rel_addr
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dst_param
->reg
.rel_addr
));
4860 if(!rel_addr
) goto free
;
4861 *rel_addr
= *ins
->dst
->reg
.rel_addr
;
4862 dst_param
->reg
.rel_addr
= rel_addr
;
4864 rec
->ins
.dst
= dst_param
;
4866 src_param
= HeapAlloc(GetProcessHeap(), 0, sizeof(*src_param
) * ins
->src_count
);
4867 if(!src_param
) goto free
;
4868 for(i
= 0; i
< ins
->src_count
; i
++)
4870 src_param
[i
] = ins
->src
[i
];
4871 if(ins
->src
[i
].reg
.rel_addr
)
4873 rel_addr
= HeapAlloc(GetProcessHeap(), 0, sizeof(*rel_addr
));
4874 if(!rel_addr
) goto free
;
4875 *rel_addr
= *ins
->src
[i
].reg
.rel_addr
;
4876 src_param
[i
].reg
.rel_addr
= rel_addr
;
4879 rec
->ins
.src
= src_param
;
4880 list_add_tail(list
, &rec
->entry
);
4884 ERR("Out of memory\n");
4887 HeapFree(GetProcessHeap(), 0, (void *) dst_param
->reg
.rel_addr
);
4888 HeapFree(GetProcessHeap(), 0, dst_param
);
4892 for(i
= 0; i
< ins
->src_count
; i
++)
4894 HeapFree(GetProcessHeap(), 0, (void *) src_param
[i
].reg
.rel_addr
);
4896 HeapFree(GetProcessHeap(), 0, src_param
);
4898 HeapFree(GetProcessHeap(), 0, rec
);
4901 static void free_recorded_instruction(struct list
*list
)
4903 struct recorded_instruction
*rec_ins
, *entry2
;
4906 LIST_FOR_EACH_ENTRY_SAFE(rec_ins
, entry2
, list
, struct recorded_instruction
, entry
)
4908 list_remove(&rec_ins
->entry
);
4909 if(rec_ins
->ins
.dst
)
4911 HeapFree(GetProcessHeap(), 0, (void *) rec_ins
->ins
.dst
->reg
.rel_addr
);
4912 HeapFree(GetProcessHeap(), 0, (void *) rec_ins
->ins
.dst
);
4914 if(rec_ins
->ins
.src
)
4916 for(i
= 0; i
< rec_ins
->ins
.src_count
; i
++)
4918 HeapFree(GetProcessHeap(), 0, (void *) rec_ins
->ins
.src
[i
].reg
.rel_addr
);
4920 HeapFree(GetProcessHeap(), 0, (void *) rec_ins
->ins
.src
);
4922 HeapFree(GetProcessHeap(), 0, rec_ins
);
4926 static void shader_arb_handle_instruction(const struct wined3d_shader_instruction
*ins
) {
4927 SHADER_HANDLER hw_fct
;
4928 struct shader_arb_ctx_priv
*priv
= ins
->ctx
->backend_data
;
4929 IWineD3DBaseShaderImpl
*This
= (IWineD3DBaseShaderImpl
*)ins
->ctx
->shader
;
4930 struct control_frame
*control_frame
;
4931 struct wined3d_shader_buffer
*buffer
= ins
->ctx
->buffer
;
4934 if(ins
->handler_idx
== WINED3DSIH_LOOP
|| ins
->handler_idx
== WINED3DSIH_REP
)
4936 control_frame
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*control_frame
));
4937 list_add_head(&priv
->control_frames
, &control_frame
->entry
);
4939 if(ins
->handler_idx
== WINED3DSIH_LOOP
) control_frame
->type
= LOOP
;
4940 if(ins
->handler_idx
== WINED3DSIH_REP
) control_frame
->type
= REP
;
4942 if(priv
->target_version
>= NV2
)
4944 control_frame
->no
.loop
= priv
->num_loops
++;
4949 /* Don't bother recording when we're in a not used if branch */
4955 if(!priv
->recording
)
4957 list_init(&priv
->record
);
4958 priv
->recording
= TRUE
;
4959 control_frame
->outer_loop
= TRUE
;
4960 get_loop_control_const(ins
, This
, ins
->src
[0].reg
.idx
, &control_frame
->loop_control
);
4961 return; /* Instruction is handled */
4963 /* Record this loop in the outer loop's recording */
4966 else if(ins
->handler_idx
== WINED3DSIH_ENDLOOP
|| ins
->handler_idx
== WINED3DSIH_ENDREP
)
4968 if(priv
->target_version
>= NV2
)
4970 /* Nothing to do. The control frame is popped after the HW instr handler */
4974 struct list
*e
= list_head(&priv
->control_frames
);
4975 control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
4976 list_remove(&control_frame
->entry
);
4978 if(control_frame
->outer_loop
)
4980 int iteration
, aL
= 0;
4983 /* Turn off recording before playback */
4984 priv
->recording
= FALSE
;
4986 /* Move the recorded instructions to a separate list and get them out of the private data
4987 * structure. If there are nested loops, the shader_arb_handle_instruction below will
4988 * be recorded again, thus priv->record might be overwritten
4991 list_move_tail(©
, &priv
->record
);
4992 list_init(&priv
->record
);
4994 if(ins
->handler_idx
== WINED3DSIH_ENDLOOP
)
4996 shader_addline(buffer
, "#unrolling loop: %u iterations, aL=%u, inc %d\n",
4997 control_frame
->loop_control
.count
, control_frame
->loop_control
.start
,
4998 control_frame
->loop_control
.step
);
4999 aL
= control_frame
->loop_control
.start
;
5003 shader_addline(buffer
, "#unrolling rep: %u iterations\n", control_frame
->loop_control
.count
);
5006 for (iteration
= 0; iteration
< control_frame
->loop_control
.count
; ++iteration
)
5008 struct recorded_instruction
*rec_ins
;
5009 if(ins
->handler_idx
== WINED3DSIH_ENDLOOP
)
5012 shader_addline(buffer
, "#Iteration %d, aL=%d\n", iteration
, aL
);
5016 shader_addline(buffer
, "#Iteration %d\n", iteration
);
5019 LIST_FOR_EACH_ENTRY(rec_ins
, ©
, struct recorded_instruction
, entry
)
5021 shader_arb_handle_instruction(&rec_ins
->ins
);
5024 if(ins
->handler_idx
== WINED3DSIH_ENDLOOP
)
5026 aL
+= control_frame
->loop_control
.step
;
5029 shader_addline(buffer
, "#end loop/rep\n");
5031 free_recorded_instruction(©
);
5032 HeapFree(GetProcessHeap(), 0, control_frame
);
5033 return; /* Instruction is handled */
5037 /* This is a nested loop. Proceed to the normal recording function */
5038 HeapFree(GetProcessHeap(), 0, control_frame
);
5045 record_instruction(&priv
->record
, ins
);
5050 if(ins
->handler_idx
== WINED3DSIH_IF
)
5052 control_frame
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*control_frame
));
5053 list_add_head(&priv
->control_frames
, &control_frame
->entry
);
5054 control_frame
->type
= IF
;
5056 bool_const
= get_bool_const(ins
, This
, ins
->src
[0].reg
.idx
);
5057 if(ins
->src
[0].modifiers
== WINED3DSPSM_NOT
) bool_const
= !bool_const
;
5058 if(!priv
->muted
&& bool_const
== FALSE
)
5060 shader_addline(buffer
, "#if(FALSE){\n");
5062 control_frame
->muting
= TRUE
;
5064 else shader_addline(buffer
, "#if(TRUE) {\n");
5066 return; /* Instruction is handled */
5068 else if(ins
->handler_idx
== WINED3DSIH_IFC
)
5070 /* IF(bool) and if_cond(a, b) use the same ELSE and ENDIF tokens */
5071 control_frame
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*control_frame
));
5072 control_frame
->type
= IFC
;
5073 control_frame
->no
.ifc
= priv
->num_ifcs
++;
5074 list_add_head(&priv
->control_frames
, &control_frame
->entry
);
5076 else if(ins
->handler_idx
== WINED3DSIH_ELSE
)
5078 struct list
*e
= list_head(&priv
->control_frames
);
5079 control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
5081 if(control_frame
->type
== IF
)
5083 shader_addline(buffer
, "#} else {\n");
5084 if(!priv
->muted
&& !control_frame
->muting
)
5087 control_frame
->muting
= TRUE
;
5089 else if(control_frame
->muting
) priv
->muted
= FALSE
;
5090 return; /* Instruction is handled. */
5092 /* In case of an ifc, generate a HW shader instruction */
5094 else if(ins
->handler_idx
== WINED3DSIH_ENDIF
)
5096 struct list
*e
= list_head(&priv
->control_frames
);
5097 control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
5099 if(control_frame
->type
== IF
)
5101 shader_addline(buffer
, "#} endif\n");
5102 if(control_frame
->muting
) priv
->muted
= FALSE
;
5103 list_remove(&control_frame
->entry
);
5104 HeapFree(GetProcessHeap(), 0, control_frame
);
5105 return; /* Instruction is handled */
5109 if(priv
->muted
) return;
5111 /* Select handler */
5112 hw_fct
= shader_arb_instruction_handler_table
[ins
->handler_idx
];
5114 /* Unhandled opcode */
5117 FIXME("Backend can't handle opcode %#x\n", ins
->handler_idx
);
5122 if(ins
->handler_idx
== WINED3DSIH_ENDLOOP
|| ins
->handler_idx
== WINED3DSIH_ENDREP
)
5124 struct list
*e
= list_head(&priv
->control_frames
);
5125 control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
5126 list_remove(&control_frame
->entry
);
5127 HeapFree(GetProcessHeap(), 0, control_frame
);
5130 else if(ins
->handler_idx
== WINED3DSIH_ENDIF
)
5132 /* Non-ifc ENDIFs don't reach that place because of the return in the if block above */
5133 struct list
*e
= list_head(&priv
->control_frames
);
5134 control_frame
= LIST_ENTRY(e
, struct control_frame
, entry
);
5135 list_remove(&control_frame
->entry
);
5136 HeapFree(GetProcessHeap(), 0, control_frame
);
5140 shader_arb_add_instruction_modifiers(ins
);
5143 const shader_backend_t arb_program_shader_backend
= {
5144 shader_arb_handle_instruction
,
5146 shader_arb_select_depth_blt
,
5147 shader_arb_deselect_depth_blt
,
5148 shader_arb_update_float_vertex_constants
,
5149 shader_arb_update_float_pixel_constants
,
5150 shader_arb_load_constants
,
5151 shader_arb_load_np2fixup_constants
,
5155 shader_arb_dirty_const
,
5156 shader_arb_get_caps
,
5157 shader_arb_color_fixup_supported
,
5160 /* ARB_fragment_program fixed function pipeline replacement definitions */
5161 #define ARB_FFP_CONST_TFACTOR 0
5162 #define ARB_FFP_CONST_SPECULAR_ENABLE ((ARB_FFP_CONST_TFACTOR) + 1)
5163 #define ARB_FFP_CONST_CONSTANT(i) ((ARB_FFP_CONST_SPECULAR_ENABLE) + 1 + i)
5164 #define ARB_FFP_CONST_BUMPMAT(i) ((ARB_FFP_CONST_CONSTANT(7)) + 1 + i)
5165 #define ARB_FFP_CONST_LUMINANCE(i) ((ARB_FFP_CONST_BUMPMAT(7)) + 1 + i)
5167 struct arbfp_ffp_desc
5169 struct ffp_frag_desc parent
;
5171 unsigned int num_textures_used
;
5174 /* Context activation is done by the caller. */
5175 static void arbfp_enable(IWineD3DDevice
*iface
, BOOL enable
) {
5178 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
5179 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");
5181 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
5182 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
5187 static HRESULT
arbfp_alloc(IWineD3DDevice
*iface
) {
5188 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5189 struct shader_arb_priv
*priv
;
5190 /* Share private data between the shader backend and the pipeline replacement, if both
5191 * are the arb implementation. This is needed to figure out whether ARBfp should be disabled
5192 * if no pixel shader is bound or not
5194 if(This
->shader_backend
== &arb_program_shader_backend
) {
5195 This
->fragment_priv
= This
->shader_priv
;
5197 This
->fragment_priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct shader_arb_priv
));
5198 if(!This
->fragment_priv
) return E_OUTOFMEMORY
;
5200 priv
= This
->fragment_priv
;
5201 if (wine_rb_init(&priv
->fragment_shaders
, &wined3d_ffp_frag_program_rb_functions
) == -1)
5203 ERR("Failed to initialize rbtree.\n");
5204 HeapFree(GetProcessHeap(), 0, This
->fragment_priv
);
5205 return E_OUTOFMEMORY
;
5207 priv
->use_arbfp_fixed_func
= TRUE
;
5211 /* Context activation is done by the caller. */
5212 static void arbfp_free_ffpshader(struct wine_rb_entry
*entry
, void *context
)
5214 const struct wined3d_gl_info
*gl_info
= context
;
5215 struct arbfp_ffp_desc
*entry_arb
= WINE_RB_ENTRY_VALUE(entry
, struct arbfp_ffp_desc
, parent
.entry
);
5218 GL_EXTCALL(glDeleteProgramsARB(1, &entry_arb
->shader
));
5219 checkGLcall("glDeleteProgramsARB(1, &entry_arb->shader)");
5220 HeapFree(GetProcessHeap(), 0, entry_arb
);
5224 /* Context activation is done by the caller. */
5225 static void arbfp_free(IWineD3DDevice
*iface
) {
5226 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5227 struct shader_arb_priv
*priv
= This
->fragment_priv
;
5229 wine_rb_destroy(&priv
->fragment_shaders
, arbfp_free_ffpshader
, &This
->adapter
->gl_info
);
5230 priv
->use_arbfp_fixed_func
= FALSE
;
5232 if(This
->shader_backend
!= &arb_program_shader_backend
) {
5233 HeapFree(GetProcessHeap(), 0, This
->fragment_priv
);
5237 static void arbfp_get_caps(WINED3DDEVTYPE devtype
, const struct wined3d_gl_info
*gl_info
, struct fragment_caps
*caps
)
5239 caps
->TextureOpCaps
= WINED3DTEXOPCAPS_DISABLE
|
5240 WINED3DTEXOPCAPS_SELECTARG1
|
5241 WINED3DTEXOPCAPS_SELECTARG2
|
5242 WINED3DTEXOPCAPS_MODULATE4X
|
5243 WINED3DTEXOPCAPS_MODULATE2X
|
5244 WINED3DTEXOPCAPS_MODULATE
|
5245 WINED3DTEXOPCAPS_ADDSIGNED2X
|
5246 WINED3DTEXOPCAPS_ADDSIGNED
|
5247 WINED3DTEXOPCAPS_ADD
|
5248 WINED3DTEXOPCAPS_SUBTRACT
|
5249 WINED3DTEXOPCAPS_ADDSMOOTH
|
5250 WINED3DTEXOPCAPS_BLENDCURRENTALPHA
|
5251 WINED3DTEXOPCAPS_BLENDFACTORALPHA
|
5252 WINED3DTEXOPCAPS_BLENDTEXTUREALPHA
|
5253 WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA
|
5254 WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM
|
5255 WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
|
5256 WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
|
5257 WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
|
5258 WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
|
5259 WINED3DTEXOPCAPS_DOTPRODUCT3
|
5260 WINED3DTEXOPCAPS_MULTIPLYADD
|
5261 WINED3DTEXOPCAPS_LERP
|
5262 WINED3DTEXOPCAPS_BUMPENVMAP
|
5263 WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE
;
5265 /* TODO: Implement WINED3DTEXOPCAPS_PREMODULATE */
5267 caps
->MaxTextureBlendStages
= 8;
5268 caps
->MaxSimultaneousTextures
= min(gl_info
->limits
.fragment_samplers
, 8);
5270 caps
->PrimitiveMiscCaps
|= WINED3DPMISCCAPS_TSSARGTEMP
;
5272 #undef GLINFO_LOCATION
5274 #define GLINFO_LOCATION stateblock->device->adapter->gl_info
5275 static void state_texfactor_arbfp(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5277 IWineD3DDeviceImpl
*device
= stateblock
->device
;
5280 /* Don't load the parameter if we're using an arbfp pixel shader, otherwise we'll overwrite
5281 * application provided constants
5283 if(device
->shader_backend
== &arb_program_shader_backend
) {
5284 if (use_ps(stateblock
)) return;
5286 context
->pshader_const_dirty
[ARB_FFP_CONST_TFACTOR
] = 1;
5287 device
->highest_dirty_ps_const
= max(device
->highest_dirty_ps_const
, ARB_FFP_CONST_TFACTOR
+ 1);
5290 D3DCOLORTOGLFLOAT4(stateblock
->renderState
[WINED3DRS_TEXTUREFACTOR
], col
);
5291 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, ARB_FFP_CONST_TFACTOR
, col
));
5292 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_TFACTOR, col)");
5296 static void state_arb_specularenable(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5298 IWineD3DDeviceImpl
*device
= stateblock
->device
;
5301 /* Don't load the parameter if we're using an arbfp pixel shader, otherwise we'll overwrite
5302 * application provided constants
5304 if(device
->shader_backend
== &arb_program_shader_backend
) {
5305 if (use_ps(stateblock
)) return;
5307 context
->pshader_const_dirty
[ARB_FFP_CONST_SPECULAR_ENABLE
] = 1;
5308 device
->highest_dirty_ps_const
= max(device
->highest_dirty_ps_const
, ARB_FFP_CONST_SPECULAR_ENABLE
+ 1);
5311 if(stateblock
->renderState
[WINED3DRS_SPECULARENABLE
]) {
5312 /* The specular color has no alpha */
5313 col
[0] = 1.0f
; col
[1] = 1.0f
;
5314 col
[2] = 1.0f
; col
[3] = 0.0f
;
5316 col
[0] = 0.0f
; col
[1] = 0.0f
;
5317 col
[2] = 0.0f
; col
[3] = 0.0f
;
5319 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, ARB_FFP_CONST_SPECULAR_ENABLE
, col
));
5320 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_SPECULAR_ENABLE, col)");
5323 static void set_bumpmat_arbfp(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5325 DWORD stage
= (state
- STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE
+ 1);
5326 IWineD3DDeviceImpl
*device
= stateblock
->device
;
5329 if (use_ps(stateblock
))
5332 && (((IWineD3DPixelShaderImpl
*)stateblock
->pixelShader
)->baseShader
.reg_maps
.bumpmat
& (1 << stage
)))
5334 /* The pixel shader has to know the bump env matrix. Do a constants update if it isn't scheduled
5337 if(!isStateDirty(context
, STATE_PIXELSHADERCONSTANT
)) {
5338 device
->StateTable
[STATE_PIXELSHADERCONSTANT
].apply(STATE_PIXELSHADERCONSTANT
, stateblock
, context
);
5342 if(device
->shader_backend
== &arb_program_shader_backend
) {
5343 /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants */
5346 } else if(device
->shader_backend
== &arb_program_shader_backend
) {
5347 context
->pshader_const_dirty
[ARB_FFP_CONST_BUMPMAT(stage
)] = 1;
5348 device
->highest_dirty_ps_const
= max(device
->highest_dirty_ps_const
, ARB_FFP_CONST_BUMPMAT(stage
) + 1);
5351 mat
[0][0] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVMAT00
]);
5352 mat
[0][1] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVMAT01
]);
5353 mat
[1][0] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVMAT10
]);
5354 mat
[1][1] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVMAT11
]);
5356 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, ARB_FFP_CONST_BUMPMAT(stage
), &mat
[0][0]));
5357 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_BUMPMAT(stage), &mat[0][0])");
5360 static void tex_bumpenvlum_arbfp(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5362 DWORD stage
= (state
- STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE
+ 1);
5363 IWineD3DDeviceImpl
*device
= stateblock
->device
;
5366 if (use_ps(stateblock
))
5369 && (((IWineD3DPixelShaderImpl
*)stateblock
->pixelShader
)->baseShader
.reg_maps
.luminanceparams
& (1 << stage
)))
5371 /* The pixel shader has to know the luminance offset. Do a constants update if it
5372 * isn't scheduled anyway
5374 if(!isStateDirty(context
, STATE_PIXELSHADERCONSTANT
)) {
5375 device
->StateTable
[STATE_PIXELSHADERCONSTANT
].apply(STATE_PIXELSHADERCONSTANT
, stateblock
, context
);
5379 if(device
->shader_backend
== &arb_program_shader_backend
) {
5380 /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants */
5383 } else if(device
->shader_backend
== &arb_program_shader_backend
) {
5384 context
->pshader_const_dirty
[ARB_FFP_CONST_LUMINANCE(stage
)] = 1;
5385 device
->highest_dirty_ps_const
= max(device
->highest_dirty_ps_const
, ARB_FFP_CONST_LUMINANCE(stage
) + 1);
5388 param
[0] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVLSCALE
]);
5389 param
[1] = *((float *) &stateblock
->textureState
[stage
][WINED3DTSS_BUMPENVLOFFSET
]);
5393 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, ARB_FFP_CONST_LUMINANCE(stage
), param
));
5394 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_LUMINANCE(stage), param)");
5397 static const char *get_argreg(struct wined3d_shader_buffer
*buffer
, DWORD argnum
, unsigned int stage
, DWORD arg
)
5401 if(arg
== ARG_UNUSED
) return "unused"; /* This is the marker for unused registers */
5403 switch(arg
& WINED3DTA_SELECTMASK
) {
5404 case WINED3DTA_DIFFUSE
:
5405 ret
= "fragment.color.primary"; break;
5407 case WINED3DTA_CURRENT
:
5408 if(stage
== 0) ret
= "fragment.color.primary";
5412 case WINED3DTA_TEXTURE
:
5414 case 0: ret
= "tex0"; break;
5415 case 1: ret
= "tex1"; break;
5416 case 2: ret
= "tex2"; break;
5417 case 3: ret
= "tex3"; break;
5418 case 4: ret
= "tex4"; break;
5419 case 5: ret
= "tex5"; break;
5420 case 6: ret
= "tex6"; break;
5421 case 7: ret
= "tex7"; break;
5422 default: ret
= "unknown texture";
5426 case WINED3DTA_TFACTOR
:
5427 ret
= "tfactor"; break;
5429 case WINED3DTA_SPECULAR
:
5430 ret
= "fragment.color.secondary"; break;
5432 case WINED3DTA_TEMP
:
5433 ret
= "tempreg"; break;
5435 case WINED3DTA_CONSTANT
:
5436 FIXME("Implement perstage constants\n");
5438 case 0: ret
= "const0"; break;
5439 case 1: ret
= "const1"; break;
5440 case 2: ret
= "const2"; break;
5441 case 3: ret
= "const3"; break;
5442 case 4: ret
= "const4"; break;
5443 case 5: ret
= "const5"; break;
5444 case 6: ret
= "const6"; break;
5445 case 7: ret
= "const7"; break;
5446 default: ret
= "unknown constant";
5454 if(arg
& WINED3DTA_COMPLEMENT
) {
5455 shader_addline(buffer
, "SUB arg%u, const.x, %s;\n", argnum
, ret
);
5456 if(argnum
== 0) ret
= "arg0";
5457 if(argnum
== 1) ret
= "arg1";
5458 if(argnum
== 2) ret
= "arg2";
5460 if(arg
& WINED3DTA_ALPHAREPLICATE
) {
5461 shader_addline(buffer
, "MOV arg%u, %s.w;\n", argnum
, ret
);
5462 if(argnum
== 0) ret
= "arg0";
5463 if(argnum
== 1) ret
= "arg1";
5464 if(argnum
== 2) ret
= "arg2";
5469 static void gen_ffp_instr(struct wined3d_shader_buffer
*buffer
, unsigned int stage
, BOOL color
,
5470 BOOL alpha
, DWORD dst
, DWORD op
, DWORD dw_arg0
, DWORD dw_arg1
, DWORD dw_arg2
)
5472 const char *dstmask
, *dstreg
, *arg0
, *arg1
, *arg2
;
5473 unsigned int mul
= 1;
5474 BOOL mul_final_dest
= FALSE
;
5476 if(color
&& alpha
) dstmask
= "";
5477 else if(color
) dstmask
= ".xyz";
5478 else dstmask
= ".w";
5480 if(dst
== tempreg
) dstreg
= "tempreg";
5481 else dstreg
= "ret";
5483 arg0
= get_argreg(buffer
, 0, stage
, dw_arg0
);
5484 arg1
= get_argreg(buffer
, 1, stage
, dw_arg1
);
5485 arg2
= get_argreg(buffer
, 2, stage
, dw_arg2
);
5488 case WINED3DTOP_DISABLE
:
5489 if(stage
== 0) shader_addline(buffer
, "MOV %s%s, fragment.color.primary;\n", dstreg
, dstmask
);
5492 case WINED3DTOP_SELECTARG2
:
5494 case WINED3DTOP_SELECTARG1
:
5495 shader_addline(buffer
, "MOV %s%s, %s;\n", dstreg
, dstmask
, arg1
);
5498 case WINED3DTOP_MODULATE4X
:
5500 case WINED3DTOP_MODULATE2X
:
5502 if(strcmp(dstreg
, "result.color") == 0) {
5504 mul_final_dest
= TRUE
;
5506 case WINED3DTOP_MODULATE
:
5507 shader_addline(buffer
, "MUL %s%s, %s, %s;\n", dstreg
, dstmask
, arg1
, arg2
);
5510 case WINED3DTOP_ADDSIGNED2X
:
5512 if(strcmp(dstreg
, "result.color") == 0) {
5514 mul_final_dest
= TRUE
;
5516 case WINED3DTOP_ADDSIGNED
:
5517 shader_addline(buffer
, "SUB arg2, %s, const.w;\n", arg2
);
5519 case WINED3DTOP_ADD
:
5520 shader_addline(buffer
, "ADD_SAT %s%s, %s, %s;\n", dstreg
, dstmask
, arg1
, arg2
);
5523 case WINED3DTOP_SUBTRACT
:
5524 shader_addline(buffer
, "SUB_SAT %s%s, %s, %s;\n", dstreg
, dstmask
, arg1
, arg2
);
5527 case WINED3DTOP_ADDSMOOTH
:
5528 shader_addline(buffer
, "SUB arg1, const.x, %s;\n", arg1
);
5529 shader_addline(buffer
, "MAD_SAT %s%s, arg1, %s, %s;\n", dstreg
, dstmask
, arg2
, arg1
);
5532 case WINED3DTOP_BLENDCURRENTALPHA
:
5533 arg0
= get_argreg(buffer
, 0, stage
, WINED3DTA_CURRENT
);
5534 shader_addline(buffer
, "LRP %s%s, %s.w, %s, %s;\n", dstreg
, dstmask
, arg0
, arg1
, arg2
);
5536 case WINED3DTOP_BLENDFACTORALPHA
:
5537 arg0
= get_argreg(buffer
, 0, stage
, WINED3DTA_TFACTOR
);
5538 shader_addline(buffer
, "LRP %s%s, %s.w, %s, %s;\n", dstreg
, dstmask
, arg0
, arg1
, arg2
);
5540 case WINED3DTOP_BLENDTEXTUREALPHA
:
5541 arg0
= get_argreg(buffer
, 0, stage
, WINED3DTA_TEXTURE
);
5542 shader_addline(buffer
, "LRP %s%s, %s.w, %s, %s;\n", dstreg
, dstmask
, arg0
, arg1
, arg2
);
5544 case WINED3DTOP_BLENDDIFFUSEALPHA
:
5545 arg0
= get_argreg(buffer
, 0, stage
, WINED3DTA_DIFFUSE
);
5546 shader_addline(buffer
, "LRP %s%s, %s.w, %s, %s;\n", dstreg
, dstmask
, arg0
, arg1
, arg2
);
5549 case WINED3DTOP_BLENDTEXTUREALPHAPM
:
5550 arg0
= get_argreg(buffer
, 0, stage
, WINED3DTA_TEXTURE
);
5551 shader_addline(buffer
, "SUB arg0.w, const.x, %s.w;\n", arg0
);
5552 shader_addline(buffer
, "MAD_SAT %s%s, %s, arg0.w, %s;\n", dstreg
, dstmask
, arg2
, arg1
);
5555 /* D3DTOP_PREMODULATE ???? */
5557 case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR
:
5558 shader_addline(buffer
, "SUB arg0.w, const.x, %s;\n", arg1
);
5559 shader_addline(buffer
, "MAD_SAT %s%s, arg0.w, %s, %s;\n", dstreg
, dstmask
, arg2
, arg1
);
5561 case WINED3DTOP_MODULATEALPHA_ADDCOLOR
:
5562 shader_addline(buffer
, "MAD_SAT %s%s, %s.w, %s, %s;\n", dstreg
, dstmask
, arg1
, arg2
, arg1
);
5564 case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA
:
5565 shader_addline(buffer
, "SUB arg0, const.x, %s;\n", arg1
);
5566 shader_addline(buffer
, "MAD_SAT %s%s, arg0, %s, %s.w;\n", dstreg
, dstmask
, arg2
, arg1
);
5568 case WINED3DTOP_MODULATECOLOR_ADDALPHA
:
5569 shader_addline(buffer
, "MAD_SAT %s%s, %s, %s, %s.w;\n", dstreg
, dstmask
, arg1
, arg2
, arg1
);
5572 case WINED3DTOP_DOTPRODUCT3
:
5574 if(strcmp(dstreg
, "result.color") == 0) {
5576 mul_final_dest
= TRUE
;
5578 shader_addline(buffer
, "SUB arg1, %s, const.w;\n", arg1
);
5579 shader_addline(buffer
, "SUB arg2, %s, const.w;\n", arg2
);
5580 shader_addline(buffer
, "DP3_SAT %s%s, arg1, arg2;\n", dstreg
, dstmask
);
5583 case WINED3DTOP_MULTIPLYADD
:
5584 shader_addline(buffer
, "MAD_SAT %s%s, %s, %s, %s;\n", dstreg
, dstmask
, arg1
, arg2
, arg0
);
5587 case WINED3DTOP_LERP
:
5588 /* The msdn is not quite right here */
5589 shader_addline(buffer
, "LRP %s%s, %s, %s, %s;\n", dstreg
, dstmask
, arg0
, arg1
, arg2
);
5592 case WINED3DTOP_BUMPENVMAP
:
5593 case WINED3DTOP_BUMPENVMAPLUMINANCE
:
5594 /* Those are handled in the first pass of the shader(generation pass 1 and 2) already */
5598 FIXME("Unhandled texture op %08x\n", op
);
5602 shader_addline(buffer
, "MUL_SAT %s%s, %s, const.y;\n", mul_final_dest
? "result.color" : dstreg
, dstmask
, dstreg
);
5603 } else if(mul
== 4) {
5604 shader_addline(buffer
, "MUL_SAT %s%s, %s, const.z;\n", mul_final_dest
? "result.color" : dstreg
, dstmask
, dstreg
);
5608 /* The stateblock is passed for GLINFO_LOCATION */
5609 static GLuint
gen_arbfp_ffp_shader(const struct ffp_frag_settings
*settings
, IWineD3DStateBlockImpl
*stateblock
)
5612 struct wined3d_shader_buffer buffer
;
5613 BOOL tex_read
[MAX_TEXTURES
] = {FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
};
5614 BOOL bump_used
[MAX_TEXTURES
] = {FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
};
5615 BOOL luminance_used
[MAX_TEXTURES
] = {FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
};
5616 const char *textype
;
5617 const char *instr
, *sat
;
5618 char colorcor_dst
[8];
5620 DWORD arg0
, arg1
, arg2
;
5621 BOOL tempreg_used
= FALSE
, tfactor_used
= FALSE
;
5623 const char *final_combiner_src
= "ret";
5626 /* Find out which textures are read */
5627 for(stage
= 0; stage
< MAX_TEXTURES
; stage
++) {
5628 if(settings
->op
[stage
].cop
== WINED3DTOP_DISABLE
) break;
5629 arg0
= settings
->op
[stage
].carg0
& WINED3DTA_SELECTMASK
;
5630 arg1
= settings
->op
[stage
].carg1
& WINED3DTA_SELECTMASK
;
5631 arg2
= settings
->op
[stage
].carg2
& WINED3DTA_SELECTMASK
;
5632 if(arg0
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5633 if(arg1
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5634 if(arg2
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5636 if(settings
->op
[stage
].cop
== WINED3DTOP_BLENDTEXTUREALPHA
) tex_read
[stage
] = TRUE
;
5637 if(settings
->op
[stage
].cop
== WINED3DTOP_BLENDTEXTUREALPHAPM
) tex_read
[stage
] = TRUE
;
5638 if(settings
->op
[stage
].cop
== WINED3DTOP_BUMPENVMAP
) {
5639 bump_used
[stage
] = TRUE
;
5640 tex_read
[stage
] = TRUE
;
5642 if(settings
->op
[stage
].cop
== WINED3DTOP_BUMPENVMAPLUMINANCE
) {
5643 bump_used
[stage
] = TRUE
;
5644 tex_read
[stage
] = TRUE
;
5645 luminance_used
[stage
] = TRUE
;
5646 } else if(settings
->op
[stage
].cop
== WINED3DTOP_BLENDFACTORALPHA
) {
5647 tfactor_used
= TRUE
;
5650 if(arg0
== WINED3DTA_TFACTOR
|| arg1
== WINED3DTA_TFACTOR
|| arg2
== WINED3DTA_TFACTOR
) {
5651 tfactor_used
= TRUE
;
5654 if(settings
->op
[stage
].dst
== tempreg
) tempreg_used
= TRUE
;
5655 if(arg0
== WINED3DTA_TEMP
|| arg1
== WINED3DTA_TEMP
|| arg2
== WINED3DTA_TEMP
) {
5656 tempreg_used
= TRUE
;
5659 if(settings
->op
[stage
].aop
== WINED3DTOP_DISABLE
) continue;
5660 arg0
= settings
->op
[stage
].aarg0
& WINED3DTA_SELECTMASK
;
5661 arg1
= settings
->op
[stage
].aarg1
& WINED3DTA_SELECTMASK
;
5662 arg2
= settings
->op
[stage
].aarg2
& WINED3DTA_SELECTMASK
;
5663 if(arg0
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5664 if(arg1
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5665 if(arg2
== WINED3DTA_TEXTURE
) tex_read
[stage
] = TRUE
;
5667 if(arg0
== WINED3DTA_TEMP
|| arg1
== WINED3DTA_TEMP
|| arg2
== WINED3DTA_TEMP
) {
5668 tempreg_used
= TRUE
;
5670 if(arg0
== WINED3DTA_TFACTOR
|| arg1
== WINED3DTA_TFACTOR
|| arg2
== WINED3DTA_TFACTOR
) {
5671 tfactor_used
= TRUE
;
5676 if (!shader_buffer_init(&buffer
))
5678 ERR("Failed to initialize shader buffer.\n");
5682 shader_addline(&buffer
, "!!ARBfp1.0\n");
5684 switch(settings
->fog
) {
5685 case FOG_OFF
: break;
5686 case FOG_LINEAR
: shader_addline(&buffer
, "OPTION ARB_fog_linear;\n"); break;
5687 case FOG_EXP
: shader_addline(&buffer
, "OPTION ARB_fog_exp;\n"); break;
5688 case FOG_EXP2
: shader_addline(&buffer
, "OPTION ARB_fog_exp2;\n"); break;
5689 default: FIXME("Unexpected fog setting %d\n", settings
->fog
);
5692 shader_addline(&buffer
, "PARAM const = {1, 2, 4, 0.5};\n");
5693 shader_addline(&buffer
, "TEMP TMP;\n");
5694 shader_addline(&buffer
, "TEMP ret;\n");
5695 if(tempreg_used
|| settings
->sRGB_write
) shader_addline(&buffer
, "TEMP tempreg;\n");
5696 shader_addline(&buffer
, "TEMP arg0;\n");
5697 shader_addline(&buffer
, "TEMP arg1;\n");
5698 shader_addline(&buffer
, "TEMP arg2;\n");
5699 for(stage
= 0; stage
< MAX_TEXTURES
; stage
++) {
5700 if(!tex_read
[stage
]) continue;
5701 shader_addline(&buffer
, "TEMP tex%u;\n", stage
);
5702 if(!bump_used
[stage
]) continue;
5703 shader_addline(&buffer
, "PARAM bumpmat%u = program.env[%u];\n", stage
, ARB_FFP_CONST_BUMPMAT(stage
));
5704 if(!luminance_used
[stage
]) continue;
5705 shader_addline(&buffer
, "PARAM luminance%u = program.env[%u];\n", stage
, ARB_FFP_CONST_LUMINANCE(stage
));
5708 shader_addline(&buffer
, "PARAM tfactor = program.env[%u];\n", ARB_FFP_CONST_TFACTOR
);
5710 shader_addline(&buffer
, "PARAM specular_enable = program.env[%u];\n", ARB_FFP_CONST_SPECULAR_ENABLE
);
5712 if(settings
->sRGB_write
) {
5713 shader_addline(&buffer
, "PARAM srgb_consts1 = {%f, %f, %f, %f};\n",
5714 srgb_mul_low
, srgb_cmp
, srgb_pow
, srgb_mul_high
);
5715 shader_addline(&buffer
, "PARAM srgb_consts2 = {%f, %f, %f, %f};\n",
5716 srgb_sub_high
, 0.0, 0.0, 0.0);
5719 if(ffp_clip_emul(stateblock
) && settings
->emul_clipplanes
) shader_addline(&buffer
, "KIL fragment.texcoord[7];\n");
5721 /* Generate texture sampling instructions) */
5722 for(stage
= 0; stage
< MAX_TEXTURES
&& settings
->op
[stage
].cop
!= WINED3DTOP_DISABLE
; stage
++) {
5723 if(!tex_read
[stage
]) continue;
5725 switch(settings
->op
[stage
].tex_type
) {
5726 case tex_1d
: textype
= "1D"; break;
5727 case tex_2d
: textype
= "2D"; break;
5728 case tex_3d
: textype
= "3D"; break;
5729 case tex_cube
: textype
= "CUBE"; break;
5730 case tex_rect
: textype
= "RECT"; break;
5731 default: textype
= "unexpected_textype"; break;
5734 if(settings
->op
[stage
].cop
== WINED3DTOP_BUMPENVMAP
||
5735 settings
->op
[stage
].cop
== WINED3DTOP_BUMPENVMAPLUMINANCE
) {
5741 if(settings
->op
[stage
].projected
== proj_none
) {
5743 } else if(settings
->op
[stage
].projected
== proj_count4
||
5744 settings
->op
[stage
].projected
== proj_count3
) {
5747 FIXME("Unexpected projection mode %d\n", settings
->op
[stage
].projected
);
5752 (settings
->op
[stage
- 1].cop
== WINED3DTOP_BUMPENVMAP
||
5753 settings
->op
[stage
- 1].cop
== WINED3DTOP_BUMPENVMAPLUMINANCE
)) {
5754 shader_addline(&buffer
, "SWZ arg1, bumpmat%u, x, z, 0, 0;\n", stage
- 1);
5755 shader_addline(&buffer
, "DP3 ret.x, arg1, tex%u;\n", stage
- 1);
5756 shader_addline(&buffer
, "SWZ arg1, bumpmat%u, y, w, 0, 0;\n", stage
- 1);
5757 shader_addline(&buffer
, "DP3 ret.y, arg1, tex%u;\n", stage
- 1);
5759 /* with projective textures, texbem only divides the static texture coord, not the displacement,
5760 * so multiply the displacement with the dividing parameter before passing it to TXP
5762 if (settings
->op
[stage
].projected
!= proj_none
) {
5763 if(settings
->op
[stage
].projected
== proj_count4
) {
5764 shader_addline(&buffer
, "MOV ret.w, fragment.texcoord[%u].w;\n", stage
);
5765 shader_addline(&buffer
, "MUL ret.xyz, ret, fragment.texcoord[%u].w, fragment.texcoord[%u];\n", stage
, stage
);
5767 shader_addline(&buffer
, "MOV ret.w, fragment.texcoord[%u].z;\n", stage
);
5768 shader_addline(&buffer
, "MAD ret.xyz, ret, fragment.texcoord[%u].z, fragment.texcoord[%u];\n", stage
, stage
);
5771 shader_addline(&buffer
, "ADD ret, ret, fragment.texcoord[%u];\n", stage
);
5774 shader_addline(&buffer
, "%s%s tex%u, ret, texture[%u], %s;\n",
5775 instr
, sat
, stage
, stage
, textype
);
5776 if(settings
->op
[stage
- 1].cop
== WINED3DTOP_BUMPENVMAPLUMINANCE
) {
5777 shader_addline(&buffer
, "MAD_SAT ret.x, tex%u.z, luminance%u.x, luminance%u.y;\n",
5778 stage
- 1, stage
- 1, stage
- 1);
5779 shader_addline(&buffer
, "MUL tex%u, tex%u, ret.x;\n", stage
, stage
);
5781 } else if(settings
->op
[stage
].projected
== proj_count3
) {
5782 shader_addline(&buffer
, "MOV ret, fragment.texcoord[%u];\n", stage
);
5783 shader_addline(&buffer
, "MOV ret.w, ret.z;\n");
5784 shader_addline(&buffer
, "%s%s tex%u, ret, texture[%u], %s;\n",
5785 instr
, sat
, stage
, stage
, textype
);
5787 shader_addline(&buffer
, "%s%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n",
5788 instr
, sat
, stage
, stage
, stage
, textype
);
5791 sprintf(colorcor_dst
, "tex%u", stage
);
5792 gen_color_correction(&buffer
, colorcor_dst
, WINED3DSP_WRITEMASK_ALL
, "const.x", "const.y",
5793 settings
->op
[stage
].color_fixup
);
5796 /* Generate the main shader */
5797 for(stage
= 0; stage
< MAX_TEXTURES
; stage
++) {
5798 if(settings
->op
[stage
].cop
== WINED3DTOP_DISABLE
) {
5800 final_combiner_src
= "fragment.color.primary";
5805 if(settings
->op
[stage
].cop
== WINED3DTOP_SELECTARG1
&&
5806 settings
->op
[stage
].aop
== WINED3DTOP_SELECTARG1
) {
5807 op_equal
= settings
->op
[stage
].carg1
== settings
->op
[stage
].aarg1
;
5808 } else if(settings
->op
[stage
].cop
== WINED3DTOP_SELECTARG1
&&
5809 settings
->op
[stage
].aop
== WINED3DTOP_SELECTARG2
) {
5810 op_equal
= settings
->op
[stage
].carg1
== settings
->op
[stage
].aarg2
;
5811 } else if(settings
->op
[stage
].cop
== WINED3DTOP_SELECTARG2
&&
5812 settings
->op
[stage
].aop
== WINED3DTOP_SELECTARG1
) {
5813 op_equal
= settings
->op
[stage
].carg2
== settings
->op
[stage
].aarg1
;
5814 } else if(settings
->op
[stage
].cop
== WINED3DTOP_SELECTARG2
&&
5815 settings
->op
[stage
].aop
== WINED3DTOP_SELECTARG2
) {
5816 op_equal
= settings
->op
[stage
].carg2
== settings
->op
[stage
].aarg2
;
5818 op_equal
= settings
->op
[stage
].aop
== settings
->op
[stage
].cop
&&
5819 settings
->op
[stage
].carg0
== settings
->op
[stage
].aarg0
&&
5820 settings
->op
[stage
].carg1
== settings
->op
[stage
].aarg1
&&
5821 settings
->op
[stage
].carg2
== settings
->op
[stage
].aarg2
;
5824 if(settings
->op
[stage
].aop
== WINED3DTOP_DISABLE
) {
5825 gen_ffp_instr(&buffer
, stage
, TRUE
, FALSE
, settings
->op
[stage
].dst
,
5826 settings
->op
[stage
].cop
, settings
->op
[stage
].carg0
,
5827 settings
->op
[stage
].carg1
, settings
->op
[stage
].carg2
);
5829 shader_addline(&buffer
, "MOV ret.w, fragment.color.primary.w;\n");
5831 } else if(op_equal
) {
5832 gen_ffp_instr(&buffer
, stage
, TRUE
, TRUE
, settings
->op
[stage
].dst
,
5833 settings
->op
[stage
].cop
, settings
->op
[stage
].carg0
,
5834 settings
->op
[stage
].carg1
, settings
->op
[stage
].carg2
);
5836 gen_ffp_instr(&buffer
, stage
, TRUE
, FALSE
, settings
->op
[stage
].dst
,
5837 settings
->op
[stage
].cop
, settings
->op
[stage
].carg0
,
5838 settings
->op
[stage
].carg1
, settings
->op
[stage
].carg2
);
5839 gen_ffp_instr(&buffer
, stage
, FALSE
, TRUE
, settings
->op
[stage
].dst
,
5840 settings
->op
[stage
].aop
, settings
->op
[stage
].aarg0
,
5841 settings
->op
[stage
].aarg1
, settings
->op
[stage
].aarg2
);
5845 if(settings
->sRGB_write
) {
5846 shader_addline(&buffer
, "MAD ret, fragment.color.secondary, specular_enable, %s;\n", final_combiner_src
);
5847 arbfp_add_sRGB_correction(&buffer
, "ret", "arg0", "arg1", "arg2", "tempreg", FALSE
);
5848 shader_addline(&buffer
, "MOV result.color, ret;\n");
5850 shader_addline(&buffer
, "MAD result.color, fragment.color.secondary, specular_enable, %s;\n", final_combiner_src
);
5854 shader_addline(&buffer
, "END\n");
5856 /* Generate the shader */
5857 GL_EXTCALL(glGenProgramsARB(1, &ret
));
5858 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, ret
));
5859 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
5860 strlen(buffer
.buffer
), buffer
.buffer
));
5861 checkGLcall("glProgramStringARB()");
5863 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &pos
);
5866 FIXME("Fragment program error at position %d: %s\n", pos
,
5867 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
5873 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
5874 checkGLcall("glGetProgramivARB()");
5875 if (!native
) WARN("Program exceeds native resource limits.\n");
5878 shader_buffer_free(&buffer
);
5882 static void fragment_prog_arbfp(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5884 IWineD3DDeviceImpl
*device
= stateblock
->device
;
5885 struct shader_arb_priv
*priv
= device
->fragment_priv
;
5886 BOOL use_pshader
= use_ps(stateblock
);
5887 BOOL use_vshader
= use_vs(stateblock
);
5888 struct ffp_frag_settings settings
;
5889 const struct arbfp_ffp_desc
*desc
;
5892 TRACE("state %#x, stateblock %p, context %p\n", state
, stateblock
, context
);
5894 if(isStateDirty(context
, STATE_RENDER(WINED3DRS_FOGENABLE
))) {
5895 if(!use_pshader
&& device
->shader_backend
== &arb_program_shader_backend
&& context
->last_was_pshader
) {
5896 /* Reload fixed function constants since they collide with the pixel shader constants */
5897 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
5898 set_bumpmat_arbfp(STATE_TEXTURESTAGE(i
, WINED3DTSS_BUMPENVMAT00
), stateblock
, context
);
5900 state_texfactor_arbfp(STATE_RENDER(WINED3DRS_TEXTUREFACTOR
), stateblock
, context
);
5901 state_arb_specularenable(STATE_RENDER(WINED3DRS_SPECULARENABLE
), stateblock
, context
);
5902 } else if(use_pshader
&& !isStateDirty(context
, device
->StateTable
[STATE_VSHADER
].representative
)) {
5903 device
->shader_backend
->shader_select(context
, use_pshader
, use_vshader
);
5909 /* Find or create a shader implementing the fixed function pipeline settings, then activate it */
5910 gen_ffp_frag_op(stateblock
, &settings
, FALSE
);
5911 desc
= (const struct arbfp_ffp_desc
*)find_ffp_frag_shader(&priv
->fragment_shaders
, &settings
);
5913 struct arbfp_ffp_desc
*new_desc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_desc
));
5916 ERR("Out of memory\n");
5919 new_desc
->num_textures_used
= 0;
5920 for (i
= 0; i
< context
->gl_info
->limits
.texture_stages
; ++i
)
5922 if(settings
.op
[i
].cop
== WINED3DTOP_DISABLE
) break;
5923 new_desc
->num_textures_used
= i
;
5926 memcpy(&new_desc
->parent
.settings
, &settings
, sizeof(settings
));
5927 new_desc
->shader
= gen_arbfp_ffp_shader(&settings
, stateblock
);
5928 add_ffp_frag_shader(&priv
->fragment_shaders
, &new_desc
->parent
);
5929 TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc
);
5933 /* Now activate the replacement program. GL_FRAGMENT_PROGRAM_ARB is already active(however, note the
5934 * comment above the shader_select call below). If e.g. GLSL is active, the shader_select call will
5937 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, desc
->shader
));
5938 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, desc->shader)");
5939 priv
->current_fprogram_id
= desc
->shader
;
5941 if(device
->shader_backend
== &arb_program_shader_backend
&& context
->last_was_pshader
) {
5942 /* Reload fixed function constants since they collide with the pixel shader constants */
5943 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
5944 set_bumpmat_arbfp(STATE_TEXTURESTAGE(i
, WINED3DTSS_BUMPENVMAT00
), stateblock
, context
);
5946 state_texfactor_arbfp(STATE_RENDER(WINED3DRS_TEXTUREFACTOR
), stateblock
, context
);
5947 state_arb_specularenable(STATE_RENDER(WINED3DRS_SPECULARENABLE
), stateblock
, context
);
5949 context
->last_was_pshader
= FALSE
;
5951 context
->last_was_pshader
= TRUE
;
5954 /* Finally, select the shader. If a pixel shader is used, it will be set and enabled by the shader backend.
5955 * If this shader backend is arbfp(most likely), then it will simply overwrite the last fixed function replace-
5956 * ment shader. If the shader backend is not ARB, it currently is important that the opengl implementation
5957 * type overwrites GL_ARB_fragment_program. This is currently the case with GLSL. If we really want to use
5958 * atifs or nvrc pixel shaders with arb fragment programs we'd have to disable GL_FRAGMENT_PROGRAM_ARB here
5960 * Don't call shader_select if the vertex shader is dirty, because it will be called later on by the vertex
5963 if(!isStateDirty(context
, device
->StateTable
[STATE_VSHADER
].representative
)) {
5964 device
->shader_backend
->shader_select(context
, use_pshader
, use_vshader
);
5966 if (!isStateDirty(context
, STATE_VERTEXSHADERCONSTANT
) && (use_vshader
|| use_pshader
)) {
5967 device
->StateTable
[STATE_VERTEXSHADERCONSTANT
].apply(STATE_VERTEXSHADERCONSTANT
, stateblock
, context
);
5971 device
->StateTable
[STATE_PIXELSHADERCONSTANT
].apply(STATE_PIXELSHADERCONSTANT
, stateblock
, context
);
5975 /* We can't link the fog states to the fragment state directly since the vertex pipeline links them
5976 * to FOGENABLE. A different linking in different pipeline parts can't be expressed in the combined
5977 * state table, so we need to handle that with a forwarding function. The other invisible side effect
5978 * is that changing the fog start and fog end(which links to FOGENABLE in vertex) results in the
5979 * fragment_prog_arbfp function being called because FOGENABLE is dirty, which calls this function here
5981 static void state_arbfp_fog(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
5983 enum fogsource new_source
;
5985 TRACE("state %#x, stateblock %p, context %p\n", state
, stateblock
, context
);
5987 if(!isStateDirty(context
, STATE_PIXELSHADER
)) {
5988 fragment_prog_arbfp(state
, stateblock
, context
);
5991 if(!stateblock
->renderState
[WINED3DRS_FOGENABLE
]) return;
5993 if(stateblock
->renderState
[WINED3DRS_FOGTABLEMODE
] == WINED3DFOG_NONE
) {
5994 if(use_vs(stateblock
)) {
5995 new_source
= FOGSOURCE_VS
;
5997 if(stateblock
->renderState
[WINED3DRS_FOGVERTEXMODE
] == WINED3DFOG_NONE
|| context
->last_was_rhw
) {
5998 new_source
= FOGSOURCE_COORD
;
6000 new_source
= FOGSOURCE_FFP
;
6004 new_source
= FOGSOURCE_FFP
;
6006 if(new_source
!= context
->fog_source
) {
6007 context
->fog_source
= new_source
;
6008 state_fogstartend(STATE_RENDER(WINED3DRS_FOGSTART
), stateblock
, context
);
6012 static void textransform(DWORD state
, IWineD3DStateBlockImpl
*stateblock
, struct wined3d_context
*context
)
6014 if(!isStateDirty(context
, STATE_PIXELSHADER
)) {
6015 fragment_prog_arbfp(state
, stateblock
, context
);
6019 #undef GLINFO_LOCATION
6021 static const struct StateEntryTemplate arbfp_fragmentstate_template
[] = {
6022 {STATE_RENDER(WINED3DRS_TEXTUREFACTOR
), { STATE_RENDER(WINED3DRS_TEXTUREFACTOR
), state_texfactor_arbfp
}, WINED3D_GL_EXT_NONE
},
6023 {STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6024 {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6025 {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6026 {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6027 {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6028 {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6029 {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6030 {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6031 {STATE_TEXTURESTAGE(0, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6032 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6033 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6034 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6035 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6036 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6037 {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6038 {STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6039 {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6040 {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6041 {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6042 {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6043 {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6044 {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6045 {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6046 {STATE_TEXTURESTAGE(1, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6047 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6048 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6049 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6050 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6051 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6052 {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6053 {STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6054 {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6055 {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6056 {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6057 {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6058 {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6059 {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6060 {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6061 {STATE_TEXTURESTAGE(2, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6062 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6063 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6064 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6065 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6066 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6067 {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6068 {STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6069 {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6070 {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6071 {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6072 {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6073 {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6074 {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6075 {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6076 {STATE_TEXTURESTAGE(3, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6077 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6078 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6079 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6080 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6081 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6082 {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6083 {STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6084 {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6085 {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6086 {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6087 {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6088 {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6089 {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6090 {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6091 {STATE_TEXTURESTAGE(4, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6092 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6093 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6094 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6095 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6096 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6097 {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6098 {STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6099 {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6100 {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6101 {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6102 {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6103 {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6104 {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6105 {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6106 {STATE_TEXTURESTAGE(5, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6107 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6108 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6109 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6110 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6111 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6112 {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6113 {STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6114 {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6115 {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6116 {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6117 {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6118 {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6119 {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6120 {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6121 {STATE_TEXTURESTAGE(6, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6122 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6123 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6124 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6125 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6126 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6127 {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6128 {STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6129 {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6130 {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6131 {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6132 {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6133 {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG1
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6134 {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG2
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6135 {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG0
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6136 {STATE_TEXTURESTAGE(7, WINED3DTSS_RESULTARG
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6137 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6138 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT01
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6139 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT10
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6140 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT11
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00
), set_bumpmat_arbfp
}, WINED3D_GL_EXT_NONE
},
6141 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLSCALE
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6142 {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLOFFSET
), { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLSCALE
), tex_bumpenvlum_arbfp
}, WINED3D_GL_EXT_NONE
},
6143 {STATE_SAMPLER(0), { STATE_SAMPLER(0), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6144 {STATE_SAMPLER(1), { STATE_SAMPLER(1), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6145 {STATE_SAMPLER(2), { STATE_SAMPLER(2), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6146 {STATE_SAMPLER(3), { STATE_SAMPLER(3), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6147 {STATE_SAMPLER(4), { STATE_SAMPLER(4), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6148 {STATE_SAMPLER(5), { STATE_SAMPLER(5), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6149 {STATE_SAMPLER(6), { STATE_SAMPLER(6), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6150 {STATE_SAMPLER(7), { STATE_SAMPLER(7), sampler_texdim
}, WINED3D_GL_EXT_NONE
},
6151 {STATE_PIXELSHADER
, { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6152 {STATE_RENDER(WINED3DRS_FOGENABLE
), { STATE_RENDER(WINED3DRS_FOGENABLE
), state_arbfp_fog
}, WINED3D_GL_EXT_NONE
},
6153 {STATE_RENDER(WINED3DRS_FOGTABLEMODE
), { STATE_RENDER(WINED3DRS_FOGENABLE
), state_arbfp_fog
}, WINED3D_GL_EXT_NONE
},
6154 {STATE_RENDER(WINED3DRS_FOGVERTEXMODE
), { STATE_RENDER(WINED3DRS_FOGENABLE
), state_arbfp_fog
}, WINED3D_GL_EXT_NONE
},
6155 {STATE_RENDER(WINED3DRS_FOGSTART
), { STATE_RENDER(WINED3DRS_FOGSTART
), state_fogstartend
}, WINED3D_GL_EXT_NONE
},
6156 {STATE_RENDER(WINED3DRS_FOGEND
), { STATE_RENDER(WINED3DRS_FOGSTART
), state_fogstartend
}, WINED3D_GL_EXT_NONE
},
6157 {STATE_RENDER(WINED3DRS_SRGBWRITEENABLE
), { STATE_PIXELSHADER
, fragment_prog_arbfp
}, WINED3D_GL_EXT_NONE
},
6158 {STATE_RENDER(WINED3DRS_FOGCOLOR
), { STATE_RENDER(WINED3DRS_FOGCOLOR
), state_fogcolor
}, WINED3D_GL_EXT_NONE
},
6159 {STATE_RENDER(WINED3DRS_FOGDENSITY
), { STATE_RENDER(WINED3DRS_FOGDENSITY
), state_fogdensity
}, WINED3D_GL_EXT_NONE
},
6160 {STATE_TEXTURESTAGE(0,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(0, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6161 {STATE_TEXTURESTAGE(1,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(1, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6162 {STATE_TEXTURESTAGE(2,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(2, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6163 {STATE_TEXTURESTAGE(3,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(3, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6164 {STATE_TEXTURESTAGE(4,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(4, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6165 {STATE_TEXTURESTAGE(5,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(5, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6166 {STATE_TEXTURESTAGE(6,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(6, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6167 {STATE_TEXTURESTAGE(7,WINED3DTSS_TEXTURETRANSFORMFLAGS
),{STATE_TEXTURESTAGE(7, WINED3DTSS_TEXTURETRANSFORMFLAGS
), textransform
}, WINED3D_GL_EXT_NONE
},
6168 {STATE_RENDER(WINED3DRS_SPECULARENABLE
), { STATE_RENDER(WINED3DRS_SPECULARENABLE
), state_arb_specularenable
}, WINED3D_GL_EXT_NONE
},
6169 {0 /* Terminate */, { 0, 0 }, WINED3D_GL_EXT_NONE
},
6172 const struct fragment_pipeline arbfp_fragment_pipeline
= {
6177 shader_arb_color_fixup_supported
,
6178 arbfp_fragmentstate_template
,
6179 TRUE
/* We can disable projected textures */
6182 #define GLINFO_LOCATION device->adapter->gl_info
6184 struct arbfp_blit_priv
{
6185 GLenum yuy2_rect_shader
, yuy2_2d_shader
;
6186 GLenum uyvy_rect_shader
, uyvy_2d_shader
;
6187 GLenum yv12_rect_shader
, yv12_2d_shader
;
6190 static HRESULT
arbfp_blit_alloc(IWineD3DDevice
*iface
) {
6191 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) iface
;
6192 device
->blit_priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct arbfp_blit_priv
));
6193 if(!device
->blit_priv
) {
6194 ERR("Out of memory\n");
6195 return E_OUTOFMEMORY
;
6200 /* Context activation is done by the caller. */
6201 static void arbfp_blit_free(IWineD3DDevice
*iface
) {
6202 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) iface
;
6203 struct arbfp_blit_priv
*priv
= device
->blit_priv
;
6206 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->yuy2_rect_shader
));
6207 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->yuy2_2d_shader
));
6208 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->uyvy_rect_shader
));
6209 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->uyvy_2d_shader
));
6210 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->yv12_rect_shader
));
6211 GL_EXTCALL(glDeleteProgramsARB(1, &priv
->yv12_2d_shader
));
6212 checkGLcall("Delete yuv programs");
6215 HeapFree(GetProcessHeap(), 0, device
->blit_priv
);
6216 device
->blit_priv
= NULL
;
6219 static BOOL
gen_planar_yuv_read(struct wined3d_shader_buffer
*buffer
, enum yuv_fixup yuv_fixup
,
6220 GLenum textype
, char *luminance
)
6223 const char *tex
, *texinstr
;
6225 if (yuv_fixup
== YUV_FIXUP_UYVY
) {
6233 case GL_TEXTURE_2D
: tex
= "2D"; texinstr
= "TXP"; break;
6234 case GL_TEXTURE_RECTANGLE_ARB
: tex
= "RECT"; texinstr
= "TEX"; break;
6236 /* This is more tricky than just replacing the texture type - we have to navigate
6237 * properly in the texture to find the correct chroma values
6239 FIXME("Implement yuv correction for non-2d, non-rect textures\n");
6243 /* First we have to read the chroma values. This means we need at least two pixels(no filtering),
6244 * or 4 pixels(with filtering). To get the unmodified chromas, we have to rid ourselves of the
6245 * filtering when we sample the texture.
6247 * These are the rules for reading the chroma:
6253 * So we have to get the sampling x position in non-normalized coordinates in integers
6255 if(textype
!= GL_TEXTURE_RECTANGLE_ARB
) {
6256 shader_addline(buffer
, "MUL texcrd.xy, fragment.texcoord[0], size.x;\n");
6257 shader_addline(buffer
, "MOV texcrd.w, size.x;\n");
6259 shader_addline(buffer
, "MOV texcrd, fragment.texcoord[0];\n");
6261 /* We must not allow filtering between pixel x and x+1, this would mix U and V
6262 * Vertical filtering is ok. However, bear in mind that the pixel center is at
6265 shader_addline(buffer
, "FLR texcrd.x, texcrd.x;\n");
6266 shader_addline(buffer
, "ADD texcrd.x, texcrd.x, coef.y;\n");
6268 /* Divide the x coordinate by 0.5 and get the fraction. This gives 0.25 and 0.75 for the
6269 * even and odd pixels respectively
6271 shader_addline(buffer
, "MUL texcrd2, texcrd, coef.y;\n");
6272 shader_addline(buffer
, "FRC texcrd2, texcrd2;\n");
6274 /* Sample Pixel 1 */
6275 shader_addline(buffer
, "%s luminance, texcrd, texture[0], %s;\n", texinstr
, tex
);
6277 /* Put the value into either of the chroma values */
6278 shader_addline(buffer
, "SGE temp.x, texcrd2.x, coef.y;\n");
6279 shader_addline(buffer
, "MUL chroma.x, luminance.%c, temp.x;\n", chroma
);
6280 shader_addline(buffer
, "SLT temp.x, texcrd2.x, coef.y;\n");
6281 shader_addline(buffer
, "MUL chroma.y, luminance.%c, temp.x;\n", chroma
);
6283 /* Sample pixel 2. If we read an even pixel(SLT above returned 1), sample
6284 * the pixel right to the current one. Otherwise, sample the left pixel.
6285 * Bias and scale the SLT result to -1;1 and add it to the texcrd.x.
6287 shader_addline(buffer
, "MAD temp.x, temp.x, coef.z, -coef.x;\n");
6288 shader_addline(buffer
, "ADD texcrd.x, texcrd, temp.x;\n");
6289 shader_addline(buffer
, "%s luminance, texcrd, texture[0], %s;\n", texinstr
, tex
);
6291 /* Put the value into the other chroma */
6292 shader_addline(buffer
, "SGE temp.x, texcrd2.x, coef.y;\n");
6293 shader_addline(buffer
, "MAD chroma.y, luminance.%c, temp.x, chroma.y;\n", chroma
);
6294 shader_addline(buffer
, "SLT temp.x, texcrd2.x, coef.y;\n");
6295 shader_addline(buffer
, "MAD chroma.x, luminance.%c, temp.x, chroma.x;\n", chroma
);
6297 /* TODO: If filtering is enabled, sample a 2nd pair of pixels left or right of
6298 * the current one and lerp the two U and V values
6301 /* This gives the correctly filtered luminance value */
6302 shader_addline(buffer
, "TEX luminance, fragment.texcoord[0], texture[0], %s;\n", tex
);
6307 static BOOL
gen_yv12_read(struct wined3d_shader_buffer
*buffer
, GLenum textype
, char *luminance
)
6312 case GL_TEXTURE_2D
: tex
= "2D"; break;
6313 case GL_TEXTURE_RECTANGLE_ARB
: tex
= "RECT"; break;
6315 FIXME("Implement yv12 correction for non-2d, non-rect textures\n");
6319 /* YV12 surfaces contain a WxH sized luminance plane, followed by a (W/2)x(H/2)
6320 * V and a (W/2)x(H/2) U plane, each with 8 bit per pixel. So the effective
6321 * bitdepth is 12 bits per pixel. Since the U and V planes have only half the
6322 * pitch of the luminance plane, the packing into the gl texture is a bit
6323 * unfortunate. If the whole texture is interpreted as luminance data it looks
6324 * approximately like this:
6326 * +----------------------------------+----
6338 * +----------------+-----------------+----
6340 * | U even rows | U odd rows |
6342 * +----------------+------------------ -
6344 * | V even rows | V odd rows |
6346 * +----------------+-----------------+----
6350 * So it appears as if there are 4 chroma images, but in fact the odd rows
6351 * in the chroma images are in the same row as the even ones. So its is
6352 * kinda tricky to read
6354 * When reading from rectangle textures, keep in mind that the input y coordinates
6355 * go from 0 to d3d_height, whereas the opengl texture height is 1.5 * d3d_height
6357 shader_addline(buffer
, "PARAM yv12_coef = {%f, %f, %f, %f};\n",
6358 2.0f
/ 3.0f
, 1.0f
/ 6.0f
, (2.0f
/ 3.0f
) + (1.0f
/ 6.0f
), 1.0f
/ 3.0f
);
6360 shader_addline(buffer
, "MOV texcrd, fragment.texcoord[0];\n");
6361 /* the chroma planes have only half the width */
6362 shader_addline(buffer
, "MUL texcrd.x, texcrd.x, coef.y;\n");
6364 /* The first value is between 2/3 and 5/6th of the texture's height, so scale+bias
6365 * the coordinate. Also read the right side of the image when reading odd lines
6367 * Don't forget to clamp the y values in into the range, otherwise we'll get filtering
6370 if(textype
== GL_TEXTURE_2D
) {
6372 shader_addline(buffer
, "RCP chroma.w, size.y;\n");
6374 shader_addline(buffer
, "MUL texcrd2.y, texcrd.y, size.y;\n");
6376 shader_addline(buffer
, "FLR texcrd2.y, texcrd2.y;\n");
6377 shader_addline(buffer
, "MAD texcrd.y, texcrd.y, yv12_coef.y, yv12_coef.x;\n");
6379 /* Read odd lines from the right side(add size * 0.5 to the x coordinate */
6380 shader_addline(buffer
, "ADD texcrd2.x, texcrd2.y, yv12_coef.y;\n"); /* To avoid 0.5 == 0.5 comparisons */
6381 shader_addline(buffer
, "FRC texcrd2.x, texcrd2.x;\n");
6382 shader_addline(buffer
, "SGE texcrd2.x, texcrd2.x, coef.y;\n");
6383 shader_addline(buffer
, "MAD texcrd.x, texcrd2.x, coef.y, texcrd.x;\n");
6385 /* clamp, keep the half pixel origin in mind */
6386 shader_addline(buffer
, "MAD temp.y, coef.y, chroma.w, yv12_coef.x;\n");
6387 shader_addline(buffer
, "MAX texcrd.y, temp.y, texcrd.y;\n");
6388 shader_addline(buffer
, "MAD temp.y, -coef.y, chroma.w, yv12_coef.z;\n");
6389 shader_addline(buffer
, "MIN texcrd.y, temp.y, texcrd.y;\n");
6391 /* Read from [size - size+size/4] */
6392 shader_addline(buffer
, "FLR texcrd.y, texcrd.y;\n");
6393 shader_addline(buffer
, "MAD texcrd.y, texcrd.y, coef.w, size.y;\n");
6395 /* Read odd lines from the right side(add size * 0.5 to the x coordinate */
6396 shader_addline(buffer
, "ADD texcrd2.x, texcrd.y, yv12_coef.y;\n"); /* To avoid 0.5 == 0.5 comparisons */
6397 shader_addline(buffer
, "FRC texcrd2.x, texcrd2.x;\n");
6398 shader_addline(buffer
, "SGE texcrd2.x, texcrd2.x, coef.y;\n");
6399 shader_addline(buffer
, "MUL texcrd2.x, texcrd2.x, size.x;\n");
6400 shader_addline(buffer
, "MAD texcrd.x, texcrd2.x, coef.y, texcrd.x;\n");
6402 /* Make sure to read exactly from the pixel center */
6403 shader_addline(buffer
, "FLR texcrd.y, texcrd.y;\n");
6404 shader_addline(buffer
, "ADD texcrd.y, texcrd.y, coef.y;\n");
6407 shader_addline(buffer
, "MAD temp.y, size.y, coef.w, size.y;\n");
6408 shader_addline(buffer
, "ADD temp.y, temp.y, -coef.y;\n");
6409 shader_addline(buffer
, "MIN texcrd.y, temp.y, texcrd.y;\n");
6410 shader_addline(buffer
, "ADD temp.y, size.y, -coef.y;\n");
6411 shader_addline(buffer
, "MAX texcrd.y, temp.y, texcrd.y;\n");
6413 /* Read the texture, put the result into the output register */
6414 shader_addline(buffer
, "TEX temp, texcrd, texture[0], %s;\n", tex
);
6415 shader_addline(buffer
, "MOV chroma.x, temp.w;\n");
6417 /* The other chroma value is 1/6th of the texture lower, from 5/6th to 6/6th
6418 * No need to clamp because we're just reusing the already clamped value from above
6420 if(textype
== GL_TEXTURE_2D
) {
6421 shader_addline(buffer
, "ADD texcrd.y, texcrd.y, yv12_coef.y;\n");
6423 shader_addline(buffer
, "MAD texcrd.y, size.y, coef.w, texcrd.y;\n");
6425 shader_addline(buffer
, "TEX temp, texcrd, texture[0], %s;\n", tex
);
6426 shader_addline(buffer
, "MOV chroma.y, temp.w;\n");
6428 /* Sample the luminance value. It is in the top 2/3rd of the texture, so scale the y coordinate.
6429 * Clamp the y coordinate to prevent the chroma values from bleeding into the sampled luminance
6430 * values due to filtering
6432 shader_addline(buffer
, "MOV texcrd, fragment.texcoord[0];\n");
6433 if(textype
== GL_TEXTURE_2D
) {
6434 /* Multiply the y coordinate by 2/3 and clamp it */
6435 shader_addline(buffer
, "MUL texcrd.y, texcrd.y, yv12_coef.x;\n");
6436 shader_addline(buffer
, "MAD temp.y, -coef.y, chroma.w, yv12_coef.x;\n");
6437 shader_addline(buffer
, "MIN texcrd.y, temp.y, texcrd.y;\n");
6438 shader_addline(buffer
, "TEX luminance, texcrd, texture[0], %s;\n", tex
);
6440 /* Reading from texture_rectangles is pretty straightforward, just use the unmodified
6441 * texture coordinate. It is still a good idea to clamp it though, since the opengl texture
6444 shader_addline(buffer
, "ADD temp.x, size.y, -coef.y;\n");
6445 shader_addline(buffer
, "MIN texcrd.y, texcrd.y, size.x;\n");
6446 shader_addline(buffer
, "TEX luminance, texcrd, texture[0], %s;\n", tex
);
6453 /* Context activation is done by the caller. */
6454 static GLuint
gen_yuv_shader(IWineD3DDeviceImpl
*device
, enum yuv_fixup yuv_fixup
, GLenum textype
)
6457 struct wined3d_shader_buffer buffer
;
6458 char luminance_component
;
6459 struct arbfp_blit_priv
*priv
= device
->blit_priv
;
6463 if (!shader_buffer_init(&buffer
))
6465 ERR("Failed to initialize shader buffer.\n");
6470 GL_EXTCALL(glGenProgramsARB(1, &shader
));
6471 checkGLcall("GL_EXTCALL(glGenProgramsARB(1, &shader))");
6472 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, shader
));
6473 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)");
6476 shader_buffer_free(&buffer
);
6480 /* The YUY2 and UYVY formats contain two pixels packed into a 32 bit macropixel,
6481 * giving effectively 16 bit per pixel. The color consists of a luminance(Y) and
6482 * two chroma(U and V) values. Each macropixel has two luminance values, one for
6483 * each single pixel it contains, and one U and one V value shared between both
6486 * The data is loaded into an A8L8 texture. With YUY2, the luminance component
6487 * contains the luminance and alpha the chroma. With UYVY it is vice versa. Thus
6488 * take the format into account when generating the read swizzles
6490 * Reading the Y value is straightforward - just sample the texture. The hardware
6491 * takes care of filtering in the horizontal and vertical direction.
6493 * Reading the U and V values is harder. We have to avoid filtering horizontally,
6494 * because that would mix the U and V values of one pixel or two adjacent pixels.
6495 * Thus floor the texture coordinate and add 0.5 to get an unfiltered read,
6496 * regardless of the filtering setting. Vertical filtering works automatically
6497 * though - the U and V values of two rows are mixed nicely.
6499 * Appart of avoiding filtering issues, the code has to know which value it just
6500 * read, and where it can find the other one. To determine this, it checks if
6501 * it sampled an even or odd pixel, and shifts the 2nd read accordingly.
6503 * Handling horizontal filtering of U and V values requires reading a 2nd pair
6504 * of pixels, extracting U and V and mixing them. This is not implemented yet.
6506 * An alternative implementation idea is to load the texture as A8R8G8B8 texture,
6507 * with width / 2. This way one read gives all 3 values, finding U and V is easy
6508 * in an unfiltered situation. Finding the luminance on the other hand requires
6509 * finding out if it is an odd or even pixel. The real drawback of this approach
6510 * is filtering. This would have to be emulated completely in the shader, reading
6511 * up two 2 packed pixels in up to 2 rows and interpolating both horizontally and
6512 * vertically. Beyond that it would require adjustments to the texture handling
6513 * code to deal with the width scaling
6515 shader_addline(&buffer
, "!!ARBfp1.0\n");
6516 shader_addline(&buffer
, "TEMP luminance;\n");
6517 shader_addline(&buffer
, "TEMP temp;\n");
6518 shader_addline(&buffer
, "TEMP chroma;\n");
6519 shader_addline(&buffer
, "TEMP texcrd;\n");
6520 shader_addline(&buffer
, "TEMP texcrd2;\n");
6521 shader_addline(&buffer
, "PARAM coef = {1.0, 0.5, 2.0, 0.25};\n");
6522 shader_addline(&buffer
, "PARAM yuv_coef = {1.403, 0.344, 0.714, 1.770};\n");
6523 shader_addline(&buffer
, "PARAM size = program.local[0];\n");
6527 case YUV_FIXUP_UYVY
:
6528 case YUV_FIXUP_YUY2
:
6529 if (!gen_planar_yuv_read(&buffer
, yuv_fixup
, textype
, &luminance_component
))
6531 shader_buffer_free(&buffer
);
6536 case YUV_FIXUP_YV12
:
6537 if (!gen_yv12_read(&buffer
, textype
, &luminance_component
))
6539 shader_buffer_free(&buffer
);
6545 FIXME("Unsupported YUV fixup %#x\n", yuv_fixup
);
6546 shader_buffer_free(&buffer
);
6550 /* Calculate the final result. Formula is taken from
6551 * http://www.fourcc.org/fccyvrgb.php. Note that the chroma
6552 * ranges from -0.5 to 0.5
6554 shader_addline(&buffer
, "SUB chroma.xy, chroma, coef.y;\n");
6556 shader_addline(&buffer
, "MAD result.color.x, chroma.x, yuv_coef.x, luminance.%c;\n", luminance_component
);
6557 shader_addline(&buffer
, "MAD temp.x, -chroma.y, yuv_coef.y, luminance.%c;\n", luminance_component
);
6558 shader_addline(&buffer
, "MAD result.color.y, -chroma.x, yuv_coef.z, temp.x;\n");
6559 shader_addline(&buffer
, "MAD result.color.z, chroma.y, yuv_coef.w, luminance.%c;\n", luminance_component
);
6560 shader_addline(&buffer
, "END\n");
6563 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
6564 strlen(buffer
.buffer
), buffer
.buffer
));
6565 checkGLcall("glProgramStringARB()");
6567 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &pos
);
6570 FIXME("Fragment program error at position %d: %s\n", pos
,
6571 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
6577 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
));
6578 checkGLcall("glGetProgramivARB()");
6579 if (!native
) WARN("Program exceeds native resource limits.\n");
6582 shader_buffer_free(&buffer
);
6587 case YUV_FIXUP_YUY2
:
6588 if (textype
== GL_TEXTURE_RECTANGLE_ARB
) priv
->yuy2_rect_shader
= shader
;
6589 else priv
->yuy2_2d_shader
= shader
;
6592 case YUV_FIXUP_UYVY
:
6593 if (textype
== GL_TEXTURE_RECTANGLE_ARB
) priv
->uyvy_rect_shader
= shader
;
6594 else priv
->uyvy_2d_shader
= shader
;
6597 case YUV_FIXUP_YV12
:
6598 if (textype
== GL_TEXTURE_RECTANGLE_ARB
) priv
->yv12_rect_shader
= shader
;
6599 else priv
->yv12_2d_shader
= shader
;
6606 /* Context activation is done by the caller. */
6607 static HRESULT
arbfp_blit_set(IWineD3DDevice
*iface
, const struct GlPixelFormatDesc
*format_desc
,
6608 GLenum textype
, UINT width
, UINT height
)
6611 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) iface
;
6612 float size
[4] = {width
, height
, 1, 1};
6613 struct arbfp_blit_priv
*priv
= device
->blit_priv
;
6614 enum yuv_fixup yuv_fixup
;
6616 if (!is_yuv_fixup(format_desc
->color_fixup
))
6619 dump_color_fixup_desc(format_desc
->color_fixup
);
6620 /* Don't bother setting up a shader for unconverted formats */
6623 checkGLcall("glEnable(textype)");
6628 yuv_fixup
= get_yuv_fixup(format_desc
->color_fixup
);
6632 case YUV_FIXUP_YUY2
:
6633 shader
= textype
== GL_TEXTURE_RECTANGLE_ARB
? priv
->yuy2_rect_shader
: priv
->yuy2_2d_shader
;
6636 case YUV_FIXUP_UYVY
:
6637 shader
= textype
== GL_TEXTURE_RECTANGLE_ARB
? priv
->uyvy_rect_shader
: priv
->uyvy_2d_shader
;
6640 case YUV_FIXUP_YV12
:
6641 shader
= textype
== GL_TEXTURE_RECTANGLE_ARB
? priv
->yv12_rect_shader
: priv
->yv12_2d_shader
;
6645 FIXME("Unsupported YUV fixup %#x, not setting a shader\n", yuv_fixup
);
6648 checkGLcall("glEnable(textype)");
6653 if (!shader
) shader
= gen_yuv_shader(device
, yuv_fixup
, textype
);
6656 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
6657 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");
6658 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, shader
));
6659 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)");
6660 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
, 0, size
));
6661 checkGLcall("glProgramLocalParameter4fvARB");
6667 /* Context activation is done by the caller. */
6668 static void arbfp_blit_unset(IWineD3DDevice
*iface
) {
6669 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) iface
;
6670 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6673 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
6674 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
6675 glDisable(GL_TEXTURE_2D
);
6676 checkGLcall("glDisable(GL_TEXTURE_2D)");
6677 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
6679 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
6680 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6682 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
6684 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
6685 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6690 static BOOL
arbfp_blit_color_fixup_supported(struct color_fixup_desc fixup
)
6692 enum yuv_fixup yuv_fixup
;
6694 if (TRACE_ON(d3d_shader
) && TRACE_ON(d3d
))
6696 TRACE("Checking support for fixup:\n");
6697 dump_color_fixup_desc(fixup
);
6700 if (is_identity_fixup(fixup
))
6706 /* We only support YUV conversions. */
6707 if (!is_yuv_fixup(fixup
))
6709 TRACE("[FAILED]\n");
6713 yuv_fixup
= get_yuv_fixup(fixup
);
6716 case YUV_FIXUP_YUY2
:
6717 case YUV_FIXUP_UYVY
:
6718 case YUV_FIXUP_YV12
:
6723 FIXME("Unsupported YUV fixup %#x\n", yuv_fixup
);
6724 TRACE("[FAILED]\n");
6729 const struct blit_shader arbfp_blit
= {
6734 arbfp_blit_color_fixup_supported
,
6737 #undef GLINFO_LOCATION