wined3d: Recognize SM5 imm_atomic_and opcode.
[wine.git] / dlls / wined3d / glsl_shader.c
blob7daa67ba174338be6e7847537a24d2537507b0d4
1 /*
2 * GLSL pixel and vertex shader implementation
4 * Copyright 2006 Jason Green
5 * Copyright 2006-2007 Henri Verbeet
6 * Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers
7 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * D3D shader asm has swizzles on source parameters, and write masks for
26 * destination parameters. GLSL uses swizzles for both. The result of this is
27 * that for example "mov dst.xw, src.zyxw" becomes "dst.xw = src.zw" in GLSL.
28 * Ie, to generate a proper GLSL source swizzle, we need to take the D3D write
29 * mask for the destination parameter into account.
32 #include "config.h"
33 #include "wine/port.h"
35 #include <limits.h>
36 #include <stdio.h>
37 #ifdef HAVE_FLOAT_H
38 # include <float.h>
39 #endif
41 #include "wined3d_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
44 WINE_DECLARE_DEBUG_CHANNEL(d3d);
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
47 #define WINED3D_GLSL_SAMPLE_PROJECTED 0x01
48 #define WINED3D_GLSL_SAMPLE_LOD 0x02
49 #define WINED3D_GLSL_SAMPLE_GRAD 0x04
50 #define WINED3D_GLSL_SAMPLE_LOAD 0x08
51 #define WINED3D_GLSL_SAMPLE_OFFSET 0x10
53 static const struct
55 unsigned int coord_size;
56 unsigned int resinfo_size;
57 const char *type_part;
59 resource_type_info[] =
61 {0, 0, ""}, /* WINED3D_SHADER_RESOURCE_NONE */
62 {1, 1, ""}, /* WINED3D_SHADER_RESOURCE_BUFFER */
63 {1, 1, "1D"}, /* WINED3D_SHADER_RESOURCE_TEXTURE_1D */
64 {2, 2, "2D"}, /* WINED3D_SHADER_RESOURCE_TEXTURE_2D */
65 {2, 2, ""}, /* WINED3D_SHADER_RESOURCE_TEXTURE_2DMS */
66 {3, 3, "3D"}, /* WINED3D_SHADER_RESOURCE_TEXTURE_3D */
67 {3, 2, "Cube"}, /* WINED3D_SHADER_RESOURCE_TEXTURE_CUBE */
68 {2, 2, ""}, /* WINED3D_SHADER_RESOURCE_TEXTURE_1DARRAY */
69 {3, 3, "2DArray"}, /* WINED3D_SHADER_RESOURCE_TEXTURE_2DARRAY */
70 {3, 3, ""}, /* WINED3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY */
73 struct glsl_dst_param
75 char reg_name[150];
76 char mask_str[6];
79 struct glsl_src_param
81 char reg_name[150];
82 char param_str[200];
85 struct glsl_sample_function
87 struct wined3d_string_buffer *name;
88 unsigned int coord_mask;
89 unsigned int deriv_mask;
90 enum wined3d_data_type data_type;
91 BOOL output_single_component;
92 unsigned int offset_size;
95 enum heap_node_op
97 HEAP_NODE_TRAVERSE_LEFT,
98 HEAP_NODE_TRAVERSE_RIGHT,
99 HEAP_NODE_POP,
102 struct constant_entry
104 unsigned int idx;
105 unsigned int version;
108 struct constant_heap
110 struct constant_entry *entries;
111 BOOL *contained;
112 unsigned int *positions;
113 unsigned int size;
116 /* GLSL shader private data */
117 struct shader_glsl_priv {
118 struct wined3d_string_buffer shader_buffer;
119 struct wined3d_string_buffer_list string_buffers;
120 struct wine_rb_tree program_lookup;
121 struct constant_heap vconst_heap;
122 struct constant_heap pconst_heap;
123 unsigned char *stack;
124 GLuint depth_blt_program_full[WINED3D_GL_RES_TYPE_COUNT];
125 GLuint depth_blt_program_masked[WINED3D_GL_RES_TYPE_COUNT];
126 UINT next_constant_version;
128 const struct wined3d_vertex_pipe_ops *vertex_pipe;
129 const struct fragment_pipeline *fragment_pipe;
130 struct wine_rb_tree ffp_vertex_shaders;
131 struct wine_rb_tree ffp_fragment_shaders;
132 BOOL ffp_proj_control;
133 BOOL legacy_lighting;
136 struct glsl_vs_program
138 struct list shader_entry;
139 GLuint id;
140 GLenum vertex_color_clamp;
141 GLint uniform_f_locations[WINED3D_MAX_VS_CONSTS_F];
142 GLint uniform_i_locations[WINED3D_MAX_CONSTS_I];
143 GLint uniform_b_locations[WINED3D_MAX_CONSTS_B];
144 GLint pos_fixup_location;
146 GLint modelview_matrix_location[MAX_VERTEX_BLENDS];
147 GLint projection_matrix_location;
148 GLint normal_matrix_location;
149 GLint texture_matrix_location[MAX_TEXTURES];
150 GLint material_ambient_location;
151 GLint material_diffuse_location;
152 GLint material_specular_location;
153 GLint material_emissive_location;
154 GLint material_shininess_location;
155 GLint light_ambient_location;
156 struct
158 GLint diffuse;
159 GLint specular;
160 GLint ambient;
161 GLint position;
162 GLint direction;
163 GLint range;
164 GLint falloff;
165 GLint c_att;
166 GLint l_att;
167 GLint q_att;
168 GLint cos_htheta;
169 GLint cos_hphi;
170 } light_location[MAX_ACTIVE_LIGHTS];
171 GLint pointsize_location;
172 GLint pointsize_min_location;
173 GLint pointsize_max_location;
174 GLint pointsize_c_att_location;
175 GLint pointsize_l_att_location;
176 GLint pointsize_q_att_location;
177 GLint clip_planes_location;
180 struct glsl_gs_program
182 struct list shader_entry;
183 GLuint id;
185 GLint pos_fixup_location;
188 struct glsl_ps_program
190 struct list shader_entry;
191 GLuint id;
192 GLint uniform_f_locations[WINED3D_MAX_PS_CONSTS_F];
193 GLint uniform_i_locations[WINED3D_MAX_CONSTS_I];
194 GLint uniform_b_locations[WINED3D_MAX_CONSTS_B];
195 GLint bumpenv_mat_location[MAX_TEXTURES];
196 GLint bumpenv_lum_scale_location[MAX_TEXTURES];
197 GLint bumpenv_lum_offset_location[MAX_TEXTURES];
198 GLint tss_constant_location[MAX_TEXTURES];
199 GLint tex_factor_location;
200 GLint specular_enable_location;
201 GLint fog_color_location;
202 GLint fog_density_location;
203 GLint fog_end_location;
204 GLint fog_scale_location;
205 GLint alpha_test_ref_location;
206 GLint ycorrection_location;
207 GLint np2_fixup_location;
208 GLint color_key_location;
209 const struct ps_np2fixup_info *np2_fixup_info;
212 /* Struct to maintain data about a linked GLSL program */
213 struct glsl_shader_prog_link
215 struct wine_rb_entry program_lookup_entry;
216 struct glsl_vs_program vs;
217 struct glsl_gs_program gs;
218 struct glsl_ps_program ps;
219 GLuint id;
220 DWORD constant_update_mask;
221 UINT constant_version;
224 struct glsl_program_key
226 GLuint vs_id;
227 GLuint gs_id;
228 GLuint ps_id;
231 struct shader_glsl_ctx_priv {
232 const struct vs_compile_args *cur_vs_args;
233 const struct ps_compile_args *cur_ps_args;
234 struct ps_np2fixup_info *cur_np2fixup_info;
235 struct wined3d_string_buffer_list *string_buffers;
238 struct glsl_context_data
240 struct glsl_shader_prog_link *glsl_program;
243 struct glsl_ps_compiled_shader
245 struct ps_compile_args args;
246 struct ps_np2fixup_info np2fixup;
247 GLuint id;
250 struct glsl_vs_compiled_shader
252 struct vs_compile_args args;
253 GLuint id;
256 struct glsl_gs_compiled_shader
258 struct gs_compile_args args;
259 GLuint id;
262 struct glsl_shader_private
264 union
266 struct glsl_vs_compiled_shader *vs;
267 struct glsl_gs_compiled_shader *gs;
268 struct glsl_ps_compiled_shader *ps;
269 } gl_shaders;
270 UINT num_gl_shaders, shader_array_size;
273 struct glsl_ffp_vertex_shader
275 struct wined3d_ffp_vs_desc desc;
276 GLuint id;
277 struct list linked_programs;
280 struct glsl_ffp_fragment_shader
282 struct ffp_frag_desc entry;
283 GLuint id;
284 struct list linked_programs;
287 struct glsl_ffp_destroy_ctx
289 struct shader_glsl_priv *priv;
290 const struct wined3d_gl_info *gl_info;
293 static const char *debug_gl_shader_type(GLenum type)
295 switch (type)
297 #define WINED3D_TO_STR(u) case u: return #u
298 WINED3D_TO_STR(GL_VERTEX_SHADER);
299 WINED3D_TO_STR(GL_TESS_CONTROL_SHADER);
300 WINED3D_TO_STR(GL_TESS_EVALUATION_SHADER);
301 WINED3D_TO_STR(GL_GEOMETRY_SHADER);
302 WINED3D_TO_STR(GL_FRAGMENT_SHADER);
303 WINED3D_TO_STR(GL_COMPUTE_SHADER);
304 #undef WINED3D_TO_STR
305 default:
306 return wine_dbg_sprintf("UNKNOWN(%#x)", type);
310 static const char *shader_glsl_get_prefix(enum wined3d_shader_type type)
312 switch (type)
314 case WINED3D_SHADER_TYPE_VERTEX:
315 return "vs";
317 case WINED3D_SHADER_TYPE_HULL:
318 return "hs";
320 case WINED3D_SHADER_TYPE_DOMAIN:
321 return "ds";
323 case WINED3D_SHADER_TYPE_GEOMETRY:
324 return "gs";
326 case WINED3D_SHADER_TYPE_PIXEL:
327 return "ps";
329 case WINED3D_SHADER_TYPE_COMPUTE:
330 return "cs";
332 default:
333 FIXME("Unhandled shader type %#x.\n", type);
334 return "unknown";
338 static unsigned int shader_glsl_get_version(const struct wined3d_gl_info *gl_info,
339 const struct wined3d_shader_version *version)
341 if (!gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
342 return 150;
343 else if (gl_info->glsl_version >= MAKEDWORD_VERSION(1, 30) && version && version->major >= 4)
344 return 130;
345 else
346 return 120;
349 static const char *shader_glsl_get_version_declaration(const struct wined3d_gl_info *gl_info,
350 const struct wined3d_shader_version *version)
352 unsigned int glsl_version;
354 switch (glsl_version = shader_glsl_get_version(gl_info, version))
356 case 150:
357 return "#version 150";
358 case 130:
359 return "#version 130";
360 case 120:
361 return "#version 120";
362 default:
363 FIXME("Unexpected GLSL version %u requested.\n", glsl_version);
364 return "";
368 static void shader_glsl_append_imm_vec4(struct wined3d_string_buffer *buffer, const float *values)
370 char str[4][17];
372 wined3d_ftoa(values[0], str[0]);
373 wined3d_ftoa(values[1], str[1]);
374 wined3d_ftoa(values[2], str[2]);
375 wined3d_ftoa(values[3], str[3]);
376 shader_addline(buffer, "vec4(%s, %s, %s, %s)", str[0], str[1], str[2], str[3]);
379 static void shader_glsl_append_imm_ivec(struct wined3d_string_buffer *buffer,
380 const int *values, unsigned int size)
382 int i;
384 if (!size || size > 4)
386 ERR("Invalid vector size %u.\n", size);
387 return;
390 if (size > 1)
391 shader_addline(buffer, "ivec%u(", size);
393 for (i = 0; i < size; ++i)
394 shader_addline(buffer, i ? ", %#x" : "%#x", values[i]);
396 if (size > 1)
397 shader_addline(buffer, ")");
400 static const char *get_info_log_line(const char **ptr)
402 const char *p, *q;
404 p = *ptr;
405 if (!(q = strstr(p, "\n")))
407 if (!*p) return NULL;
408 *ptr += strlen(p);
409 return p;
411 *ptr = q + 1;
413 return p;
416 /* Context activation is done by the caller. */
417 void print_glsl_info_log(const struct wined3d_gl_info *gl_info, GLuint id, BOOL program)
419 int length = 0;
420 char *log;
422 if (!WARN_ON(d3d_shader) && !FIXME_ON(d3d_shader))
423 return;
425 if (program)
426 GL_EXTCALL(glGetProgramiv(id, GL_INFO_LOG_LENGTH, &length));
427 else
428 GL_EXTCALL(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
430 /* A size of 1 is just a null-terminated string, so the log should be bigger than
431 * that if there are errors. */
432 if (length > 1)
434 const char *ptr, *line;
436 log = HeapAlloc(GetProcessHeap(), 0, length);
437 /* The info log is supposed to be zero-terminated, but at least some
438 * versions of fglrx don't terminate the string properly. The reported
439 * length does include the terminator, so explicitly set it to zero
440 * here. */
441 log[length - 1] = 0;
442 if (program)
443 GL_EXTCALL(glGetProgramInfoLog(id, length, NULL, log));
444 else
445 GL_EXTCALL(glGetShaderInfoLog(id, length, NULL, log));
447 ptr = log;
448 if (gl_info->quirks & WINED3D_QUIRK_INFO_LOG_SPAM)
450 WARN("Info log received from GLSL shader #%u:\n", id);
451 while ((line = get_info_log_line(&ptr))) WARN(" %.*s", (int)(ptr - line), line);
453 else
455 FIXME("Info log received from GLSL shader #%u:\n", id);
456 while ((line = get_info_log_line(&ptr))) FIXME(" %.*s", (int)(ptr - line), line);
458 HeapFree(GetProcessHeap(), 0, log);
462 /* Context activation is done by the caller. */
463 static void shader_glsl_compile(const struct wined3d_gl_info *gl_info, GLuint shader, const char *src)
465 const char *ptr, *line;
467 TRACE("Compiling shader object %u.\n", shader);
469 if (TRACE_ON(d3d_shader))
471 ptr = src;
472 while ((line = get_info_log_line(&ptr))) TRACE_(d3d_shader)(" %.*s", (int)(ptr - line), line);
475 GL_EXTCALL(glShaderSource(shader, 1, &src, NULL));
476 checkGLcall("glShaderSource");
477 GL_EXTCALL(glCompileShader(shader));
478 checkGLcall("glCompileShader");
479 print_glsl_info_log(gl_info, shader, FALSE);
482 /* Context activation is done by the caller. */
483 static void shader_glsl_dump_program_source(const struct wined3d_gl_info *gl_info, GLuint program)
485 GLint i, shader_count, source_size = -1;
486 GLuint *shaders;
487 char *source = NULL;
489 GL_EXTCALL(glGetProgramiv(program, GL_ATTACHED_SHADERS, &shader_count));
490 if (!(shaders = wined3d_calloc(shader_count, sizeof(*shaders))))
492 ERR("Failed to allocate shader array memory.\n");
493 return;
496 GL_EXTCALL(glGetAttachedShaders(program, shader_count, NULL, shaders));
497 for (i = 0; i < shader_count; ++i)
499 const char *ptr, *line;
500 GLint tmp;
502 GL_EXTCALL(glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &tmp));
504 if (source_size < tmp)
506 HeapFree(GetProcessHeap(), 0, source);
508 source = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, tmp);
509 if (!source)
511 ERR("Failed to allocate %d bytes for shader source.\n", tmp);
512 HeapFree(GetProcessHeap(), 0, shaders);
513 return;
515 source_size = tmp;
518 FIXME("Shader %u:\n", shaders[i]);
519 GL_EXTCALL(glGetShaderiv(shaders[i], GL_SHADER_TYPE, &tmp));
520 FIXME(" GL_SHADER_TYPE: %s.\n", debug_gl_shader_type(tmp));
521 GL_EXTCALL(glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &tmp));
522 FIXME(" GL_COMPILE_STATUS: %d.\n", tmp);
523 FIXME("\n");
525 ptr = source;
526 GL_EXTCALL(glGetShaderSource(shaders[i], source_size, NULL, source));
527 while ((line = get_info_log_line(&ptr))) FIXME(" %.*s", (int)(ptr - line), line);
528 FIXME("\n");
531 HeapFree(GetProcessHeap(), 0, source);
532 HeapFree(GetProcessHeap(), 0, shaders);
535 /* Context activation is done by the caller. */
536 void shader_glsl_validate_link(const struct wined3d_gl_info *gl_info, GLuint program)
538 GLint tmp;
540 if (!TRACE_ON(d3d_shader) && !FIXME_ON(d3d_shader))
541 return;
543 GL_EXTCALL(glGetProgramiv(program, GL_LINK_STATUS, &tmp));
544 if (!tmp)
546 FIXME("Program %u link status invalid.\n", program);
547 shader_glsl_dump_program_source(gl_info, program);
550 print_glsl_info_log(gl_info, program, TRUE);
553 /* Context activation is done by the caller. */
554 static void shader_glsl_load_samplers(const struct wined3d_gl_info *gl_info,
555 struct shader_glsl_priv *priv, const DWORD *tex_unit_map, GLuint program_id)
557 unsigned int mapped_unit;
558 struct wined3d_string_buffer *sampler_name = string_buffer_get(&priv->string_buffers);
559 const char *prefix;
560 unsigned int i, j;
561 GLint name_loc;
563 static const struct
565 enum wined3d_shader_type type;
566 unsigned int base_idx;
567 unsigned int count;
569 sampler_info[] =
571 {WINED3D_SHADER_TYPE_PIXEL, 0, MAX_FRAGMENT_SAMPLERS},
572 {WINED3D_SHADER_TYPE_VERTEX, MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS},
575 for (i = 0; i < ARRAY_SIZE(sampler_info); ++i)
577 prefix = shader_glsl_get_prefix(sampler_info[i].type);
579 for (j = 0; j < sampler_info[i].count; ++j)
581 string_buffer_sprintf(sampler_name, "%s_sampler%u", prefix, j);
582 name_loc = GL_EXTCALL(glGetUniformLocation(program_id, sampler_name->buffer));
583 if (name_loc == -1)
584 continue;
586 mapped_unit = tex_unit_map[sampler_info[i].base_idx + j];
587 if (mapped_unit == WINED3D_UNMAPPED_STAGE || mapped_unit >= gl_info->limits.combined_samplers)
589 ERR("Trying to load sampler %s on unsupported unit %u.\n", sampler_name->buffer, mapped_unit);
590 continue;
593 TRACE("Loading sampler %s on unit %u.\n", sampler_name->buffer, mapped_unit);
594 GL_EXTCALL(glUniform1i(name_loc, mapped_unit));
597 checkGLcall("Load sampler bindings");
598 string_buffer_release(&priv->string_buffers, sampler_name);
601 static void shader_glsl_load_icb(const struct wined3d_gl_info *gl_info, struct shader_glsl_priv *priv,
602 GLuint program_id, const struct wined3d_shader_reg_maps *reg_maps)
604 const struct wined3d_shader_immediate_constant_buffer *icb = reg_maps->icb;
606 if (icb)
608 struct wined3d_string_buffer *icb_name = string_buffer_get(&priv->string_buffers);
609 const char *prefix = shader_glsl_get_prefix(reg_maps->shader_version.type);
610 GLint icb_location;
612 string_buffer_sprintf(icb_name, "%s_icb", prefix);
613 icb_location = GL_EXTCALL(glGetUniformLocation(program_id, icb_name->buffer));
614 GL_EXTCALL(glUniform4fv(icb_location, icb->vec4_count, (const GLfloat *)icb->data));
615 checkGLcall("Load immediate constant buffer");
617 string_buffer_release(&priv->string_buffers, icb_name);
621 /* Context activation is done by the caller. */
622 static void shader_glsl_load_images(const struct wined3d_gl_info *gl_info, struct shader_glsl_priv *priv,
623 GLuint program_id, const struct wined3d_shader_reg_maps *reg_maps)
625 struct wined3d_string_buffer *name = string_buffer_get(&priv->string_buffers);
626 GLint location;
627 unsigned int i;
629 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
631 if (!reg_maps->uav_resource_info[i].type)
632 continue;
634 string_buffer_sprintf(name, "ps_image%u", i);
635 location = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
636 if (location == -1)
637 continue;
639 TRACE("Loading image %s on unit %u.\n", name->buffer, i);
640 GL_EXTCALL(glUniform1i(location, i));
642 checkGLcall("Load image bindings");
643 string_buffer_release(&priv->string_buffers, name);
646 /* Context activation is done by the caller. */
647 static inline void walk_constant_heap(const struct wined3d_gl_info *gl_info, const struct wined3d_vec4 *constants,
648 const GLint *constant_locations, const struct constant_heap *heap, unsigned char *stack, DWORD version)
650 unsigned int start = ~0U, end = 0;
651 int stack_idx = 0;
652 unsigned int heap_idx = 1;
653 unsigned int idx;
655 if (heap->entries[heap_idx].version <= version) return;
657 idx = heap->entries[heap_idx].idx;
658 if (constant_locations[idx] != -1)
659 start = end = idx;
660 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
662 while (stack_idx >= 0)
664 /* Note that we fall through to the next case statement. */
665 switch(stack[stack_idx])
667 case HEAP_NODE_TRAVERSE_LEFT:
669 unsigned int left_idx = heap_idx << 1;
670 if (left_idx < heap->size && heap->entries[left_idx].version > version)
672 heap_idx = left_idx;
673 idx = heap->entries[heap_idx].idx;
674 if (constant_locations[idx] != -1)
676 if (start > idx)
677 start = idx;
678 if (end < idx)
679 end = idx;
682 stack[stack_idx++] = HEAP_NODE_TRAVERSE_RIGHT;
683 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
684 break;
688 case HEAP_NODE_TRAVERSE_RIGHT:
690 unsigned int right_idx = (heap_idx << 1) + 1;
691 if (right_idx < heap->size && heap->entries[right_idx].version > version)
693 heap_idx = right_idx;
694 idx = heap->entries[heap_idx].idx;
695 if (constant_locations[idx] != -1)
697 if (start > idx)
698 start = idx;
699 if (end < idx)
700 end = idx;
703 stack[stack_idx++] = HEAP_NODE_POP;
704 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
705 break;
709 case HEAP_NODE_POP:
710 heap_idx >>= 1;
711 --stack_idx;
712 break;
715 if (start <= end)
716 GL_EXTCALL(glUniform4fv(constant_locations[start], end - start + 1, &constants[start].x));
717 checkGLcall("walk_constant_heap()");
720 /* Context activation is done by the caller. */
721 static inline void apply_clamped_constant(const struct wined3d_gl_info *gl_info,
722 GLint location, const struct wined3d_vec4 *data)
724 GLfloat clamped_constant[4];
726 if (location == -1) return;
728 clamped_constant[0] = data->x < -1.0f ? -1.0f : data->x > 1.0f ? 1.0f : data->x;
729 clamped_constant[1] = data->y < -1.0f ? -1.0f : data->y > 1.0f ? 1.0f : data->y;
730 clamped_constant[2] = data->z < -1.0f ? -1.0f : data->z > 1.0f ? 1.0f : data->z;
731 clamped_constant[3] = data->w < -1.0f ? -1.0f : data->w > 1.0f ? 1.0f : data->w;
733 GL_EXTCALL(glUniform4fv(location, 1, clamped_constant));
736 /* Context activation is done by the caller. */
737 static inline void walk_constant_heap_clamped(const struct wined3d_gl_info *gl_info,
738 const struct wined3d_vec4 *constants, const GLint *constant_locations,
739 const struct constant_heap *heap, unsigned char *stack, DWORD version)
741 int stack_idx = 0;
742 unsigned int heap_idx = 1;
743 unsigned int idx;
745 if (heap->entries[heap_idx].version <= version) return;
747 idx = heap->entries[heap_idx].idx;
748 apply_clamped_constant(gl_info, constant_locations[idx], &constants[idx]);
749 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
751 while (stack_idx >= 0)
753 /* Note that we fall through to the next case statement. */
754 switch(stack[stack_idx])
756 case HEAP_NODE_TRAVERSE_LEFT:
758 unsigned int left_idx = heap_idx << 1;
759 if (left_idx < heap->size && heap->entries[left_idx].version > version)
761 heap_idx = left_idx;
762 idx = heap->entries[heap_idx].idx;
763 apply_clamped_constant(gl_info, constant_locations[idx], &constants[idx]);
765 stack[stack_idx++] = HEAP_NODE_TRAVERSE_RIGHT;
766 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
767 break;
771 case HEAP_NODE_TRAVERSE_RIGHT:
773 unsigned int right_idx = (heap_idx << 1) + 1;
774 if (right_idx < heap->size && heap->entries[right_idx].version > version)
776 heap_idx = right_idx;
777 idx = heap->entries[heap_idx].idx;
778 apply_clamped_constant(gl_info, constant_locations[idx], &constants[idx]);
780 stack[stack_idx++] = HEAP_NODE_POP;
781 stack[stack_idx] = HEAP_NODE_TRAVERSE_LEFT;
782 break;
786 case HEAP_NODE_POP:
787 heap_idx >>= 1;
788 --stack_idx;
789 break;
792 checkGLcall("walk_constant_heap_clamped()");
795 /* Context activation is done by the caller. */
796 static void shader_glsl_load_constants_f(const struct wined3d_shader *shader, const struct wined3d_gl_info *gl_info,
797 const struct wined3d_vec4 *constants, const GLint *constant_locations, const struct constant_heap *heap,
798 unsigned char *stack, unsigned int version)
800 const struct wined3d_shader_lconst *lconst;
802 /* 1.X pshaders have the constants clamped to [-1;1] implicitly. */
803 if (shader->reg_maps.shader_version.major == 1
804 && shader->reg_maps.shader_version.type == WINED3D_SHADER_TYPE_PIXEL)
805 walk_constant_heap_clamped(gl_info, constants, constant_locations, heap, stack, version);
806 else
807 walk_constant_heap(gl_info, constants, constant_locations, heap, stack, version);
809 if (!shader->load_local_constsF)
811 TRACE("No need to load local float constants for this shader.\n");
812 return;
815 /* Immediate constants are clamped to [-1;1] at shader creation time if needed */
816 LIST_FOR_EACH_ENTRY(lconst, &shader->constantsF, struct wined3d_shader_lconst, entry)
818 GL_EXTCALL(glUniform4fv(constant_locations[lconst->idx], 1, (const GLfloat *)lconst->value));
820 checkGLcall("glUniform4fv()");
823 /* Context activation is done by the caller. */
824 static void shader_glsl_load_constants_i(const struct wined3d_shader *shader, const struct wined3d_gl_info *gl_info,
825 const struct wined3d_ivec4 *constants, const GLint locations[WINED3D_MAX_CONSTS_I], WORD constants_set)
827 unsigned int i;
828 struct list* ptr;
830 for (i = 0; constants_set; constants_set >>= 1, ++i)
832 if (!(constants_set & 1)) continue;
834 /* We found this uniform name in the program - go ahead and send the data */
835 GL_EXTCALL(glUniform4iv(locations[i], 1, &constants[i].x));
838 /* Load immediate constants */
839 ptr = list_head(&shader->constantsI);
840 while (ptr)
842 const struct wined3d_shader_lconst *lconst = LIST_ENTRY(ptr, const struct wined3d_shader_lconst, entry);
843 unsigned int idx = lconst->idx;
844 const GLint *values = (const GLint *)lconst->value;
846 /* We found this uniform name in the program - go ahead and send the data */
847 GL_EXTCALL(glUniform4iv(locations[idx], 1, values));
848 ptr = list_next(&shader->constantsI, ptr);
850 checkGLcall("glUniform4iv()");
853 /* Context activation is done by the caller. */
854 static void shader_glsl_load_constantsB(const struct wined3d_shader *shader, const struct wined3d_gl_info *gl_info,
855 const GLint locations[WINED3D_MAX_CONSTS_B], const BOOL *constants, WORD constants_set)
857 unsigned int i;
858 struct list* ptr;
860 for (i = 0; constants_set; constants_set >>= 1, ++i)
862 if (!(constants_set & 1)) continue;
864 GL_EXTCALL(glUniform1iv(locations[i], 1, &constants[i]));
867 /* Load immediate constants */
868 ptr = list_head(&shader->constantsB);
869 while (ptr)
871 const struct wined3d_shader_lconst *lconst = LIST_ENTRY(ptr, const struct wined3d_shader_lconst, entry);
872 unsigned int idx = lconst->idx;
873 const GLint *values = (const GLint *)lconst->value;
875 GL_EXTCALL(glUniform1iv(locations[idx], 1, values));
876 ptr = list_next(&shader->constantsB, ptr);
878 checkGLcall("glUniform1iv()");
881 static void reset_program_constant_version(struct wine_rb_entry *entry, void *context)
883 WINE_RB_ENTRY_VALUE(entry, struct glsl_shader_prog_link, program_lookup_entry)->constant_version = 0;
886 /* Context activation is done by the caller (state handler). */
887 static void shader_glsl_load_np2fixup_constants(const struct glsl_ps_program *ps,
888 const struct wined3d_gl_info *gl_info, const struct wined3d_state *state)
890 GLfloat np2fixup_constants[4 * MAX_FRAGMENT_SAMPLERS];
891 UINT fixup = ps->np2_fixup_info->active;
892 UINT i;
894 for (i = 0; fixup; fixup >>= 1, ++i)
896 const struct wined3d_texture *tex = state->textures[i];
897 unsigned char idx = ps->np2_fixup_info->idx[i];
898 GLfloat *tex_dim = &np2fixup_constants[(idx >> 1) * 4];
900 if (!tex)
902 ERR("Nonexistent texture is flagged for NP2 texcoord fixup.\n");
903 continue;
906 if (idx % 2)
908 tex_dim[2] = tex->pow2_matrix[0];
909 tex_dim[3] = tex->pow2_matrix[5];
911 else
913 tex_dim[0] = tex->pow2_matrix[0];
914 tex_dim[1] = tex->pow2_matrix[5];
918 GL_EXTCALL(glUniform4fv(ps->np2_fixup_location, ps->np2_fixup_info->num_consts, np2fixup_constants));
921 /* Taken and adapted from Mesa. */
922 static BOOL invert_matrix_3d(struct wined3d_matrix *out, const struct wined3d_matrix *in)
924 float pos, neg, t, det;
925 struct wined3d_matrix temp;
927 /* Calculate the determinant of upper left 3x3 submatrix and
928 * determine if the matrix is singular. */
929 pos = neg = 0.0f;
930 t = in->_11 * in->_22 * in->_33;
931 if (t >= 0.0f)
932 pos += t;
933 else
934 neg += t;
936 t = in->_21 * in->_32 * in->_13;
937 if (t >= 0.0f)
938 pos += t;
939 else
940 neg += t;
941 t = in->_31 * in->_12 * in->_23;
942 if (t >= 0.0f)
943 pos += t;
944 else
945 neg += t;
947 t = -in->_31 * in->_22 * in->_13;
948 if (t >= 0.0f)
949 pos += t;
950 else
951 neg += t;
952 t = -in->_21 * in->_12 * in->_33;
953 if (t >= 0.0f)
954 pos += t;
955 else
956 neg += t;
958 t = -in->_11 * in->_32 * in->_23;
959 if (t >= 0.0f)
960 pos += t;
961 else
962 neg += t;
964 det = pos + neg;
966 if (fabsf(det) < 1e-25f)
967 return FALSE;
969 det = 1.0f / det;
970 temp._11 = (in->_22 * in->_33 - in->_32 * in->_23) * det;
971 temp._12 = -(in->_12 * in->_33 - in->_32 * in->_13) * det;
972 temp._13 = (in->_12 * in->_23 - in->_22 * in->_13) * det;
973 temp._21 = -(in->_21 * in->_33 - in->_31 * in->_23) * det;
974 temp._22 = (in->_11 * in->_33 - in->_31 * in->_13) * det;
975 temp._23 = -(in->_11 * in->_23 - in->_21 * in->_13) * det;
976 temp._31 = (in->_21 * in->_32 - in->_31 * in->_22) * det;
977 temp._32 = -(in->_11 * in->_32 - in->_31 * in->_12) * det;
978 temp._33 = (in->_11 * in->_22 - in->_21 * in->_12) * det;
980 *out = temp;
981 return TRUE;
984 static void swap_rows(float **a, float **b)
986 float *tmp = *a;
988 *a = *b;
989 *b = tmp;
992 static BOOL invert_matrix(struct wined3d_matrix *out, struct wined3d_matrix *m)
994 float wtmp[4][8];
995 float m0, m1, m2, m3, s;
996 float *r0, *r1, *r2, *r3;
998 r0 = wtmp[0];
999 r1 = wtmp[1];
1000 r2 = wtmp[2];
1001 r3 = wtmp[3];
1003 r0[0] = m->_11;
1004 r0[1] = m->_12;
1005 r0[2] = m->_13;
1006 r0[3] = m->_14;
1007 r0[4] = 1.0f;
1008 r0[5] = r0[6] = r0[7] = 0.0f;
1010 r1[0] = m->_21;
1011 r1[1] = m->_22;
1012 r1[2] = m->_23;
1013 r1[3] = m->_24;
1014 r1[5] = 1.0f;
1015 r1[4] = r1[6] = r1[7] = 0.0f;
1017 r2[0] = m->_31;
1018 r2[1] = m->_32;
1019 r2[2] = m->_33;
1020 r2[3] = m->_34;
1021 r2[6] = 1.0f;
1022 r2[4] = r2[5] = r2[7] = 0.0f;
1024 r3[0] = m->_41;
1025 r3[1] = m->_42;
1026 r3[2] = m->_43;
1027 r3[3] = m->_44;
1028 r3[7] = 1.0f;
1029 r3[4] = r3[5] = r3[6] = 0.0f;
1031 /* Choose pivot - or die. */
1032 if (fabsf(r3[0]) > fabsf(r2[0]))
1033 swap_rows(&r3, &r2);
1034 if (fabsf(r2[0]) > fabsf(r1[0]))
1035 swap_rows(&r2, &r1);
1036 if (fabsf(r1[0]) > fabsf(r0[0]))
1037 swap_rows(&r1, &r0);
1038 if (r0[0] == 0.0f)
1039 return FALSE;
1041 /* Eliminate first variable. */
1042 m1 = r1[0] / r0[0]; m2 = r2[0] / r0[0]; m3 = r3[0] / r0[0];
1043 s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
1044 s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
1045 s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
1046 s = r0[4];
1047 if (s != 0.0f)
1049 r1[4] -= m1 * s;
1050 r2[4] -= m2 * s;
1051 r3[4] -= m3 * s;
1053 s = r0[5];
1054 if (s != 0.0f)
1056 r1[5] -= m1 * s;
1057 r2[5] -= m2 * s;
1058 r3[5] -= m3 * s;
1060 s = r0[6];
1061 if (s != 0.0f)
1063 r1[6] -= m1 * s;
1064 r2[6] -= m2 * s;
1065 r3[6] -= m3 * s;
1067 s = r0[7];
1068 if (s != 0.0f)
1070 r1[7] -= m1 * s;
1071 r2[7] -= m2 * s;
1072 r3[7] -= m3 * s;
1075 /* Choose pivot - or die. */
1076 if (fabsf(r3[1]) > fabsf(r2[1]))
1077 swap_rows(&r3, &r2);
1078 if (fabsf(r2[1]) > fabsf(r1[1]))
1079 swap_rows(&r2, &r1);
1080 if (r1[1] == 0.0f)
1081 return FALSE;
1083 /* Eliminate second variable. */
1084 m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1];
1085 r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
1086 r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
1087 s = r1[4];
1088 if (s != 0.0f)
1090 r2[4] -= m2 * s;
1091 r3[4] -= m3 * s;
1093 s = r1[5];
1094 if (s != 0.0f)
1096 r2[5] -= m2 * s;
1097 r3[5] -= m3 * s;
1099 s = r1[6];
1100 if (s != 0.0f)
1102 r2[6] -= m2 * s;
1103 r3[6] -= m3 * s;
1105 s = r1[7];
1106 if (s != 0.0f)
1108 r2[7] -= m2 * s;
1109 r3[7] -= m3 * s;
1112 /* Choose pivot - or die. */
1113 if (fabsf(r3[2]) > fabsf(r2[2]))
1114 swap_rows(&r3, &r2);
1115 if (r2[2] == 0.0f)
1116 return FALSE;
1118 /* Eliminate third variable. */
1119 m3 = r3[2] / r2[2];
1120 r3[3] -= m3 * r2[3];
1121 r3[4] -= m3 * r2[4];
1122 r3[5] -= m3 * r2[5];
1123 r3[6] -= m3 * r2[6];
1124 r3[7] -= m3 * r2[7];
1126 /* Last check. */
1127 if (r3[3] == 0.0f)
1128 return FALSE;
1130 /* Back substitute row 3. */
1131 s = 1.0f / r3[3];
1132 r3[4] *= s;
1133 r3[5] *= s;
1134 r3[6] *= s;
1135 r3[7] *= s;
1137 /* Back substitute row 2. */
1138 m2 = r2[3];
1139 s = 1.0f / r2[2];
1140 r2[4] = s * (r2[4] - r3[4] * m2);
1141 r2[5] = s * (r2[5] - r3[5] * m2);
1142 r2[6] = s * (r2[6] - r3[6] * m2);
1143 r2[7] = s * (r2[7] - r3[7] * m2);
1144 m1 = r1[3];
1145 r1[4] -= r3[4] * m1;
1146 r1[5] -= r3[5] * m1;
1147 r1[6] -= r3[6] * m1;
1148 r1[7] -= r3[7] * m1;
1149 m0 = r0[3];
1150 r0[4] -= r3[4] * m0;
1151 r0[5] -= r3[5] * m0;
1152 r0[6] -= r3[6] * m0;
1153 r0[7] -= r3[7] * m0;
1155 /* Back substitute row 1. */
1156 m1 = r1[2];
1157 s = 1.0f / r1[1];
1158 r1[4] = s * (r1[4] - r2[4] * m1);
1159 r1[5] = s * (r1[5] - r2[5] * m1);
1160 r1[6] = s * (r1[6] - r2[6] * m1);
1161 r1[7] = s * (r1[7] - r2[7] * m1);
1162 m0 = r0[2];
1163 r0[4] -= r2[4] * m0;
1164 r0[5] -= r2[5] * m0;
1165 r0[6] -= r2[6] * m0;
1166 r0[7] -= r2[7] * m0;
1168 /* Back substitute row 0. */
1169 m0 = r0[1];
1170 s = 1.0f / r0[0];
1171 r0[4] = s * (r0[4] - r1[4] * m0);
1172 r0[5] = s * (r0[5] - r1[5] * m0);
1173 r0[6] = s * (r0[6] - r1[6] * m0);
1174 r0[7] = s * (r0[7] - r1[7] * m0);
1176 out->_11 = r0[4];
1177 out->_12 = r0[5];
1178 out->_13 = r0[6];
1179 out->_14 = r0[7];
1180 out->_21 = r1[4];
1181 out->_22 = r1[5];
1182 out->_23 = r1[6];
1183 out->_24 = r1[7];
1184 out->_31 = r2[4];
1185 out->_32 = r2[5];
1186 out->_33 = r2[6];
1187 out->_34 = r2[7];
1188 out->_41 = r3[4];
1189 out->_42 = r3[5];
1190 out->_43 = r3[6];
1191 out->_44 = r3[7];
1193 return TRUE;
1196 static void shader_glsl_ffp_vertex_normalmatrix_uniform(const struct wined3d_context *context,
1197 const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
1199 const struct wined3d_gl_info *gl_info = context->gl_info;
1200 float mat[3 * 3];
1201 struct wined3d_matrix mv;
1202 unsigned int i, j;
1204 if (prog->vs.normal_matrix_location == -1)
1205 return;
1207 get_modelview_matrix(context, state, 0, &mv);
1208 if (context->d3d_info->wined3d_creation_flags & WINED3D_LEGACY_FFP_LIGHTING)
1209 invert_matrix_3d(&mv, &mv);
1210 else
1211 invert_matrix(&mv, &mv);
1212 /* Tests show that singular modelview matrices are used unchanged as normal
1213 * matrices on D3D3 and older. There seems to be no clearly consistent
1214 * behavior on newer D3D versions so always follow older ddraw behavior. */
1215 for (i = 0; i < 3; ++i)
1216 for (j = 0; j < 3; ++j)
1217 mat[i * 3 + j] = (&mv._11)[j * 4 + i];
1219 GL_EXTCALL(glUniformMatrix3fv(prog->vs.normal_matrix_location, 1, FALSE, mat));
1220 checkGLcall("glUniformMatrix3fv");
1223 static void shader_glsl_ffp_vertex_texmatrix_uniform(const struct wined3d_context *context,
1224 const struct wined3d_state *state, unsigned int tex, struct glsl_shader_prog_link *prog)
1226 const struct wined3d_gl_info *gl_info = context->gl_info;
1227 struct wined3d_matrix mat;
1229 if (tex >= MAX_TEXTURES)
1230 return;
1231 if (prog->vs.texture_matrix_location[tex] == -1)
1232 return;
1234 get_texture_matrix(context, state, tex, &mat);
1235 GL_EXTCALL(glUniformMatrix4fv(prog->vs.texture_matrix_location[tex], 1, FALSE, &mat._11));
1236 checkGLcall("glUniformMatrix4fv");
1239 static void shader_glsl_ffp_vertex_material_uniform(const struct wined3d_context *context,
1240 const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
1242 const struct wined3d_gl_info *gl_info = context->gl_info;
1244 if (state->render_states[WINED3D_RS_SPECULARENABLE])
1246 GL_EXTCALL(glUniform4fv(prog->vs.material_specular_location, 1, &state->material.specular.r));
1247 GL_EXTCALL(glUniform1f(prog->vs.material_shininess_location, state->material.power));
1249 else
1251 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
1253 GL_EXTCALL(glUniform4fv(prog->vs.material_specular_location, 1, black));
1255 GL_EXTCALL(glUniform4fv(prog->vs.material_ambient_location, 1, &state->material.ambient.r));
1256 GL_EXTCALL(glUniform4fv(prog->vs.material_diffuse_location, 1, &state->material.diffuse.r));
1257 GL_EXTCALL(glUniform4fv(prog->vs.material_emissive_location, 1, &state->material.emissive.r));
1258 checkGLcall("setting FFP material uniforms");
1261 static void shader_glsl_ffp_vertex_lightambient_uniform(const struct wined3d_context *context,
1262 const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
1264 const struct wined3d_gl_info *gl_info = context->gl_info;
1265 struct wined3d_color color;
1267 wined3d_color_from_d3dcolor(&color, state->render_states[WINED3D_RS_AMBIENT]);
1268 GL_EXTCALL(glUniform3fv(prog->vs.light_ambient_location, 1, &color.r));
1269 checkGLcall("glUniform3fv");
1272 static void multiply_vector_matrix(struct wined3d_vec4 *dest, const struct wined3d_vec4 *src1,
1273 const struct wined3d_matrix *src2)
1275 struct wined3d_vec4 temp;
1277 temp.x = (src1->x * src2->_11) + (src1->y * src2->_21) + (src1->z * src2->_31) + (src1->w * src2->_41);
1278 temp.y = (src1->x * src2->_12) + (src1->y * src2->_22) + (src1->z * src2->_32) + (src1->w * src2->_42);
1279 temp.z = (src1->x * src2->_13) + (src1->y * src2->_23) + (src1->z * src2->_33) + (src1->w * src2->_43);
1280 temp.w = (src1->x * src2->_14) + (src1->y * src2->_24) + (src1->z * src2->_34) + (src1->w * src2->_44);
1282 *dest = temp;
1285 static void shader_glsl_ffp_vertex_light_uniform(const struct wined3d_context *context,
1286 const struct wined3d_state *state, unsigned int light, struct glsl_shader_prog_link *prog)
1288 const struct wined3d_gl_info *gl_info = context->gl_info;
1289 const struct wined3d_light_info *light_info = state->lights[light];
1290 struct wined3d_vec4 vec4;
1291 const struct wined3d_matrix *view = &state->transforms[WINED3D_TS_VIEW];
1293 if (!light_info)
1294 return;
1296 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].diffuse, 1, &light_info->OriginalParms.diffuse.r));
1297 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].specular, 1, &light_info->OriginalParms.specular.r));
1298 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].ambient, 1, &light_info->OriginalParms.ambient.r));
1300 switch (light_info->OriginalParms.type)
1302 case WINED3D_LIGHT_POINT:
1303 multiply_vector_matrix(&vec4, &light_info->position, view);
1304 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].position, 1, &vec4.x));
1305 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].range, light_info->OriginalParms.range));
1306 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].c_att, light_info->OriginalParms.attenuation0));
1307 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].l_att, light_info->OriginalParms.attenuation1));
1308 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].q_att, light_info->OriginalParms.attenuation2));
1309 break;
1311 case WINED3D_LIGHT_SPOT:
1312 multiply_vector_matrix(&vec4, &light_info->position, view);
1313 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].position, 1, &vec4.x));
1315 multiply_vector_matrix(&vec4, &light_info->direction, view);
1316 GL_EXTCALL(glUniform3fv(prog->vs.light_location[light].direction, 1, &vec4.x));
1318 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].range, light_info->OriginalParms.range));
1319 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].falloff, light_info->OriginalParms.falloff));
1320 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].c_att, light_info->OriginalParms.attenuation0));
1321 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].l_att, light_info->OriginalParms.attenuation1));
1322 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].q_att, light_info->OriginalParms.attenuation2));
1323 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].cos_htheta, cosf(light_info->OriginalParms.theta / 2.0f)));
1324 GL_EXTCALL(glUniform1f(prog->vs.light_location[light].cos_hphi, cosf(light_info->OriginalParms.phi / 2.0f)));
1325 break;
1327 case WINED3D_LIGHT_DIRECTIONAL:
1328 multiply_vector_matrix(&vec4, &light_info->direction, view);
1329 GL_EXTCALL(glUniform3fv(prog->vs.light_location[light].direction, 1, &vec4.x));
1330 break;
1332 case WINED3D_LIGHT_PARALLELPOINT:
1333 multiply_vector_matrix(&vec4, &light_info->position, view);
1334 GL_EXTCALL(glUniform4fv(prog->vs.light_location[light].position, 1, &vec4.x));
1335 break;
1337 default:
1338 FIXME("Unrecognized light type %#x.\n", light_info->OriginalParms.type);
1340 checkGLcall("setting FFP lights uniforms");
1343 static void shader_glsl_pointsize_uniform(const struct wined3d_context *context,
1344 const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
1346 const struct wined3d_gl_info *gl_info = context->gl_info;
1347 float min, max;
1348 float size, att[3];
1350 get_pointsize_minmax(context, state, &min, &max);
1352 GL_EXTCALL(glUniform1f(prog->vs.pointsize_min_location, min));
1353 checkGLcall("glUniform1f");
1354 GL_EXTCALL(glUniform1f(prog->vs.pointsize_max_location, max));
1355 checkGLcall("glUniform1f");
1357 get_pointsize(context, state, &size, att);
1359 GL_EXTCALL(glUniform1f(prog->vs.pointsize_location, size));
1360 checkGLcall("glUniform1f");
1361 GL_EXTCALL(glUniform1f(prog->vs.pointsize_c_att_location, att[0]));
1362 checkGLcall("glUniform1f");
1363 GL_EXTCALL(glUniform1f(prog->vs.pointsize_l_att_location, att[1]));
1364 checkGLcall("glUniform1f");
1365 GL_EXTCALL(glUniform1f(prog->vs.pointsize_q_att_location, att[2]));
1366 checkGLcall("glUniform1f");
1369 static void shader_glsl_load_fog_uniform(const struct wined3d_context *context,
1370 const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
1372 const struct wined3d_gl_info *gl_info = context->gl_info;
1373 struct wined3d_color color;
1374 float start, end, scale;
1375 union
1377 DWORD d;
1378 float f;
1379 } tmpvalue;
1381 wined3d_color_from_d3dcolor(&color, state->render_states[WINED3D_RS_FOGCOLOR]);
1382 GL_EXTCALL(glUniform4fv(prog->ps.fog_color_location, 1, &color.r));
1383 tmpvalue.d = state->render_states[WINED3D_RS_FOGDENSITY];
1384 GL_EXTCALL(glUniform1f(prog->ps.fog_density_location, tmpvalue.f));
1385 get_fog_start_end(context, state, &start, &end);
1386 scale = 1.0f / (end - start);
1387 GL_EXTCALL(glUniform1f(prog->ps.fog_end_location, end));
1388 GL_EXTCALL(glUniform1f(prog->ps.fog_scale_location, scale));
1389 checkGLcall("fog emulation uniforms");
1392 static void shader_glsl_clip_plane_uniform(const struct wined3d_context *context,
1393 const struct wined3d_state *state, unsigned int index, struct glsl_shader_prog_link *prog)
1395 const struct wined3d_gl_info *gl_info = context->gl_info;
1396 struct wined3d_vec4 plane;
1398 /* Clip planes are affected by the view transform in d3d for FFP draws. */
1399 if (!use_vs(state))
1400 multiply_vector_matrix(&plane, &state->clip_planes[index], &state->transforms[WINED3D_TS_VIEW]);
1401 else
1402 plane = state->clip_planes[index];
1404 GL_EXTCALL(glUniform4fv(prog->vs.clip_planes_location + index, 1, &plane.x));
1407 /* Context activation is done by the caller (state handler). */
1408 static void shader_glsl_load_color_key_constant(const struct glsl_ps_program *ps,
1409 const struct wined3d_gl_info *gl_info, const struct wined3d_state *state)
1411 struct wined3d_color float_key[2];
1412 const struct wined3d_texture *texture = state->textures[0];
1414 wined3d_format_get_float_color_key(texture->resource.format, &texture->async.src_blt_color_key, float_key);
1415 GL_EXTCALL(glUniform4fv(ps->color_key_location, 2, &float_key[0].r));
1418 /* Context activation is done by the caller (state handler). */
1419 static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context *context,
1420 const struct wined3d_state *state)
1422 const struct glsl_context_data *ctx_data = context->shader_backend_data;
1423 const struct wined3d_shader *vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
1424 const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
1425 const struct wined3d_gl_info *gl_info = context->gl_info;
1426 struct shader_glsl_priv *priv = shader_priv;
1427 float position_fixup[4];
1428 DWORD update_mask;
1430 struct glsl_shader_prog_link *prog = ctx_data->glsl_program;
1431 UINT constant_version;
1432 int i;
1434 if (!prog) {
1435 /* No GLSL program set - nothing to do. */
1436 return;
1438 constant_version = prog->constant_version;
1439 update_mask = context->constant_update_mask & prog->constant_update_mask;
1441 if (update_mask & WINED3D_SHADER_CONST_VS_F)
1442 shader_glsl_load_constants_f(vshader, gl_info, state->vs_consts_f,
1443 prog->vs.uniform_f_locations, &priv->vconst_heap, priv->stack, constant_version);
1445 if (update_mask & WINED3D_SHADER_CONST_VS_I)
1446 shader_glsl_load_constants_i(vshader, gl_info, state->vs_consts_i,
1447 prog->vs.uniform_i_locations, vshader->reg_maps.integer_constants);
1449 if (update_mask & WINED3D_SHADER_CONST_VS_B)
1450 shader_glsl_load_constantsB(vshader, gl_info, prog->vs.uniform_b_locations, state->vs_consts_b,
1451 vshader->reg_maps.boolean_constants);
1453 if (update_mask & WINED3D_SHADER_CONST_VS_CLIP_PLANES)
1455 for (i = 0; i < gl_info->limits.user_clip_distances; ++i)
1456 shader_glsl_clip_plane_uniform(context, state, i, prog);
1459 if (update_mask & WINED3D_SHADER_CONST_VS_POINTSIZE)
1460 shader_glsl_pointsize_uniform(context, state, prog);
1462 if (update_mask & WINED3D_SHADER_CONST_POS_FIXUP)
1464 shader_get_position_fixup(context, state, position_fixup);
1465 if (state->shader[WINED3D_SHADER_TYPE_GEOMETRY])
1466 GL_EXTCALL(glUniform4fv(prog->gs.pos_fixup_location, 1, position_fixup));
1467 else
1468 GL_EXTCALL(glUniform4fv(prog->vs.pos_fixup_location, 1, position_fixup));
1469 checkGLcall("glUniform4fv");
1472 if (update_mask & WINED3D_SHADER_CONST_FFP_MODELVIEW)
1474 struct wined3d_matrix mat;
1476 get_modelview_matrix(context, state, 0, &mat);
1477 GL_EXTCALL(glUniformMatrix4fv(prog->vs.modelview_matrix_location[0], 1, FALSE, &mat._11));
1478 checkGLcall("glUniformMatrix4fv");
1480 shader_glsl_ffp_vertex_normalmatrix_uniform(context, state, prog);
1483 if (update_mask & WINED3D_SHADER_CONST_FFP_VERTEXBLEND)
1485 struct wined3d_matrix mat;
1487 for (i = 1; i < MAX_VERTEX_BLENDS; ++i)
1489 if (prog->vs.modelview_matrix_location[i] == -1)
1490 break;
1492 get_modelview_matrix(context, state, i, &mat);
1493 GL_EXTCALL(glUniformMatrix4fv(prog->vs.modelview_matrix_location[i], 1, FALSE, &mat._11));
1494 checkGLcall("glUniformMatrix4fv");
1498 if (update_mask & WINED3D_SHADER_CONST_FFP_PROJ)
1500 struct wined3d_matrix projection;
1502 get_projection_matrix(context, state, &projection);
1503 GL_EXTCALL(glUniformMatrix4fv(prog->vs.projection_matrix_location, 1, FALSE, &projection._11));
1504 checkGLcall("glUniformMatrix4fv");
1507 if (update_mask & WINED3D_SHADER_CONST_FFP_TEXMATRIX)
1509 for (i = 0; i < MAX_TEXTURES; ++i)
1510 shader_glsl_ffp_vertex_texmatrix_uniform(context, state, i, prog);
1513 if (update_mask & WINED3D_SHADER_CONST_FFP_MATERIAL)
1514 shader_glsl_ffp_vertex_material_uniform(context, state, prog);
1516 if (update_mask & WINED3D_SHADER_CONST_FFP_LIGHTS)
1518 shader_glsl_ffp_vertex_lightambient_uniform(context, state, prog);
1519 for (i = 0; i < MAX_ACTIVE_LIGHTS; ++i)
1520 shader_glsl_ffp_vertex_light_uniform(context, state, i, prog);
1523 if (update_mask & WINED3D_SHADER_CONST_PS_F)
1524 shader_glsl_load_constants_f(pshader, gl_info, state->ps_consts_f,
1525 prog->ps.uniform_f_locations, &priv->pconst_heap, priv->stack, constant_version);
1527 if (update_mask & WINED3D_SHADER_CONST_PS_I)
1528 shader_glsl_load_constants_i(pshader, gl_info, state->ps_consts_i,
1529 prog->ps.uniform_i_locations, pshader->reg_maps.integer_constants);
1531 if (update_mask & WINED3D_SHADER_CONST_PS_B)
1532 shader_glsl_load_constantsB(pshader, gl_info, prog->ps.uniform_b_locations, state->ps_consts_b,
1533 pshader->reg_maps.boolean_constants);
1535 if (update_mask & WINED3D_SHADER_CONST_PS_BUMP_ENV)
1537 for (i = 0; i < MAX_TEXTURES; ++i)
1539 if (prog->ps.bumpenv_mat_location[i] == -1)
1540 continue;
1542 GL_EXTCALL(glUniformMatrix2fv(prog->ps.bumpenv_mat_location[i], 1, 0,
1543 (const GLfloat *)&state->texture_states[i][WINED3D_TSS_BUMPENV_MAT00]));
1545 if (prog->ps.bumpenv_lum_scale_location[i] != -1)
1547 GL_EXTCALL(glUniform1fv(prog->ps.bumpenv_lum_scale_location[i], 1,
1548 (const GLfloat *)&state->texture_states[i][WINED3D_TSS_BUMPENV_LSCALE]));
1549 GL_EXTCALL(glUniform1fv(prog->ps.bumpenv_lum_offset_location[i], 1,
1550 (const GLfloat *)&state->texture_states[i][WINED3D_TSS_BUMPENV_LOFFSET]));
1554 checkGLcall("bump env uniforms");
1557 if (update_mask & WINED3D_SHADER_CONST_PS_Y_CORR)
1559 const struct wined3d_vec4 correction_params =
1561 /* Position is relative to the framebuffer, not the viewport. */
1562 context->render_offscreen ? 0.0f : (float)state->fb->render_targets[0]->height,
1563 context->render_offscreen ? 1.0f : -1.0f,
1564 0.0f,
1565 0.0f,
1568 GL_EXTCALL(glUniform4fv(prog->ps.ycorrection_location, 1, &correction_params.x));
1571 if (update_mask & WINED3D_SHADER_CONST_PS_NP2_FIXUP)
1572 shader_glsl_load_np2fixup_constants(&prog->ps, gl_info, state);
1573 if (update_mask & WINED3D_SHADER_CONST_FFP_COLOR_KEY)
1574 shader_glsl_load_color_key_constant(&prog->ps, gl_info, state);
1576 if (update_mask & WINED3D_SHADER_CONST_FFP_PS)
1578 struct wined3d_color color;
1580 if (prog->ps.tex_factor_location != -1)
1582 wined3d_color_from_d3dcolor(&color, state->render_states[WINED3D_RS_TEXTUREFACTOR]);
1583 GL_EXTCALL(glUniform4fv(prog->ps.tex_factor_location, 1, &color.r));
1586 if (state->render_states[WINED3D_RS_SPECULARENABLE])
1587 GL_EXTCALL(glUniform4f(prog->ps.specular_enable_location, 1.0f, 1.0f, 1.0f, 0.0f));
1588 else
1589 GL_EXTCALL(glUniform4f(prog->ps.specular_enable_location, 0.0f, 0.0f, 0.0f, 0.0f));
1591 for (i = 0; i < MAX_TEXTURES; ++i)
1593 if (prog->ps.tss_constant_location[i] == -1)
1594 continue;
1596 wined3d_color_from_d3dcolor(&color, state->texture_states[i][WINED3D_TSS_CONSTANT]);
1597 GL_EXTCALL(glUniform4fv(prog->ps.tss_constant_location[i], 1, &color.r));
1600 checkGLcall("fixed function uniforms");
1603 if (update_mask & WINED3D_SHADER_CONST_PS_FOG)
1604 shader_glsl_load_fog_uniform(context, state, prog);
1606 if (update_mask & WINED3D_SHADER_CONST_PS_ALPHA_TEST)
1608 float ref = state->render_states[WINED3D_RS_ALPHAREF] / 255.0f;
1610 GL_EXTCALL(glUniform1f(prog->ps.alpha_test_ref_location, ref));
1611 checkGLcall("alpha test emulation uniform");
1614 if (priv->next_constant_version == UINT_MAX)
1616 TRACE("Max constant version reached, resetting to 0.\n");
1617 wine_rb_for_each_entry(&priv->program_lookup, reset_program_constant_version, NULL);
1618 priv->next_constant_version = 1;
1620 else
1622 prog->constant_version = priv->next_constant_version++;
1626 static void update_heap_entry(struct constant_heap *heap, unsigned int idx, DWORD new_version)
1628 struct constant_entry *entries = heap->entries;
1629 unsigned int *positions = heap->positions;
1630 unsigned int heap_idx, parent_idx;
1632 if (!heap->contained[idx])
1634 heap_idx = heap->size++;
1635 heap->contained[idx] = TRUE;
1637 else
1639 heap_idx = positions[idx];
1642 while (heap_idx > 1)
1644 parent_idx = heap_idx >> 1;
1646 if (new_version <= entries[parent_idx].version) break;
1648 entries[heap_idx] = entries[parent_idx];
1649 positions[entries[parent_idx].idx] = heap_idx;
1650 heap_idx = parent_idx;
1653 entries[heap_idx].version = new_version;
1654 entries[heap_idx].idx = idx;
1655 positions[idx] = heap_idx;
1658 static void shader_glsl_update_float_vertex_constants(struct wined3d_device *device, UINT start, UINT count)
1660 struct shader_glsl_priv *priv = device->shader_priv;
1661 struct constant_heap *heap = &priv->vconst_heap;
1662 UINT i;
1664 for (i = start; i < count + start; ++i)
1666 update_heap_entry(heap, i, priv->next_constant_version);
1670 static void shader_glsl_update_float_pixel_constants(struct wined3d_device *device, UINT start, UINT count)
1672 struct shader_glsl_priv *priv = device->shader_priv;
1673 struct constant_heap *heap = &priv->pconst_heap;
1674 UINT i;
1676 for (i = start; i < count + start; ++i)
1678 update_heap_entry(heap, i, priv->next_constant_version);
1682 static unsigned int vec4_varyings(DWORD shader_major, const struct wined3d_gl_info *gl_info)
1684 unsigned int ret = gl_info->limits.glsl_varyings / 4;
1685 /* 4.0 shaders do not write clip coords because d3d10 does not support user clipplanes */
1686 if(shader_major > 3) return ret;
1688 /* 3.0 shaders may need an extra varying for the clip coord on some cards(mostly dx10 ones) */
1689 if (gl_info->quirks & WINED3D_QUIRK_GLSL_CLIP_VARYING) ret -= 1;
1690 return ret;
1693 static BOOL needs_legacy_glsl_syntax(const struct wined3d_gl_info *gl_info)
1695 return gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
1698 static BOOL shader_glsl_use_explicit_attrib_location(const struct wined3d_gl_info *gl_info)
1700 return !needs_legacy_glsl_syntax(gl_info) && gl_info->supported[ARB_EXPLICIT_ATTRIB_LOCATION];
1703 static const char *get_attribute_keyword(const struct wined3d_gl_info *gl_info)
1705 return needs_legacy_glsl_syntax(gl_info) ? "attribute" : "in";
1708 static void PRINTF_ATTR(4, 5) declare_in_varying(const struct wined3d_gl_info *gl_info,
1709 struct wined3d_string_buffer *buffer, BOOL flat, const char *format, ...)
1711 va_list args;
1712 int ret;
1714 shader_addline(buffer, "%s%s ", flat ? "flat " : "",
1715 needs_legacy_glsl_syntax(gl_info) ? "varying" : "in");
1716 for (;;)
1718 va_start(args, format);
1719 ret = shader_vaddline(buffer, format, args);
1720 va_end(args);
1721 if (!ret)
1722 return;
1723 if (!string_buffer_resize(buffer, ret))
1724 return;
1728 static void PRINTF_ATTR(4, 5) declare_out_varying(const struct wined3d_gl_info *gl_info,
1729 struct wined3d_string_buffer *buffer, BOOL flat, const char *format, ...)
1731 va_list args;
1732 int ret;
1734 shader_addline(buffer, "%s%s ", flat ? "flat " : "",
1735 needs_legacy_glsl_syntax(gl_info) ? "varying" : "out");
1736 for (;;)
1738 va_start(args, format);
1739 ret = shader_vaddline(buffer, format, args);
1740 va_end(args);
1741 if (!ret)
1742 return;
1743 if (!string_buffer_resize(buffer, ret))
1744 return;
1748 static const char *get_fragment_output(const struct wined3d_gl_info *gl_info)
1750 return needs_legacy_glsl_syntax(gl_info) ? "gl_FragData" : "ps_out";
1753 static const char *glsl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
1755 switch (primitive_type)
1757 case WINED3D_PT_POINTLIST:
1758 return "points";
1760 case WINED3D_PT_LINELIST:
1761 return "lines";
1763 case WINED3D_PT_LINESTRIP:
1764 return "line_strip";
1766 case WINED3D_PT_TRIANGLELIST:
1767 return "triangles";
1769 case WINED3D_PT_TRIANGLESTRIP:
1770 return "triangle_strip";
1772 case WINED3D_PT_LINELIST_ADJ:
1773 return "lines_adjacency";
1775 case WINED3D_PT_TRIANGLELIST_ADJ:
1776 return "triangles_adjacency";
1778 default:
1779 FIXME("Unhandled primitive type %s.\n", debug_d3dprimitivetype(primitive_type));
1780 return "";
1784 static BOOL glsl_is_color_reg_read(const struct wined3d_shader *shader, unsigned int idx)
1786 const struct wined3d_shader_signature *input_signature = &shader->input_signature;
1787 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
1788 const BOOL *input_reg_used = shader->u.ps.input_reg_used;
1789 unsigned int i;
1791 if (reg_maps->shader_version.major < 3)
1792 return input_reg_used[idx];
1794 for (i = 0; i < input_signature->element_count; ++i)
1796 const struct wined3d_shader_signature_element *input = &input_signature->elements[i];
1798 if (!(reg_maps->input_registers & (1u << input->register_idx)))
1799 continue;
1801 if (shader_match_semantic(input->semantic_name, WINED3D_DECL_USAGE_COLOR)
1802 && input->semantic_idx == idx)
1804 if (input_reg_used[input->register_idx])
1805 return TRUE;
1806 else
1807 return FALSE;
1810 return FALSE;
1813 static BOOL glsl_is_shadow_sampler(const struct wined3d_shader *shader,
1814 const struct ps_compile_args *ps_args, unsigned int resource_idx, unsigned int sampler_idx)
1816 const struct wined3d_shader_version *version = &shader->reg_maps.shader_version;
1818 if (version->major >= 4)
1819 return shader->reg_maps.sampler_comparison_mode & (1u << sampler_idx);
1820 else
1821 return version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->shadow & (1u << resource_idx));
1824 static void shader_glsl_declare_typed_vertex_attribute(struct wined3d_string_buffer *buffer,
1825 const struct wined3d_gl_info *gl_info, const char *vector_type, const char *scalar_type,
1826 unsigned int index)
1828 shader_addline(buffer, "%s %s4 vs_in_%s%u;\n",
1829 get_attribute_keyword(gl_info), vector_type, scalar_type, index);
1830 shader_addline(buffer, "vec4 vs_in%u = %sBitsToFloat(vs_in_%s%u);\n",
1831 index, scalar_type, scalar_type, index);
1834 static void shader_glsl_declare_generic_vertex_attribute(struct wined3d_string_buffer *buffer,
1835 const struct wined3d_gl_info *gl_info, const struct wined3d_shader_signature_element *e)
1837 unsigned int index = e->register_idx;
1839 if (e->sysval_semantic == WINED3D_SV_VERTEX_ID)
1841 shader_addline(buffer, "vec4 vs_in%u = vec4(intBitsToFloat(gl_VertexID), 0.0, 0.0, 0.0);\n",
1842 index);
1843 return;
1845 if (e->sysval_semantic == WINED3D_SV_INSTANCE_ID)
1847 shader_addline(buffer, "vec4 vs_in%u = vec4(intBitsToFloat(gl_InstanceID), 0.0, 0.0, 0.0);\n",
1848 index);
1849 return;
1851 if (e->sysval_semantic && e->sysval_semantic != WINED3D_SV_POSITION)
1852 FIXME("Unhandled sysval semantic %#x.\n", e->sysval_semantic);
1854 if (shader_glsl_use_explicit_attrib_location(gl_info))
1855 shader_addline(buffer, "layout(location = %u) ", index);
1857 switch (e->component_type)
1859 case WINED3D_TYPE_UINT:
1860 shader_glsl_declare_typed_vertex_attribute(buffer, gl_info, "uvec", "uint", index);
1861 break;
1862 case WINED3D_TYPE_INT:
1863 shader_glsl_declare_typed_vertex_attribute(buffer, gl_info, "ivec", "int", index);
1864 break;
1866 default:
1867 FIXME("Unhandled type %#x.\n", e->component_type);
1868 /* Fall through. */
1869 case WINED3D_TYPE_UNKNOWN:
1870 case WINED3D_TYPE_FLOAT:
1871 shader_addline(buffer, "%s vec4 vs_in%u;\n", get_attribute_keyword(gl_info), index);
1872 break;
1876 /** Generate the variable & register declarations for the GLSL output target */
1877 static void shader_generate_glsl_declarations(const struct wined3d_context *context,
1878 struct wined3d_string_buffer *buffer, const struct wined3d_shader *shader,
1879 const struct wined3d_shader_reg_maps *reg_maps, const struct shader_glsl_ctx_priv *ctx_priv)
1881 const struct wined3d_shader_version *version = &reg_maps->shader_version;
1882 const struct vs_compile_args *vs_args = ctx_priv->cur_vs_args;
1883 const struct ps_compile_args *ps_args = ctx_priv->cur_ps_args;
1884 const struct wined3d_gl_info *gl_info = context->gl_info;
1885 const struct wined3d_shader_indexable_temp *idx_temp_reg;
1886 unsigned int i, extra_constants_needed = 0;
1887 const struct wined3d_shader_lconst *lconst;
1888 const char *prefix;
1889 DWORD map;
1891 prefix = shader_glsl_get_prefix(version->type);
1893 /* Prototype the subroutines */
1894 for (i = 0, map = reg_maps->labels; map; map >>= 1, ++i)
1896 if (map & 1) shader_addline(buffer, "void subroutine%u();\n", i);
1899 /* Declare the constants (aka uniforms) */
1900 if (shader->limits->constant_float > 0)
1902 unsigned max_constantsF;
1904 /* Unless the shader uses indirect addressing, always declare the
1905 * maximum array size and ignore that we need some uniforms privately.
1906 * E.g. if GL supports 256 uniforms, and we need 2 for the pos fixup
1907 * and immediate values, still declare VC[256]. If the shader needs
1908 * more uniforms than we have it won't work in any case. If it uses
1909 * less, the compiler will figure out which uniforms are really used
1910 * and strip them out. This allows a shader to use c255 on a dx9 card,
1911 * as long as it doesn't also use all the other constants.
1913 * If the shader uses indirect addressing the compiler must assume
1914 * that all declared uniforms are used. In this case, declare only the
1915 * amount that we're assured to have.
1917 * Thus we run into problems in these two cases:
1918 * 1) The shader really uses more uniforms than supported.
1919 * 2) The shader uses indirect addressing, less constants than
1920 * supported, but uses a constant index > #supported consts. */
1921 if (version->type == WINED3D_SHADER_TYPE_PIXEL)
1923 /* No indirect addressing here. */
1924 max_constantsF = gl_info->limits.glsl_ps_float_constants;
1926 else
1928 if (reg_maps->usesrelconstF)
1930 /* Subtract the other potential uniforms from the max
1931 * available (bools, ints, and 1 row of projection matrix).
1932 * Subtract another uniform for immediate values, which have
1933 * to be loaded via uniform by the driver as well. The shader
1934 * code only uses 0.5, 2.0, 1.0, 128 and -128 in vertex
1935 * shader code, so one vec4 should be enough. (Unfortunately
1936 * the Nvidia driver doesn't store 128 and -128 in one float).
1938 * Writing gl_ClipVertex requires one uniform for each
1939 * clipplane as well. */
1940 max_constantsF = gl_info->limits.glsl_vs_float_constants - 3;
1941 if (vs_args->clip_enabled)
1942 max_constantsF -= gl_info->limits.user_clip_distances;
1943 max_constantsF -= wined3d_popcount(reg_maps->integer_constants);
1944 /* Strictly speaking a bool only uses one scalar, but the nvidia(Linux) compiler doesn't pack them properly,
1945 * so each scalar requires a full vec4. We could work around this by packing the booleans ourselves, but
1946 * for now take this into account when calculating the number of available constants
1948 max_constantsF -= wined3d_popcount(reg_maps->boolean_constants);
1949 /* Set by driver quirks in directx.c */
1950 max_constantsF -= gl_info->reserved_glsl_constants;
1952 if (max_constantsF < shader->limits->constant_float)
1954 static unsigned int once;
1956 if (!once++)
1957 ERR_(winediag)("The hardware does not support enough uniform components to run this shader,"
1958 " it may not render correctly.\n");
1959 else
1960 WARN("The hardware does not support enough uniform components to run this shader.\n");
1963 else
1965 max_constantsF = gl_info->limits.glsl_vs_float_constants;
1968 max_constantsF = min(shader->limits->constant_float, max_constantsF);
1969 shader_addline(buffer, "uniform vec4 %s_c[%u];\n", prefix, max_constantsF);
1972 /* Always declare the full set of constants, the compiler can remove the
1973 * unused ones because d3d doesn't (yet) support indirect int and bool
1974 * constant addressing. This avoids problems if the app uses e.g. i0 and i9. */
1975 if (shader->limits->constant_int > 0 && reg_maps->integer_constants)
1976 shader_addline(buffer, "uniform ivec4 %s_i[%u];\n", prefix, shader->limits->constant_int);
1978 if (shader->limits->constant_bool > 0 && reg_maps->boolean_constants)
1979 shader_addline(buffer, "uniform bool %s_b[%u];\n", prefix, shader->limits->constant_bool);
1981 /* Declare immediate constant buffer */
1982 if (reg_maps->icb)
1983 shader_addline(buffer, "uniform vec4 %s_icb[%u];\n", prefix, reg_maps->icb->vec4_count);
1985 /* Declare constant buffers */
1986 for (i = 0; i < WINED3D_MAX_CBS; ++i)
1988 if (reg_maps->cb_sizes[i])
1989 shader_addline(buffer, "layout(std140) uniform block_%s_cb%u { vec4 %s_cb%u[%u]; };\n",
1990 prefix, i, prefix, i, reg_maps->cb_sizes[i]);
1993 /* Declare texture samplers */
1994 for (i = 0; i < reg_maps->sampler_map.count; ++i)
1996 struct wined3d_shader_sampler_map_entry *entry;
1997 const char *sampler_type_prefix, *sampler_type;
1998 BOOL shadow_sampler, tex_rect;
2000 entry = &reg_maps->sampler_map.entries[i];
2002 if (entry->resource_idx >= ARRAY_SIZE(reg_maps->resource_info))
2004 ERR("Invalid resource index %u.\n", entry->resource_idx);
2005 continue;
2008 switch (reg_maps->resource_info[entry->resource_idx].data_type)
2010 case WINED3D_DATA_FLOAT:
2011 case WINED3D_DATA_UNORM:
2012 case WINED3D_DATA_SNORM:
2013 sampler_type_prefix = "";
2014 break;
2016 case WINED3D_DATA_INT:
2017 sampler_type_prefix = "i";
2018 break;
2020 case WINED3D_DATA_UINT:
2021 sampler_type_prefix = "u";
2022 break;
2024 default:
2025 sampler_type_prefix = "";
2026 ERR("Unhandled resource data type %#x.\n", reg_maps->resource_info[i].data_type);
2027 break;
2030 shadow_sampler = glsl_is_shadow_sampler(shader, ps_args, entry->resource_idx, entry->sampler_idx);
2031 switch (reg_maps->resource_info[entry->resource_idx].type)
2033 case WINED3D_SHADER_RESOURCE_TEXTURE_1D:
2034 if (shadow_sampler)
2035 sampler_type = "sampler1DShadow";
2036 else
2037 sampler_type = "sampler1D";
2038 break;
2040 case WINED3D_SHADER_RESOURCE_TEXTURE_2D:
2041 tex_rect = version->type == WINED3D_SHADER_TYPE_PIXEL
2042 && (ps_args->np2_fixup & (1u << entry->resource_idx))
2043 && gl_info->supported[ARB_TEXTURE_RECTANGLE];
2044 if (shadow_sampler)
2046 if (tex_rect)
2047 sampler_type = "sampler2DRectShadow";
2048 else
2049 sampler_type = "sampler2DShadow";
2051 else
2053 if (tex_rect)
2054 sampler_type = "sampler2DRect";
2055 else
2056 sampler_type = "sampler2D";
2058 break;
2060 case WINED3D_SHADER_RESOURCE_TEXTURE_3D:
2061 if (shadow_sampler)
2062 FIXME("Unsupported 3D shadow sampler.\n");
2063 sampler_type = "sampler3D";
2064 break;
2066 case WINED3D_SHADER_RESOURCE_TEXTURE_CUBE:
2067 if (shadow_sampler)
2068 FIXME("Unsupported Cube shadow sampler.\n");
2069 sampler_type = "samplerCube";
2070 break;
2072 case WINED3D_SHADER_RESOURCE_TEXTURE_2DARRAY:
2073 if (shadow_sampler)
2074 sampler_type = "sampler2DArrayShadow";
2075 else
2076 sampler_type = "sampler2DArray";
2077 break;
2079 default:
2080 sampler_type = "unsupported_sampler";
2081 FIXME("Unhandled resource type %#x.\n", reg_maps->resource_info[entry->resource_idx].type);
2082 break;
2084 shader_addline(buffer, "uniform %s%s %s_sampler%u;\n",
2085 sampler_type_prefix, sampler_type, prefix, entry->bind_idx);
2088 /* Declare images */
2089 for (i = 0; i < ARRAY_SIZE(reg_maps->uav_resource_info); ++i)
2091 const char *image_type_prefix, *image_type, *read_format;
2093 if (!reg_maps->uav_resource_info[i].type)
2094 continue;
2096 switch (reg_maps->uav_resource_info[i].data_type)
2098 case WINED3D_DATA_FLOAT:
2099 case WINED3D_DATA_UNORM:
2100 case WINED3D_DATA_SNORM:
2101 image_type_prefix = "";
2102 read_format = "r32f";
2103 break;
2105 case WINED3D_DATA_INT:
2106 image_type_prefix = "i";
2107 read_format = "r32i";
2108 break;
2110 case WINED3D_DATA_UINT:
2111 image_type_prefix = "u";
2112 read_format = "r32ui";
2113 break;
2115 default:
2116 image_type_prefix = "";
2117 read_format = "";
2118 ERR("Unhandled resource data type %#x.\n", reg_maps->uav_resource_info[i].data_type);
2119 break;
2122 switch (reg_maps->uav_resource_info[i].type)
2124 case WINED3D_SHADER_RESOURCE_TEXTURE_2D:
2125 image_type = "image2D";
2126 break;
2128 case WINED3D_SHADER_RESOURCE_TEXTURE_3D:
2129 image_type = "image3D";
2130 break;
2132 default:
2133 image_type = "unsupported_image";
2134 FIXME("Unhandled resource type %#x.\n", reg_maps->uav_resource_info[i].type);
2135 break;
2138 if (reg_maps->uav_read_mask & (1u << i))
2139 shader_addline(buffer, "layout(%s) uniform %s%s %s_image%u;\n",
2140 read_format, image_type_prefix, image_type, prefix, i);
2141 else
2142 shader_addline(buffer, "writeonly uniform %s%s %s_image%u;\n",
2143 image_type_prefix, image_type, prefix, i);
2146 /* Declare uniforms for NP2 texcoord fixup:
2147 * This is NOT done inside the loop that declares the texture samplers
2148 * since the NP2 fixup code is currently only used for the GeforceFX
2149 * series and when forcing the ARB_npot extension off. Modern cards just
2150 * skip the code anyway, so put it inside a separate loop. */
2151 if (version->type == WINED3D_SHADER_TYPE_PIXEL && ps_args->np2_fixup)
2153 struct ps_np2fixup_info *fixup = ctx_priv->cur_np2fixup_info;
2154 UINT cur = 0;
2156 /* NP2/RECT textures in OpenGL use texcoords in the range [0,width]x[0,height]
2157 * while D3D has them in the (normalized) [0,1]x[0,1] range.
2158 * samplerNP2Fixup stores texture dimensions and is updated through
2159 * shader_glsl_load_np2fixup_constants when the sampler changes. */
2161 for (i = 0; i < shader->limits->sampler; ++i)
2163 if (!reg_maps->resource_info[i].type || !(ps_args->np2_fixup & (1u << i)))
2164 continue;
2166 if (reg_maps->resource_info[i].type != WINED3D_SHADER_RESOURCE_TEXTURE_2D)
2168 FIXME("Non-2D texture is flagged for NP2 texcoord fixup.\n");
2169 continue;
2172 fixup->idx[i] = cur++;
2175 fixup->num_consts = (cur + 1) >> 1;
2176 fixup->active = ps_args->np2_fixup;
2177 shader_addline(buffer, "uniform vec4 %s_samplerNP2Fixup[%u];\n", prefix, fixup->num_consts);
2180 /* Declare address variables */
2181 for (i = 0, map = reg_maps->address; map; map >>= 1, ++i)
2183 if (map & 1) shader_addline(buffer, "ivec4 A%u;\n", i);
2186 if (version->type == WINED3D_SHADER_TYPE_VERTEX)
2188 for (i = 0; i < shader->input_signature.element_count; ++i)
2189 shader_glsl_declare_generic_vertex_attribute(buffer, gl_info, &shader->input_signature.elements[i]);
2191 if (vs_args->point_size && !vs_args->per_vertex_point_size)
2193 shader_addline(buffer, "uniform struct\n{\n");
2194 shader_addline(buffer, " float size;\n");
2195 shader_addline(buffer, " float size_min;\n");
2196 shader_addline(buffer, " float size_max;\n");
2197 shader_addline(buffer, "} ffp_point;\n");
2200 if (!gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2202 if (vs_args->clip_enabled)
2203 shader_addline(buffer, "uniform vec4 clip_planes[%u];\n", gl_info->limits.user_clip_distances);
2205 if (version->major < 3)
2207 declare_out_varying(gl_info, buffer, vs_args->flatshading, "vec4 ffp_varying_diffuse;\n");
2208 declare_out_varying(gl_info, buffer, vs_args->flatshading, "vec4 ffp_varying_specular;\n");
2209 declare_out_varying(gl_info, buffer, FALSE, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
2210 declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
2214 if (version->major < 4)
2215 shader_addline(buffer, "void setup_vs_output(in vec4[%u]);\n", shader->limits->packed_output);
2217 else if (version->type == WINED3D_SHADER_TYPE_GEOMETRY)
2219 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2221 shader_addline(buffer, "varying in vec4 gs_in[][%u];\n", shader->limits->packed_input);
2223 else
2225 shader_addline(buffer, "layout(%s) in;\n", glsl_primitive_type_from_d3d(shader->u.gs.input_type));
2226 shader_addline(buffer, "layout(%s, max_vertices = %u) out;\n",
2227 glsl_primitive_type_from_d3d(shader->u.gs.output_type), shader->u.gs.vertices_out);
2228 shader_addline(buffer, "in vs_gs_iface { vec4 gs_in[%u]; } gs_in[];\n", shader->limits->packed_input);
2231 else if (version->type == WINED3D_SHADER_TYPE_PIXEL)
2233 if (version->major < 3 || ps_args->vp_mode != vertexshader)
2235 shader_addline(buffer, "uniform struct\n{\n");
2236 shader_addline(buffer, " vec4 color;\n");
2237 shader_addline(buffer, " float density;\n");
2238 shader_addline(buffer, " float end;\n");
2239 shader_addline(buffer, " float scale;\n");
2240 shader_addline(buffer, "} ffp_fog;\n");
2242 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2244 if (glsl_is_color_reg_read(shader, 0))
2245 shader_addline(buffer, "vec4 ffp_varying_diffuse;\n");
2246 if (glsl_is_color_reg_read(shader, 1))
2247 shader_addline(buffer, "vec4 ffp_varying_specular;\n");
2248 shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
2249 shader_addline(buffer, "float ffp_varying_fogcoord;\n");
2251 else
2253 if (glsl_is_color_reg_read(shader, 0))
2254 declare_in_varying(gl_info, buffer, ps_args->flatshading, "vec4 ffp_varying_diffuse;\n");
2255 if (glsl_is_color_reg_read(shader, 1))
2256 declare_in_varying(gl_info, buffer, ps_args->flatshading, "vec4 ffp_varying_specular;\n");
2257 declare_in_varying(gl_info, buffer, FALSE, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
2258 shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
2259 declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
2263 if (version->major >= 3)
2265 UINT in_count = min(vec4_varyings(version->major, gl_info), shader->limits->packed_input);
2267 if (ps_args->vp_mode == vertexshader)
2268 declare_in_varying(gl_info, buffer, FALSE, "vec4 %s_link[%u];\n", prefix, in_count);
2269 shader_addline(buffer, "vec4 %s_in[%u];\n", prefix, in_count);
2272 for (i = 0, map = reg_maps->bumpmat; map; map >>= 1, ++i)
2274 if (!(map & 1))
2275 continue;
2277 shader_addline(buffer, "uniform mat2 bumpenv_mat%u;\n", i);
2279 if (reg_maps->luminanceparams & (1u << i))
2281 shader_addline(buffer, "uniform float bumpenv_lum_scale%u;\n", i);
2282 shader_addline(buffer, "uniform float bumpenv_lum_offset%u;\n", i);
2283 extra_constants_needed++;
2286 extra_constants_needed++;
2289 if (ps_args->srgb_correction)
2291 shader_addline(buffer, "const vec4 srgb_const0 = ");
2292 shader_glsl_append_imm_vec4(buffer, wined3d_srgb_const0);
2293 shader_addline(buffer, ";\n");
2294 shader_addline(buffer, "const vec4 srgb_const1 = ");
2295 shader_glsl_append_imm_vec4(buffer, wined3d_srgb_const1);
2296 shader_addline(buffer, ";\n");
2298 if (reg_maps->vpos || reg_maps->usesdsy)
2300 if (reg_maps->usesdsy || !gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
2302 ++extra_constants_needed;
2303 shader_addline(buffer, "uniform vec4 ycorrection;\n");
2305 if (reg_maps->vpos)
2307 if (gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
2309 if (context->d3d_info->wined3d_creation_flags & WINED3D_PIXEL_CENTER_INTEGER)
2310 shader_addline(buffer, "layout(%spixel_center_integer) in vec4 gl_FragCoord;\n",
2311 ps_args->render_offscreen ? "" : "origin_upper_left, ");
2312 else if (!ps_args->render_offscreen)
2313 shader_addline(buffer, "layout(origin_upper_left) in vec4 gl_FragCoord;\n");
2315 shader_addline(buffer, "vec4 vpos;\n");
2319 if (ps_args->alpha_test_func + 1 != WINED3D_CMP_ALWAYS)
2320 shader_addline(buffer, "uniform float alpha_test_ref;\n");
2322 if (!needs_legacy_glsl_syntax(gl_info))
2323 shader_addline(buffer, "out vec4 ps_out[%u];\n", gl_info->limits.buffers);
2325 if (shader->limits->constant_float + extra_constants_needed >= gl_info->limits.glsl_ps_float_constants)
2326 FIXME("Insufficient uniforms to run this shader.\n");
2329 /* Declare output register temporaries */
2330 if (shader->limits->packed_output)
2331 shader_addline(buffer, "vec4 %s_out[%u];\n", prefix, shader->limits->packed_output);
2333 /* Declare temporary variables */
2334 if (reg_maps->temporary_count)
2336 for (i = 0; i < reg_maps->temporary_count; ++i)
2337 shader_addline(buffer, "vec4 R%u;\n", i);
2339 else
2341 for (i = 0, map = reg_maps->temporary; map; map >>= 1, ++i)
2343 if (map & 1)
2344 shader_addline(buffer, "vec4 R%u;\n", i);
2348 /* Declare indexable temporary variables */
2349 LIST_FOR_EACH_ENTRY(idx_temp_reg, &reg_maps->indexable_temps, struct wined3d_shader_indexable_temp, entry)
2351 if (idx_temp_reg->component_count != 4)
2352 FIXME("Ignoring component count %u.\n", idx_temp_reg->component_count);
2353 shader_addline(buffer, "vec4 X%u[%u];\n", idx_temp_reg->register_idx, idx_temp_reg->register_size);
2356 /* Declare loop registers aLx */
2357 if (version->major < 4)
2359 for (i = 0; i < reg_maps->loop_depth; ++i)
2361 shader_addline(buffer, "int aL%u;\n", i);
2362 shader_addline(buffer, "int tmpInt%u;\n", i);
2366 /* Temporary variables for matrix operations */
2367 shader_addline(buffer, "vec4 tmp0;\n");
2368 shader_addline(buffer, "vec4 tmp1;\n");
2370 if (!shader->load_local_constsF)
2372 LIST_FOR_EACH_ENTRY(lconst, &shader->constantsF, struct wined3d_shader_lconst, entry)
2374 shader_addline(buffer, "const vec4 %s_lc%u = ", prefix, lconst->idx);
2375 shader_glsl_append_imm_vec4(buffer, (const float *)lconst->value);
2376 shader_addline(buffer, ";\n");
2381 /*****************************************************************************
2382 * Functions to generate GLSL strings from DirectX Shader bytecode begin here.
2384 * For more information, see http://wiki.winehq.org/DirectX-Shaders
2385 ****************************************************************************/
2387 /* Prototypes */
2388 static void shader_glsl_add_src_param(const struct wined3d_shader_instruction *ins,
2389 const struct wined3d_shader_src_param *wined3d_src, DWORD mask, struct glsl_src_param *glsl_src);
2391 /** Used for opcode modifiers - They multiply the result by the specified amount */
2392 static const char * const shift_glsl_tab[] = {
2393 "", /* 0 (none) */
2394 "2.0 * ", /* 1 (x2) */
2395 "4.0 * ", /* 2 (x4) */
2396 "8.0 * ", /* 3 (x8) */
2397 "16.0 * ", /* 4 (x16) */
2398 "32.0 * ", /* 5 (x32) */
2399 "", /* 6 (x64) */
2400 "", /* 7 (x128) */
2401 "", /* 8 (d256) */
2402 "", /* 9 (d128) */
2403 "", /* 10 (d64) */
2404 "", /* 11 (d32) */
2405 "0.0625 * ", /* 12 (d16) */
2406 "0.125 * ", /* 13 (d8) */
2407 "0.25 * ", /* 14 (d4) */
2408 "0.5 * " /* 15 (d2) */
2411 /* Generate a GLSL parameter that does the input modifier computation and return the input register/mask to use */
2412 static void shader_glsl_gen_modifier(enum wined3d_shader_src_modifier src_modifier,
2413 const char *in_reg, const char *in_regswizzle, char *out_str)
2415 switch (src_modifier)
2417 case WINED3DSPSM_DZ: /* Need to handle this in the instructions itself (texld & texcrd). */
2418 case WINED3DSPSM_DW:
2419 case WINED3DSPSM_NONE:
2420 sprintf(out_str, "%s%s", in_reg, in_regswizzle);
2421 break;
2422 case WINED3DSPSM_NEG:
2423 sprintf(out_str, "-%s%s", in_reg, in_regswizzle);
2424 break;
2425 case WINED3DSPSM_NOT:
2426 sprintf(out_str, "!%s%s", in_reg, in_regswizzle);
2427 break;
2428 case WINED3DSPSM_BIAS:
2429 sprintf(out_str, "(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle);
2430 break;
2431 case WINED3DSPSM_BIASNEG:
2432 sprintf(out_str, "-(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle);
2433 break;
2434 case WINED3DSPSM_SIGN:
2435 sprintf(out_str, "(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle);
2436 break;
2437 case WINED3DSPSM_SIGNNEG:
2438 sprintf(out_str, "-(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle);
2439 break;
2440 case WINED3DSPSM_COMP:
2441 sprintf(out_str, "(1.0 - %s%s)", in_reg, in_regswizzle);
2442 break;
2443 case WINED3DSPSM_X2:
2444 sprintf(out_str, "(2.0 * %s%s)", in_reg, in_regswizzle);
2445 break;
2446 case WINED3DSPSM_X2NEG:
2447 sprintf(out_str, "-(2.0 * %s%s)", in_reg, in_regswizzle);
2448 break;
2449 case WINED3DSPSM_ABS:
2450 sprintf(out_str, "abs(%s%s)", in_reg, in_regswizzle);
2451 break;
2452 case WINED3DSPSM_ABSNEG:
2453 sprintf(out_str, "-abs(%s%s)", in_reg, in_regswizzle);
2454 break;
2455 default:
2456 FIXME("Unhandled modifier %u\n", src_modifier);
2457 sprintf(out_str, "%s%s", in_reg, in_regswizzle);
2461 /** Writes the GLSL variable name that corresponds to the register that the
2462 * DX opcode parameter is trying to access */
2463 static void shader_glsl_get_register_name(const struct wined3d_shader_register *reg,
2464 char *register_name, BOOL *is_color, const struct wined3d_shader_instruction *ins)
2466 /* oPos, oFog and oPts in D3D */
2467 static const char * const hwrastout_reg_names[] = {"vs_out[10]", "vs_out[11].x", "vs_out[11].y"};
2469 const struct wined3d_shader *shader = ins->ctx->shader;
2470 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps;
2471 const struct wined3d_shader_version *version = &reg_maps->shader_version;
2472 const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
2473 const char *prefix = shader_glsl_get_prefix(version->type);
2474 struct glsl_src_param rel_param0, rel_param1;
2475 char imm_str[4][17];
2477 if (reg->idx[0].offset != ~0U && reg->idx[0].rel_addr)
2478 shader_glsl_add_src_param(ins, reg->idx[0].rel_addr, WINED3DSP_WRITEMASK_0, &rel_param0);
2479 if (reg->idx[1].offset != ~0U && reg->idx[1].rel_addr)
2480 shader_glsl_add_src_param(ins, reg->idx[1].rel_addr, WINED3DSP_WRITEMASK_0, &rel_param1);
2481 *is_color = FALSE;
2483 switch (reg->type)
2485 case WINED3DSPR_TEMP:
2486 sprintf(register_name, "R%u", reg->idx[0].offset);
2487 break;
2489 case WINED3DSPR_INPUT:
2490 if (version->type == WINED3D_SHADER_TYPE_VERTEX)
2492 struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data;
2494 if (reg->idx[0].rel_addr)
2495 FIXME("VS3+ input registers relative addressing.\n");
2496 if (priv->cur_vs_args->swizzle_map & (1u << reg->idx[0].offset))
2497 *is_color = TRUE;
2498 sprintf(register_name, "%s_in%u", prefix, reg->idx[0].offset);
2499 break;
2502 if (version->type == WINED3D_SHADER_TYPE_GEOMETRY)
2504 if (reg->idx[0].rel_addr)
2506 if (reg->idx[1].rel_addr)
2507 sprintf(register_name, "gs_in[%s + %u]%s[%s + %u]",
2508 rel_param0.param_str, reg->idx[0].offset,
2509 gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] ? "" : ".gs_in",
2510 rel_param1.param_str, reg->idx[1].offset);
2511 else
2512 sprintf(register_name, "gs_in[%s + %u]%s[%u]",
2513 rel_param0.param_str, reg->idx[0].offset,
2514 gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] ? "" : ".gs_in",
2515 reg->idx[1].offset);
2517 else if (reg->idx[1].rel_addr)
2518 sprintf(register_name, "gs_in[%u]%s[%s + %u]", reg->idx[0].offset,
2519 gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] ? "" : ".gs_in",
2520 rel_param1.param_str, reg->idx[1].offset);
2521 else
2522 sprintf(register_name, "gs_in[%u]%s[%u]", reg->idx[0].offset,
2523 gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] ? "" : ".gs_in",
2524 reg->idx[1].offset);
2525 break;
2528 /* pixel shaders >= 3.0 */
2529 if (version->major >= 3)
2531 DWORD idx = shader->u.ps.input_reg_map[reg->idx[0].offset];
2532 unsigned int in_count = vec4_varyings(version->major, gl_info);
2534 if (reg->idx[0].rel_addr)
2536 /* Removing a + 0 would be an obvious optimization, but
2537 * OS X doesn't see the NOP operation there. */
2538 if (idx)
2540 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]
2541 && shader->u.ps.declared_in_count > in_count)
2543 sprintf(register_name,
2544 "((%s + %u) > %u ? (%s + %u) > %u ? gl_SecondaryColor : gl_Color : %s_in[%s + %u])",
2545 rel_param0.param_str, idx, in_count - 1, rel_param0.param_str, idx, in_count,
2546 prefix, rel_param0.param_str, idx);
2548 else
2550 sprintf(register_name, "%s_in[%s + %u]", prefix, rel_param0.param_str, idx);
2553 else
2555 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]
2556 && shader->u.ps.declared_in_count > in_count)
2558 sprintf(register_name, "((%s) > %u ? (%s) > %u ? gl_SecondaryColor : gl_Color : %s_in[%s])",
2559 rel_param0.param_str, in_count - 1, rel_param0.param_str, in_count,
2560 prefix, rel_param0.param_str);
2562 else
2564 sprintf(register_name, "%s_in[%s]", prefix, rel_param0.param_str);
2568 else
2570 if (idx == in_count) sprintf(register_name, "gl_Color");
2571 else if (idx == in_count + 1) sprintf(register_name, "gl_SecondaryColor");
2572 else sprintf(register_name, "%s_in[%u]", prefix, idx);
2575 else
2577 if (!reg->idx[0].offset)
2578 strcpy(register_name, "ffp_varying_diffuse");
2579 else
2580 strcpy(register_name, "ffp_varying_specular");
2581 break;
2583 break;
2585 case WINED3DSPR_CONST:
2587 /* Relative addressing */
2588 if (reg->idx[0].rel_addr)
2590 if (wined3d_settings.check_float_constants)
2591 sprintf(register_name, "(%s + %u >= 0 && %s + %u < %u ? %s_c[%s + %u] : vec4(0.0))",
2592 rel_param0.param_str, reg->idx[0].offset,
2593 rel_param0.param_str, reg->idx[0].offset, shader->limits->constant_float,
2594 prefix, rel_param0.param_str, reg->idx[0].offset);
2595 else if (reg->idx[0].offset)
2596 sprintf(register_name, "%s_c[%s + %u]", prefix, rel_param0.param_str, reg->idx[0].offset);
2597 else
2598 sprintf(register_name, "%s_c[%s]", prefix, rel_param0.param_str);
2600 else
2602 if (shader_constant_is_local(shader, reg->idx[0].offset))
2603 sprintf(register_name, "%s_lc%u", prefix, reg->idx[0].offset);
2604 else
2605 sprintf(register_name, "%s_c[%u]", prefix, reg->idx[0].offset);
2608 break;
2610 case WINED3DSPR_CONSTINT:
2611 sprintf(register_name, "%s_i[%u]", prefix, reg->idx[0].offset);
2612 break;
2614 case WINED3DSPR_CONSTBOOL:
2615 sprintf(register_name, "%s_b[%u]", prefix, reg->idx[0].offset);
2616 break;
2618 case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */
2619 if (version->type == WINED3D_SHADER_TYPE_PIXEL)
2620 sprintf(register_name, "T%u", reg->idx[0].offset);
2621 else
2622 sprintf(register_name, "A%u", reg->idx[0].offset);
2623 break;
2625 case WINED3DSPR_LOOP:
2626 sprintf(register_name, "aL%u", ins->ctx->loop_state->current_reg - 1);
2627 break;
2629 case WINED3DSPR_SAMPLER:
2630 sprintf(register_name, "%s_sampler%u", prefix, reg->idx[0].offset);
2631 break;
2633 case WINED3DSPR_COLOROUT:
2634 if (reg->idx[0].offset >= gl_info->limits.buffers)
2635 WARN("Write to render target %u, only %d supported.\n",
2636 reg->idx[0].offset, gl_info->limits.buffers);
2638 sprintf(register_name, "%s[%u]", get_fragment_output(gl_info), reg->idx[0].offset);
2639 break;
2641 case WINED3DSPR_RASTOUT:
2642 sprintf(register_name, "%s", hwrastout_reg_names[reg->idx[0].offset]);
2643 break;
2645 case WINED3DSPR_DEPTHOUT:
2646 sprintf(register_name, "gl_FragDepth");
2647 break;
2649 case WINED3DSPR_ATTROUT:
2650 if (!reg->idx[0].offset)
2651 sprintf(register_name, "%s_out[8]", prefix);
2652 else
2653 sprintf(register_name, "%s_out[9]", prefix);
2654 break;
2656 case WINED3DSPR_TEXCRDOUT:
2657 /* Vertex shaders >= 3.0: WINED3DSPR_OUTPUT */
2658 if (reg->idx[0].rel_addr)
2659 FIXME("VS3 output registers relative addressing.\n");
2660 sprintf(register_name, "%s_out[%u]", prefix, reg->idx[0].offset);
2661 break;
2663 case WINED3DSPR_MISCTYPE:
2664 if (!reg->idx[0].offset)
2666 /* vPos */
2667 sprintf(register_name, "vpos");
2669 else if (reg->idx[0].offset == 1)
2671 /* Note that gl_FrontFacing is a bool, while vFace is
2672 * a float for which the sign determines front/back */
2673 sprintf(register_name, "(gl_FrontFacing ? 1.0 : -1.0)");
2675 else
2677 FIXME("Unhandled misctype register %u.\n", reg->idx[0].offset);
2678 sprintf(register_name, "unrecognized_register");
2680 break;
2682 case WINED3DSPR_IMMCONST:
2683 switch (reg->immconst_type)
2685 case WINED3D_IMMCONST_SCALAR:
2686 switch (reg->data_type)
2688 case WINED3D_DATA_FLOAT:
2689 if (gl_info->supported[ARB_SHADER_BIT_ENCODING])
2690 sprintf(register_name, "uintBitsToFloat(%#xu)", reg->immconst_data[0]);
2691 else
2692 wined3d_ftoa(*(const float *)reg->immconst_data, register_name);
2693 break;
2694 case WINED3D_DATA_INT:
2695 sprintf(register_name, "%#x", reg->immconst_data[0]);
2696 break;
2697 case WINED3D_DATA_RESOURCE:
2698 case WINED3D_DATA_SAMPLER:
2699 case WINED3D_DATA_UINT:
2700 sprintf(register_name, "%#xu", reg->immconst_data[0]);
2701 break;
2702 default:
2703 sprintf(register_name, "<unhandled data type %#x>", reg->data_type);
2704 break;
2706 break;
2708 case WINED3D_IMMCONST_VEC4:
2709 switch (reg->data_type)
2711 case WINED3D_DATA_FLOAT:
2712 if (gl_info->supported[ARB_SHADER_BIT_ENCODING])
2714 sprintf(register_name, "uintBitsToFloat(uvec4(%#xu, %#xu, %#xu, %#xu))",
2715 reg->immconst_data[0], reg->immconst_data[1],
2716 reg->immconst_data[2], reg->immconst_data[3]);
2718 else
2720 wined3d_ftoa(*(const float *)&reg->immconst_data[0], imm_str[0]);
2721 wined3d_ftoa(*(const float *)&reg->immconst_data[1], imm_str[1]);
2722 wined3d_ftoa(*(const float *)&reg->immconst_data[2], imm_str[2]);
2723 wined3d_ftoa(*(const float *)&reg->immconst_data[3], imm_str[3]);
2724 sprintf(register_name, "vec4(%s, %s, %s, %s)",
2725 imm_str[0], imm_str[1], imm_str[2], imm_str[3]);
2727 break;
2728 case WINED3D_DATA_INT:
2729 sprintf(register_name, "ivec4(%#x, %#x, %#x, %#x)",
2730 reg->immconst_data[0], reg->immconst_data[1],
2731 reg->immconst_data[2], reg->immconst_data[3]);
2732 break;
2733 case WINED3D_DATA_RESOURCE:
2734 case WINED3D_DATA_SAMPLER:
2735 case WINED3D_DATA_UINT:
2736 sprintf(register_name, "uvec4(%#xu, %#xu, %#xu, %#xu)",
2737 reg->immconst_data[0], reg->immconst_data[1],
2738 reg->immconst_data[2], reg->immconst_data[3]);
2739 break;
2740 default:
2741 sprintf(register_name, "<unhandled data type %#x>", reg->data_type);
2742 break;
2744 break;
2746 default:
2747 FIXME("Unhandled immconst type %#x\n", reg->immconst_type);
2748 sprintf(register_name, "<unhandled_immconst_type %#x>", reg->immconst_type);
2750 break;
2752 case WINED3DSPR_CONSTBUFFER:
2753 if (reg->idx[1].rel_addr)
2754 sprintf(register_name, "%s_cb%u[%s + %u]",
2755 prefix, reg->idx[0].offset, rel_param1.param_str, reg->idx[1].offset);
2756 else
2757 sprintf(register_name, "%s_cb%u[%u]", prefix, reg->idx[0].offset, reg->idx[1].offset);
2758 break;
2760 case WINED3DSPR_IMMCONSTBUFFER:
2761 if (reg->idx[0].rel_addr)
2762 sprintf(register_name, "%s_icb[%s + %u]", prefix, rel_param0.param_str, reg->idx[0].offset);
2763 else
2764 sprintf(register_name, "%s_icb[%u]", prefix, reg->idx[0].offset);
2765 break;
2767 case WINED3DSPR_PRIMID:
2768 sprintf(register_name, "uint(gl_PrimitiveIDIn)");
2769 break;
2771 case WINED3DSPR_IDXTEMP:
2772 if (reg->idx[1].rel_addr)
2773 sprintf(register_name, "X%u[%s + %u]", reg->idx[0].offset, rel_param1.param_str, reg->idx[1].offset);
2774 else
2775 sprintf(register_name, "X%u[%u]", reg->idx[0].offset, reg->idx[1].offset);
2776 break;
2778 default:
2779 FIXME("Unhandled register type %#x.\n", reg->type);
2780 sprintf(register_name, "unrecognized_register");
2781 break;
2785 static void shader_glsl_write_mask_to_str(DWORD write_mask, char *str)
2787 *str++ = '.';
2788 if (write_mask & WINED3DSP_WRITEMASK_0) *str++ = 'x';
2789 if (write_mask & WINED3DSP_WRITEMASK_1) *str++ = 'y';
2790 if (write_mask & WINED3DSP_WRITEMASK_2) *str++ = 'z';
2791 if (write_mask & WINED3DSP_WRITEMASK_3) *str++ = 'w';
2792 *str = '\0';
2795 /* Get the GLSL write mask for the destination register */
2796 static DWORD shader_glsl_get_write_mask(const struct wined3d_shader_dst_param *param, char *write_mask)
2798 DWORD mask = param->write_mask;
2800 if (shader_is_scalar(&param->reg))
2802 mask = WINED3DSP_WRITEMASK_0;
2803 *write_mask = '\0';
2805 else
2807 shader_glsl_write_mask_to_str(mask, write_mask);
2810 return mask;
2813 static unsigned int shader_glsl_get_write_mask_size(DWORD write_mask) {
2814 unsigned int size = 0;
2816 if (write_mask & WINED3DSP_WRITEMASK_0) ++size;
2817 if (write_mask & WINED3DSP_WRITEMASK_1) ++size;
2818 if (write_mask & WINED3DSP_WRITEMASK_2) ++size;
2819 if (write_mask & WINED3DSP_WRITEMASK_3) ++size;
2821 return size;
2824 static void shader_glsl_swizzle_to_str(const DWORD swizzle, BOOL fixup, DWORD mask, char *str)
2826 /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra",
2827 * but addressed as "rgba". To fix this we need to swap the register's x
2828 * and z components. */
2829 const char *swizzle_chars = fixup ? "zyxw" : "xyzw";
2831 *str++ = '.';
2832 /* swizzle bits fields: wwzzyyxx */
2833 if (mask & WINED3DSP_WRITEMASK_0) *str++ = swizzle_chars[swizzle & 0x03];
2834 if (mask & WINED3DSP_WRITEMASK_1) *str++ = swizzle_chars[(swizzle >> 2) & 0x03];
2835 if (mask & WINED3DSP_WRITEMASK_2) *str++ = swizzle_chars[(swizzle >> 4) & 0x03];
2836 if (mask & WINED3DSP_WRITEMASK_3) *str++ = swizzle_chars[(swizzle >> 6) & 0x03];
2837 *str = '\0';
2840 static void shader_glsl_get_swizzle(const struct wined3d_shader_src_param *param,
2841 BOOL fixup, DWORD mask, char *swizzle_str)
2843 if (shader_is_scalar(&param->reg))
2844 *swizzle_str = '\0';
2845 else
2846 shader_glsl_swizzle_to_str(param->swizzle, fixup, mask, swizzle_str);
2849 /* From a given parameter token, generate the corresponding GLSL string.
2850 * Also, return the actual register name and swizzle in case the
2851 * caller needs this information as well. */
2852 static void shader_glsl_add_src_param_ext(const struct wined3d_shader_instruction *ins,
2853 const struct wined3d_shader_src_param *wined3d_src, DWORD mask, struct glsl_src_param *glsl_src,
2854 enum wined3d_data_type data_type)
2856 BOOL is_color = FALSE;
2857 char swizzle_str[6];
2859 glsl_src->reg_name[0] = '\0';
2860 glsl_src->param_str[0] = '\0';
2861 swizzle_str[0] = '\0';
2863 shader_glsl_get_register_name(&wined3d_src->reg, glsl_src->reg_name, &is_color, ins);
2864 shader_glsl_get_swizzle(wined3d_src, is_color, mask, swizzle_str);
2866 if (wined3d_src->reg.type == WINED3DSPR_IMMCONST || wined3d_src->reg.type == WINED3DSPR_PRIMID)
2868 shader_glsl_gen_modifier(wined3d_src->modifiers, glsl_src->reg_name, swizzle_str, glsl_src->param_str);
2870 else
2872 char reg_name[200];
2874 switch (data_type)
2876 case WINED3D_DATA_FLOAT:
2877 sprintf(reg_name, "%s", glsl_src->reg_name);
2878 break;
2879 case WINED3D_DATA_INT:
2880 sprintf(reg_name, "floatBitsToInt(%s)", glsl_src->reg_name);
2881 break;
2882 case WINED3D_DATA_RESOURCE:
2883 case WINED3D_DATA_SAMPLER:
2884 case WINED3D_DATA_UINT:
2885 sprintf(reg_name, "floatBitsToUint(%s)", glsl_src->reg_name);
2886 break;
2887 default:
2888 FIXME("Unhandled data type %#x.\n", data_type);
2889 sprintf(reg_name, "%s", glsl_src->reg_name);
2890 break;
2893 shader_glsl_gen_modifier(wined3d_src->modifiers, reg_name, swizzle_str, glsl_src->param_str);
2897 static void shader_glsl_add_src_param(const struct wined3d_shader_instruction *ins,
2898 const struct wined3d_shader_src_param *wined3d_src, DWORD mask, struct glsl_src_param *glsl_src)
2900 shader_glsl_add_src_param_ext(ins, wined3d_src, mask, glsl_src, wined3d_src->reg.data_type);
2903 /* From a given parameter token, generate the corresponding GLSL string.
2904 * Also, return the actual register name and swizzle in case the
2905 * caller needs this information as well. */
2906 static DWORD shader_glsl_add_dst_param(const struct wined3d_shader_instruction *ins,
2907 const struct wined3d_shader_dst_param *wined3d_dst, struct glsl_dst_param *glsl_dst)
2909 BOOL is_color = FALSE;
2911 glsl_dst->mask_str[0] = '\0';
2912 glsl_dst->reg_name[0] = '\0';
2914 shader_glsl_get_register_name(&wined3d_dst->reg, glsl_dst->reg_name, &is_color, ins);
2915 return shader_glsl_get_write_mask(wined3d_dst, glsl_dst->mask_str);
2918 /* Append the destination part of the instruction to the buffer, return the effective write mask */
2919 static DWORD shader_glsl_append_dst_ext(struct wined3d_string_buffer *buffer,
2920 const struct wined3d_shader_instruction *ins, const struct wined3d_shader_dst_param *dst,
2921 enum wined3d_data_type data_type)
2923 struct glsl_dst_param glsl_dst;
2924 DWORD mask;
2926 if ((mask = shader_glsl_add_dst_param(ins, dst, &glsl_dst)))
2928 switch (data_type)
2930 case WINED3D_DATA_FLOAT:
2931 shader_addline(buffer, "%s%s = %s(",
2932 glsl_dst.reg_name, glsl_dst.mask_str, shift_glsl_tab[dst->shift]);
2933 break;
2934 case WINED3D_DATA_INT:
2935 shader_addline(buffer, "%s%s = %sintBitsToFloat(",
2936 glsl_dst.reg_name, glsl_dst.mask_str, shift_glsl_tab[dst->shift]);
2937 break;
2938 case WINED3D_DATA_RESOURCE:
2939 case WINED3D_DATA_SAMPLER:
2940 case WINED3D_DATA_UINT:
2941 shader_addline(buffer, "%s%s = %suintBitsToFloat(",
2942 glsl_dst.reg_name, glsl_dst.mask_str, shift_glsl_tab[dst->shift]);
2943 break;
2944 default:
2945 FIXME("Unhandled data type %#x.\n", data_type);
2946 shader_addline(buffer, "%s%s = %s(",
2947 glsl_dst.reg_name, glsl_dst.mask_str, shift_glsl_tab[dst->shift]);
2948 break;
2952 return mask;
2955 /* Append the destination part of the instruction to the buffer, return the effective write mask */
2956 static DWORD shader_glsl_append_dst(struct wined3d_string_buffer *buffer, const struct wined3d_shader_instruction *ins)
2958 return shader_glsl_append_dst_ext(buffer, ins, &ins->dst[0], ins->dst[0].reg.data_type);
2961 /** Process GLSL instruction modifiers */
2962 static void shader_glsl_add_instruction_modifiers(const struct wined3d_shader_instruction *ins)
2964 struct glsl_dst_param dst_param;
2965 DWORD modifiers;
2967 if (!ins->dst_count) return;
2969 modifiers = ins->dst[0].modifiers;
2970 if (!modifiers) return;
2972 shader_glsl_add_dst_param(ins, &ins->dst[0], &dst_param);
2974 if (modifiers & WINED3DSPDM_SATURATE)
2976 /* _SAT means to clamp the value of the register to between 0 and 1 */
2977 shader_addline(ins->ctx->buffer, "%s%s = clamp(%s%s, 0.0, 1.0);\n", dst_param.reg_name,
2978 dst_param.mask_str, dst_param.reg_name, dst_param.mask_str);
2981 if (modifiers & WINED3DSPDM_MSAMPCENTROID)
2983 FIXME("_centroid modifier not handled\n");
2986 if (modifiers & WINED3DSPDM_PARTIALPRECISION)
2988 /* MSDN says this modifier can be safely ignored, so that's what we'll do. */
2992 static const char *shader_glsl_get_rel_op(enum wined3d_shader_rel_op op)
2994 switch (op)
2996 case WINED3D_SHADER_REL_OP_GT: return ">";
2997 case WINED3D_SHADER_REL_OP_EQ: return "==";
2998 case WINED3D_SHADER_REL_OP_GE: return ">=";
2999 case WINED3D_SHADER_REL_OP_LT: return "<";
3000 case WINED3D_SHADER_REL_OP_NE: return "!=";
3001 case WINED3D_SHADER_REL_OP_LE: return "<=";
3002 default:
3003 FIXME("Unrecognized operator %#x.\n", op);
3004 return "(\?\?)";
3008 static BOOL shader_glsl_has_core_grad(const struct wined3d_gl_info *gl_info,
3009 const struct wined3d_shader_version *version)
3011 return shader_glsl_get_version(gl_info, version) >= 130 || gl_info->supported[EXT_GPU_SHADER4];
3014 static void shader_glsl_get_sample_function(const struct wined3d_shader_context *ctx,
3015 DWORD resource_idx, DWORD sampler_idx, DWORD flags, struct glsl_sample_function *sample_function)
3017 enum wined3d_shader_resource_type resource_type = ctx->reg_maps->resource_info[resource_idx].type;
3018 struct shader_glsl_ctx_priv *priv = ctx->backend_data;
3019 const struct wined3d_gl_info *gl_info = ctx->gl_info;
3020 BOOL shadow = glsl_is_shadow_sampler(ctx->shader, priv->cur_ps_args, resource_idx, sampler_idx);
3021 BOOL projected = flags & WINED3D_GLSL_SAMPLE_PROJECTED;
3022 BOOL texrect = ctx->reg_maps->shader_version.type == WINED3D_SHADER_TYPE_PIXEL
3023 && priv->cur_ps_args->np2_fixup & (1u << resource_idx)
3024 && gl_info->supported[ARB_TEXTURE_RECTANGLE];
3025 BOOL lod = flags & WINED3D_GLSL_SAMPLE_LOD;
3026 BOOL grad = flags & WINED3D_GLSL_SAMPLE_GRAD;
3027 BOOL offset = flags & WINED3D_GLSL_SAMPLE_OFFSET;
3028 const char *base = "texture", *type_part = "", *suffix = "";
3029 unsigned int coord_size, deriv_size;
3030 BOOL array;
3032 sample_function->data_type = ctx->reg_maps->resource_info[resource_idx].data_type;
3034 if (resource_type >= ARRAY_SIZE(resource_type_info))
3036 ERR("Unexpected resource type %#x.\n", resource_type);
3037 resource_type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
3039 array = resource_type == WINED3D_SHADER_RESOURCE_TEXTURE_1DARRAY
3040 || resource_type == WINED3D_SHADER_RESOURCE_TEXTURE_2DARRAY;
3042 /* Note that there's no such thing as a projected cube texture. */
3043 if (resource_type == WINED3D_SHADER_RESOURCE_TEXTURE_CUBE)
3044 projected = FALSE;
3046 if (needs_legacy_glsl_syntax(gl_info))
3048 if (shadow)
3049 base = "shadow";
3051 type_part = resource_type_info[resource_type].type_part;
3052 if (resource_type == WINED3D_SHADER_RESOURCE_TEXTURE_2D && texrect)
3053 type_part = "2DRect";
3054 if (!type_part[0])
3055 FIXME("Unhandled resource type %#x.\n", resource_type);
3057 if (!lod && grad && !shader_glsl_has_core_grad(gl_info, &ctx->shader->reg_maps.shader_version))
3059 if (gl_info->supported[ARB_SHADER_TEXTURE_LOD])
3060 suffix = "ARB";
3061 else
3062 FIXME("Unsupported grad function.\n");
3066 if (flags & WINED3D_GLSL_SAMPLE_LOAD)
3068 static const DWORD texel_fetch_flags = WINED3D_GLSL_SAMPLE_LOAD | WINED3D_GLSL_SAMPLE_OFFSET;
3069 if (flags & ~texel_fetch_flags)
3070 ERR("Unexpected flags %#x for texelFetch.\n", flags & ~texel_fetch_flags);
3072 base = "texelFetch";
3073 type_part = "";
3076 sample_function->name = string_buffer_get(priv->string_buffers);
3077 string_buffer_sprintf(sample_function->name, "%s%s%s%s%s%s", base, type_part, projected ? "Proj" : "",
3078 lod ? "Lod" : grad ? "Grad" : "", offset ? "Offset" : "", suffix);
3080 coord_size = resource_type_info[resource_type].coord_size;
3081 deriv_size = coord_size;
3082 if (shadow)
3083 ++coord_size;
3084 if (array)
3085 --deriv_size;
3086 sample_function->offset_size = offset ? deriv_size : 0;
3087 sample_function->coord_mask = (1u << coord_size) - 1;
3088 sample_function->deriv_mask = (1u << deriv_size) - 1;
3089 sample_function->output_single_component = shadow && !needs_legacy_glsl_syntax(gl_info);
3092 static void shader_glsl_release_sample_function(const struct wined3d_shader_context *ctx,
3093 struct glsl_sample_function *sample_function)
3095 const struct shader_glsl_ctx_priv *priv = ctx->backend_data;
3097 string_buffer_release(priv->string_buffers, sample_function->name);
3100 static void shader_glsl_append_fixup_arg(char *arguments, const char *reg_name,
3101 BOOL sign_fixup, enum fixup_channel_source channel_source)
3103 switch(channel_source)
3105 case CHANNEL_SOURCE_ZERO:
3106 strcat(arguments, "0.0");
3107 break;
3109 case CHANNEL_SOURCE_ONE:
3110 strcat(arguments, "1.0");
3111 break;
3113 case CHANNEL_SOURCE_X:
3114 strcat(arguments, reg_name);
3115 strcat(arguments, ".x");
3116 break;
3118 case CHANNEL_SOURCE_Y:
3119 strcat(arguments, reg_name);
3120 strcat(arguments, ".y");
3121 break;
3123 case CHANNEL_SOURCE_Z:
3124 strcat(arguments, reg_name);
3125 strcat(arguments, ".z");
3126 break;
3128 case CHANNEL_SOURCE_W:
3129 strcat(arguments, reg_name);
3130 strcat(arguments, ".w");
3131 break;
3133 default:
3134 FIXME("Unhandled channel source %#x\n", channel_source);
3135 strcat(arguments, "undefined");
3136 break;
3139 if (sign_fixup) strcat(arguments, " * 2.0 - 1.0");
3142 static void shader_glsl_color_correction_ext(struct wined3d_string_buffer *buffer,
3143 const char *reg_name, DWORD mask, struct color_fixup_desc fixup)
3145 unsigned int mask_size, remaining;
3146 DWORD fixup_mask = 0;
3147 char arguments[256];
3148 char mask_str[6];
3150 if (fixup.x_sign_fixup || fixup.x_source != CHANNEL_SOURCE_X) fixup_mask |= WINED3DSP_WRITEMASK_0;
3151 if (fixup.y_sign_fixup || fixup.y_source != CHANNEL_SOURCE_Y) fixup_mask |= WINED3DSP_WRITEMASK_1;
3152 if (fixup.z_sign_fixup || fixup.z_source != CHANNEL_SOURCE_Z) fixup_mask |= WINED3DSP_WRITEMASK_2;
3153 if (fixup.w_sign_fixup || fixup.w_source != CHANNEL_SOURCE_W) fixup_mask |= WINED3DSP_WRITEMASK_3;
3154 if (!(mask &= fixup_mask))
3155 return;
3157 if (is_complex_fixup(fixup))
3159 enum complex_fixup complex_fixup = get_complex_fixup(fixup);
3160 FIXME("Complex fixup (%#x) not supported\n",complex_fixup);
3161 return;
3164 shader_glsl_write_mask_to_str(mask, mask_str);
3165 mask_size = shader_glsl_get_write_mask_size(mask);
3167 arguments[0] = '\0';
3168 remaining = mask_size;
3169 if (mask & WINED3DSP_WRITEMASK_0)
3171 shader_glsl_append_fixup_arg(arguments, reg_name, fixup.x_sign_fixup, fixup.x_source);
3172 if (--remaining) strcat(arguments, ", ");
3174 if (mask & WINED3DSP_WRITEMASK_1)
3176 shader_glsl_append_fixup_arg(arguments, reg_name, fixup.y_sign_fixup, fixup.y_source);
3177 if (--remaining) strcat(arguments, ", ");
3179 if (mask & WINED3DSP_WRITEMASK_2)
3181 shader_glsl_append_fixup_arg(arguments, reg_name, fixup.z_sign_fixup, fixup.z_source);
3182 if (--remaining) strcat(arguments, ", ");
3184 if (mask & WINED3DSP_WRITEMASK_3)
3186 shader_glsl_append_fixup_arg(arguments, reg_name, fixup.w_sign_fixup, fixup.w_source);
3187 if (--remaining) strcat(arguments, ", ");
3190 if (mask_size > 1)
3191 shader_addline(buffer, "%s%s = vec%u(%s);\n", reg_name, mask_str, mask_size, arguments);
3192 else
3193 shader_addline(buffer, "%s%s = %s;\n", reg_name, mask_str, arguments);
3196 static void shader_glsl_color_correction(const struct wined3d_shader_instruction *ins, struct color_fixup_desc fixup)
3198 char reg_name[256];
3199 BOOL is_color;
3201 shader_glsl_get_register_name(&ins->dst[0].reg, reg_name, &is_color, ins);
3202 shader_glsl_color_correction_ext(ins->ctx->buffer, reg_name, ins->dst[0].write_mask, fixup);
3205 static void PRINTF_ATTR(9, 10) shader_glsl_gen_sample_code(const struct wined3d_shader_instruction *ins,
3206 unsigned int sampler_bind_idx, const struct glsl_sample_function *sample_function, DWORD swizzle,
3207 const char *dx, const char *dy, const char *bias, const struct wined3d_shader_texel_offset *offset,
3208 const char *coord_reg_fmt, ...)
3210 const struct wined3d_shader_version *version = &ins->ctx->reg_maps->shader_version;
3211 char dst_swizzle[6];
3212 struct color_fixup_desc fixup;
3213 BOOL np2_fixup = FALSE;
3214 va_list args;
3215 int ret;
3217 shader_glsl_swizzle_to_str(swizzle, FALSE, ins->dst[0].write_mask, dst_swizzle);
3219 /* If ARB_texture_swizzle is supported we don't need to do anything here.
3220 * We actually rely on it for vertex shaders and SM4+. */
3221 if (version->type == WINED3D_SHADER_TYPE_PIXEL && version->major < 4)
3223 const struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data;
3224 fixup = priv->cur_ps_args->color_fixup[sampler_bind_idx];
3226 if (priv->cur_ps_args->np2_fixup & (1u << sampler_bind_idx))
3227 np2_fixup = TRUE;
3229 else
3231 fixup = COLOR_FIXUP_IDENTITY;
3234 shader_glsl_append_dst_ext(ins->ctx->buffer, ins, &ins->dst[0], sample_function->data_type);
3236 if (sample_function->output_single_component)
3237 shader_addline(ins->ctx->buffer, "vec4(");
3239 shader_addline(ins->ctx->buffer, "%s(%s_sampler%u, ",
3240 sample_function->name->buffer, shader_glsl_get_prefix(version->type), sampler_bind_idx);
3242 for (;;)
3244 va_start(args, coord_reg_fmt);
3245 ret = shader_vaddline(ins->ctx->buffer, coord_reg_fmt, args);
3246 va_end(args);
3247 if (!ret)
3248 break;
3249 if (!string_buffer_resize(ins->ctx->buffer, ret))
3250 break;
3253 if (np2_fixup)
3255 const struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data;
3256 const unsigned char idx = priv->cur_np2fixup_info->idx[sampler_bind_idx];
3258 switch (shader_glsl_get_write_mask_size(sample_function->coord_mask))
3260 case 1:
3261 shader_addline(ins->ctx->buffer, " * ps_samplerNP2Fixup[%u].%s",
3262 idx >> 1, (idx % 2) ? "z" : "x");
3263 break;
3264 case 2:
3265 shader_addline(ins->ctx->buffer, " * ps_samplerNP2Fixup[%u].%s",
3266 idx >> 1, (idx % 2) ? "zw" : "xy");
3267 break;
3268 case 3:
3269 shader_addline(ins->ctx->buffer, " * vec3(ps_samplerNP2Fixup[%u].%s, 1.0)",
3270 idx >> 1, (idx % 2) ? "zw" : "xy");
3271 break;
3272 case 4:
3273 shader_addline(ins->ctx->buffer, " * vec4(ps_samplerNP2Fixup[%u].%s, 1.0, 1.0)",
3274 idx >> 1, (idx % 2) ? "zw" : "xy");
3275 break;
3278 if (dx && dy)
3279 shader_addline(ins->ctx->buffer, ", %s, %s", dx, dy);
3280 else if (bias)
3281 shader_addline(ins->ctx->buffer, ", %s", bias);
3282 if (sample_function->offset_size)
3284 int offset_immdata[4] = {offset->u, offset->v, offset->w};
3285 shader_addline(ins->ctx->buffer, ", ");
3286 shader_glsl_append_imm_ivec(ins->ctx->buffer, offset_immdata, sample_function->offset_size);
3288 shader_addline(ins->ctx->buffer, ")");
3290 if (sample_function->output_single_component)
3291 shader_addline(ins->ctx->buffer, ")");
3293 shader_addline(ins->ctx->buffer, "%s);\n", dst_swizzle);
3295 if (!is_identity_fixup(fixup))
3296 shader_glsl_color_correction(ins, fixup);
3299 static void shader_glsl_fixup_position(struct wined3d_string_buffer *buffer)
3301 /* Write the final position.
3303 * OpenGL coordinates specify the center of the pixel while D3D coords
3304 * specify the corner. The offsets are stored in z and w in
3305 * pos_fixup. pos_fixup.y contains 1.0 or -1.0 to turn the rendering
3306 * upside down for offscreen rendering. pos_fixup.x contains 1.0 to allow
3307 * a MAD. */
3308 shader_addline(buffer, "gl_Position.y = gl_Position.y * pos_fixup.y;\n");
3309 shader_addline(buffer, "gl_Position.xy += pos_fixup.zw * gl_Position.ww;\n");
3311 /* Z coord [0;1]->[-1;1] mapping, see comment in get_projection_matrix()
3312 * in utils.c
3314 * Basically we want (in homogeneous coordinates) z = z * 2 - 1. However,
3315 * shaders are run before the homogeneous divide, so we have to take the w
3316 * into account: z = ((z / w) * 2 - 1) * w, which is the same as
3317 * z = z * 2 - w. */
3318 shader_addline(buffer, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
3321 /*****************************************************************************
3322 * Begin processing individual instruction opcodes
3323 ****************************************************************************/
3325 static void shader_glsl_binop(const struct wined3d_shader_instruction *ins)
3327 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3328 struct glsl_src_param src0_param;
3329 struct glsl_src_param src1_param;
3330 DWORD write_mask;
3331 const char *op;
3333 /* Determine the GLSL operator to use based on the opcode */
3334 switch (ins->handler_idx)
3336 case WINED3DSIH_ADD: op = "+"; break;
3337 case WINED3DSIH_AND: op = "&"; break;
3338 case WINED3DSIH_DIV: op = "/"; break;
3339 case WINED3DSIH_IADD: op = "+"; break;
3340 case WINED3DSIH_ISHL: op = "<<"; break;
3341 case WINED3DSIH_ISHR: op = ">>"; break;
3342 case WINED3DSIH_MUL: op = "*"; break;
3343 case WINED3DSIH_OR: op = "|"; break;
3344 case WINED3DSIH_SUB: op = "-"; break;
3345 case WINED3DSIH_USHR: op = ">>"; break;
3346 case WINED3DSIH_XOR: op = "^"; break;
3347 default:
3348 op = "<unhandled operator>";
3349 FIXME("Opcode %s not yet handled in GLSL.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
3350 break;
3353 write_mask = shader_glsl_append_dst(buffer, ins);
3354 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3355 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3356 shader_addline(buffer, "%s %s %s);\n", src0_param.param_str, op, src1_param.param_str);
3359 static void shader_glsl_relop(const struct wined3d_shader_instruction *ins)
3361 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3362 struct glsl_src_param src0_param;
3363 struct glsl_src_param src1_param;
3364 unsigned int mask_size;
3365 DWORD write_mask;
3366 const char *op;
3368 write_mask = shader_glsl_append_dst(buffer, ins);
3369 mask_size = shader_glsl_get_write_mask_size(write_mask);
3370 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3371 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3373 if (mask_size > 1)
3375 switch (ins->handler_idx)
3377 case WINED3DSIH_EQ: op = "equal"; break;
3378 case WINED3DSIH_IEQ: op = "equal"; break;
3379 case WINED3DSIH_GE: op = "greaterThanEqual"; break;
3380 case WINED3DSIH_IGE: op = "greaterThanEqual"; break;
3381 case WINED3DSIH_UGE: op = "greaterThanEqual"; break;
3382 case WINED3DSIH_LT: op = "lessThan"; break;
3383 case WINED3DSIH_ILT: op = "lessThan"; break;
3384 case WINED3DSIH_ULT: op = "lessThan"; break;
3385 case WINED3DSIH_NE: op = "notEqual"; break;
3386 case WINED3DSIH_INE: op = "notEqual"; break;
3387 default:
3388 op = "<unhandled operator>";
3389 ERR("Unhandled opcode %#x.\n", ins->handler_idx);
3390 break;
3393 shader_addline(buffer, "uvec%u(%s(%s, %s)) * 0xffffffffu);\n",
3394 mask_size, op, src0_param.param_str, src1_param.param_str);
3396 else
3398 switch (ins->handler_idx)
3400 case WINED3DSIH_EQ: op = "=="; break;
3401 case WINED3DSIH_IEQ: op = "=="; break;
3402 case WINED3DSIH_GE: op = ">="; break;
3403 case WINED3DSIH_IGE: op = ">="; break;
3404 case WINED3DSIH_UGE: op = ">="; break;
3405 case WINED3DSIH_LT: op = "<"; break;
3406 case WINED3DSIH_ILT: op = "<"; break;
3407 case WINED3DSIH_ULT: op = "<"; break;
3408 case WINED3DSIH_NE: op = "!="; break;
3409 case WINED3DSIH_INE: op = "!="; break;
3410 default:
3411 op = "<unhandled operator>";
3412 ERR("Unhandled opcode %#x.\n", ins->handler_idx);
3413 break;
3416 shader_addline(buffer, "%s %s %s ? 0xffffffffu : 0u);\n",
3417 src0_param.param_str, op, src1_param.param_str);
3421 static void shader_glsl_unary_op(const struct wined3d_shader_instruction *ins)
3423 struct glsl_src_param src_param;
3424 DWORD write_mask;
3425 const char *op;
3427 switch (ins->handler_idx)
3429 case WINED3DSIH_INEG: op = "-"; break;
3430 case WINED3DSIH_NOT: op = "~"; break;
3431 default:
3432 op = "<unhandled operator>";
3433 ERR("Unhandled opcode %s.\n",
3434 debug_d3dshaderinstructionhandler(ins->handler_idx));
3435 break;
3438 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
3439 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src_param);
3440 shader_addline(ins->ctx->buffer, "%s%s);\n", op, src_param.param_str);
3443 static void shader_glsl_imul(const struct wined3d_shader_instruction *ins)
3445 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3446 struct glsl_src_param src0_param;
3447 struct glsl_src_param src1_param;
3448 DWORD write_mask;
3450 /* If we have ARB_gpu_shader5 or GLSL 4.0, we can use imulExtended(). If
3451 * not, we can emulate it. */
3452 if (ins->dst[0].reg.type != WINED3DSPR_NULL)
3453 FIXME("64-bit integer multiplies not implemented.\n");
3455 if (ins->dst[1].reg.type != WINED3DSPR_NULL)
3457 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[1], ins->dst[1].reg.data_type);
3458 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3459 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3461 shader_addline(ins->ctx->buffer, "%s * %s);\n",
3462 src0_param.param_str, src1_param.param_str);
3466 static void shader_glsl_udiv(const struct wined3d_shader_instruction *ins)
3468 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3469 struct glsl_src_param src0_param, src1_param;
3470 DWORD write_mask;
3472 if (ins->dst[0].reg.type != WINED3DSPR_NULL)
3474 if (ins->dst[1].reg.type != WINED3DSPR_NULL)
3476 char dst_mask[6];
3478 write_mask = shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
3479 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3480 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3481 shader_addline(buffer, "tmp0%s = uintBitsToFloat(%s / %s);\n",
3482 dst_mask, src0_param.param_str, src1_param.param_str);
3484 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[1], ins->dst[1].reg.data_type);
3485 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3486 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3487 shader_addline(buffer, "%s %% %s);\n", src0_param.param_str, src1_param.param_str);
3489 shader_glsl_append_dst_ext(buffer, ins, &ins->dst[0], WINED3D_DATA_FLOAT);
3490 shader_addline(buffer, "tmp0%s);\n", dst_mask);
3492 else
3494 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[0], ins->dst[0].reg.data_type);
3495 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3496 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3497 shader_addline(buffer, "%s / %s);\n", src0_param.param_str, src1_param.param_str);
3500 else if (ins->dst[1].reg.type != WINED3DSPR_NULL)
3502 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[1], ins->dst[1].reg.data_type);
3503 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3504 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3505 shader_addline(buffer, "%s %% %s);\n", src0_param.param_str, src1_param.param_str);
3509 /* Process the WINED3DSIO_MOV opcode using GLSL (dst = src) */
3510 static void shader_glsl_mov(const struct wined3d_shader_instruction *ins)
3512 const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
3513 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3514 struct glsl_src_param src0_param;
3515 DWORD write_mask;
3517 write_mask = shader_glsl_append_dst(buffer, ins);
3518 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3520 /* In vs_1_1 WINED3DSIO_MOV can write to the address register. In later
3521 * shader versions WINED3DSIO_MOVA is used for this. */
3522 if (ins->ctx->reg_maps->shader_version.major == 1
3523 && ins->ctx->reg_maps->shader_version.type == WINED3D_SHADER_TYPE_VERTEX
3524 && ins->dst[0].reg.type == WINED3DSPR_ADDR)
3526 /* This is a simple floor() */
3527 unsigned int mask_size = shader_glsl_get_write_mask_size(write_mask);
3528 if (mask_size > 1) {
3529 shader_addline(buffer, "ivec%d(floor(%s)));\n", mask_size, src0_param.param_str);
3530 } else {
3531 shader_addline(buffer, "int(floor(%s)));\n", src0_param.param_str);
3534 else if (ins->handler_idx == WINED3DSIH_MOVA)
3536 const struct wined3d_shader_version *version = &ins->ctx->shader->reg_maps.shader_version;
3537 unsigned int mask_size = shader_glsl_get_write_mask_size(write_mask);
3539 if (shader_glsl_get_version(gl_info, version) >= 130 || gl_info->supported[EXT_GPU_SHADER4])
3541 if (mask_size > 1)
3542 shader_addline(buffer, "ivec%d(round(%s)));\n", mask_size, src0_param.param_str);
3543 else
3544 shader_addline(buffer, "int(round(%s)));\n", src0_param.param_str);
3546 else
3548 if (mask_size > 1)
3549 shader_addline(buffer, "ivec%d(floor(abs(%s) + vec%d(0.5)) * sign(%s)));\n",
3550 mask_size, src0_param.param_str, mask_size, src0_param.param_str);
3551 else
3552 shader_addline(buffer, "int(floor(abs(%s) + 0.5) * sign(%s)));\n",
3553 src0_param.param_str, src0_param.param_str);
3556 else
3558 shader_addline(buffer, "%s);\n", src0_param.param_str);
3562 /* Process the dot product operators DP3 and DP4 in GLSL (dst = dot(src0, src1)) */
3563 static void shader_glsl_dot(const struct wined3d_shader_instruction *ins)
3565 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3566 struct glsl_src_param src0_param;
3567 struct glsl_src_param src1_param;
3568 DWORD dst_write_mask, src_write_mask;
3569 unsigned int dst_size;
3571 dst_write_mask = shader_glsl_append_dst(buffer, ins);
3572 dst_size = shader_glsl_get_write_mask_size(dst_write_mask);
3574 /* dp4 works on vec4, dp3 on vec3, etc. */
3575 if (ins->handler_idx == WINED3DSIH_DP4)
3576 src_write_mask = WINED3DSP_WRITEMASK_ALL;
3577 else if (ins->handler_idx == WINED3DSIH_DP3)
3578 src_write_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
3579 else
3580 src_write_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1;
3582 shader_glsl_add_src_param(ins, &ins->src[0], src_write_mask, &src0_param);
3583 shader_glsl_add_src_param(ins, &ins->src[1], src_write_mask, &src1_param);
3585 if (dst_size > 1) {
3586 shader_addline(buffer, "vec%d(dot(%s, %s)));\n", dst_size, src0_param.param_str, src1_param.param_str);
3587 } else {
3588 shader_addline(buffer, "dot(%s, %s));\n", src0_param.param_str, src1_param.param_str);
3592 /* Note that this instruction has some restrictions. The destination write mask
3593 * can't contain the w component, and the source swizzles have to be .xyzw */
3594 static void shader_glsl_cross(const struct wined3d_shader_instruction *ins)
3596 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
3597 struct glsl_src_param src0_param;
3598 struct glsl_src_param src1_param;
3599 char dst_mask[6];
3601 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
3602 shader_glsl_append_dst(ins->ctx->buffer, ins);
3603 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
3604 shader_glsl_add_src_param(ins, &ins->src[1], src_mask, &src1_param);
3605 shader_addline(ins->ctx->buffer, "cross(%s, %s)%s);\n", src0_param.param_str, src1_param.param_str, dst_mask);
3608 static void shader_glsl_cut(const struct wined3d_shader_instruction *ins)
3610 unsigned int stream = ins->handler_idx == WINED3DSIH_CUT ? 0 : ins->src[0].reg.idx[0].offset;
3612 if (!stream)
3613 shader_addline(ins->ctx->buffer, "EndPrimitive();\n");
3614 else
3615 FIXME("Unhandled primitive stream %u.\n", stream);
3618 /* Process the WINED3DSIO_POW instruction in GLSL (dst = |src0|^src1)
3619 * Src0 and src1 are scalars. Note that D3D uses the absolute of src0, while
3620 * GLSL uses the value as-is. */
3621 static void shader_glsl_pow(const struct wined3d_shader_instruction *ins)
3623 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3624 struct glsl_src_param src0_param;
3625 struct glsl_src_param src1_param;
3626 DWORD dst_write_mask;
3627 unsigned int dst_size;
3629 dst_write_mask = shader_glsl_append_dst(buffer, ins);
3630 dst_size = shader_glsl_get_write_mask_size(dst_write_mask);
3632 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
3633 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0, &src1_param);
3635 if (dst_size > 1)
3637 shader_addline(buffer, "vec%u(%s == 0.0 ? 1.0 : pow(abs(%s), %s)));\n",
3638 dst_size, src1_param.param_str, src0_param.param_str, src1_param.param_str);
3640 else
3642 shader_addline(buffer, "%s == 0.0 ? 1.0 : pow(abs(%s), %s));\n",
3643 src1_param.param_str, src0_param.param_str, src1_param.param_str);
3647 /* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */
3648 static void shader_glsl_map2gl(const struct wined3d_shader_instruction *ins)
3650 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3651 struct glsl_src_param src_param;
3652 const char *instruction;
3653 DWORD write_mask;
3654 unsigned i;
3656 /* Determine the GLSL function to use based on the opcode */
3657 /* TODO: Possibly make this a table for faster lookups */
3658 switch (ins->handler_idx)
3660 case WINED3DSIH_ABS: instruction = "abs"; break;
3661 case WINED3DSIH_DSX: instruction = "dFdx"; break;
3662 case WINED3DSIH_DSX_COARSE: instruction = "dFdxCoarse"; break;
3663 case WINED3DSIH_DSX_FINE: instruction = "dFdxFine"; break;
3664 case WINED3DSIH_DSY: instruction = "ycorrection.y * dFdy"; break;
3665 case WINED3DSIH_DSY_COARSE: instruction = "ycorrection.y * dFdyCoarse"; break;
3666 case WINED3DSIH_DSY_FINE: instruction = "ycorrection.y * dFdyFine"; break;
3667 case WINED3DSIH_FRC: instruction = "fract"; break;
3668 case WINED3DSIH_IMAX: instruction = "max"; break;
3669 case WINED3DSIH_IMIN: instruction = "min"; break;
3670 case WINED3DSIH_MAX: instruction = "max"; break;
3671 case WINED3DSIH_MIN: instruction = "min"; break;
3672 case WINED3DSIH_ROUND_NE: instruction = "roundEven"; break;
3673 case WINED3DSIH_ROUND_NI: instruction = "floor"; break;
3674 case WINED3DSIH_ROUND_PI: instruction = "ceil"; break;
3675 case WINED3DSIH_ROUND_Z: instruction = "trunc"; break;
3676 case WINED3DSIH_SQRT: instruction = "sqrt"; break;
3677 case WINED3DSIH_UMAX: instruction = "max"; break;
3678 case WINED3DSIH_UMIN: instruction = "min"; break;
3679 default: instruction = "";
3680 ERR("Opcode %s not yet handled in GLSL.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
3681 break;
3684 write_mask = shader_glsl_append_dst(buffer, ins);
3686 shader_addline(buffer, "%s(", instruction);
3688 if (ins->src_count)
3690 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src_param);
3691 shader_addline(buffer, "%s", src_param.param_str);
3692 for (i = 1; i < ins->src_count; ++i)
3694 shader_glsl_add_src_param(ins, &ins->src[i], write_mask, &src_param);
3695 shader_addline(buffer, ", %s", src_param.param_str);
3699 shader_addline(buffer, "));\n");
3702 static void shader_glsl_nop(const struct wined3d_shader_instruction *ins) {}
3704 static void shader_glsl_nrm(const struct wined3d_shader_instruction *ins)
3706 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3707 struct glsl_src_param src_param;
3708 unsigned int mask_size;
3709 DWORD write_mask;
3710 char dst_mask[6];
3712 write_mask = shader_glsl_get_write_mask(ins->dst, dst_mask);
3713 mask_size = shader_glsl_get_write_mask_size(write_mask);
3714 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src_param);
3716 shader_addline(buffer, "tmp0.x = dot(%s, %s);\n",
3717 src_param.param_str, src_param.param_str);
3718 shader_glsl_append_dst(buffer, ins);
3720 if (mask_size > 1)
3722 shader_addline(buffer, "tmp0.x == 0.0 ? vec%u(0.0) : (%s * inversesqrt(tmp0.x)));\n",
3723 mask_size, src_param.param_str);
3725 else
3727 shader_addline(buffer, "tmp0.x == 0.0 ? 0.0 : (%s * inversesqrt(tmp0.x)));\n",
3728 src_param.param_str);
3732 static void shader_glsl_scalar_op(const struct wined3d_shader_instruction *ins)
3734 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major,
3735 ins->ctx->reg_maps->shader_version.minor);
3736 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3737 struct glsl_src_param src0_param;
3738 const char *prefix, *suffix;
3739 unsigned int dst_size;
3740 DWORD dst_write_mask;
3742 dst_write_mask = shader_glsl_append_dst(buffer, ins);
3743 dst_size = shader_glsl_get_write_mask_size(dst_write_mask);
3745 if (shader_version < WINED3D_SHADER_VERSION(4, 0))
3746 dst_write_mask = WINED3DSP_WRITEMASK_3;
3748 shader_glsl_add_src_param(ins, &ins->src[0], dst_write_mask, &src0_param);
3750 switch (ins->handler_idx)
3752 case WINED3DSIH_EXP:
3753 case WINED3DSIH_EXPP:
3754 prefix = "exp2(";
3755 suffix = ")";
3756 break;
3758 case WINED3DSIH_LOG:
3759 case WINED3DSIH_LOGP:
3760 prefix = "log2(abs(";
3761 suffix = "))";
3762 break;
3764 case WINED3DSIH_RCP:
3765 prefix = "1.0 / ";
3766 suffix = "";
3767 break;
3769 case WINED3DSIH_RSQ:
3770 prefix = "inversesqrt(abs(";
3771 suffix = "))";
3772 break;
3774 default:
3775 prefix = "";
3776 suffix = "";
3777 FIXME("Unhandled instruction %#x.\n", ins->handler_idx);
3778 break;
3781 if (dst_size > 1 && shader_version < WINED3D_SHADER_VERSION(4, 0))
3782 shader_addline(buffer, "vec%u(%s%s%s));\n", dst_size, prefix, src0_param.param_str, suffix);
3783 else
3784 shader_addline(buffer, "%s%s%s);\n", prefix, src0_param.param_str, suffix);
3787 /** Process the WINED3DSIO_EXPP instruction in GLSL:
3788 * For shader model 1.x, do the following (and honor the writemask, so use a temporary variable):
3789 * dst.x = 2^(floor(src))
3790 * dst.y = src - floor(src)
3791 * dst.z = 2^src (partial precision is allowed, but optional)
3792 * dst.w = 1.0;
3793 * For 2.0 shaders, just do this (honoring writemask and swizzle):
3794 * dst = 2^src; (partial precision is allowed, but optional)
3796 static void shader_glsl_expp(const struct wined3d_shader_instruction *ins)
3798 if (ins->ctx->reg_maps->shader_version.major < 2)
3800 struct glsl_src_param src_param;
3801 char dst_mask[6];
3803 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &src_param);
3805 shader_addline(ins->ctx->buffer, "tmp0.x = exp2(floor(%s));\n", src_param.param_str);
3806 shader_addline(ins->ctx->buffer, "tmp0.y = %s - floor(%s);\n", src_param.param_str, src_param.param_str);
3807 shader_addline(ins->ctx->buffer, "tmp0.z = exp2(%s);\n", src_param.param_str);
3808 shader_addline(ins->ctx->buffer, "tmp0.w = 1.0;\n");
3810 shader_glsl_append_dst(ins->ctx->buffer, ins);
3811 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
3812 shader_addline(ins->ctx->buffer, "tmp0%s);\n", dst_mask);
3813 return;
3816 shader_glsl_scalar_op(ins);
3819 static void shader_glsl_cast(const struct wined3d_shader_instruction *ins,
3820 const char *vector_constructor, const char *scalar_constructor)
3822 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
3823 struct glsl_src_param src_param;
3824 unsigned int mask_size;
3825 DWORD write_mask;
3827 write_mask = shader_glsl_append_dst(buffer, ins);
3828 mask_size = shader_glsl_get_write_mask_size(write_mask);
3829 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src_param);
3831 if (mask_size > 1)
3832 shader_addline(buffer, "%s%u(%s));\n", vector_constructor, mask_size, src_param.param_str);
3833 else
3834 shader_addline(buffer, "%s(%s));\n", scalar_constructor, src_param.param_str);
3837 static void shader_glsl_to_int(const struct wined3d_shader_instruction *ins)
3839 shader_glsl_cast(ins, "ivec", "int");
3842 static void shader_glsl_to_uint(const struct wined3d_shader_instruction *ins)
3844 shader_glsl_cast(ins, "uvec", "uint");
3847 static void shader_glsl_to_float(const struct wined3d_shader_instruction *ins)
3849 shader_glsl_cast(ins, "vec", "float");
3852 /** Process signed comparison opcodes in GLSL. */
3853 static void shader_glsl_compare(const struct wined3d_shader_instruction *ins)
3855 struct glsl_src_param src0_param;
3856 struct glsl_src_param src1_param;
3857 DWORD write_mask;
3858 unsigned int mask_size;
3860 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
3861 mask_size = shader_glsl_get_write_mask_size(write_mask);
3862 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3863 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3865 if (mask_size > 1) {
3866 const char *compare;
3868 switch(ins->handler_idx)
3870 case WINED3DSIH_SLT: compare = "lessThan"; break;
3871 case WINED3DSIH_SGE: compare = "greaterThanEqual"; break;
3872 default: compare = "";
3873 FIXME("Can't handle opcode %s.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
3876 shader_addline(ins->ctx->buffer, "vec%d(%s(%s, %s)));\n", mask_size, compare,
3877 src0_param.param_str, src1_param.param_str);
3878 } else {
3879 switch(ins->handler_idx)
3881 case WINED3DSIH_SLT:
3882 /* Step(src0, src1) is not suitable here because if src0 == src1 SLT is supposed,
3883 * to return 0.0 but step returns 1.0 because step is not < x
3884 * An alternative is a bvec compare padded with an unused second component.
3885 * step(src1 * -1.0, src0 * -1.0) is not an option because it suffers from the same
3886 * issue. Playing with not() is not possible either because not() does not accept
3887 * a scalar.
3889 shader_addline(ins->ctx->buffer, "(%s < %s) ? 1.0 : 0.0);\n",
3890 src0_param.param_str, src1_param.param_str);
3891 break;
3892 case WINED3DSIH_SGE:
3893 /* Here we can use the step() function and safe a conditional */
3894 shader_addline(ins->ctx->buffer, "step(%s, %s));\n", src1_param.param_str, src0_param.param_str);
3895 break;
3896 default:
3897 FIXME("Can't handle opcode %s.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
3903 static void shader_glsl_conditional_move(const struct wined3d_shader_instruction *ins)
3905 const char *condition_prefix, *condition_suffix;
3906 struct wined3d_shader_dst_param dst;
3907 struct glsl_src_param src0_param;
3908 struct glsl_src_param src1_param;
3909 struct glsl_src_param src2_param;
3910 BOOL temp_destination = FALSE;
3911 DWORD cmp_channel = 0;
3912 unsigned int i, j;
3913 char mask_char[6];
3914 DWORD write_mask;
3916 switch (ins->handler_idx)
3918 case WINED3DSIH_CMP:
3919 condition_prefix = "";
3920 condition_suffix = " >= 0.0";
3921 break;
3923 case WINED3DSIH_CND:
3924 condition_prefix = "";
3925 condition_suffix = " > 0.5";
3926 break;
3928 case WINED3DSIH_MOVC:
3929 condition_prefix = "bool(";
3930 condition_suffix = ")";
3931 break;
3933 default:
3934 FIXME("Unhandled instruction %#x.\n", ins->handler_idx);
3935 condition_prefix = "<unhandled prefix>";
3936 condition_suffix = "<unhandled suffix>";
3937 break;
3940 if (shader_is_scalar(&ins->dst[0].reg) || shader_is_scalar(&ins->src[0].reg))
3942 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
3943 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
3944 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3945 shader_glsl_add_src_param(ins, &ins->src[2], write_mask, &src2_param);
3947 shader_addline(ins->ctx->buffer, "%s%s%s ? %s : %s);\n",
3948 condition_prefix, src0_param.param_str, condition_suffix,
3949 src1_param.param_str, src2_param.param_str);
3950 return;
3953 dst = ins->dst[0];
3955 /* Splitting the instruction up in multiple lines imposes a problem:
3956 * The first lines may overwrite source parameters of the following lines.
3957 * Deal with that by using a temporary destination register if needed. */
3958 if ((ins->src[0].reg.idx[0].offset == dst.reg.idx[0].offset
3959 && ins->src[0].reg.type == dst.reg.type)
3960 || (ins->src[1].reg.idx[0].offset == dst.reg.idx[0].offset
3961 && ins->src[1].reg.type == dst.reg.type)
3962 || (ins->src[2].reg.idx[0].offset == dst.reg.idx[0].offset
3963 && ins->src[2].reg.type == dst.reg.type))
3964 temp_destination = TRUE;
3966 /* Cycle through all source0 channels. */
3967 for (i = 0; i < 4; ++i)
3969 write_mask = 0;
3970 /* Find the destination channels which use the current source0 channel. */
3971 for (j = 0; j < 4; ++j)
3973 if (((ins->src[0].swizzle >> (2 * j)) & 0x3) == i)
3975 write_mask |= WINED3DSP_WRITEMASK_0 << j;
3976 cmp_channel = WINED3DSP_WRITEMASK_0 << j;
3979 dst.write_mask = ins->dst[0].write_mask & write_mask;
3981 if (temp_destination)
3983 if (!(write_mask = shader_glsl_get_write_mask(&dst, mask_char)))
3984 continue;
3985 shader_addline(ins->ctx->buffer, "tmp0%s = (", mask_char);
3987 else if (!(write_mask = shader_glsl_append_dst_ext(ins->ctx->buffer, ins, &dst, dst.reg.data_type)))
3988 continue;
3990 shader_glsl_add_src_param(ins, &ins->src[0], cmp_channel, &src0_param);
3991 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
3992 shader_glsl_add_src_param(ins, &ins->src[2], write_mask, &src2_param);
3994 shader_addline(ins->ctx->buffer, "%s%s%s ? %s : %s);\n",
3995 condition_prefix, src0_param.param_str, condition_suffix,
3996 src1_param.param_str, src2_param.param_str);
3999 if (temp_destination)
4001 shader_glsl_get_write_mask(&ins->dst[0], mask_char);
4002 shader_glsl_append_dst(ins->ctx->buffer, ins);
4003 shader_addline(ins->ctx->buffer, "tmp0%s);\n", mask_char);
4007 /** Process the CND opcode in GLSL (dst = (src0 > 0.5) ? src1 : src2) */
4008 /* For ps 1.1-1.3, only a single component of src0 is used. For ps 1.4
4009 * the compare is done per component of src0. */
4010 static void shader_glsl_cnd(const struct wined3d_shader_instruction *ins)
4012 struct glsl_src_param src0_param;
4013 struct glsl_src_param src1_param;
4014 struct glsl_src_param src2_param;
4015 DWORD write_mask;
4016 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major,
4017 ins->ctx->reg_maps->shader_version.minor);
4019 if (shader_version < WINED3D_SHADER_VERSION(1, 4))
4021 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
4022 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4023 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
4024 shader_glsl_add_src_param(ins, &ins->src[2], write_mask, &src2_param);
4026 if (ins->coissue && ins->dst->write_mask != WINED3DSP_WRITEMASK_3)
4027 shader_addline(ins->ctx->buffer, "%s /* COISSUE! */);\n", src1_param.param_str);
4028 else
4029 shader_addline(ins->ctx->buffer, "%s > 0.5 ? %s : %s);\n",
4030 src0_param.param_str, src1_param.param_str, src2_param.param_str);
4031 return;
4034 shader_glsl_conditional_move(ins);
4037 /** GLSL code generation for WINED3DSIO_MAD: Multiply the first 2 opcodes, then add the last */
4038 static void shader_glsl_mad(const struct wined3d_shader_instruction *ins)
4040 struct glsl_src_param src0_param;
4041 struct glsl_src_param src1_param;
4042 struct glsl_src_param src2_param;
4043 DWORD write_mask;
4045 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
4046 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4047 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
4048 shader_glsl_add_src_param(ins, &ins->src[2], write_mask, &src2_param);
4049 shader_addline(ins->ctx->buffer, "(%s * %s) + %s);\n",
4050 src0_param.param_str, src1_param.param_str, src2_param.param_str);
4053 /* Handles transforming all WINED3DSIO_M?x? opcodes for
4054 Vertex shaders to GLSL codes */
4055 static void shader_glsl_mnxn(const struct wined3d_shader_instruction *ins)
4057 int i;
4058 int nComponents = 0;
4059 struct wined3d_shader_dst_param tmp_dst = {{0}};
4060 struct wined3d_shader_src_param tmp_src[2] = {{{0}}};
4061 struct wined3d_shader_instruction tmp_ins;
4063 memset(&tmp_ins, 0, sizeof(tmp_ins));
4065 /* Set constants for the temporary argument */
4066 tmp_ins.ctx = ins->ctx;
4067 tmp_ins.dst_count = 1;
4068 tmp_ins.dst = &tmp_dst;
4069 tmp_ins.src_count = 2;
4070 tmp_ins.src = tmp_src;
4072 switch(ins->handler_idx)
4074 case WINED3DSIH_M4x4:
4075 nComponents = 4;
4076 tmp_ins.handler_idx = WINED3DSIH_DP4;
4077 break;
4078 case WINED3DSIH_M4x3:
4079 nComponents = 3;
4080 tmp_ins.handler_idx = WINED3DSIH_DP4;
4081 break;
4082 case WINED3DSIH_M3x4:
4083 nComponents = 4;
4084 tmp_ins.handler_idx = WINED3DSIH_DP3;
4085 break;
4086 case WINED3DSIH_M3x3:
4087 nComponents = 3;
4088 tmp_ins.handler_idx = WINED3DSIH_DP3;
4089 break;
4090 case WINED3DSIH_M3x2:
4091 nComponents = 2;
4092 tmp_ins.handler_idx = WINED3DSIH_DP3;
4093 break;
4094 default:
4095 break;
4098 tmp_dst = ins->dst[0];
4099 tmp_src[0] = ins->src[0];
4100 tmp_src[1] = ins->src[1];
4101 for (i = 0; i < nComponents; ++i)
4103 tmp_dst.write_mask = WINED3DSP_WRITEMASK_0 << i;
4104 shader_glsl_dot(&tmp_ins);
4105 ++tmp_src[1].reg.idx[0].offset;
4110 The LRP instruction performs a component-wise linear interpolation
4111 between the second and third operands using the first operand as the
4112 blend factor. Equation: (dst = src2 + src0 * (src1 - src2))
4113 This is equivalent to mix(src2, src1, src0);
4115 static void shader_glsl_lrp(const struct wined3d_shader_instruction *ins)
4117 struct glsl_src_param src0_param;
4118 struct glsl_src_param src1_param;
4119 struct glsl_src_param src2_param;
4120 DWORD write_mask;
4122 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
4124 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4125 shader_glsl_add_src_param(ins, &ins->src[1], write_mask, &src1_param);
4126 shader_glsl_add_src_param(ins, &ins->src[2], write_mask, &src2_param);
4128 shader_addline(ins->ctx->buffer, "mix(%s, %s, %s));\n",
4129 src2_param.param_str, src1_param.param_str, src0_param.param_str);
4132 /** Process the WINED3DSIO_LIT instruction in GLSL:
4133 * dst.x = dst.w = 1.0
4134 * dst.y = (src0.x > 0) ? src0.x
4135 * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0
4136 * where src.w is clamped at +- 128
4138 static void shader_glsl_lit(const struct wined3d_shader_instruction *ins)
4140 struct glsl_src_param src0_param;
4141 struct glsl_src_param src1_param;
4142 struct glsl_src_param src3_param;
4143 char dst_mask[6];
4145 shader_glsl_append_dst(ins->ctx->buffer, ins);
4146 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
4148 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4149 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_1, &src1_param);
4150 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &src3_param);
4152 /* The sdk specifies the instruction like this
4153 * dst.x = 1.0;
4154 * if(src.x > 0.0) dst.y = src.x
4155 * else dst.y = 0.0.
4156 * if(src.x > 0.0 && src.y > 0.0) dst.z = pow(src.y, power);
4157 * else dst.z = 0.0;
4158 * dst.w = 1.0;
4159 * (where power = src.w clamped between -128 and 128)
4161 * Obviously that has quite a few conditionals in it which we don't like. So the first step is this:
4162 * dst.x = 1.0 ... No further explanation needed
4163 * dst.y = max(src.y, 0.0); ... If x < 0.0, use 0.0, otherwise x. Same as the conditional
4164 * dst.z = x > 0.0 ? pow(max(y, 0.0), p) : 0; ... 0 ^ power is 0, and otherwise we use y anyway
4165 * dst.w = 1.0. ... Nothing fancy.
4167 * So we still have one conditional in there. So do this:
4168 * dst.z = pow(max(0.0, src.y) * step(0.0, src.x), power);
4170 * step(0.0, x) will return 1 if src.x > 0.0, and 0 otherwise. So if y is 0 we get pow(0.0 * 1.0, power),
4171 * which sets dst.z to 0. If y > 0, but x = 0.0, we get pow(y * 0.0, power), which results in 0 too.
4172 * if both x and y are > 0, we get pow(y * 1.0, power), as it is supposed to.
4174 * Unfortunately pow(0.0 ^ 0.0) returns NaN on most GPUs, but lit with src.y = 0 and src.w = 0 returns
4175 * a non-NaN value in dst.z. What we return doesn't matter, as long as it is not NaN. Return 0, which is
4176 * what all Windows HW drivers and GL_ARB_vertex_program's LIT do.
4178 shader_addline(ins->ctx->buffer,
4179 "vec4(1.0, max(%s, 0.0), %s == 0.0 ? 0.0 : "
4180 "pow(max(0.0, %s) * step(0.0, %s), clamp(%s, -128.0, 128.0)), 1.0)%s);\n",
4181 src0_param.param_str, src3_param.param_str, src1_param.param_str,
4182 src0_param.param_str, src3_param.param_str, dst_mask);
4185 /** Process the WINED3DSIO_DST instruction in GLSL:
4186 * dst.x = 1.0
4187 * dst.y = src0.x * src0.y
4188 * dst.z = src0.z
4189 * dst.w = src1.w
4191 static void shader_glsl_dst(const struct wined3d_shader_instruction *ins)
4193 struct glsl_src_param src0y_param;
4194 struct glsl_src_param src0z_param;
4195 struct glsl_src_param src1y_param;
4196 struct glsl_src_param src1w_param;
4197 char dst_mask[6];
4199 shader_glsl_append_dst(ins->ctx->buffer, ins);
4200 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
4202 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_1, &src0y_param);
4203 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_2, &src0z_param);
4204 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_1, &src1y_param);
4205 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_3, &src1w_param);
4207 shader_addline(ins->ctx->buffer, "vec4(1.0, %s * %s, %s, %s))%s;\n",
4208 src0y_param.param_str, src1y_param.param_str, src0z_param.param_str, src1w_param.param_str, dst_mask);
4211 /** Process the WINED3DSIO_SINCOS instruction in GLSL:
4212 * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware
4213 * can handle it. But, these functions are built-in for GLSL, so we can just ignore the last 2 params.
4215 * dst.x = cos(src0.?)
4216 * dst.y = sin(src0.?)
4217 * dst.z = dst.z
4218 * dst.w = dst.w
4220 static void shader_glsl_sincos(const struct wined3d_shader_instruction *ins)
4222 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
4223 struct glsl_src_param src0_param;
4224 DWORD write_mask;
4226 if (ins->ctx->reg_maps->shader_version.major < 4)
4228 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4230 write_mask = shader_glsl_append_dst(buffer, ins);
4231 switch (write_mask)
4233 case WINED3DSP_WRITEMASK_0:
4234 shader_addline(buffer, "cos(%s));\n", src0_param.param_str);
4235 break;
4237 case WINED3DSP_WRITEMASK_1:
4238 shader_addline(buffer, "sin(%s));\n", src0_param.param_str);
4239 break;
4241 case (WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1):
4242 shader_addline(buffer, "vec2(cos(%s), sin(%s)));\n",
4243 src0_param.param_str, src0_param.param_str);
4244 break;
4246 default:
4247 ERR("Write mask should be .x, .y or .xy\n");
4248 break;
4251 return;
4254 if (ins->dst[0].reg.type != WINED3DSPR_NULL)
4257 if (ins->dst[1].reg.type != WINED3DSPR_NULL)
4259 char dst_mask[6];
4261 write_mask = shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
4262 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4263 shader_addline(buffer, "tmp0%s = sin(%s);\n", dst_mask, src0_param.param_str);
4265 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[1], ins->dst[1].reg.data_type);
4266 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4267 shader_addline(buffer, "cos(%s));\n", src0_param.param_str);
4269 shader_glsl_append_dst_ext(buffer, ins, &ins->dst[0], ins->dst[0].reg.data_type);
4270 shader_addline(buffer, "tmp0%s);\n", dst_mask);
4272 else
4274 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[0], ins->dst[0].reg.data_type);
4275 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4276 shader_addline(buffer, "sin(%s));\n", src0_param.param_str);
4279 else if (ins->dst[1].reg.type != WINED3DSPR_NULL)
4281 write_mask = shader_glsl_append_dst_ext(buffer, ins, &ins->dst[1], ins->dst[1].reg.data_type);
4282 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4283 shader_addline(buffer, "cos(%s));\n", src0_param.param_str);
4287 /* sgn in vs_2_0 has 2 extra parameters(registers for temporary storage) which we don't use
4288 * here. But those extra parameters require a dedicated function for sgn, since map2gl would
4289 * generate invalid code
4291 static void shader_glsl_sgn(const struct wined3d_shader_instruction *ins)
4293 struct glsl_src_param src0_param;
4294 DWORD write_mask;
4296 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
4297 shader_glsl_add_src_param(ins, &ins->src[0], write_mask, &src0_param);
4299 shader_addline(ins->ctx->buffer, "sign(%s));\n", src0_param.param_str);
4302 /** Process the WINED3DSIO_LOOP instruction in GLSL:
4303 * Start a for() loop where src1.y is the initial value of aL,
4304 * increment aL by src1.z for a total of src1.x iterations.
4305 * Need to use a temporary variable for this operation.
4307 /* FIXME: I don't think nested loops will work correctly this way. */
4308 static void shader_glsl_loop(const struct wined3d_shader_instruction *ins)
4310 struct wined3d_shader_loop_state *loop_state = ins->ctx->loop_state;
4311 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
4312 const struct wined3d_shader *shader = ins->ctx->shader;
4313 const struct wined3d_shader_lconst *constant;
4314 struct glsl_src_param src1_param;
4315 const DWORD *control_values = NULL;
4317 if (ins->ctx->reg_maps->shader_version.major < 4)
4319 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_ALL, &src1_param);
4321 /* Try to hardcode the loop control parameters if possible. Direct3D 9
4322 * class hardware doesn't support real varying indexing, but Microsoft
4323 * designed this feature for Shader model 2.x+. If the loop control is
4324 * known at compile time, the GLSL compiler can unroll the loop, and
4325 * replace indirect addressing with direct addressing. */
4326 if (ins->src[1].reg.type == WINED3DSPR_CONSTINT)
4328 LIST_FOR_EACH_ENTRY(constant, &shader->constantsI, struct wined3d_shader_lconst, entry)
4330 if (constant->idx == ins->src[1].reg.idx[0].offset)
4332 control_values = constant->value;
4333 break;
4338 if (control_values)
4340 struct wined3d_shader_loop_control loop_control;
4341 loop_control.count = control_values[0];
4342 loop_control.start = control_values[1];
4343 loop_control.step = (int)control_values[2];
4345 if (loop_control.step > 0)
4347 shader_addline(buffer, "for (aL%u = %u; aL%u < (%u * %d + %u); aL%u += %d)\n{\n",
4348 loop_state->current_depth, loop_control.start,
4349 loop_state->current_depth, loop_control.count, loop_control.step, loop_control.start,
4350 loop_state->current_depth, loop_control.step);
4352 else if (loop_control.step < 0)
4354 shader_addline(buffer, "for (aL%u = %u; aL%u > (%u * %d + %u); aL%u += %d)\n{\n",
4355 loop_state->current_depth, loop_control.start,
4356 loop_state->current_depth, loop_control.count, loop_control.step, loop_control.start,
4357 loop_state->current_depth, loop_control.step);
4359 else
4361 shader_addline(buffer, "for (aL%u = %u, tmpInt%u = 0; tmpInt%u < %u; tmpInt%u++)\n{\n",
4362 loop_state->current_depth, loop_control.start, loop_state->current_depth,
4363 loop_state->current_depth, loop_control.count,
4364 loop_state->current_depth);
4367 else
4369 shader_addline(buffer, "for (tmpInt%u = 0, aL%u = %s.y; tmpInt%u < %s.x; tmpInt%u++, aL%u += %s.z)\n{\n",
4370 loop_state->current_depth, loop_state->current_reg,
4371 src1_param.reg_name, loop_state->current_depth, src1_param.reg_name,
4372 loop_state->current_depth, loop_state->current_reg, src1_param.reg_name);
4375 ++loop_state->current_reg;
4377 else
4379 shader_addline(buffer, "for (;;)\n{\n");
4382 ++loop_state->current_depth;
4385 static void shader_glsl_end(const struct wined3d_shader_instruction *ins)
4387 struct wined3d_shader_loop_state *loop_state = ins->ctx->loop_state;
4389 shader_addline(ins->ctx->buffer, "}\n");
4391 if (ins->handler_idx == WINED3DSIH_ENDLOOP)
4393 --loop_state->current_depth;
4394 --loop_state->current_reg;
4397 if (ins->handler_idx == WINED3DSIH_ENDREP)
4399 --loop_state->current_depth;
4403 static void shader_glsl_rep(const struct wined3d_shader_instruction *ins)
4405 const struct wined3d_shader *shader = ins->ctx->shader;
4406 struct wined3d_shader_loop_state *loop_state = ins->ctx->loop_state;
4407 const struct wined3d_shader_lconst *constant;
4408 struct glsl_src_param src0_param;
4409 const DWORD *control_values = NULL;
4411 /* Try to hardcode local values to help the GLSL compiler to unroll and optimize the loop */
4412 if (ins->src[0].reg.type == WINED3DSPR_CONSTINT)
4414 LIST_FOR_EACH_ENTRY(constant, &shader->constantsI, struct wined3d_shader_lconst, entry)
4416 if (constant->idx == ins->src[0].reg.idx[0].offset)
4418 control_values = constant->value;
4419 break;
4424 if (control_values)
4426 shader_addline(ins->ctx->buffer, "for (tmpInt%d = 0; tmpInt%d < %d; tmpInt%d++) {\n",
4427 loop_state->current_depth, loop_state->current_depth,
4428 control_values[0], loop_state->current_depth);
4430 else
4432 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4433 shader_addline(ins->ctx->buffer, "for (tmpInt%d = 0; tmpInt%d < %s; tmpInt%d++) {\n",
4434 loop_state->current_depth, loop_state->current_depth,
4435 src0_param.param_str, loop_state->current_depth);
4438 ++loop_state->current_depth;
4441 static void shader_glsl_switch(const struct wined3d_shader_instruction *ins)
4443 struct glsl_src_param src0_param;
4445 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4446 shader_addline(ins->ctx->buffer, "switch (%s)\n{\n", src0_param.param_str);
4449 static void shader_glsl_case(const struct wined3d_shader_instruction *ins)
4451 struct glsl_src_param src0_param;
4453 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4454 shader_addline(ins->ctx->buffer, "case %s:\n", src0_param.param_str);
4457 static void shader_glsl_default(const struct wined3d_shader_instruction *ins)
4459 shader_addline(ins->ctx->buffer, "default:\n");
4462 static void shader_glsl_if(const struct wined3d_shader_instruction *ins)
4464 const char *condition = (ins->flags == WINED3D_SHADER_CONDITIONAL_OP_NZ) ? "bool" : "!bool";
4465 struct glsl_src_param src0_param;
4467 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4468 shader_addline(ins->ctx->buffer, "if (%s(%s)) {\n", condition, src0_param.param_str);
4471 static void shader_glsl_ifc(const struct wined3d_shader_instruction *ins)
4473 struct glsl_src_param src0_param;
4474 struct glsl_src_param src1_param;
4476 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4477 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0, &src1_param);
4479 shader_addline(ins->ctx->buffer, "if (%s %s %s) {\n",
4480 src0_param.param_str, shader_glsl_get_rel_op(ins->flags), src1_param.param_str);
4483 static void shader_glsl_else(const struct wined3d_shader_instruction *ins)
4485 shader_addline(ins->ctx->buffer, "} else {\n");
4488 static void shader_glsl_emit(const struct wined3d_shader_instruction *ins)
4490 unsigned int stream = ins->handler_idx == WINED3DSIH_EMIT ? 0 : ins->src[0].reg.idx[0].offset;
4492 shader_addline(ins->ctx->buffer, "setup_gs_output(gs_out);\n");
4493 if (!ins->ctx->gl_info->supported[ARB_CLIP_CONTROL])
4494 shader_glsl_fixup_position(ins->ctx->buffer);
4496 if (!stream)
4497 shader_addline(ins->ctx->buffer, "EmitVertex();\n");
4498 else
4499 FIXME("Unhandled primitive stream %u.\n", stream);
4502 static void shader_glsl_break(const struct wined3d_shader_instruction *ins)
4504 shader_addline(ins->ctx->buffer, "break;\n");
4507 /* FIXME: According to MSDN the compare is done per component. */
4508 static void shader_glsl_breakc(const struct wined3d_shader_instruction *ins)
4510 struct glsl_src_param src0_param;
4511 struct glsl_src_param src1_param;
4513 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src0_param);
4514 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0, &src1_param);
4516 shader_addline(ins->ctx->buffer, "if (%s %s %s) break;\n",
4517 src0_param.param_str, shader_glsl_get_rel_op(ins->flags), src1_param.param_str);
4520 static void shader_glsl_breakp(const struct wined3d_shader_instruction *ins)
4522 const char *condition = (ins->flags == WINED3D_SHADER_CONDITIONAL_OP_NZ) ? "bool" : "!bool";
4523 struct glsl_src_param src_param;
4525 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src_param);
4526 shader_addline(ins->ctx->buffer, "if (%s(%s)) break;\n", condition, src_param.param_str);
4529 static void shader_glsl_continue(const struct wined3d_shader_instruction *ins)
4531 shader_addline(ins->ctx->buffer, "continue;\n");
4534 static void shader_glsl_label(const struct wined3d_shader_instruction *ins)
4536 shader_addline(ins->ctx->buffer, "}\n");
4537 shader_addline(ins->ctx->buffer, "void subroutine%u()\n{\n", ins->src[0].reg.idx[0].offset);
4540 static void shader_glsl_call(const struct wined3d_shader_instruction *ins)
4542 shader_addline(ins->ctx->buffer, "subroutine%u();\n", ins->src[0].reg.idx[0].offset);
4545 static void shader_glsl_callnz(const struct wined3d_shader_instruction *ins)
4547 struct glsl_src_param src1_param;
4549 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0, &src1_param);
4550 shader_addline(ins->ctx->buffer, "if (%s) subroutine%u();\n",
4551 src1_param.param_str, ins->src[0].reg.idx[0].offset);
4554 static void shader_glsl_ret(const struct wined3d_shader_instruction *ins)
4556 /* No-op. The closing } is written when a new function is started, and at the end of the shader. This
4557 * function only suppresses the unhandled instruction warning
4561 /*********************************************
4562 * Pixel Shader Specific Code begins here
4563 ********************************************/
4564 static void shader_glsl_tex(const struct wined3d_shader_instruction *ins)
4566 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major,
4567 ins->ctx->reg_maps->shader_version.minor);
4568 struct glsl_sample_function sample_function;
4569 DWORD sample_flags = 0;
4570 DWORD resource_idx;
4571 DWORD mask = 0, swizzle;
4572 const struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data;
4574 /* 1.0-1.4: Use destination register as sampler source.
4575 * 2.0+: Use provided sampler source. */
4576 if (shader_version < WINED3D_SHADER_VERSION(2,0))
4577 resource_idx = ins->dst[0].reg.idx[0].offset;
4578 else
4579 resource_idx = ins->src[1].reg.idx[0].offset;
4581 if (shader_version < WINED3D_SHADER_VERSION(1,4))
4583 DWORD flags = (priv->cur_ps_args->tex_transform >> resource_idx * WINED3D_PSARGS_TEXTRANSFORM_SHIFT)
4584 & WINED3D_PSARGS_TEXTRANSFORM_MASK;
4585 enum wined3d_shader_resource_type resource_type = ins->ctx->reg_maps->resource_info[resource_idx].type;
4587 /* Projected cube textures don't make a lot of sense, the resulting coordinates stay the same. */
4588 if (flags & WINED3D_PSARGS_PROJECTED && resource_type != WINED3D_SHADER_RESOURCE_TEXTURE_CUBE)
4590 sample_flags |= WINED3D_GLSL_SAMPLE_PROJECTED;
4591 switch (flags & ~WINED3D_PSARGS_PROJECTED)
4593 case WINED3D_TTFF_COUNT1:
4594 FIXME("WINED3D_TTFF_PROJECTED with WINED3D_TTFF_COUNT1?\n");
4595 break;
4596 case WINED3D_TTFF_COUNT2:
4597 mask = WINED3DSP_WRITEMASK_1;
4598 break;
4599 case WINED3D_TTFF_COUNT3:
4600 mask = WINED3DSP_WRITEMASK_2;
4601 break;
4602 case WINED3D_TTFF_COUNT4:
4603 case WINED3D_TTFF_DISABLE:
4604 mask = WINED3DSP_WRITEMASK_3;
4605 break;
4609 else if (shader_version < WINED3D_SHADER_VERSION(2,0))
4611 enum wined3d_shader_src_modifier src_mod = ins->src[0].modifiers;
4613 if (src_mod == WINED3DSPSM_DZ) {
4614 sample_flags |= WINED3D_GLSL_SAMPLE_PROJECTED;
4615 mask = WINED3DSP_WRITEMASK_2;
4616 } else if (src_mod == WINED3DSPSM_DW) {
4617 sample_flags |= WINED3D_GLSL_SAMPLE_PROJECTED;
4618 mask = WINED3DSP_WRITEMASK_3;
4621 else
4623 if ((ins->flags & WINED3DSI_TEXLD_PROJECT)
4624 && ins->ctx->reg_maps->resource_info[resource_idx].type != WINED3D_SHADER_RESOURCE_TEXTURE_CUBE)
4626 /* ps 2.0 texldp instruction always divides by the fourth component. */
4627 sample_flags |= WINED3D_GLSL_SAMPLE_PROJECTED;
4628 mask = WINED3DSP_WRITEMASK_3;
4632 shader_glsl_get_sample_function(ins->ctx, resource_idx, resource_idx, sample_flags, &sample_function);
4633 mask |= sample_function.coord_mask;
4634 sample_function.coord_mask = mask;
4636 if (shader_version < WINED3D_SHADER_VERSION(2,0)) swizzle = WINED3DSP_NOSWIZZLE;
4637 else swizzle = ins->src[1].swizzle;
4639 /* 1.0-1.3: Use destination register as coordinate source.
4640 1.4+: Use provided coordinate source register. */
4641 if (shader_version < WINED3D_SHADER_VERSION(1,4))
4643 char coord_mask[6];
4644 shader_glsl_write_mask_to_str(mask, coord_mask);
4645 shader_glsl_gen_sample_code(ins, resource_idx, &sample_function, swizzle, NULL, NULL, NULL, NULL,
4646 "T%u%s", resource_idx, coord_mask);
4648 else
4650 struct glsl_src_param coord_param;
4651 shader_glsl_add_src_param(ins, &ins->src[0], mask, &coord_param);
4652 if (ins->flags & WINED3DSI_TEXLD_BIAS)
4654 struct glsl_src_param bias;
4655 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &bias);
4656 shader_glsl_gen_sample_code(ins, resource_idx, &sample_function, swizzle, NULL, NULL, bias.param_str,
4657 NULL, "%s", coord_param.param_str);
4658 } else {
4659 shader_glsl_gen_sample_code(ins, resource_idx, &sample_function, swizzle, NULL, NULL, NULL, NULL,
4660 "%s", coord_param.param_str);
4663 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4666 static void shader_glsl_texldd(const struct wined3d_shader_instruction *ins)
4668 const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
4669 struct glsl_src_param coord_param, dx_param, dy_param;
4670 struct glsl_sample_function sample_function;
4671 DWORD sampler_idx;
4672 DWORD swizzle = ins->src[1].swizzle;
4674 if (!shader_glsl_has_core_grad(gl_info, &ins->ctx->shader->reg_maps.shader_version)
4675 && !gl_info->supported[ARB_SHADER_TEXTURE_LOD])
4677 FIXME("texldd used, but not supported by hardware. Falling back to regular tex\n");
4678 shader_glsl_tex(ins);
4679 return;
4682 sampler_idx = ins->src[1].reg.idx[0].offset;
4684 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, WINED3D_GLSL_SAMPLE_GRAD, &sample_function);
4685 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
4686 shader_glsl_add_src_param(ins, &ins->src[2], sample_function.deriv_mask, &dx_param);
4687 shader_glsl_add_src_param(ins, &ins->src[3], sample_function.deriv_mask, &dy_param);
4689 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, swizzle, dx_param.param_str, dy_param.param_str,
4690 NULL, NULL, "%s", coord_param.param_str);
4691 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4694 static void shader_glsl_texldl(const struct wined3d_shader_instruction *ins)
4696 const struct wined3d_shader_version *shader_version = &ins->ctx->reg_maps->shader_version;
4697 const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
4698 struct glsl_src_param coord_param, lod_param;
4699 struct glsl_sample_function sample_function;
4700 DWORD swizzle = ins->src[1].swizzle;
4701 DWORD sampler_idx;
4703 sampler_idx = ins->src[1].reg.idx[0].offset;
4705 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, WINED3D_GLSL_SAMPLE_LOD, &sample_function);
4706 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
4708 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &lod_param);
4710 if (shader_version->type == WINED3D_SHADER_TYPE_PIXEL && !shader_glsl_has_core_grad(gl_info, shader_version)
4711 && !gl_info->supported[ARB_SHADER_TEXTURE_LOD])
4713 /* Plain GLSL only supports Lod sampling functions in vertex shaders.
4714 * However, the NVIDIA drivers allow them in fragment shaders as well,
4715 * even without the appropriate extension. */
4716 WARN("Using %s in fragment shader.\n", sample_function.name->buffer);
4718 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, swizzle, NULL, NULL, lod_param.param_str, NULL,
4719 "%s", coord_param.param_str);
4720 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4723 static unsigned int shader_glsl_find_sampler(const struct wined3d_shader_sampler_map *sampler_map,
4724 unsigned int resource_idx, unsigned int sampler_idx)
4726 struct wined3d_shader_sampler_map_entry *entries = sampler_map->entries;
4727 unsigned int i;
4729 for (i = 0; i < sampler_map->count; ++i)
4731 if (entries[i].resource_idx == resource_idx && entries[i].sampler_idx == sampler_idx)
4732 return entries[i].bind_idx;
4735 ERR("No GLSL sampler found for resource %u / sampler %u.\n", resource_idx, sampler_idx);
4737 return ~0u;
4740 static void shader_glsl_atomic(const struct wined3d_shader_instruction *ins)
4742 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps;
4743 const struct wined3d_shader_version *version = &reg_maps->shader_version;
4744 struct glsl_src_param image_coord_param, image_data_param;
4745 enum wined3d_shader_resource_type resource_type;
4746 enum wined3d_data_type data_type;
4747 unsigned int uav_idx;
4748 DWORD coord_mask;
4749 const char *op;
4751 switch (ins->handler_idx)
4753 case WINED3DSIH_ATOMIC_IADD: op = "imageAtomicAdd"; break;
4754 default:
4755 ERR("Unhandled opcode %#x.\n", ins->handler_idx);
4756 return;
4759 uav_idx = ins->dst[0].reg.idx[0].offset;
4760 resource_type = reg_maps->uav_resource_info[uav_idx].type;
4761 if (resource_type >= ARRAY_SIZE(resource_type_info))
4763 ERR("Unexpected resource type %#x.\n", resource_type);
4764 resource_type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
4766 data_type = reg_maps->uav_resource_info[uav_idx].data_type;
4767 coord_mask = (1u << resource_type_info[resource_type].coord_size) - 1;
4769 shader_glsl_add_src_param(ins, &ins->src[0], coord_mask, &image_coord_param);
4770 shader_glsl_add_src_param_ext(ins, &ins->src[1], WINED3DSP_WRITEMASK_ALL, &image_data_param, data_type);
4771 shader_addline(ins->ctx->buffer, "%s(%s_image%u, %s, %s);\n",
4772 op, shader_glsl_get_prefix(version->type), uav_idx,
4773 image_coord_param.param_str, image_data_param.param_str);
4776 static void shader_glsl_ld_uav(const struct wined3d_shader_instruction *ins)
4778 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps;
4779 const struct wined3d_shader_version *version = &reg_maps->shader_version;
4780 enum wined3d_shader_resource_type resource_type;
4781 struct glsl_src_param image_coord_param;
4782 enum wined3d_data_type data_type;
4783 DWORD coord_mask, write_mask;
4784 unsigned int uav_idx;
4785 char dst_swizzle[6];
4787 uav_idx = ins->src[1].reg.idx[0].offset;
4788 if (uav_idx >= ARRAY_SIZE(reg_maps->uav_resource_info))
4790 ERR("Invalid UAV index %u.\n", uav_idx);
4791 return;
4793 resource_type = reg_maps->uav_resource_info[uav_idx].type;
4794 if (resource_type >= ARRAY_SIZE(resource_type_info))
4796 ERR("Unexpected resource type %#x.\n", resource_type);
4797 resource_type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
4799 data_type = reg_maps->uav_resource_info[uav_idx].data_type;
4800 coord_mask = (1u << resource_type_info[resource_type].coord_size) - 1;
4802 write_mask = shader_glsl_append_dst_ext(ins->ctx->buffer, ins, &ins->dst[0], data_type);
4803 shader_glsl_get_swizzle(&ins->src[1], FALSE, write_mask, dst_swizzle);
4805 shader_glsl_add_src_param(ins, &ins->src[0], coord_mask, &image_coord_param);
4806 shader_addline(ins->ctx->buffer, "imageLoad(%s_image%u, %s)%s);\n",
4807 shader_glsl_get_prefix(version->type), uav_idx, image_coord_param.param_str, dst_swizzle);
4810 static void shader_glsl_resinfo(const struct wined3d_shader_instruction *ins)
4812 const struct wined3d_shader_version *version = &ins->ctx->reg_maps->shader_version;
4813 const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
4814 enum wined3d_shader_resource_type resource_type;
4815 enum wined3d_shader_register_type reg_type;
4816 unsigned int resource_idx, bind_idx, i;
4817 enum wined3d_data_type dst_data_type;
4818 struct glsl_src_param lod_param;
4819 char dst_swizzle[6];
4820 DWORD write_mask;
4822 dst_data_type = ins->dst[0].reg.data_type;
4823 if (ins->flags == WINED3DSI_RESINFO_UINT)
4824 dst_data_type = WINED3D_DATA_UINT;
4825 else if (ins->flags)
4826 FIXME("Unhandled flags %#x.\n", ins->flags);
4828 write_mask = shader_glsl_append_dst_ext(ins->ctx->buffer, ins, &ins->dst[0], dst_data_type);
4829 shader_glsl_get_swizzle(&ins->src[1], FALSE, write_mask, dst_swizzle);
4831 reg_type = ins->src[1].reg.type;
4832 resource_idx = ins->src[1].reg.idx[0].offset;
4833 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &lod_param);
4834 if (reg_type == WINED3DSPR_RESOURCE)
4836 resource_type = ins->ctx->reg_maps->resource_info[resource_idx].type;
4837 bind_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map,
4838 resource_idx, WINED3D_SAMPLER_DEFAULT);
4840 else
4842 resource_type = ins->ctx->reg_maps->uav_resource_info[resource_idx].type;
4843 bind_idx = resource_idx;
4846 if (resource_type >= ARRAY_SIZE(resource_type_info))
4848 ERR("Unexpected resource type %#x.\n", resource_type);
4849 resource_type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
4852 if (dst_data_type == WINED3D_DATA_UINT)
4853 shader_addline(ins->ctx->buffer, "uvec4(");
4854 else
4855 shader_addline(ins->ctx->buffer, "vec4(");
4857 if (reg_type == WINED3DSPR_RESOURCE)
4859 shader_addline(ins->ctx->buffer, "textureSize(%s_sampler%u, %s), ",
4860 shader_glsl_get_prefix(version->type), bind_idx, lod_param.param_str);
4862 for (i = 0; i < 3 - resource_type_info[resource_type].resinfo_size; ++i)
4863 shader_addline(ins->ctx->buffer, "0, ");
4865 if (gl_info->supported[ARB_TEXTURE_QUERY_LEVELS])
4867 shader_addline(ins->ctx->buffer, "textureQueryLevels(%s_sampler%u)",
4868 shader_glsl_get_prefix(version->type), bind_idx);
4870 else
4872 FIXME("textureQueryLevels is not supported, returning 1 mipmap level.\n");
4873 shader_addline(ins->ctx->buffer, "1");
4876 else
4878 shader_addline(ins->ctx->buffer, "imageSize(%s_image%u), ",
4879 shader_glsl_get_prefix(version->type), bind_idx);
4881 for (i = 0; i < 3 - resource_type_info[resource_type].resinfo_size; ++i)
4882 shader_addline(ins->ctx->buffer, "0, ");
4884 /* For UAVs the returned miplevel count is always 1. */
4885 shader_addline(ins->ctx->buffer, "1");
4888 shader_addline(ins->ctx->buffer, ")%s);\n", dst_swizzle);
4891 /* FIXME: The current implementation does not handle multisample textures correctly. */
4892 static void shader_glsl_ld(const struct wined3d_shader_instruction *ins)
4894 unsigned int resource_idx, sampler_idx, sampler_bind_idx;
4895 struct glsl_src_param coord_param, lod_param;
4896 struct glsl_sample_function sample_function;
4897 DWORD flags = WINED3D_GLSL_SAMPLE_LOAD;
4899 if (wined3d_shader_instruction_has_texel_offset(ins))
4900 flags |= WINED3D_GLSL_SAMPLE_OFFSET;
4902 resource_idx = ins->src[1].reg.idx[0].offset;
4903 sampler_idx = WINED3D_SAMPLER_DEFAULT;
4905 shader_glsl_get_sample_function(ins->ctx, resource_idx, sampler_idx, flags, &sample_function);
4906 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
4907 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &lod_param);
4908 sampler_bind_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map, resource_idx, sampler_idx);
4909 shader_glsl_gen_sample_code(ins, sampler_bind_idx, &sample_function, ins->src[1].swizzle,
4910 NULL, NULL, lod_param.param_str, &ins->texel_offset, "%s", coord_param.param_str);
4911 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4914 static void shader_glsl_sample(const struct wined3d_shader_instruction *ins)
4916 const char *lod_param_str = NULL, *dx_param_str = NULL, *dy_param_str = NULL;
4917 struct glsl_src_param coord_param, lod_param, dx_param, dy_param;
4918 unsigned int resource_idx, sampler_idx, sampler_bind_idx;
4919 struct glsl_sample_function sample_function;
4920 DWORD flags = 0;
4922 if (ins->handler_idx == WINED3DSIH_SAMPLE_GRAD)
4923 flags |= WINED3D_GLSL_SAMPLE_GRAD;
4924 if (ins->handler_idx == WINED3DSIH_SAMPLE_LOD)
4925 flags |= WINED3D_GLSL_SAMPLE_LOD;
4926 if (wined3d_shader_instruction_has_texel_offset(ins))
4927 flags |= WINED3D_GLSL_SAMPLE_OFFSET;
4929 resource_idx = ins->src[1].reg.idx[0].offset;
4930 sampler_idx = ins->src[2].reg.idx[0].offset;
4932 shader_glsl_get_sample_function(ins->ctx, resource_idx, sampler_idx, flags, &sample_function);
4933 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
4935 switch (ins->handler_idx)
4937 case WINED3DSIH_SAMPLE:
4938 break;
4939 case WINED3DSIH_SAMPLE_B:
4940 shader_glsl_add_src_param(ins, &ins->src[3], WINED3DSP_WRITEMASK_0, &lod_param);
4941 lod_param_str = lod_param.param_str;
4942 break;
4943 case WINED3DSIH_SAMPLE_GRAD:
4944 shader_glsl_add_src_param(ins, &ins->src[3], sample_function.deriv_mask, &dx_param);
4945 shader_glsl_add_src_param(ins, &ins->src[4], sample_function.deriv_mask, &dy_param);
4946 dx_param_str = dx_param.param_str;
4947 dy_param_str = dy_param.param_str;
4948 break;
4949 case WINED3DSIH_SAMPLE_LOD:
4950 shader_glsl_add_src_param(ins, &ins->src[3], WINED3DSP_WRITEMASK_0, &lod_param);
4951 lod_param_str = lod_param.param_str;
4952 break;
4953 default:
4954 ERR("Unhandled opcode %s.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
4955 break;
4958 sampler_bind_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map, resource_idx, sampler_idx);
4959 shader_glsl_gen_sample_code(ins, sampler_bind_idx, &sample_function, ins->src[1].swizzle,
4960 dx_param_str, dy_param_str, lod_param_str, &ins->texel_offset, "%s", coord_param.param_str);
4961 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4964 static void shader_glsl_sample_c(const struct wined3d_shader_instruction *ins)
4966 unsigned int resource_idx, sampler_idx, sampler_bind_idx;
4967 struct glsl_src_param coord_param, compare_param;
4968 struct glsl_sample_function sample_function;
4969 const char *lod_param = NULL;
4970 DWORD flags = 0;
4971 UINT coord_size;
4973 if (ins->handler_idx == WINED3DSIH_SAMPLE_C_LZ)
4975 lod_param = "0";
4976 flags |= WINED3D_GLSL_SAMPLE_LOD;
4979 if (wined3d_shader_instruction_has_texel_offset(ins))
4980 flags |= WINED3D_GLSL_SAMPLE_OFFSET;
4982 resource_idx = ins->src[1].reg.idx[0].offset;
4983 sampler_idx = ins->src[2].reg.idx[0].offset;
4985 shader_glsl_get_sample_function(ins->ctx, resource_idx, sampler_idx, flags, &sample_function);
4986 coord_size = shader_glsl_get_write_mask_size(sample_function.coord_mask);
4987 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask >> 1, &coord_param);
4988 shader_glsl_add_src_param(ins, &ins->src[3], WINED3DSP_WRITEMASK_0, &compare_param);
4989 sampler_bind_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map, resource_idx, sampler_idx);
4990 shader_glsl_gen_sample_code(ins, sampler_bind_idx, &sample_function, WINED3DSP_NOSWIZZLE,
4991 NULL, NULL, lod_param, &ins->texel_offset, "vec%u(%s, %s)",
4992 coord_size, coord_param.param_str, compare_param.param_str);
4993 shader_glsl_release_sample_function(ins->ctx, &sample_function);
4996 static void shader_glsl_texcoord(const struct wined3d_shader_instruction *ins)
4998 /* FIXME: Make this work for more than just 2D textures */
4999 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5000 DWORD write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
5002 if (!(ins->ctx->reg_maps->shader_version.major == 1 && ins->ctx->reg_maps->shader_version.minor == 4))
5004 char dst_mask[6];
5006 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
5007 shader_addline(buffer, "clamp(ffp_texcoord[%u], 0.0, 1.0)%s);\n",
5008 ins->dst[0].reg.idx[0].offset, dst_mask);
5010 else
5012 enum wined3d_shader_src_modifier src_mod = ins->src[0].modifiers;
5013 DWORD reg = ins->src[0].reg.idx[0].offset;
5014 char dst_swizzle[6];
5016 shader_glsl_get_swizzle(&ins->src[0], FALSE, write_mask, dst_swizzle);
5018 if (src_mod == WINED3DSPSM_DZ || src_mod == WINED3DSPSM_DW)
5020 unsigned int mask_size = shader_glsl_get_write_mask_size(write_mask);
5021 struct glsl_src_param div_param;
5022 DWORD src_writemask = src_mod == WINED3DSPSM_DZ ? WINED3DSP_WRITEMASK_2 : WINED3DSP_WRITEMASK_3;
5024 shader_glsl_add_src_param(ins, &ins->src[0], src_writemask, &div_param);
5026 if (mask_size > 1)
5027 shader_addline(buffer, "ffp_texcoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str);
5028 else
5029 shader_addline(buffer, "ffp_texcoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str);
5031 else
5033 shader_addline(buffer, "ffp_texcoord[%u]%s);\n", reg, dst_swizzle);
5038 /** Process the WINED3DSIO_TEXDP3TEX instruction in GLSL:
5039 * Take a 3-component dot product of the TexCoord[dstreg] and src,
5040 * then perform a 1D texture lookup from stage dstregnum, place into dst. */
5041 static void shader_glsl_texdp3tex(const struct wined3d_shader_instruction *ins)
5043 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5044 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset;
5045 struct glsl_sample_function sample_function;
5046 struct glsl_src_param src0_param;
5047 UINT mask_size;
5049 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5051 /* Do I have to take care about the projected bit? I don't think so, since the dp3 returns only one
5052 * scalar, and projected sampling would require 4.
5054 * It is a dependent read - not valid with conditional NP2 textures
5056 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, 0, &sample_function);
5057 mask_size = shader_glsl_get_write_mask_size(sample_function.coord_mask);
5059 switch(mask_size)
5061 case 1:
5062 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL,
5063 NULL, "dot(ffp_texcoord[%u].xyz, %s)", sampler_idx, src0_param.param_str);
5064 break;
5066 case 2:
5067 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL,
5068 NULL, "vec2(dot(ffp_texcoord[%u].xyz, %s), 0.0)", sampler_idx, src0_param.param_str);
5069 break;
5071 case 3:
5072 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL,
5073 NULL, "vec3(dot(ffp_texcoord[%u].xyz, %s), 0.0, 0.0)", sampler_idx, src0_param.param_str);
5074 break;
5076 default:
5077 FIXME("Unexpected mask size %u\n", mask_size);
5078 break;
5080 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5083 /** Process the WINED3DSIO_TEXDP3 instruction in GLSL:
5084 * Take a 3-component dot product of the TexCoord[dstreg] and src. */
5085 static void shader_glsl_texdp3(const struct wined3d_shader_instruction *ins)
5087 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5088 DWORD dstreg = ins->dst[0].reg.idx[0].offset;
5089 struct glsl_src_param src0_param;
5090 DWORD dst_mask;
5091 unsigned int mask_size;
5093 dst_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
5094 mask_size = shader_glsl_get_write_mask_size(dst_mask);
5095 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5097 if (mask_size > 1) {
5098 shader_addline(ins->ctx->buffer, "vec%d(dot(T%u.xyz, %s)));\n", mask_size, dstreg, src0_param.param_str);
5099 } else {
5100 shader_addline(ins->ctx->buffer, "dot(T%u.xyz, %s));\n", dstreg, src0_param.param_str);
5104 /** Process the WINED3DSIO_TEXDEPTH instruction in GLSL:
5105 * Calculate the depth as dst.x / dst.y */
5106 static void shader_glsl_texdepth(const struct wined3d_shader_instruction *ins)
5108 struct glsl_dst_param dst_param;
5110 shader_glsl_add_dst_param(ins, &ins->dst[0], &dst_param);
5112 /* Tests show that texdepth never returns anything below 0.0, and that r5.y is clamped to 1.0.
5113 * Negative input is accepted, -0.25 / -0.5 returns 0.5. GL should clamp gl_FragDepth to [0;1], but
5114 * this doesn't always work, so clamp the results manually. Whether or not the x value is clamped at 1
5115 * too is irrelevant, since if x = 0, any y value < 1.0 (and > 1.0 is not allowed) results in a result
5116 * >= 1.0 or < 0.0
5118 shader_addline(ins->ctx->buffer, "gl_FragDepth = clamp((%s.x / min(%s.y, 1.0)), 0.0, 1.0);\n",
5119 dst_param.reg_name, dst_param.reg_name);
5122 /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in GLSL:
5123 * Last row of a 3x2 matrix multiply, use the result to calculate the depth:
5124 * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated)
5125 * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y
5127 static void shader_glsl_texm3x2depth(const struct wined3d_shader_instruction *ins)
5129 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5130 DWORD dstreg = ins->dst[0].reg.idx[0].offset;
5131 struct glsl_src_param src0_param;
5133 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5135 shader_addline(ins->ctx->buffer, "tmp0.y = dot(T%u.xyz, %s);\n", dstreg, src0_param.param_str);
5136 shader_addline(ins->ctx->buffer, "gl_FragDepth = (tmp0.y == 0.0) ? 1.0 : clamp(tmp0.x / tmp0.y, 0.0, 1.0);\n");
5139 /** Process the WINED3DSIO_TEXM3X2PAD instruction in GLSL
5140 * Calculate the 1st of a 2-row matrix multiplication. */
5141 static void shader_glsl_texm3x2pad(const struct wined3d_shader_instruction *ins)
5143 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5144 DWORD reg = ins->dst[0].reg.idx[0].offset;
5145 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5146 struct glsl_src_param src0_param;
5148 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5149 shader_addline(buffer, "tmp0.x = dot(T%u.xyz, %s);\n", reg, src0_param.param_str);
5152 /** Process the WINED3DSIO_TEXM3X3PAD instruction in GLSL
5153 * Calculate the 1st or 2nd row of a 3-row matrix multiplication. */
5154 static void shader_glsl_texm3x3pad(const struct wined3d_shader_instruction *ins)
5156 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5157 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5158 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx;
5159 DWORD reg = ins->dst[0].reg.idx[0].offset;
5160 struct glsl_src_param src0_param;
5162 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5163 shader_addline(buffer, "tmp0.%c = dot(T%u.xyz, %s);\n", 'x' + tex_mx->current_row, reg, src0_param.param_str);
5164 tex_mx->texcoord_w[tex_mx->current_row++] = reg;
5167 static void shader_glsl_texm3x2tex(const struct wined3d_shader_instruction *ins)
5169 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5170 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5171 struct glsl_sample_function sample_function;
5172 DWORD reg = ins->dst[0].reg.idx[0].offset;
5173 struct glsl_src_param src0_param;
5175 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5176 shader_addline(buffer, "tmp0.y = dot(T%u.xyz, %s);\n", reg, src0_param.param_str);
5178 shader_glsl_get_sample_function(ins->ctx, reg, reg, 0, &sample_function);
5180 /* Sample the texture using the calculated coordinates */
5181 shader_glsl_gen_sample_code(ins, reg, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL, "tmp0.xy");
5182 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5185 /** Process the WINED3DSIO_TEXM3X3TEX instruction in GLSL
5186 * Perform the 3rd row of a 3x3 matrix multiply, then sample the texture using the calculated coordinates */
5187 static void shader_glsl_texm3x3tex(const struct wined3d_shader_instruction *ins)
5189 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5190 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx;
5191 struct glsl_sample_function sample_function;
5192 DWORD reg = ins->dst[0].reg.idx[0].offset;
5193 struct glsl_src_param src0_param;
5195 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5196 shader_addline(ins->ctx->buffer, "tmp0.z = dot(T%u.xyz, %s);\n", reg, src0_param.param_str);
5198 /* Dependent read, not valid with conditional NP2 */
5199 shader_glsl_get_sample_function(ins->ctx, reg, reg, 0, &sample_function);
5201 /* Sample the texture using the calculated coordinates */
5202 shader_glsl_gen_sample_code(ins, reg, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL, "tmp0.xyz");
5203 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5205 tex_mx->current_row = 0;
5208 /** Process the WINED3DSIO_TEXM3X3 instruction in GLSL
5209 * Perform the 3rd row of a 3x3 matrix multiply */
5210 static void shader_glsl_texm3x3(const struct wined3d_shader_instruction *ins)
5212 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5213 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx;
5214 DWORD reg = ins->dst[0].reg.idx[0].offset;
5215 struct glsl_src_param src0_param;
5216 char dst_mask[6];
5218 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5220 shader_glsl_append_dst(ins->ctx->buffer, ins);
5221 shader_glsl_get_write_mask(&ins->dst[0], dst_mask);
5222 shader_addline(ins->ctx->buffer, "vec4(tmp0.xy, dot(T%u.xyz, %s), 1.0)%s);\n", reg, src0_param.param_str, dst_mask);
5224 tex_mx->current_row = 0;
5227 /* Process the WINED3DSIO_TEXM3X3SPEC instruction in GLSL
5228 * Perform the final texture lookup based on the previous 2 3x3 matrix multiplies */
5229 static void shader_glsl_texm3x3spec(const struct wined3d_shader_instruction *ins)
5231 struct glsl_src_param src0_param;
5232 struct glsl_src_param src1_param;
5233 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5234 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx;
5235 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5236 struct glsl_sample_function sample_function;
5237 DWORD reg = ins->dst[0].reg.idx[0].offset;
5238 char coord_mask[6];
5240 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5241 shader_glsl_add_src_param(ins, &ins->src[1], src_mask, &src1_param);
5243 /* Perform the last matrix multiply operation */
5244 shader_addline(buffer, "tmp0.z = dot(T%u.xyz, %s);\n", reg, src0_param.param_str);
5245 /* Reflection calculation */
5246 shader_addline(buffer, "tmp0.xyz = -reflect((%s), normalize(tmp0.xyz));\n", src1_param.param_str);
5248 /* Dependent read, not valid with conditional NP2 */
5249 shader_glsl_get_sample_function(ins->ctx, reg, reg, 0, &sample_function);
5250 shader_glsl_write_mask_to_str(sample_function.coord_mask, coord_mask);
5252 /* Sample the texture */
5253 shader_glsl_gen_sample_code(ins, reg, &sample_function, WINED3DSP_NOSWIZZLE,
5254 NULL, NULL, NULL, NULL, "tmp0%s", coord_mask);
5255 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5257 tex_mx->current_row = 0;
5260 /* Process the WINED3DSIO_TEXM3X3VSPEC instruction in GLSL
5261 * Perform the final texture lookup based on the previous 2 3x3 matrix multiplies */
5262 static void shader_glsl_texm3x3vspec(const struct wined3d_shader_instruction *ins)
5264 struct wined3d_string_buffer *buffer = ins->ctx->buffer;
5265 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx;
5266 DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
5267 struct glsl_sample_function sample_function;
5268 DWORD reg = ins->dst[0].reg.idx[0].offset;
5269 struct glsl_src_param src0_param;
5270 char coord_mask[6];
5272 shader_glsl_add_src_param(ins, &ins->src[0], src_mask, &src0_param);
5274 /* Perform the last matrix multiply operation */
5275 shader_addline(buffer, "tmp0.z = dot(vec3(T%u), vec3(%s));\n", reg, src0_param.param_str);
5277 /* Construct the eye-ray vector from w coordinates */
5278 shader_addline(buffer, "tmp1.xyz = normalize(vec3(ffp_texcoord[%u].w, ffp_texcoord[%u].w, ffp_texcoord[%u].w));\n",
5279 tex_mx->texcoord_w[0], tex_mx->texcoord_w[1], reg);
5280 shader_addline(buffer, "tmp0.xyz = -reflect(tmp1.xyz, normalize(tmp0.xyz));\n");
5282 /* Dependent read, not valid with conditional NP2 */
5283 shader_glsl_get_sample_function(ins->ctx, reg, reg, 0, &sample_function);
5284 shader_glsl_write_mask_to_str(sample_function.coord_mask, coord_mask);
5286 /* Sample the texture using the calculated coordinates */
5287 shader_glsl_gen_sample_code(ins, reg, &sample_function, WINED3DSP_NOSWIZZLE,
5288 NULL, NULL, NULL, NULL, "tmp0%s", coord_mask);
5289 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5291 tex_mx->current_row = 0;
5294 /** Process the WINED3DSIO_TEXBEM instruction in GLSL.
5295 * Apply a fake bump map transform.
5296 * texbem is pshader <= 1.3 only, this saves a few version checks
5298 static void shader_glsl_texbem(const struct wined3d_shader_instruction *ins)
5300 const struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data;
5301 struct glsl_sample_function sample_function;
5302 struct glsl_src_param coord_param;
5303 DWORD sampler_idx;
5304 DWORD mask;
5305 DWORD flags;
5306 char coord_mask[6];
5308 sampler_idx = ins->dst[0].reg.idx[0].offset;
5309 flags = (priv->cur_ps_args->tex_transform >> sampler_idx * WINED3D_PSARGS_TEXTRANSFORM_SHIFT)
5310 & WINED3D_PSARGS_TEXTRANSFORM_MASK;
5312 /* Dependent read, not valid with conditional NP2 */
5313 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, 0, &sample_function);
5314 mask = sample_function.coord_mask;
5316 shader_glsl_write_mask_to_str(mask, coord_mask);
5318 /* With projected textures, texbem only divides the static texture coord,
5319 * not the displacement, so we can't let GL handle this. */
5320 if (flags & WINED3D_PSARGS_PROJECTED)
5322 DWORD div_mask=0;
5323 char coord_div_mask[3];
5324 switch (flags & ~WINED3D_PSARGS_PROJECTED)
5326 case WINED3D_TTFF_COUNT1:
5327 FIXME("WINED3D_TTFF_PROJECTED with WINED3D_TTFF_COUNT1?\n");
5328 break;
5329 case WINED3D_TTFF_COUNT2:
5330 div_mask = WINED3DSP_WRITEMASK_1;
5331 break;
5332 case WINED3D_TTFF_COUNT3:
5333 div_mask = WINED3DSP_WRITEMASK_2;
5334 break;
5335 case WINED3D_TTFF_COUNT4:
5336 case WINED3D_TTFF_DISABLE:
5337 div_mask = WINED3DSP_WRITEMASK_3;
5338 break;
5340 shader_glsl_write_mask_to_str(div_mask, coord_div_mask);
5341 shader_addline(ins->ctx->buffer, "T%u%s /= T%u%s;\n", sampler_idx, coord_mask, sampler_idx, coord_div_mask);
5344 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &coord_param);
5346 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL,
5347 "T%u%s + vec4(bumpenv_mat%u * %s, 0.0, 0.0)%s", sampler_idx, coord_mask, sampler_idx,
5348 coord_param.param_str, coord_mask);
5350 if (ins->handler_idx == WINED3DSIH_TEXBEML)
5352 struct glsl_src_param luminance_param;
5353 struct glsl_dst_param dst_param;
5355 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_2, &luminance_param);
5356 shader_glsl_add_dst_param(ins, &ins->dst[0], &dst_param);
5358 shader_addline(ins->ctx->buffer, "%s%s *= (%s * bumpenv_lum_scale%u + bumpenv_lum_offset%u);\n",
5359 dst_param.reg_name, dst_param.mask_str,
5360 luminance_param.param_str, sampler_idx, sampler_idx);
5362 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5365 static void shader_glsl_bem(const struct wined3d_shader_instruction *ins)
5367 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset;
5368 struct glsl_src_param src0_param, src1_param;
5370 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src0_param);
5371 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src1_param);
5373 shader_glsl_append_dst(ins->ctx->buffer, ins);
5374 shader_addline(ins->ctx->buffer, "%s + bumpenv_mat%u * %s);\n",
5375 src0_param.param_str, sampler_idx, src1_param.param_str);
5378 /** Process the WINED3DSIO_TEXREG2AR instruction in GLSL
5379 * Sample 2D texture at dst using the alpha & red (wx) components of src as texture coordinates */
5380 static void shader_glsl_texreg2ar(const struct wined3d_shader_instruction *ins)
5382 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset;
5383 struct glsl_sample_function sample_function;
5384 struct glsl_src_param src0_param;
5386 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_ALL, &src0_param);
5388 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, 0, &sample_function);
5389 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL,
5390 "%s.wx", src0_param.reg_name);
5391 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5394 /** Process the WINED3DSIO_TEXREG2GB instruction in GLSL
5395 * Sample 2D texture at dst using the green & blue (yz) components of src as texture coordinates */
5396 static void shader_glsl_texreg2gb(const struct wined3d_shader_instruction *ins)
5398 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset;
5399 struct glsl_sample_function sample_function;
5400 struct glsl_src_param src0_param;
5402 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_ALL, &src0_param);
5404 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, 0, &sample_function);
5405 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL,
5406 "%s.yz", src0_param.reg_name);
5407 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5410 /** Process the WINED3DSIO_TEXREG2RGB instruction in GLSL
5411 * Sample texture at dst using the rgb (xyz) components of src as texture coordinates */
5412 static void shader_glsl_texreg2rgb(const struct wined3d_shader_instruction *ins)
5414 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset;
5415 struct glsl_sample_function sample_function;
5416 struct glsl_src_param src0_param;
5418 /* Dependent read, not valid with conditional NP2 */
5419 shader_glsl_get_sample_function(ins->ctx, sampler_idx, sampler_idx, 0, &sample_function);
5420 shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &src0_param);
5422 shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, NULL,
5423 "%s", src0_param.param_str);
5424 shader_glsl_release_sample_function(ins->ctx, &sample_function);
5427 /** Process the WINED3DSIO_TEXKILL instruction in GLSL.
5428 * If any of the first 3 components are < 0, discard this pixel */
5429 static void shader_glsl_texkill(const struct wined3d_shader_instruction *ins)
5431 if (ins->ctx->reg_maps->shader_version.major >= 4)
5433 struct glsl_src_param src_param;
5435 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0, &src_param);
5436 shader_addline(ins->ctx->buffer, "if (bool(floatBitsToUint(%s))) discard;\n", src_param.param_str);
5438 else
5440 struct glsl_dst_param dst_param;
5442 /* The argument is a destination parameter, and no writemasks are allowed */
5443 shader_glsl_add_dst_param(ins, &ins->dst[0], &dst_param);
5445 /* 2.0 shaders compare all 4 components in texkill. */
5446 if (ins->ctx->reg_maps->shader_version.major >= 2)
5447 shader_addline(ins->ctx->buffer, "if (any(lessThan(%s.xyzw, vec4(0.0)))) discard;\n", dst_param.reg_name);
5448 /* 1.x shaders only compare the first 3 components, probably due to
5449 * the nature of the texkill instruction as a tex* instruction, and
5450 * phase, which kills all .w components. Even if all 4 components are
5451 * defined, only the first 3 are used. */
5452 else
5453 shader_addline(ins->ctx->buffer, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_param.reg_name);
5457 /** Process the WINED3DSIO_DP2ADD instruction in GLSL.
5458 * dst = dot2(src0, src1) + src2 */
5459 static void shader_glsl_dp2add(const struct wined3d_shader_instruction *ins)
5461 struct glsl_src_param src0_param;
5462 struct glsl_src_param src1_param;
5463 struct glsl_src_param src2_param;
5464 DWORD write_mask;
5465 unsigned int mask_size;
5467 write_mask = shader_glsl_append_dst(ins->ctx->buffer, ins);
5468 mask_size = shader_glsl_get_write_mask_size(write_mask);
5470 shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src0_param);
5471 shader_glsl_add_src_param(ins, &ins->src[1], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src1_param);
5472 shader_glsl_add_src_param(ins, &ins->src[2], WINED3DSP_WRITEMASK_0, &src2_param);
5474 if (mask_size > 1) {
5475 shader_addline(ins->ctx->buffer, "vec%d(dot(%s, %s) + %s));\n",
5476 mask_size, src0_param.param_str, src1_param.param_str, src2_param.param_str);
5477 } else {
5478 shader_addline(ins->ctx->buffer, "dot(%s, %s) + %s);\n",
5479 src0_param.param_str, src1_param.param_str, src2_param.param_str);
5483 static void shader_glsl_input_pack(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer,
5484 const struct wined3d_shader_signature *input_signature,
5485 const struct wined3d_shader_reg_maps *reg_maps,
5486 const struct ps_compile_args *args, const struct wined3d_gl_info *gl_info)
5488 unsigned int i;
5490 for (i = 0; i < input_signature->element_count; ++i)
5492 const struct wined3d_shader_signature_element *input = &input_signature->elements[i];
5493 const char *semantic_name;
5494 UINT semantic_idx;
5495 char reg_mask[6];
5497 /* Unused */
5498 if (!(reg_maps->input_registers & (1u << input->register_idx)))
5499 continue;
5501 semantic_name = input->semantic_name;
5502 semantic_idx = input->semantic_idx;
5503 shader_glsl_write_mask_to_str(input->mask, reg_mask);
5505 if (args->vp_mode == vertexshader)
5507 if (input->sysval_semantic == WINED3D_SV_POSITION && !semantic_idx)
5509 shader_addline(buffer, "ps_in[%u]%s = vpos%s;\n",
5510 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5512 else if (args->pointsprite && shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD))
5514 shader_addline(buffer, "ps_in[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n", input->register_idx);
5516 else if (input->sysval_semantic == WINED3D_SV_IS_FRONT_FACE)
5518 shader_addline(buffer, "ps_in[%u] = vec4("
5519 "uintBitsToFloat(gl_FrontFacing ? 0xffffffffu : 0u), 0.0, 0.0, 0.0);\n",
5520 input->register_idx);
5522 else
5524 if (input->sysval_semantic)
5525 FIXME("Unhandled sysval semantic %#x.\n", input->sysval_semantic);
5526 shader_addline(buffer, "ps_in[%u]%s = ps_link[%u]%s;\n",
5527 shader->u.ps.input_reg_map[input->register_idx], reg_mask,
5528 shader->u.ps.input_reg_map[input->register_idx], reg_mask);
5531 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD))
5533 if (args->pointsprite)
5534 shader_addline(buffer, "ps_in[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n",
5535 shader->u.ps.input_reg_map[input->register_idx]);
5536 else if (args->vp_mode == pretransformed && args->texcoords_initialized & (1u << semantic_idx))
5537 shader_addline(buffer, "ps_in[%u]%s = %s[%u]%s;\n",
5538 shader->u.ps.input_reg_map[input->register_idx], reg_mask,
5539 gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]
5540 ? "gl_TexCoord" : "ffp_varying_texcoord", semantic_idx, reg_mask);
5541 else
5542 shader_addline(buffer, "ps_in[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
5543 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5545 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_COLOR))
5547 if (!semantic_idx)
5548 shader_addline(buffer, "ps_in[%u]%s = vec4(ffp_varying_diffuse)%s;\n",
5549 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5550 else if (semantic_idx == 1)
5551 shader_addline(buffer, "ps_in[%u]%s = vec4(ffp_varying_specular)%s;\n",
5552 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5553 else
5554 shader_addline(buffer, "ps_in[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
5555 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5557 else
5559 shader_addline(buffer, "ps_in[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
5560 shader->u.ps.input_reg_map[input->register_idx], reg_mask, reg_mask);
5565 /*********************************************
5566 * Vertex Shader Specific Code begins here
5567 ********************************************/
5569 static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_shader_prog_link *entry)
5571 struct glsl_program_key key;
5573 key.vs_id = entry->vs.id;
5574 key.gs_id = entry->gs.id;
5575 key.ps_id = entry->ps.id;
5577 if (wine_rb_put(&priv->program_lookup, &key, &entry->program_lookup_entry) == -1)
5579 ERR("Failed to insert program entry.\n");
5583 static struct glsl_shader_prog_link *get_glsl_program_entry(const struct shader_glsl_priv *priv,
5584 GLuint vs_id, GLuint gs_id, GLuint ps_id)
5586 struct wine_rb_entry *entry;
5587 struct glsl_program_key key;
5589 key.vs_id = vs_id;
5590 key.gs_id = gs_id;
5591 key.ps_id = ps_id;
5593 entry = wine_rb_get(&priv->program_lookup, &key);
5594 return entry ? WINE_RB_ENTRY_VALUE(entry, struct glsl_shader_prog_link, program_lookup_entry) : NULL;
5597 /* Context activation is done by the caller. */
5598 static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const struct wined3d_gl_info *gl_info,
5599 struct glsl_shader_prog_link *entry)
5601 wine_rb_remove(&priv->program_lookup, &entry->program_lookup_entry);
5603 GL_EXTCALL(glDeleteProgram(entry->id));
5604 if (entry->vs.id)
5605 list_remove(&entry->vs.shader_entry);
5606 if (entry->gs.id)
5607 list_remove(&entry->gs.shader_entry);
5608 if (entry->ps.id)
5609 list_remove(&entry->ps.shader_entry);
5610 HeapFree(GetProcessHeap(), 0, entry);
5613 static void shader_glsl_setup_vs3_output(struct shader_glsl_priv *priv,
5614 const struct wined3d_gl_info *gl_info, const DWORD *map,
5615 const struct wined3d_shader_signature *input_signature,
5616 const struct wined3d_shader_reg_maps *reg_maps_in,
5617 const struct wined3d_shader_signature *output_signature,
5618 const struct wined3d_shader_reg_maps *reg_maps_out, const char *out_array_name)
5620 struct wined3d_string_buffer *destination = string_buffer_get(&priv->string_buffers);
5621 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
5622 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5623 unsigned int in_count = vec4_varyings(3, gl_info);
5624 unsigned int max_varyings = legacy_context ? in_count + 2 : in_count;
5625 DWORD in_idx, *set = NULL;
5626 unsigned int i, j;
5627 char reg_mask[6];
5629 set = wined3d_calloc(max_varyings, sizeof(*set));
5631 for (i = 0; i < input_signature->element_count; ++i)
5633 const struct wined3d_shader_signature_element *input = &input_signature->elements[i];
5635 if (!(reg_maps_in->input_registers & (1u << input->register_idx)))
5636 continue;
5638 in_idx = map[input->register_idx];
5639 /* Declared, but not read register */
5640 if (in_idx == ~0u)
5641 continue;
5642 if (in_idx >= max_varyings)
5644 FIXME("More input varyings declared than supported, expect issues.\n");
5645 continue;
5648 if (in_idx == in_count)
5649 string_buffer_sprintf(destination, "gl_FrontColor");
5650 else if (in_idx == in_count + 1)
5651 string_buffer_sprintf(destination, "gl_FrontSecondaryColor");
5652 else
5653 string_buffer_sprintf(destination, "%s[%u]", out_array_name, in_idx);
5655 if (!set[in_idx])
5656 set[in_idx] = ~0u;
5658 for (j = 0; j < output_signature->element_count; ++j)
5660 const struct wined3d_shader_signature_element *output = &output_signature->elements[j];
5661 DWORD mask;
5663 if (!(reg_maps_out->output_registers & (1u << output->register_idx))
5664 || input->semantic_idx != output->semantic_idx
5665 || strcmp(input->semantic_name, output->semantic_name)
5666 || !(mask = input->mask & output->mask))
5667 continue;
5669 if (set[in_idx] == ~0u)
5670 set[in_idx] = 0;
5671 set[in_idx] |= mask & reg_maps_out->u.output_registers_mask[output->register_idx];
5672 shader_glsl_write_mask_to_str(mask, reg_mask);
5674 shader_addline(buffer, "%s%s = shader_out[%u]%s;\n",
5675 destination->buffer, reg_mask, output->register_idx, reg_mask);
5679 for (i = 0; i < max_varyings; ++i)
5681 unsigned int size;
5683 if (!set[i] || set[i] == WINED3DSP_WRITEMASK_ALL)
5684 continue;
5686 if (set[i] == ~0u)
5687 set[i] = 0;
5689 size = 0;
5690 if (!(set[i] & WINED3DSP_WRITEMASK_0))
5691 reg_mask[size++] = 'x';
5692 if (!(set[i] & WINED3DSP_WRITEMASK_1))
5693 reg_mask[size++] = 'y';
5694 if (!(set[i] & WINED3DSP_WRITEMASK_2))
5695 reg_mask[size++] = 'z';
5696 if (!(set[i] & WINED3DSP_WRITEMASK_3))
5697 reg_mask[size++] = 'w';
5698 reg_mask[size] = '\0';
5700 if (i == in_count)
5701 string_buffer_sprintf(destination, "gl_FrontColor");
5702 else if (i == in_count + 1)
5703 string_buffer_sprintf(destination, "gl_FrontSecondaryColor");
5704 else
5705 string_buffer_sprintf(destination, "%s[%u]", out_array_name, i);
5707 if (size == 1)
5708 shader_addline(buffer, "%s.%s = 0.0;\n", destination->buffer, reg_mask);
5709 else
5710 shader_addline(buffer, "%s.%s = vec%u(0.0);\n", destination->buffer, reg_mask, size);
5713 HeapFree(GetProcessHeap(), 0, set);
5714 string_buffer_release(&priv->string_buffers, destination);
5717 static void shader_glsl_setup_sm4_shader_output(struct shader_glsl_priv *priv,
5718 unsigned int input_count, const struct wined3d_shader_signature *output_signature,
5719 const struct wined3d_shader_reg_maps *reg_maps_out, const char *out_array_name)
5721 struct wined3d_string_buffer *destination = string_buffer_get(&priv->string_buffers);
5722 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5723 char reg_mask[6];
5724 unsigned int i;
5726 for (i = 0; i < output_signature->element_count; ++i)
5728 const struct wined3d_shader_signature_element *output = &output_signature->elements[i];
5730 if (!(reg_maps_out->output_registers & (1u << output->register_idx)))
5731 continue;
5733 if (output->register_idx >= input_count)
5734 continue;
5736 string_buffer_sprintf(destination, "%s[%u]", out_array_name, output->register_idx);
5738 shader_glsl_write_mask_to_str(output->mask, reg_mask);
5740 shader_addline(buffer, "%s%s = shader_out[%u]%s;\n",
5741 destination->buffer, reg_mask, output->register_idx, reg_mask);
5744 string_buffer_release(&priv->string_buffers, destination);
5747 /* Context activation is done by the caller. */
5748 static void shader_glsl_generate_vs_gs_setup(struct shader_glsl_priv *priv,
5749 const struct wined3d_shader *vs, unsigned int input_count,
5750 const struct wined3d_gl_info *gl_info)
5752 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
5753 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5755 if (legacy_context)
5756 shader_addline(buffer, "varying out vec4 gs_in[%u];\n", input_count);
5757 else
5758 shader_addline(buffer, "out vs_gs_iface { vec4 gs_in[%u]; } gs_in;\n", input_count);
5759 shader_addline(buffer, "void setup_vs_output(in vec4 shader_out[%u])\n{\n", vs->limits->packed_output);
5761 shader_glsl_setup_sm4_shader_output(priv, input_count, &vs->output_signature, &vs->reg_maps,
5762 legacy_context ? "gs_in" : "gs_in.gs_in");
5764 shader_addline(buffer, "}\n");
5767 static void shader_glsl_setup_sm3_rasterizer_input(struct shader_glsl_priv *priv,
5768 const struct wined3d_gl_info *gl_info, const DWORD *map,
5769 const struct wined3d_shader_signature *input_signature,
5770 const struct wined3d_shader_reg_maps *reg_maps_in, unsigned int input_count,
5771 const struct wined3d_shader_signature *output_signature,
5772 const struct wined3d_shader_reg_maps *reg_maps_out, BOOL per_vertex_point_size)
5774 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5775 const char *semantic_name;
5776 UINT semantic_idx;
5777 char reg_mask[6];
5778 unsigned int i;
5780 /* First, sort out position and point size system values. */
5781 for (i = 0; i < output_signature->element_count; ++i)
5783 const struct wined3d_shader_signature_element *output = &output_signature->elements[i];
5785 if (!(reg_maps_out->output_registers & (1u << output->register_idx)))
5786 continue;
5788 semantic_name = output->semantic_name;
5789 semantic_idx = output->semantic_idx;
5790 shader_glsl_write_mask_to_str(output->mask, reg_mask);
5792 if (output->sysval_semantic == WINED3D_SV_POSITION && !semantic_idx)
5794 shader_addline(buffer, "gl_Position%s = shader_out[%u]%s;\n",
5795 reg_mask, output->register_idx, reg_mask);
5797 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_PSIZE) && per_vertex_point_size)
5799 shader_addline(buffer, "gl_PointSize = clamp(shader_out[%u].%c, "
5800 "ffp_point.size_min, ffp_point.size_max);\n", output->register_idx, reg_mask[1]);
5802 else if (output->sysval_semantic)
5804 FIXME("Unhandled sysval semantic %#x.\n", output->sysval_semantic);
5808 /* Then, setup the pixel shader input. */
5809 if (reg_maps_out->shader_version.major < 4)
5810 shader_glsl_setup_vs3_output(priv, gl_info, map, input_signature, reg_maps_in,
5811 output_signature, reg_maps_out, "ps_link");
5812 else
5813 shader_glsl_setup_sm4_shader_output(priv, input_count, output_signature, reg_maps_out, "ps_link");
5816 /* Context activation is done by the caller. */
5817 static GLuint shader_glsl_generate_vs3_rasterizer_input_setup(struct shader_glsl_priv *priv,
5818 const struct wined3d_shader *vs, const struct wined3d_shader *ps,
5819 BOOL per_vertex_point_size, BOOL flatshading, const struct wined3d_gl_info *gl_info)
5821 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5822 GLuint ret;
5823 DWORD ps_major = ps ? ps->reg_maps.shader_version.major : 0;
5824 unsigned int i;
5825 const char *semantic_name;
5826 UINT semantic_idx;
5827 char reg_mask[6];
5828 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
5830 string_buffer_clear(buffer);
5832 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, &vs->reg_maps.shader_version));
5834 if (per_vertex_point_size)
5836 shader_addline(buffer, "uniform struct\n{\n");
5837 shader_addline(buffer, " float size_min;\n");
5838 shader_addline(buffer, " float size_max;\n");
5839 shader_addline(buffer, "} ffp_point;\n");
5842 if (ps_major < 3)
5844 DWORD colors_written_mask[2] = {0};
5845 DWORD texcoords_written_mask[MAX_TEXTURES] = {0};
5847 if (!legacy_context)
5849 declare_out_varying(gl_info, buffer, flatshading, "vec4 ffp_varying_diffuse;\n");
5850 declare_out_varying(gl_info, buffer, flatshading, "vec4 ffp_varying_specular;\n");
5851 declare_out_varying(gl_info, buffer, FALSE, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
5852 declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
5855 shader_addline(buffer, "void setup_vs_output(in vec4 shader_out[%u])\n{\n", vs->limits->packed_output);
5857 for (i = 0; i < vs->output_signature.element_count; ++i)
5859 const struct wined3d_shader_signature_element *output = &vs->output_signature.elements[i];
5860 DWORD write_mask;
5862 if (!(vs->reg_maps.output_registers & (1u << output->register_idx)))
5863 continue;
5865 semantic_name = output->semantic_name;
5866 semantic_idx = output->semantic_idx;
5867 write_mask = output->mask;
5868 shader_glsl_write_mask_to_str(write_mask, reg_mask);
5870 if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_COLOR) && semantic_idx < 2)
5872 if (legacy_context)
5873 shader_addline(buffer, "gl_Front%sColor%s = shader_out[%u]%s;\n",
5874 semantic_idx ? "Secondary" : "", reg_mask, output->register_idx, reg_mask);
5875 else
5876 shader_addline(buffer, "ffp_varying_%s%s = clamp(shader_out[%u]%s, 0.0, 1.0);\n",
5877 semantic_idx ? "specular" : "diffuse", reg_mask, output->register_idx, reg_mask);
5879 colors_written_mask[semantic_idx] = write_mask;
5881 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_POSITION) && !semantic_idx)
5883 shader_addline(buffer, "gl_Position%s = shader_out[%u]%s;\n",
5884 reg_mask, output->register_idx, reg_mask);
5886 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD))
5888 if (semantic_idx < MAX_TEXTURES)
5890 shader_addline(buffer, "%s[%u]%s = shader_out[%u]%s;\n",
5891 legacy_context ? "gl_TexCoord" : "ffp_varying_texcoord",
5892 semantic_idx, reg_mask, output->register_idx, reg_mask);
5893 texcoords_written_mask[semantic_idx] = write_mask;
5896 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_PSIZE) && per_vertex_point_size)
5898 shader_addline(buffer, "gl_PointSize = clamp(shader_out[%u].%c, "
5899 "ffp_point.size_min, ffp_point.size_max);\n", output->register_idx, reg_mask[1]);
5901 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_FOG))
5903 shader_addline(buffer, "%s = clamp(shader_out[%u].%c, 0.0, 1.0);\n",
5904 legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord",
5905 output->register_idx, reg_mask[1]);
5909 for (i = 0; i < 2; ++i)
5911 if (colors_written_mask[i] != WINED3DSP_WRITEMASK_ALL)
5913 shader_glsl_write_mask_to_str(~colors_written_mask[i] & WINED3DSP_WRITEMASK_ALL, reg_mask);
5914 if (!i)
5915 shader_addline(buffer, "%s%s = vec4(1.0)%s;\n",
5916 legacy_context ? "gl_FrontColor" : "ffp_varying_diffuse",
5917 reg_mask, reg_mask);
5918 else
5919 shader_addline(buffer, "%s%s = vec4(0.0)%s;\n",
5920 legacy_context ? "gl_FrontSecondaryColor" : "ffp_varying_specular",
5921 reg_mask, reg_mask);
5924 for (i = 0; i < MAX_TEXTURES; ++i)
5926 if (ps && !(ps->reg_maps.texcoord & (1u << i)))
5927 continue;
5929 if (texcoords_written_mask[i] != WINED3DSP_WRITEMASK_ALL)
5931 if (gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(gl_info)
5932 && !texcoords_written_mask[i])
5933 continue;
5935 shader_glsl_write_mask_to_str(~texcoords_written_mask[i] & WINED3DSP_WRITEMASK_ALL, reg_mask);
5936 shader_addline(buffer, "%s[%u]%s = vec4(0.0)%s;\n",
5937 legacy_context ? "gl_TexCoord" : "ffp_varying_texcoord", i, reg_mask, reg_mask);
5941 else
5943 UINT in_count = min(vec4_varyings(ps_major, gl_info), ps->limits->packed_input);
5945 declare_out_varying(gl_info, buffer, FALSE, "vec4 ps_link[%u];\n", in_count);
5946 shader_addline(buffer, "void setup_vs_output(in vec4 shader_out[%u])\n{\n", vs->limits->packed_output);
5947 shader_glsl_setup_sm3_rasterizer_input(priv, gl_info, ps->u.ps.input_reg_map, &ps->input_signature,
5948 &ps->reg_maps, 0, &vs->output_signature, &vs->reg_maps, per_vertex_point_size);
5951 shader_addline(buffer, "}\n");
5953 ret = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER));
5954 checkGLcall("glCreateShader(GL_VERTEX_SHADER)");
5955 shader_glsl_compile(gl_info, ret, buffer->buffer);
5957 return ret;
5960 static void shader_glsl_generate_sm4_rasterizer_input_setup(struct shader_glsl_priv *priv,
5961 const struct wined3d_shader *shader, unsigned int input_count,
5962 const struct wined3d_gl_info *gl_info)
5964 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
5966 if (input_count)
5967 declare_out_varying(gl_info, buffer, FALSE, "vec4 ps_link[%u];\n", min(vec4_varyings(4, gl_info), input_count));
5969 shader_addline(buffer, "void setup_%s_output(in vec4 shader_out[%u])\n{\n",
5970 shader_glsl_get_prefix(shader->reg_maps.shader_version.type), shader->limits->packed_output);
5972 shader_glsl_setup_sm3_rasterizer_input(priv, gl_info, NULL, NULL,
5973 NULL, input_count, &shader->output_signature, &shader->reg_maps, FALSE);
5975 shader_addline(buffer, "}\n");
5978 static void shader_glsl_generate_srgb_write_correction(struct wined3d_string_buffer *buffer,
5979 const struct wined3d_gl_info *gl_info)
5981 const char *output = get_fragment_output(gl_info);
5983 shader_addline(buffer, "tmp0.xyz = pow(%s[0].xyz, vec3(srgb_const0.x));\n", output);
5984 shader_addline(buffer, "tmp0.xyz = tmp0.xyz * vec3(srgb_const0.y) - vec3(srgb_const0.z);\n");
5985 shader_addline(buffer, "tmp1.xyz = %s[0].xyz * vec3(srgb_const0.w);\n", output);
5986 shader_addline(buffer, "bvec3 srgb_compare = lessThan(%s[0].xyz, vec3(srgb_const1.x));\n", output);
5987 shader_addline(buffer, "%s[0].xyz = mix(tmp0.xyz, tmp1.xyz, vec3(srgb_compare));\n", output);
5988 shader_addline(buffer, "%s[0] = clamp(%s[0], 0.0, 1.0);\n", output, output);
5991 static void shader_glsl_generate_fog_code(struct wined3d_string_buffer *buffer,
5992 const struct wined3d_gl_info *gl_info, enum wined3d_ffp_ps_fog_mode mode)
5994 const char *output = get_fragment_output(gl_info);
5996 switch (mode)
5998 case WINED3D_FFP_PS_FOG_OFF:
5999 return;
6001 case WINED3D_FFP_PS_FOG_LINEAR:
6002 shader_addline(buffer, "float fog = (ffp_fog.end - ffp_varying_fogcoord) * ffp_fog.scale;\n");
6003 break;
6005 case WINED3D_FFP_PS_FOG_EXP:
6006 shader_addline(buffer, "float fog = exp(-ffp_fog.density * ffp_varying_fogcoord);\n");
6007 break;
6009 case WINED3D_FFP_PS_FOG_EXP2:
6010 shader_addline(buffer, "float fog = exp(-ffp_fog.density * ffp_fog.density"
6011 " * ffp_varying_fogcoord * ffp_varying_fogcoord);\n");
6012 break;
6014 default:
6015 ERR("Invalid fog mode %#x.\n", mode);
6016 return;
6019 shader_addline(buffer, "%s[0].xyz = mix(ffp_fog.color.xyz, %s[0].xyz, clamp(fog, 0.0, 1.0));\n",
6020 output, output);
6023 static void shader_glsl_generate_alpha_test(struct wined3d_string_buffer *buffer,
6024 const struct wined3d_gl_info *gl_info, enum wined3d_cmp_func alpha_func)
6026 /* alpha_func is the PASS condition, not the DISCARD condition. Instead of
6027 * flipping all the operators here, just negate the comparison below. */
6028 static const char * const comparison_operator[] =
6030 "", /* WINED3D_CMP_NEVER */
6031 "<", /* WINED3D_CMP_LESS */
6032 "==", /* WINED3D_CMP_EQUAL */
6033 "<=", /* WINED3D_CMP_LESSEQUAL */
6034 ">", /* WINED3D_CMP_GREATER */
6035 "!=", /* WINED3D_CMP_NOTEQUAL */
6036 ">=", /* WINED3D_CMP_GREATEREQUAL */
6037 "" /* WINED3D_CMP_ALWAYS */
6040 if (alpha_func == WINED3D_CMP_ALWAYS)
6041 return;
6043 if (alpha_func != WINED3D_CMP_NEVER)
6044 shader_addline(buffer, "if (!(%s[0].a %s alpha_test_ref))\n",
6045 get_fragment_output(gl_info), comparison_operator[alpha_func - WINED3D_CMP_NEVER]);
6046 shader_addline(buffer, " discard;\n");
6049 static void shader_glsl_enable_extensions(struct wined3d_string_buffer *buffer,
6050 const struct wined3d_gl_info *gl_info)
6052 if (gl_info->supported[ARB_SHADER_BIT_ENCODING])
6053 shader_addline(buffer, "#extension GL_ARB_shader_bit_encoding : enable\n");
6054 if (gl_info->supported[ARB_SHADER_IMAGE_LOAD_STORE])
6055 shader_addline(buffer, "#extension GL_ARB_shader_image_load_store : enable\n");
6056 if (gl_info->supported[ARB_SHADER_IMAGE_SIZE])
6057 shader_addline(buffer, "#extension GL_ARB_shader_image_size : enable\n");
6058 if (gl_info->supported[ARB_TEXTURE_QUERY_LEVELS])
6059 shader_addline(buffer, "#extension GL_ARB_texture_query_levels : enable\n");
6060 if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT])
6061 shader_addline(buffer, "#extension GL_ARB_uniform_buffer_object : enable\n");
6062 if (gl_info->supported[EXT_GPU_SHADER4])
6063 shader_addline(buffer, "#extension GL_EXT_gpu_shader4 : enable\n");
6064 if (gl_info->supported[EXT_TEXTURE_ARRAY])
6065 shader_addline(buffer, "#extension GL_EXT_texture_array : enable\n");
6068 /* Context activation is done by the caller. */
6069 static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context,
6070 struct wined3d_string_buffer *buffer, struct wined3d_string_buffer_list *string_buffers,
6071 const struct wined3d_shader *shader,
6072 const struct ps_compile_args *args, struct ps_np2fixup_info *np2fixup_info)
6074 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
6075 const struct wined3d_gl_info *gl_info = context->gl_info;
6076 const DWORD *function = shader->function;
6077 struct shader_glsl_ctx_priv priv_ctx;
6078 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
6080 /* Create the hw GLSL shader object and assign it as the shader->prgId */
6081 GLuint shader_id = GL_EXTCALL(glCreateShader(GL_FRAGMENT_SHADER));
6083 memset(&priv_ctx, 0, sizeof(priv_ctx));
6084 priv_ctx.cur_ps_args = args;
6085 priv_ctx.cur_np2fixup_info = np2fixup_info;
6086 priv_ctx.string_buffers = string_buffers;
6088 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, &reg_maps->shader_version));
6090 shader_glsl_enable_extensions(buffer, gl_info);
6091 if (gl_info->supported[ARB_DERIVATIVE_CONTROL])
6092 shader_addline(buffer, "#extension GL_ARB_derivative_control : enable\n");
6093 if (gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
6094 shader_addline(buffer, "#extension GL_ARB_fragment_coord_conventions : enable\n");
6095 if (gl_info->supported[ARB_SHADER_TEXTURE_LOD])
6096 shader_addline(buffer, "#extension GL_ARB_shader_texture_lod : enable\n");
6097 /* The spec says that it doesn't have to be explicitly enabled, but the
6098 * nvidia drivers write a warning if we don't do so. */
6099 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6100 shader_addline(buffer, "#extension GL_ARB_texture_rectangle : enable\n");
6102 /* Base Declarations */
6103 shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
6105 shader_addline(buffer, "void main()\n{\n");
6107 /* Direct3D applications expect integer vPos values, while OpenGL drivers
6108 * add approximately 0.5. This causes off-by-one problems as spotted by
6109 * the vPos d3d9 visual test. Unfortunately ATI cards do not add exactly
6110 * 0.5, but rather something like 0.49999999 or 0.50000001, which still
6111 * causes precision troubles when we just subtract 0.5.
6113 * To deal with that, just floor() the position. This will eliminate the
6114 * fraction on all cards.
6116 * TODO: Test how this behaves with multisampling.
6118 * An advantage of floor is that it works even if the driver doesn't add
6119 * 0.5. It is somewhat questionable if 1.5, 2.5, ... are the proper values
6120 * to return in gl_FragCoord, even though coordinates specify the pixel
6121 * centers instead of the pixel corners. This code will behave correctly
6122 * on drivers that returns integer values. */
6123 if (reg_maps->vpos)
6125 if (gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
6126 shader_addline(buffer, "vpos = gl_FragCoord;\n");
6127 else if (context->d3d_info->wined3d_creation_flags & WINED3D_PIXEL_CENTER_INTEGER)
6128 shader_addline(buffer,
6129 "vpos = floor(vec4(0, ycorrection[0], 0, 0) + gl_FragCoord * vec4(1, ycorrection[1], 1, 1));\n");
6130 else
6131 shader_addline(buffer,
6132 "vpos = vec4(0, ycorrection[0], 0, 0) + gl_FragCoord * vec4(1, ycorrection[1], 1, 1);\n");
6135 if (reg_maps->shader_version.major < 3 || args->vp_mode != vertexshader)
6137 unsigned int i;
6138 WORD map = reg_maps->texcoord;
6140 if (legacy_context)
6142 if (glsl_is_color_reg_read(shader, 0))
6143 shader_addline(buffer, "ffp_varying_diffuse = gl_Color;\n");
6144 if (glsl_is_color_reg_read(shader, 1))
6145 shader_addline(buffer, "ffp_varying_specular = gl_SecondaryColor;\n");
6148 for (i = 0; map; map >>= 1, ++i)
6150 if (map & 1)
6152 if (args->pointsprite)
6153 shader_addline(buffer, "ffp_texcoord[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n", i);
6154 else if (args->texcoords_initialized & (1u << i))
6155 shader_addline(buffer, "ffp_texcoord[%u] = %s[%u];\n", i,
6156 legacy_context ? "gl_TexCoord" : "ffp_varying_texcoord", i);
6157 else
6158 shader_addline(buffer, "ffp_texcoord[%u] = vec4(0.0);\n", i);
6159 shader_addline(buffer, "vec4 T%u = ffp_texcoord[%u];\n", i, i);
6163 if (legacy_context)
6164 shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n");
6167 /* Pack 3.0 inputs */
6168 if (reg_maps->shader_version.major >= 3)
6169 shader_glsl_input_pack(shader, buffer, &shader->input_signature, reg_maps, args, gl_info);
6171 /* Base Shader Body */
6172 shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx);
6174 /* Pixel shaders < 2.0 place the resulting color in R0 implicitly */
6175 if (reg_maps->shader_version.major < 2)
6176 shader_addline(buffer, "%s[0] = R0;\n", get_fragment_output(gl_info));
6178 if (args->srgb_correction)
6179 shader_glsl_generate_srgb_write_correction(buffer, gl_info);
6181 /* SM < 3 does not replace the fog stage. */
6182 if (reg_maps->shader_version.major < 3)
6183 shader_glsl_generate_fog_code(buffer, gl_info, args->fog);
6185 shader_glsl_generate_alpha_test(buffer, gl_info, args->alpha_test_func + 1);
6187 shader_addline(buffer, "}\n");
6189 TRACE("Compiling shader object %u.\n", shader_id);
6190 shader_glsl_compile(gl_info, shader_id, buffer->buffer);
6192 return shader_id;
6195 /* Context activation is done by the caller. */
6196 static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context,
6197 struct shader_glsl_priv *priv, const struct wined3d_shader *shader, const struct vs_compile_args *args)
6199 struct wined3d_string_buffer_list *string_buffers = &priv->string_buffers;
6200 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
6201 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
6202 const struct wined3d_gl_info *gl_info = context->gl_info;
6203 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
6204 const DWORD *function = shader->function;
6205 struct shader_glsl_ctx_priv priv_ctx;
6206 unsigned int i;
6208 /* Create the hw GLSL shader program and assign it as the shader->prgId */
6209 GLuint shader_id = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER));
6211 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, &reg_maps->shader_version));
6213 shader_glsl_enable_extensions(buffer, gl_info);
6214 if (gl_info->supported[ARB_DRAW_INSTANCED])
6215 shader_addline(buffer, "#extension GL_ARB_draw_instanced : enable\n");
6216 if (gl_info->supported[ARB_EXPLICIT_ATTRIB_LOCATION])
6217 shader_addline(buffer, "#extension GL_ARB_explicit_attrib_location : enable\n");
6219 memset(&priv_ctx, 0, sizeof(priv_ctx));
6220 priv_ctx.cur_vs_args = args;
6221 priv_ctx.string_buffers = string_buffers;
6223 /* Base Declarations */
6224 shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
6226 if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL && !gl_info->supported[ARB_CLIP_CONTROL])
6227 shader_addline(buffer, "uniform vec4 pos_fixup;\n");
6229 if (reg_maps->shader_version.major >= 4)
6231 if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL)
6232 shader_glsl_generate_sm4_rasterizer_input_setup(priv, shader, args->next_shader_input_count, gl_info);
6233 else if (args->next_shader_type == WINED3D_SHADER_TYPE_GEOMETRY)
6234 shader_glsl_generate_vs_gs_setup(priv, shader, args->next_shader_input_count, gl_info);
6237 shader_addline(buffer, "void main()\n{\n");
6239 /* Base Shader Body */
6240 shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx);
6242 /* Unpack outputs */
6243 shader_addline(buffer, "setup_vs_output(vs_out);\n");
6245 /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used
6246 * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE),
6247 * the fog frag coord is thrown away. If the fog frag coord is used, but not written by
6248 * the shader, it is set to 0.0(fully fogged, since start = 1.0, end = 0.0)
6250 if (reg_maps->shader_version.major < 3)
6252 if (args->fog_src == VS_FOG_Z)
6253 shader_addline(buffer, "%s = gl_Position.z;\n",
6254 legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord");
6255 else if (!reg_maps->fog)
6256 shader_addline(buffer, "%s = 0.0;\n",
6257 legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord");
6260 /* We always store the clipplanes without y inversion */
6261 if (args->clip_enabled)
6263 if (legacy_context)
6264 shader_addline(buffer, "gl_ClipVertex = gl_Position;\n");
6265 else
6266 for (i = 0; i < gl_info->limits.user_clip_distances; ++i)
6267 shader_addline(buffer, "gl_ClipDistance[%u] = dot(gl_Position, clip_planes[%u]);\n", i, i);
6270 if (args->point_size && !args->per_vertex_point_size)
6271 shader_addline(buffer, "gl_PointSize = clamp(ffp_point.size, ffp_point.size_min, ffp_point.size_max);\n");
6273 if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL && !gl_info->supported[ARB_CLIP_CONTROL])
6274 shader_glsl_fixup_position(buffer);
6276 shader_addline(buffer, "}\n");
6278 TRACE("Compiling shader object %u.\n", shader_id);
6279 shader_glsl_compile(gl_info, shader_id, buffer->buffer);
6281 return shader_id;
6284 /* Context activation is done by the caller. */
6285 static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context *context,
6286 struct shader_glsl_priv *priv, const struct wined3d_shader *shader, const struct gs_compile_args *args)
6288 struct wined3d_string_buffer_list *string_buffers = &priv->string_buffers;
6289 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
6290 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
6291 const struct wined3d_gl_info *gl_info = context->gl_info;
6292 const DWORD *function = shader->function;
6293 struct shader_glsl_ctx_priv priv_ctx;
6294 GLuint shader_id;
6296 shader_id = GL_EXTCALL(glCreateShader(GL_GEOMETRY_SHADER));
6298 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, &reg_maps->shader_version));
6300 shader_glsl_enable_extensions(buffer, gl_info);
6301 if (gl_info->supported[ARB_GEOMETRY_SHADER4])
6302 shader_addline(buffer, "#extension GL_ARB_geometry_shader4 : enable\n");
6304 memset(&priv_ctx, 0, sizeof(priv_ctx));
6305 priv_ctx.string_buffers = string_buffers;
6306 shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
6307 if (!gl_info->supported[ARB_CLIP_CONTROL])
6308 shader_addline(buffer, "uniform vec4 pos_fixup;\n");
6309 shader_glsl_generate_sm4_rasterizer_input_setup(priv, shader, args->ps_input_count, gl_info);
6310 shader_addline(buffer, "void main()\n{\n");
6311 shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx);
6312 shader_addline(buffer, "}\n");
6314 TRACE("Compiling shader object %u.\n", shader_id);
6315 shader_glsl_compile(gl_info, shader_id, buffer->buffer);
6317 return shader_id;
6320 static GLuint find_glsl_pshader(const struct wined3d_context *context,
6321 struct wined3d_string_buffer *buffer, struct wined3d_string_buffer_list *string_buffers,
6322 struct wined3d_shader *shader,
6323 const struct ps_compile_args *args, const struct ps_np2fixup_info **np2fixup_info)
6325 struct glsl_ps_compiled_shader *gl_shaders, *new_array;
6326 struct glsl_shader_private *shader_data;
6327 struct ps_np2fixup_info *np2fixup;
6328 UINT i;
6329 DWORD new_size;
6330 GLuint ret;
6332 if (!shader->backend_data)
6334 shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data));
6335 if (!shader->backend_data)
6337 ERR("Failed to allocate backend data.\n");
6338 return 0;
6341 shader_data = shader->backend_data;
6342 gl_shaders = shader_data->gl_shaders.ps;
6344 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2),
6345 * so a linear search is more performant than a hashmap or a binary search
6346 * (cache coherency etc)
6348 for (i = 0; i < shader_data->num_gl_shaders; ++i)
6350 if (!memcmp(&gl_shaders[i].args, args, sizeof(*args)))
6352 if (args->np2_fixup)
6353 *np2fixup_info = &gl_shaders[i].np2fixup;
6354 return gl_shaders[i].id;
6358 TRACE("No matching GL shader found for shader %p, compiling a new shader.\n", shader);
6359 if(shader_data->shader_array_size == shader_data->num_gl_shaders) {
6360 if (shader_data->num_gl_shaders)
6362 new_size = shader_data->shader_array_size + max(1, shader_data->shader_array_size / 2);
6363 new_array = HeapReAlloc(GetProcessHeap(), 0, shader_data->gl_shaders.ps,
6364 new_size * sizeof(*gl_shaders));
6366 else
6368 new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*gl_shaders));
6369 new_size = 1;
6372 if(!new_array) {
6373 ERR("Out of memory\n");
6374 return 0;
6376 shader_data->gl_shaders.ps = new_array;
6377 shader_data->shader_array_size = new_size;
6378 gl_shaders = new_array;
6381 gl_shaders[shader_data->num_gl_shaders].args = *args;
6383 np2fixup = &gl_shaders[shader_data->num_gl_shaders].np2fixup;
6384 memset(np2fixup, 0, sizeof(*np2fixup));
6385 *np2fixup_info = args->np2_fixup ? np2fixup : NULL;
6387 pixelshader_update_resource_types(shader, args->tex_types);
6389 string_buffer_clear(buffer);
6390 ret = shader_glsl_generate_pshader(context, buffer, string_buffers, shader, args, np2fixup);
6391 gl_shaders[shader_data->num_gl_shaders++].id = ret;
6393 return ret;
6396 static inline BOOL vs_args_equal(const struct vs_compile_args *stored, const struct vs_compile_args *new,
6397 const DWORD use_map)
6399 if((stored->swizzle_map & use_map) != new->swizzle_map) return FALSE;
6400 if((stored->clip_enabled) != new->clip_enabled) return FALSE;
6401 if (stored->point_size != new->point_size)
6402 return FALSE;
6403 if (stored->per_vertex_point_size != new->per_vertex_point_size)
6404 return FALSE;
6405 if (stored->flatshading != new->flatshading)
6406 return FALSE;
6407 if (stored->next_shader_type != new->next_shader_type)
6408 return FALSE;
6409 if (stored->next_shader_input_count != new->next_shader_input_count)
6410 return FALSE;
6411 return stored->fog_src == new->fog_src;
6414 static GLuint find_glsl_vshader(const struct wined3d_context *context, struct shader_glsl_priv *priv,
6415 struct wined3d_shader *shader, const struct vs_compile_args *args)
6417 UINT i;
6418 DWORD new_size;
6419 DWORD use_map = context->stream_info.use_map;
6420 struct glsl_vs_compiled_shader *gl_shaders, *new_array;
6421 struct glsl_shader_private *shader_data;
6422 GLuint ret;
6424 if (!shader->backend_data)
6426 shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data));
6427 if (!shader->backend_data)
6429 ERR("Failed to allocate backend data.\n");
6430 return 0;
6433 shader_data = shader->backend_data;
6434 gl_shaders = shader_data->gl_shaders.vs;
6436 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2),
6437 * so a linear search is more performant than a hashmap or a binary search
6438 * (cache coherency etc)
6440 for (i = 0; i < shader_data->num_gl_shaders; ++i)
6442 if (vs_args_equal(&gl_shaders[i].args, args, use_map))
6443 return gl_shaders[i].id;
6446 TRACE("No matching GL shader found for shader %p, compiling a new shader.\n", shader);
6448 if(shader_data->shader_array_size == shader_data->num_gl_shaders) {
6449 if (shader_data->num_gl_shaders)
6451 new_size = shader_data->shader_array_size + max(1, shader_data->shader_array_size / 2);
6452 new_array = HeapReAlloc(GetProcessHeap(), 0, shader_data->gl_shaders.vs,
6453 new_size * sizeof(*gl_shaders));
6455 else
6457 new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*gl_shaders));
6458 new_size = 1;
6461 if(!new_array) {
6462 ERR("Out of memory\n");
6463 return 0;
6465 shader_data->gl_shaders.vs = new_array;
6466 shader_data->shader_array_size = new_size;
6467 gl_shaders = new_array;
6470 gl_shaders[shader_data->num_gl_shaders].args = *args;
6472 string_buffer_clear(&priv->shader_buffer);
6473 ret = shader_glsl_generate_vshader(context, priv, shader, args);
6474 gl_shaders[shader_data->num_gl_shaders++].id = ret;
6476 return ret;
6479 static GLuint find_glsl_geometry_shader(const struct wined3d_context *context,
6480 struct shader_glsl_priv *priv, struct wined3d_shader *shader, const struct gs_compile_args *args)
6482 struct glsl_gs_compiled_shader *gl_shaders, *new_array;
6483 struct glsl_shader_private *shader_data;
6484 unsigned int i, new_size;
6485 GLuint ret;
6487 if (!shader->backend_data)
6489 if (!(shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data))))
6491 ERR("Failed to allocate backend data.\n");
6492 return 0;
6495 shader_data = shader->backend_data;
6496 gl_shaders = shader_data->gl_shaders.gs;
6498 for (i = 0; i < shader_data->num_gl_shaders; ++i)
6500 if (!memcmp(&gl_shaders[i].args, args, sizeof(*args)))
6501 return gl_shaders[i].id;
6504 TRACE("No matching GL shader found for shader %p, compiling a new shader.\n", shader);
6506 if (shader_data->num_gl_shaders)
6508 new_size = shader_data->shader_array_size + 1;
6509 new_array = HeapReAlloc(GetProcessHeap(), 0, shader_data->gl_shaders.gs,
6510 new_size * sizeof(*new_array));
6512 else
6514 new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
6515 new_size = 1;
6518 if (!new_array)
6520 ERR("Failed to allocate GL shaders array.\n");
6521 return 0;
6523 shader_data->gl_shaders.gs = new_array;
6524 shader_data->shader_array_size = new_size;
6525 gl_shaders = new_array;
6527 string_buffer_clear(&priv->shader_buffer);
6528 ret = shader_glsl_generate_geometry_shader(context, priv, shader, args);
6529 gl_shaders[shader_data->num_gl_shaders].args = *args;
6530 gl_shaders[shader_data->num_gl_shaders++].id = ret;
6532 return ret;
6535 static const char *shader_glsl_ffp_mcs(enum wined3d_material_color_source mcs, const char *material)
6537 switch (mcs)
6539 case WINED3D_MCS_MATERIAL:
6540 return material;
6541 case WINED3D_MCS_COLOR1:
6542 return "ffp_attrib_diffuse";
6543 case WINED3D_MCS_COLOR2:
6544 return "ffp_attrib_specular";
6545 default:
6546 ERR("Invalid material color source %#x.\n", mcs);
6547 return "<invalid>";
6551 static void shader_glsl_ffp_vertex_lighting(struct wined3d_string_buffer *buffer,
6552 const struct wined3d_ffp_vs_settings *settings, BOOL legacy_lighting)
6554 const char *diffuse, *specular, *emissive, *ambient;
6555 enum wined3d_light_type light_type;
6556 unsigned int i;
6558 if (!settings->lighting)
6560 shader_addline(buffer, "ffp_varying_diffuse = ffp_attrib_diffuse;\n");
6561 shader_addline(buffer, "ffp_varying_specular = ffp_attrib_specular;\n");
6562 return;
6565 shader_addline(buffer, "vec3 ambient = ffp_light_ambient;\n");
6566 shader_addline(buffer, "vec3 diffuse = vec3(0.0);\n");
6567 shader_addline(buffer, "vec4 specular = vec4(0.0);\n");
6568 shader_addline(buffer, "vec3 dir, dst;\n");
6569 shader_addline(buffer, "float att, t;\n");
6571 ambient = shader_glsl_ffp_mcs(settings->ambient_source, "ffp_material.ambient");
6572 diffuse = shader_glsl_ffp_mcs(settings->diffuse_source, "ffp_material.diffuse");
6573 specular = shader_glsl_ffp_mcs(settings->specular_source, "ffp_material.specular");
6574 emissive = shader_glsl_ffp_mcs(settings->emissive_source, "ffp_material.emissive");
6576 for (i = 0; i < MAX_ACTIVE_LIGHTS; ++i)
6578 light_type = (settings->light_type >> WINED3D_FFP_LIGHT_TYPE_SHIFT(i)) & WINED3D_FFP_LIGHT_TYPE_MASK;
6579 switch (light_type)
6581 case WINED3D_LIGHT_POINT:
6582 shader_addline(buffer, "dir = ffp_light[%u].position.xyz - ec_pos.xyz;\n", i);
6583 shader_addline(buffer, "dst.z = dot(dir, dir);\n");
6584 shader_addline(buffer, "dst.y = sqrt(dst.z);\n");
6585 shader_addline(buffer, "dst.x = 1.0;\n");
6586 if (legacy_lighting)
6588 shader_addline(buffer, "dst.y = (ffp_light[%u].range - dst.y) / ffp_light[%u].range;\n", i, i);
6589 shader_addline(buffer, "dst.z = dst.y * dst.y;\n");
6591 else
6593 shader_addline(buffer, "if (dst.y <= ffp_light[%u].range)\n{\n", i);
6595 shader_addline(buffer, "att = dot(dst.xyz, vec3(ffp_light[%u].c_att,"
6596 " ffp_light[%u].l_att, ffp_light[%u].q_att));\n", i, i, i);
6597 if (!legacy_lighting)
6598 shader_addline(buffer, "att = 1.0 / att;\n");
6599 shader_addline(buffer, "ambient += ffp_light[%u].ambient.xyz * att;\n", i);
6600 if (!settings->normal)
6602 if (!legacy_lighting)
6603 shader_addline(buffer, "}\n");
6604 break;
6606 shader_addline(buffer, "dir = normalize(dir);\n");
6607 shader_addline(buffer, "diffuse += (clamp(dot(dir, normal), 0.0, 1.0)"
6608 " * ffp_light[%u].diffuse.xyz) * att;\n", i);
6609 if (settings->localviewer)
6610 shader_addline(buffer, "t = dot(normal, normalize(dir - normalize(ec_pos.xyz)));\n");
6611 else
6612 shader_addline(buffer, "t = dot(normal, normalize(dir + vec3(0.0, 0.0, -1.0)));\n");
6613 shader_addline(buffer, "if (t > 0.0) specular += (pow(t, ffp_material.shininess)"
6614 " * ffp_light[%u].specular) * att;\n", i);
6615 if (!legacy_lighting)
6616 shader_addline(buffer, "}\n");
6617 break;
6619 case WINED3D_LIGHT_SPOT:
6620 shader_addline(buffer, "dir = ffp_light[%u].position.xyz - ec_pos.xyz;\n", i);
6621 shader_addline(buffer, "dst.z = dot(dir, dir);\n");
6622 shader_addline(buffer, "dst.y = sqrt(dst.z);\n");
6623 shader_addline(buffer, "dst.x = 1.0;\n");
6624 if (legacy_lighting)
6626 shader_addline(buffer, "dst.y = (ffp_light[%u].range - dst.y) / ffp_light[%u].range;\n", i, i);
6627 shader_addline(buffer, "dst.z = dst.y * dst.y;\n");
6629 else
6631 shader_addline(buffer, "if (dst.y <= ffp_light[%u].range)\n{\n", i);
6633 shader_addline(buffer, "dir = normalize(dir);\n");
6634 shader_addline(buffer, "t = dot(-dir, normalize(ffp_light[%u].direction));\n", i);
6635 shader_addline(buffer, "if (t > ffp_light[%u].cos_htheta) att = 1.0;\n", i);
6636 shader_addline(buffer, "else if (t <= ffp_light[%u].cos_hphi) att = 0.0;\n", i);
6637 shader_addline(buffer, "else att = pow((t - ffp_light[%u].cos_hphi)"
6638 " / (ffp_light[%u].cos_htheta - ffp_light[%u].cos_hphi), ffp_light[%u].falloff);\n",
6639 i, i, i, i);
6640 if (legacy_lighting)
6641 shader_addline(buffer, "att *= dot(dst.xyz, vec3(ffp_light[%u].c_att,"
6642 " ffp_light[%u].l_att, ffp_light[%u].q_att));\n",
6643 i, i, i);
6644 else
6645 shader_addline(buffer, "att /= dot(dst.xyz, vec3(ffp_light[%u].c_att,"
6646 " ffp_light[%u].l_att, ffp_light[%u].q_att));\n",
6647 i, i, i);
6648 shader_addline(buffer, "ambient += ffp_light[%u].ambient.xyz * att;\n", i);
6649 if (!settings->normal)
6651 if (!legacy_lighting)
6652 shader_addline(buffer, "}\n");
6653 break;
6655 shader_addline(buffer, "diffuse += (clamp(dot(dir, normal), 0.0, 1.0)"
6656 " * ffp_light[%u].diffuse.xyz) * att;\n", i);
6657 if (settings->localviewer)
6658 shader_addline(buffer, "t = dot(normal, normalize(dir - normalize(ec_pos.xyz)));\n");
6659 else
6660 shader_addline(buffer, "t = dot(normal, normalize(dir + vec3(0.0, 0.0, -1.0)));\n");
6661 shader_addline(buffer, "if (t > 0.0) specular += (pow(t, ffp_material.shininess)"
6662 " * ffp_light[%u].specular) * att;\n", i);
6663 if (!legacy_lighting)
6664 shader_addline(buffer, "}\n");
6665 break;
6667 case WINED3D_LIGHT_DIRECTIONAL:
6668 shader_addline(buffer, "ambient += ffp_light[%u].ambient.xyz;\n", i);
6669 if (!settings->normal)
6670 break;
6671 shader_addline(buffer, "dir = normalize(ffp_light[%u].direction.xyz);\n", i);
6672 shader_addline(buffer, "diffuse += clamp(dot(dir, normal), 0.0, 1.0)"
6673 " * ffp_light[%u].diffuse.xyz;\n", i);
6674 /* TODO: In the non-local viewer case the halfvector is constant
6675 * and could be precomputed and stored in a uniform. */
6676 if (settings->localviewer)
6677 shader_addline(buffer, "t = dot(normal, normalize(dir - normalize(ec_pos.xyz)));\n");
6678 else
6679 shader_addline(buffer, "t = dot(normal, normalize(dir + vec3(0.0, 0.0, -1.0)));\n");
6680 shader_addline(buffer, "if (t > 0.0) specular += pow(t, ffp_material.shininess)"
6681 " * ffp_light[%u].specular;\n", i);
6682 break;
6684 case WINED3D_LIGHT_PARALLELPOINT:
6685 shader_addline(buffer, "ambient += ffp_light[%u].ambient.xyz;\n", i);
6686 if (!settings->normal)
6687 break;
6688 shader_addline(buffer, "dir = normalize(ffp_light[%u].position.xyz);\n", i);
6689 shader_addline(buffer, "diffuse += clamp(dot(dir, normal), 0.0, 1.0)"
6690 " * ffp_light[%u].diffuse.xyz;\n", i);
6691 shader_addline(buffer, "t = dot(normal, normalize(dir - normalize(ec_pos.xyz)));\n");
6692 shader_addline(buffer, "if (t > 0.0) specular += pow(t, ffp_material.shininess)"
6693 " * ffp_light[%u].specular;\n", i);
6694 break;
6696 default:
6697 if (light_type)
6698 FIXME("Unhandled light type %#x.\n", light_type);
6699 continue;
6703 shader_addline(buffer, "ffp_varying_diffuse.xyz = %s.xyz * ambient + %s.xyz * diffuse + %s.xyz;\n",
6704 ambient, diffuse, emissive);
6705 shader_addline(buffer, "ffp_varying_diffuse.w = %s.w;\n", diffuse);
6706 shader_addline(buffer, "ffp_varying_specular = %s * specular;\n", specular);
6709 /* Context activation is done by the caller. */
6710 static GLuint shader_glsl_generate_ffp_vertex_shader(struct shader_glsl_priv *priv,
6711 const struct wined3d_ffp_vs_settings *settings, const struct wined3d_gl_info *gl_info)
6713 static const struct attrib_info
6715 const char type[6];
6716 const char name[24];
6718 attrib_info[] =
6720 {"vec4", "ffp_attrib_position"}, /* WINED3D_FFP_POSITION */
6721 {"vec4", "ffp_attrib_blendweight"}, /* WINED3D_FFP_BLENDWEIGHT */
6722 /* TODO: Indexed vertex blending */
6723 {"float", ""}, /* WINED3D_FFP_BLENDINDICES */
6724 {"vec3", "ffp_attrib_normal"}, /* WINED3D_FFP_NORMAL */
6725 {"float", "ffp_attrib_psize"}, /* WINED3D_FFP_PSIZE */
6726 {"vec4", "ffp_attrib_diffuse"}, /* WINED3D_FFP_DIFFUSE */
6727 {"vec4", "ffp_attrib_specular"}, /* WINED3D_FFP_SPECULAR */
6729 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
6730 BOOL legacy_lighting = priv->legacy_lighting;
6731 GLuint shader_obj;
6732 unsigned int i;
6733 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
6734 BOOL output_legacy_fogcoord = legacy_context;
6736 string_buffer_clear(buffer);
6738 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, NULL));
6740 if (shader_glsl_use_explicit_attrib_location(gl_info))
6741 shader_addline(buffer, "#extension GL_ARB_explicit_attrib_location : enable\n");
6743 for (i = 0; i < WINED3D_FFP_ATTRIBS_COUNT; ++i)
6745 const char *type = i < ARRAY_SIZE(attrib_info) ? attrib_info[i].type : "vec4";
6747 if (shader_glsl_use_explicit_attrib_location(gl_info))
6748 shader_addline(buffer, "layout(location = %u) ", i);
6749 shader_addline(buffer, "%s %s vs_in%u;\n", get_attribute_keyword(gl_info), type, i);
6751 shader_addline(buffer, "\n");
6753 shader_addline(buffer, "uniform mat4 ffp_modelview_matrix[%u];\n", MAX_VERTEX_BLENDS);
6754 shader_addline(buffer, "uniform mat4 ffp_projection_matrix;\n");
6755 shader_addline(buffer, "uniform mat3 ffp_normal_matrix;\n");
6756 shader_addline(buffer, "uniform mat4 ffp_texture_matrix[%u];\n", MAX_TEXTURES);
6758 shader_addline(buffer, "uniform struct\n{\n");
6759 shader_addline(buffer, " vec4 emissive;\n");
6760 shader_addline(buffer, " vec4 ambient;\n");
6761 shader_addline(buffer, " vec4 diffuse;\n");
6762 shader_addline(buffer, " vec4 specular;\n");
6763 shader_addline(buffer, " float shininess;\n");
6764 shader_addline(buffer, "} ffp_material;\n");
6766 shader_addline(buffer, "uniform vec3 ffp_light_ambient;\n");
6767 shader_addline(buffer, "uniform struct\n{\n");
6768 shader_addline(buffer, " vec4 diffuse;\n");
6769 shader_addline(buffer, " vec4 specular;\n");
6770 shader_addline(buffer, " vec4 ambient;\n");
6771 shader_addline(buffer, " vec4 position;\n");
6772 shader_addline(buffer, " vec3 direction;\n");
6773 shader_addline(buffer, " float range;\n");
6774 shader_addline(buffer, " float falloff;\n");
6775 shader_addline(buffer, " float c_att;\n");
6776 shader_addline(buffer, " float l_att;\n");
6777 shader_addline(buffer, " float q_att;\n");
6778 shader_addline(buffer, " float cos_htheta;\n");
6779 shader_addline(buffer, " float cos_hphi;\n");
6780 shader_addline(buffer, "} ffp_light[%u];\n", MAX_ACTIVE_LIGHTS);
6782 if (settings->point_size)
6784 shader_addline(buffer, "uniform struct\n{\n");
6785 shader_addline(buffer, " float size;\n");
6786 shader_addline(buffer, " float size_min;\n");
6787 shader_addline(buffer, " float size_max;\n");
6788 shader_addline(buffer, " float c_att;\n");
6789 shader_addline(buffer, " float l_att;\n");
6790 shader_addline(buffer, " float q_att;\n");
6791 shader_addline(buffer, "} ffp_point;\n");
6794 if (legacy_context)
6796 shader_addline(buffer, "vec4 ffp_varying_diffuse;\n");
6797 shader_addline(buffer, "vec4 ffp_varying_specular;\n");
6798 shader_addline(buffer, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
6799 shader_addline(buffer, "float ffp_varying_fogcoord;\n");
6801 else
6803 if (settings->clipping)
6804 shader_addline(buffer, "uniform vec4 clip_planes[%u];\n", gl_info->limits.user_clip_distances);
6806 declare_out_varying(gl_info, buffer, settings->flatshading, "vec4 ffp_varying_diffuse;\n");
6807 declare_out_varying(gl_info, buffer, settings->flatshading, "vec4 ffp_varying_specular;\n");
6808 declare_out_varying(gl_info, buffer, FALSE, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
6809 declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
6812 shader_addline(buffer, "\nvoid main()\n{\n");
6813 shader_addline(buffer, "float m;\n");
6814 shader_addline(buffer, "vec3 r;\n");
6816 for (i = 0; i < ARRAY_SIZE(attrib_info); ++i)
6818 if (attrib_info[i].name[0])
6819 shader_addline(buffer, "%s %s = vs_in%u%s;\n", attrib_info[i].type, attrib_info[i].name,
6820 i, settings->swizzle_map & (1u << i) ? ".zyxw" : "");
6822 for (i = 0; i < MAX_TEXTURES; ++i)
6824 unsigned int coord_idx = settings->texgen[i] & 0x0000ffff;
6825 if ((settings->texgen[i] & 0xffff0000) == WINED3DTSS_TCI_PASSTHRU
6826 && settings->texcoords & (1u << i))
6827 shader_addline(buffer, "vec4 ffp_attrib_texcoord%u = vs_in%u;\n", i, coord_idx + WINED3D_FFP_TEXCOORD0);
6830 shader_addline(buffer, "ffp_attrib_blendweight[%u] = 1.0;\n", settings->vertexblends);
6832 if (settings->transformed)
6834 shader_addline(buffer, "vec4 ec_pos = vec4(ffp_attrib_position.xyz, 1.0);\n");
6835 shader_addline(buffer, "gl_Position = ffp_projection_matrix * ec_pos;\n");
6836 shader_addline(buffer, "if (ffp_attrib_position.w != 0.0) gl_Position /= ffp_attrib_position.w;\n");
6838 else
6840 for (i = 0; i < settings->vertexblends; ++i)
6841 shader_addline(buffer, "ffp_attrib_blendweight[%u] -= ffp_attrib_blendweight[%u];\n", settings->vertexblends, i);
6843 shader_addline(buffer, "vec4 ec_pos = vec4(0.0);\n");
6844 for (i = 0; i < settings->vertexblends + 1; ++i)
6845 shader_addline(buffer, "ec_pos += ffp_attrib_blendweight[%u] * (ffp_modelview_matrix[%u] * ffp_attrib_position);\n", i, i);
6847 shader_addline(buffer, "gl_Position = ffp_projection_matrix * ec_pos;\n");
6848 if (settings->clipping)
6850 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
6851 shader_addline(buffer, "gl_ClipVertex = ec_pos;\n");
6852 else
6853 for (i = 0; i < gl_info->limits.user_clip_distances; ++i)
6854 shader_addline(buffer, "gl_ClipDistance[%u] = dot(ec_pos, clip_planes[%u]);\n", i, i);
6856 shader_addline(buffer, "ec_pos /= ec_pos.w;\n");
6859 shader_addline(buffer, "vec3 normal = vec3(0.0);\n");
6860 if (settings->normal)
6862 if (!settings->vertexblends)
6864 shader_addline(buffer, "normal = ffp_normal_matrix * ffp_attrib_normal;\n");
6866 else
6868 for (i = 0; i < settings->vertexblends + 1; ++i)
6869 shader_addline(buffer, "normal += ffp_attrib_blendweight[%u] * (mat3(ffp_modelview_matrix[%u]) * ffp_attrib_normal);\n", i, i);
6872 if (settings->normalize)
6873 shader_addline(buffer, "normal = normalize(normal);\n");
6876 shader_glsl_ffp_vertex_lighting(buffer, settings, legacy_lighting);
6877 if (legacy_context)
6879 shader_addline(buffer, "gl_FrontColor = ffp_varying_diffuse;\n");
6880 shader_addline(buffer, "gl_FrontSecondaryColor = ffp_varying_specular;\n");
6882 else
6884 shader_addline(buffer, "ffp_varying_diffuse = clamp(ffp_varying_diffuse, 0.0, 1.0);\n");
6885 shader_addline(buffer, "ffp_varying_specular = clamp(ffp_varying_specular, 0.0, 1.0);\n");
6888 for (i = 0; i < MAX_TEXTURES; ++i)
6890 BOOL output_legacy_texcoord = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
6892 switch (settings->texgen[i] & 0xffff0000)
6894 case WINED3DTSS_TCI_PASSTHRU:
6895 if (settings->texcoords & (1u << i))
6896 shader_addline(buffer, "ffp_varying_texcoord[%u] = ffp_texture_matrix[%u] * ffp_attrib_texcoord%u;\n",
6897 i, i, i);
6898 else if (gl_info->limits.glsl_varyings >= wined3d_max_compat_varyings(gl_info))
6899 shader_addline(buffer, "ffp_varying_texcoord[%u] = vec4(0.0);\n", i);
6900 else
6901 output_legacy_texcoord = FALSE;
6902 break;
6904 case WINED3DTSS_TCI_CAMERASPACENORMAL:
6905 shader_addline(buffer, "ffp_varying_texcoord[%u] = ffp_texture_matrix[%u] * vec4(normal, 1.0);\n", i, i);
6906 break;
6908 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
6909 shader_addline(buffer, "ffp_varying_texcoord[%u] = ffp_texture_matrix[%u] * ec_pos;\n", i, i);
6910 break;
6912 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
6913 shader_addline(buffer, "ffp_varying_texcoord[%u] = ffp_texture_matrix[%u]"
6914 " * vec4(reflect(normalize(ec_pos.xyz), normal), 1.0);\n", i, i);
6915 break;
6917 case WINED3DTSS_TCI_SPHEREMAP:
6918 shader_addline(buffer, "r = reflect(normalize(ec_pos.xyz), normal);\n");
6919 shader_addline(buffer, "m = 2.0 * length(vec3(r.x, r.y, r.z + 1.0));\n");
6920 shader_addline(buffer, "ffp_varying_texcoord[%u] = ffp_texture_matrix[%u]"
6921 " * vec4(r.x / m + 0.5, r.y / m + 0.5, 0.0, 1.0);\n", i, i);
6922 break;
6924 default:
6925 ERR("Unhandled texgen %#x.\n", settings->texgen[i]);
6926 break;
6928 if (output_legacy_texcoord)
6929 shader_addline(buffer, "gl_TexCoord[%u] = ffp_varying_texcoord[%u];\n", i, i);
6932 switch (settings->fog_mode)
6934 case WINED3D_FFP_VS_FOG_OFF:
6935 output_legacy_fogcoord = FALSE;
6936 break;
6938 case WINED3D_FFP_VS_FOG_FOGCOORD:
6939 shader_addline(buffer, "ffp_varying_fogcoord = ffp_attrib_specular.w * 255.0;\n");
6940 break;
6942 case WINED3D_FFP_VS_FOG_RANGE:
6943 shader_addline(buffer, "ffp_varying_fogcoord = length(ec_pos.xyz);\n");
6944 break;
6946 case WINED3D_FFP_VS_FOG_DEPTH:
6947 if (settings->ortho_fog)
6949 if (gl_info->supported[ARB_CLIP_CONTROL])
6950 shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z;\n");
6951 else
6952 /* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
6953 shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z * 0.5 + 0.5;\n");
6955 else if (settings->transformed)
6957 shader_addline(buffer, "ffp_varying_fogcoord = ec_pos.z;\n");
6959 else
6961 shader_addline(buffer, "ffp_varying_fogcoord = abs(ec_pos.z);\n");
6963 break;
6965 default:
6966 ERR("Unhandled fog mode %#x.\n", settings->fog_mode);
6967 break;
6969 if (output_legacy_fogcoord)
6970 shader_addline(buffer, "gl_FogFragCoord = ffp_varying_fogcoord;\n");
6972 if (settings->point_size)
6974 shader_addline(buffer, "gl_PointSize = %s / sqrt(ffp_point.c_att"
6975 " + ffp_point.l_att * length(ec_pos.xyz)"
6976 " + ffp_point.q_att * dot(ec_pos.xyz, ec_pos.xyz));\n",
6977 settings->per_vertex_point_size ? "ffp_attrib_psize" : "ffp_point.size");
6978 shader_addline(buffer, "gl_PointSize = clamp(gl_PointSize, ffp_point.size_min, ffp_point.size_max);\n");
6981 shader_addline(buffer, "}\n");
6983 shader_obj = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER));
6984 shader_glsl_compile(gl_info, shader_obj, buffer->buffer);
6986 return shader_obj;
6989 static const char *shader_glsl_get_ffp_fragment_op_arg(struct wined3d_string_buffer *buffer,
6990 DWORD argnum, unsigned int stage, DWORD arg)
6992 const char *ret;
6994 if (arg == ARG_UNUSED)
6995 return "<unused arg>";
6997 switch (arg & WINED3DTA_SELECTMASK)
6999 case WINED3DTA_DIFFUSE:
7000 ret = "ffp_varying_diffuse";
7001 break;
7003 case WINED3DTA_CURRENT:
7004 ret = "ret";
7005 break;
7007 case WINED3DTA_TEXTURE:
7008 switch (stage)
7010 case 0: ret = "tex0"; break;
7011 case 1: ret = "tex1"; break;
7012 case 2: ret = "tex2"; break;
7013 case 3: ret = "tex3"; break;
7014 case 4: ret = "tex4"; break;
7015 case 5: ret = "tex5"; break;
7016 case 6: ret = "tex6"; break;
7017 case 7: ret = "tex7"; break;
7018 default:
7019 ret = "<invalid texture>";
7020 break;
7022 break;
7024 case WINED3DTA_TFACTOR:
7025 ret = "tex_factor";
7026 break;
7028 case WINED3DTA_SPECULAR:
7029 ret = "ffp_varying_specular";
7030 break;
7032 case WINED3DTA_TEMP:
7033 ret = "temp_reg";
7034 break;
7036 case WINED3DTA_CONSTANT:
7037 switch (stage)
7039 case 0: ret = "tss_const0"; break;
7040 case 1: ret = "tss_const1"; break;
7041 case 2: ret = "tss_const2"; break;
7042 case 3: ret = "tss_const3"; break;
7043 case 4: ret = "tss_const4"; break;
7044 case 5: ret = "tss_const5"; break;
7045 case 6: ret = "tss_const6"; break;
7046 case 7: ret = "tss_const7"; break;
7047 default:
7048 ret = "<invalid constant>";
7049 break;
7051 break;
7053 default:
7054 return "<unhandled arg>";
7057 if (arg & WINED3DTA_COMPLEMENT)
7059 shader_addline(buffer, "arg%u = vec4(1.0) - %s;\n", argnum, ret);
7060 if (argnum == 0)
7061 ret = "arg0";
7062 else if (argnum == 1)
7063 ret = "arg1";
7064 else if (argnum == 2)
7065 ret = "arg2";
7068 if (arg & WINED3DTA_ALPHAREPLICATE)
7070 shader_addline(buffer, "arg%u = vec4(%s.w);\n", argnum, ret);
7071 if (argnum == 0)
7072 ret = "arg0";
7073 else if (argnum == 1)
7074 ret = "arg1";
7075 else if (argnum == 2)
7076 ret = "arg2";
7079 return ret;
7082 static void shader_glsl_ffp_fragment_op(struct wined3d_string_buffer *buffer, unsigned int stage, BOOL color,
7083 BOOL alpha, DWORD dst, DWORD op, DWORD dw_arg0, DWORD dw_arg1, DWORD dw_arg2)
7085 const char *dstmask, *dstreg, *arg0, *arg1, *arg2;
7087 if (color && alpha)
7088 dstmask = "";
7089 else if (color)
7090 dstmask = ".xyz";
7091 else
7092 dstmask = ".w";
7094 if (dst == tempreg)
7095 dstreg = "temp_reg";
7096 else
7097 dstreg = "ret";
7099 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, dw_arg0);
7100 arg1 = shader_glsl_get_ffp_fragment_op_arg(buffer, 1, stage, dw_arg1);
7101 arg2 = shader_glsl_get_ffp_fragment_op_arg(buffer, 2, stage, dw_arg2);
7103 switch (op)
7105 case WINED3D_TOP_DISABLE:
7106 break;
7108 case WINED3D_TOP_SELECT_ARG1:
7109 shader_addline(buffer, "%s%s = %s%s;\n", dstreg, dstmask, arg1, dstmask);
7110 break;
7112 case WINED3D_TOP_SELECT_ARG2:
7113 shader_addline(buffer, "%s%s = %s%s;\n", dstreg, dstmask, arg2, dstmask);
7114 break;
7116 case WINED3D_TOP_MODULATE:
7117 shader_addline(buffer, "%s%s = %s%s * %s%s;\n", dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7118 break;
7120 case WINED3D_TOP_MODULATE_4X:
7121 shader_addline(buffer, "%s%s = clamp(%s%s * %s%s * 4.0, 0.0, 1.0);\n",
7122 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7123 break;
7125 case WINED3D_TOP_MODULATE_2X:
7126 shader_addline(buffer, "%s%s = clamp(%s%s * %s%s * 2.0, 0.0, 1.0);\n",
7127 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7128 break;
7130 case WINED3D_TOP_ADD:
7131 shader_addline(buffer, "%s%s = clamp(%s%s + %s%s, 0.0, 1.0);\n",
7132 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7133 break;
7135 case WINED3D_TOP_ADD_SIGNED:
7136 shader_addline(buffer, "%s%s = clamp(%s%s + (%s - vec4(0.5))%s, 0.0, 1.0);\n",
7137 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7138 break;
7140 case WINED3D_TOP_ADD_SIGNED_2X:
7141 shader_addline(buffer, "%s%s = clamp((%s%s + (%s - vec4(0.5))%s) * 2.0, 0.0, 1.0);\n",
7142 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7143 break;
7145 case WINED3D_TOP_SUBTRACT:
7146 shader_addline(buffer, "%s%s = clamp(%s%s - %s%s, 0.0, 1.0);\n",
7147 dstreg, dstmask, arg1, dstmask, arg2, dstmask);
7148 break;
7150 case WINED3D_TOP_ADD_SMOOTH:
7151 shader_addline(buffer, "%s%s = clamp((vec4(1.0) - %s)%s * %s%s + %s%s, 0.0, 1.0);\n",
7152 dstreg, dstmask, arg1, dstmask, arg2, dstmask, arg1, dstmask);
7153 break;
7155 case WINED3D_TOP_BLEND_DIFFUSE_ALPHA:
7156 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, WINED3DTA_DIFFUSE);
7157 shader_addline(buffer, "%s%s = mix(%s%s, %s%s, %s.w);\n",
7158 dstreg, dstmask, arg2, dstmask, arg1, dstmask, arg0);
7159 break;
7161 case WINED3D_TOP_BLEND_TEXTURE_ALPHA:
7162 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, WINED3DTA_TEXTURE);
7163 shader_addline(buffer, "%s%s = mix(%s%s, %s%s, %s.w);\n",
7164 dstreg, dstmask, arg2, dstmask, arg1, dstmask, arg0);
7165 break;
7167 case WINED3D_TOP_BLEND_FACTOR_ALPHA:
7168 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, WINED3DTA_TFACTOR);
7169 shader_addline(buffer, "%s%s = mix(%s%s, %s%s, %s.w);\n",
7170 dstreg, dstmask, arg2, dstmask, arg1, dstmask, arg0);
7171 break;
7173 case WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM:
7174 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, WINED3DTA_TEXTURE);
7175 shader_addline(buffer, "%s%s = clamp(%s%s * (1.0 - %s.w) + %s%s, 0.0, 1.0);\n",
7176 dstreg, dstmask, arg2, dstmask, arg0, arg1, dstmask);
7177 break;
7179 case WINED3D_TOP_BLEND_CURRENT_ALPHA:
7180 arg0 = shader_glsl_get_ffp_fragment_op_arg(buffer, 0, stage, WINED3DTA_CURRENT);
7181 shader_addline(buffer, "%s%s = mix(%s%s, %s%s, %s.w);\n",
7182 dstreg, dstmask, arg2, dstmask, arg1, dstmask, arg0);
7183 break;
7185 case WINED3D_TOP_MODULATE_ALPHA_ADD_COLOR:
7186 shader_addline(buffer, "%s%s = clamp(%s%s * %s.w + %s%s, 0.0, 1.0);\n",
7187 dstreg, dstmask, arg2, dstmask, arg1, arg1, dstmask);
7188 break;
7190 case WINED3D_TOP_MODULATE_COLOR_ADD_ALPHA:
7191 shader_addline(buffer, "%s%s = clamp(%s%s * %s%s + %s.w, 0.0, 1.0);\n",
7192 dstreg, dstmask, arg1, dstmask, arg2, dstmask, arg1);
7193 break;
7195 case WINED3D_TOP_MODULATE_INVALPHA_ADD_COLOR:
7196 shader_addline(buffer, "%s%s = clamp(%s%s * (1.0 - %s.w) + %s%s, 0.0, 1.0);\n",
7197 dstreg, dstmask, arg2, dstmask, arg1, arg1, dstmask);
7198 break;
7199 case WINED3D_TOP_MODULATE_INVCOLOR_ADD_ALPHA:
7200 shader_addline(buffer, "%s%s = clamp((vec4(1.0) - %s)%s * %s%s + %s.w, 0.0, 1.0);\n",
7201 dstreg, dstmask, arg1, dstmask, arg2, dstmask, arg1);
7202 break;
7204 case WINED3D_TOP_BUMPENVMAP:
7205 case WINED3D_TOP_BUMPENVMAP_LUMINANCE:
7206 /* These are handled in the first pass, nothing to do. */
7207 break;
7209 case WINED3D_TOP_DOTPRODUCT3:
7210 shader_addline(buffer, "%s%s = vec4(clamp(dot(%s.xyz - 0.5, %s.xyz - 0.5) * 4.0, 0.0, 1.0))%s;\n",
7211 dstreg, dstmask, arg1, arg2, dstmask);
7212 break;
7214 case WINED3D_TOP_MULTIPLY_ADD:
7215 shader_addline(buffer, "%s%s = clamp(%s%s * %s%s + %s%s, 0.0, 1.0);\n",
7216 dstreg, dstmask, arg1, dstmask, arg2, dstmask, arg0, dstmask);
7217 break;
7219 case WINED3D_TOP_LERP:
7220 /* MSDN isn't quite right here. */
7221 shader_addline(buffer, "%s%s = mix(%s%s, %s%s, %s%s);\n",
7222 dstreg, dstmask, arg2, dstmask, arg1, dstmask, arg0, dstmask);
7223 break;
7225 default:
7226 FIXME("Unhandled operation %#x.\n", op);
7227 break;
7231 /* Context activation is done by the caller. */
7232 static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *priv,
7233 const struct ffp_frag_settings *settings, const struct wined3d_gl_info *gl_info)
7235 struct wined3d_string_buffer *tex_reg_name = string_buffer_get(&priv->string_buffers);
7236 enum wined3d_cmp_func alpha_test_func = settings->alpha_test_func + 1;
7237 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
7238 struct wined3d_string_buffer *buffer = &priv->shader_buffer;
7239 BYTE lum_map = 0, bump_map = 0, tex_map = 0, tss_const_map = 0;
7240 BOOL tempreg_used = FALSE, tfactor_used = FALSE;
7241 UINT lowest_disabled_stage;
7242 GLuint shader_id;
7243 DWORD arg0, arg1, arg2;
7244 unsigned int stage;
7246 string_buffer_clear(buffer);
7248 /* Find out which textures are read */
7249 for (stage = 0; stage < MAX_TEXTURES; ++stage)
7251 if (settings->op[stage].cop == WINED3D_TOP_DISABLE)
7252 break;
7254 arg0 = settings->op[stage].carg0 & WINED3DTA_SELECTMASK;
7255 arg1 = settings->op[stage].carg1 & WINED3DTA_SELECTMASK;
7256 arg2 = settings->op[stage].carg2 & WINED3DTA_SELECTMASK;
7258 if (arg0 == WINED3DTA_TEXTURE || arg1 == WINED3DTA_TEXTURE || arg2 == WINED3DTA_TEXTURE
7259 || (stage == 0 && settings->color_key_enabled))
7260 tex_map |= 1u << stage;
7261 if (arg0 == WINED3DTA_TFACTOR || arg1 == WINED3DTA_TFACTOR || arg2 == WINED3DTA_TFACTOR)
7262 tfactor_used = TRUE;
7263 if (arg0 == WINED3DTA_TEMP || arg1 == WINED3DTA_TEMP || arg2 == WINED3DTA_TEMP)
7264 tempreg_used = TRUE;
7265 if (settings->op[stage].dst == tempreg)
7266 tempreg_used = TRUE;
7267 if (arg0 == WINED3DTA_CONSTANT || arg1 == WINED3DTA_CONSTANT || arg2 == WINED3DTA_CONSTANT)
7268 tss_const_map |= 1u << stage;
7270 switch (settings->op[stage].cop)
7272 case WINED3D_TOP_BUMPENVMAP_LUMINANCE:
7273 lum_map |= 1u << stage;
7274 /* fall through */
7275 case WINED3D_TOP_BUMPENVMAP:
7276 bump_map |= 1u << stage;
7277 /* fall through */
7278 case WINED3D_TOP_BLEND_TEXTURE_ALPHA:
7279 case WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM:
7280 tex_map |= 1u << stage;
7281 break;
7283 case WINED3D_TOP_BLEND_FACTOR_ALPHA:
7284 tfactor_used = TRUE;
7285 break;
7287 default:
7288 break;
7291 if (settings->op[stage].aop == WINED3D_TOP_DISABLE)
7292 continue;
7294 arg0 = settings->op[stage].aarg0 & WINED3DTA_SELECTMASK;
7295 arg1 = settings->op[stage].aarg1 & WINED3DTA_SELECTMASK;
7296 arg2 = settings->op[stage].aarg2 & WINED3DTA_SELECTMASK;
7298 if (arg0 == WINED3DTA_TEXTURE || arg1 == WINED3DTA_TEXTURE || arg2 == WINED3DTA_TEXTURE)
7299 tex_map |= 1u << stage;
7300 if (arg0 == WINED3DTA_TFACTOR || arg1 == WINED3DTA_TFACTOR || arg2 == WINED3DTA_TFACTOR)
7301 tfactor_used = TRUE;
7302 if (arg0 == WINED3DTA_TEMP || arg1 == WINED3DTA_TEMP || arg2 == WINED3DTA_TEMP)
7303 tempreg_used = TRUE;
7304 if (arg0 == WINED3DTA_CONSTANT || arg1 == WINED3DTA_CONSTANT || arg2 == WINED3DTA_CONSTANT)
7305 tss_const_map |= 1u << stage;
7307 lowest_disabled_stage = stage;
7309 shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, NULL));
7311 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
7312 shader_addline(buffer, "#extension GL_ARB_texture_rectangle : enable\n");
7314 if (!needs_legacy_glsl_syntax(gl_info))
7315 shader_addline(buffer, "out vec4 ps_out[1];\n");
7317 shader_addline(buffer, "vec4 tmp0, tmp1;\n");
7318 shader_addline(buffer, "vec4 ret;\n");
7319 if (tempreg_used || settings->sRGB_write)
7320 shader_addline(buffer, "vec4 temp_reg = vec4(0.0);\n");
7321 shader_addline(buffer, "vec4 arg0, arg1, arg2;\n");
7323 for (stage = 0; stage < MAX_TEXTURES; ++stage)
7325 if (tss_const_map & (1u << stage))
7326 shader_addline(buffer, "uniform vec4 tss_const%u;\n", stage);
7328 if (!(tex_map & (1u << stage)))
7329 continue;
7331 switch (settings->op[stage].tex_type)
7333 case WINED3D_GL_RES_TYPE_TEX_1D:
7334 shader_addline(buffer, "uniform sampler1D ps_sampler%u;\n", stage);
7335 break;
7336 case WINED3D_GL_RES_TYPE_TEX_2D:
7337 shader_addline(buffer, "uniform sampler2D ps_sampler%u;\n", stage);
7338 break;
7339 case WINED3D_GL_RES_TYPE_TEX_3D:
7340 shader_addline(buffer, "uniform sampler3D ps_sampler%u;\n", stage);
7341 break;
7342 case WINED3D_GL_RES_TYPE_TEX_CUBE:
7343 shader_addline(buffer, "uniform samplerCube ps_sampler%u;\n", stage);
7344 break;
7345 case WINED3D_GL_RES_TYPE_TEX_RECT:
7346 shader_addline(buffer, "uniform sampler2DRect ps_sampler%u;\n", stage);
7347 break;
7348 default:
7349 FIXME("Unhandled sampler type %#x.\n", settings->op[stage].tex_type);
7350 break;
7353 shader_addline(buffer, "vec4 tex%u;\n", stage);
7355 if (!(bump_map & (1u << stage)))
7356 continue;
7357 shader_addline(buffer, "uniform mat2 bumpenv_mat%u;\n", stage);
7359 if (!(lum_map & (1u << stage)))
7360 continue;
7361 shader_addline(buffer, "uniform float bumpenv_lum_scale%u;\n", stage);
7362 shader_addline(buffer, "uniform float bumpenv_lum_offset%u;\n", stage);
7364 if (tfactor_used)
7365 shader_addline(buffer, "uniform vec4 tex_factor;\n");
7366 if (settings->color_key_enabled)
7367 shader_addline(buffer, "uniform vec4 color_key[2];\n");
7368 shader_addline(buffer, "uniform vec4 specular_enable;\n");
7370 if (settings->sRGB_write)
7372 shader_addline(buffer, "const vec4 srgb_const0 = ");
7373 shader_glsl_append_imm_vec4(buffer, wined3d_srgb_const0);
7374 shader_addline(buffer, ";\n");
7375 shader_addline(buffer, "const vec4 srgb_const1 = ");
7376 shader_glsl_append_imm_vec4(buffer, wined3d_srgb_const1);
7377 shader_addline(buffer, ";\n");
7380 shader_addline(buffer, "uniform struct\n{\n");
7381 shader_addline(buffer, " vec4 color;\n");
7382 shader_addline(buffer, " float density;\n");
7383 shader_addline(buffer, " float end;\n");
7384 shader_addline(buffer, " float scale;\n");
7385 shader_addline(buffer, "} ffp_fog;\n");
7387 if (alpha_test_func != WINED3D_CMP_ALWAYS)
7388 shader_addline(buffer, "uniform float alpha_test_ref;\n");
7390 if (legacy_context)
7392 shader_addline(buffer, "vec4 ffp_varying_diffuse;\n");
7393 shader_addline(buffer, "vec4 ffp_varying_specular;\n");
7394 shader_addline(buffer, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
7395 shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
7396 shader_addline(buffer, "float ffp_varying_fogcoord;\n");
7398 else
7400 declare_in_varying(gl_info, buffer, settings->flatshading, "vec4 ffp_varying_diffuse;\n");
7401 declare_in_varying(gl_info, buffer, settings->flatshading, "vec4 ffp_varying_specular;\n");
7402 declare_in_varying(gl_info, buffer, FALSE, "vec4 ffp_varying_texcoord[%u];\n", MAX_TEXTURES);
7403 shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
7404 declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
7407 shader_addline(buffer, "void main()\n{\n");
7409 if (legacy_context)
7411 shader_addline(buffer, "ffp_varying_diffuse = gl_Color;\n");
7412 shader_addline(buffer, "ffp_varying_specular = gl_SecondaryColor;\n");
7415 for (stage = 0; stage < MAX_TEXTURES; ++stage)
7417 if (tex_map & (1u << stage))
7419 if (settings->pointsprite)
7420 shader_addline(buffer, "ffp_texcoord[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n", stage);
7421 else if (settings->texcoords_initialized & (1u << stage))
7422 shader_addline(buffer, "ffp_texcoord[%u] = %s[%u];\n",
7423 stage, legacy_context ? "gl_TexCoord" : "ffp_varying_texcoord", stage);
7424 else
7425 shader_addline(buffer, "ffp_texcoord[%u] = vec4(0.0);\n", stage);
7429 if (legacy_context && settings->fog != WINED3D_FFP_PS_FOG_OFF)
7430 shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n");
7432 if (lowest_disabled_stage < 7 && settings->emul_clipplanes)
7433 shader_addline(buffer, "if (any(lessThan(ffp_texcoord[7], vec4(0.0)))) discard;\n");
7435 /* Generate texture sampling instructions */
7436 for (stage = 0; stage < MAX_TEXTURES && settings->op[stage].cop != WINED3D_TOP_DISABLE; ++stage)
7438 const char *texture_function, *coord_mask;
7439 BOOL proj;
7441 if (!(tex_map & (1u << stage)))
7442 continue;
7444 if (settings->op[stage].projected == proj_none)
7446 proj = FALSE;
7448 else if (settings->op[stage].projected == proj_count4
7449 || settings->op[stage].projected == proj_count3)
7451 proj = TRUE;
7453 else
7455 FIXME("Unexpected projection mode %d\n", settings->op[stage].projected);
7456 proj = TRUE;
7459 if (settings->op[stage].tex_type == WINED3D_GL_RES_TYPE_TEX_CUBE)
7460 proj = FALSE;
7462 switch (settings->op[stage].tex_type)
7464 case WINED3D_GL_RES_TYPE_TEX_1D:
7465 if (proj)
7467 texture_function = "texture1DProj";
7468 coord_mask = "xw";
7470 else
7472 texture_function = "texture1D";
7473 coord_mask = "x";
7475 break;
7476 case WINED3D_GL_RES_TYPE_TEX_2D:
7477 if (proj)
7479 texture_function = "texture2DProj";
7480 coord_mask = "xyw";
7482 else
7484 texture_function = "texture2D";
7485 coord_mask = "xy";
7487 break;
7488 case WINED3D_GL_RES_TYPE_TEX_3D:
7489 if (proj)
7491 texture_function = "texture3DProj";
7492 coord_mask = "xyzw";
7494 else
7496 texture_function = "texture3D";
7497 coord_mask = "xyz";
7499 break;
7500 case WINED3D_GL_RES_TYPE_TEX_CUBE:
7501 texture_function = "textureCube";
7502 coord_mask = "xyz";
7503 break;
7504 case WINED3D_GL_RES_TYPE_TEX_RECT:
7505 if (proj)
7507 texture_function = "texture2DRectProj";
7508 coord_mask = "xyw";
7510 else
7512 texture_function = "texture2DRect";
7513 coord_mask = "xy";
7515 break;
7516 default:
7517 FIXME("Unhandled texture type %#x.\n", settings->op[stage].tex_type);
7518 texture_function = "";
7519 coord_mask = "xyzw";
7520 break;
7522 if (!needs_legacy_glsl_syntax(gl_info))
7523 texture_function = proj ? "textureProj" : "texture";
7525 if (stage > 0
7526 && (settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP
7527 || settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE))
7529 shader_addline(buffer, "ret.xy = bumpenv_mat%u * tex%u.xy;\n", stage - 1, stage - 1);
7531 /* With projective textures, texbem only divides the static
7532 * texture coord, not the displacement, so multiply the
7533 * displacement with the dividing parameter before passing it to
7534 * TXP. */
7535 if (settings->op[stage].projected != proj_none)
7537 if (settings->op[stage].projected == proj_count4)
7539 shader_addline(buffer, "ret.xy = (ret.xy * ffp_texcoord[%u].w) + ffp_texcoord[%u].xy;\n",
7540 stage, stage);
7541 shader_addline(buffer, "ret.zw = ffp_texcoord[%u].ww;\n", stage);
7543 else
7545 shader_addline(buffer, "ret.xy = (ret.xy * ffp_texcoord[%u].z) + ffp_texcoord[%u].xy;\n",
7546 stage, stage);
7547 shader_addline(buffer, "ret.zw = ffp_texcoord[%u].zz;\n", stage);
7550 else
7552 shader_addline(buffer, "ret = ffp_texcoord[%u] + ret.xyxy;\n", stage);
7555 shader_addline(buffer, "tex%u = %s(ps_sampler%u, ret.%s);\n",
7556 stage, texture_function, stage, coord_mask);
7558 if (settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
7559 shader_addline(buffer, "tex%u *= clamp(tex%u.z * bumpenv_lum_scale%u + bumpenv_lum_offset%u, 0.0, 1.0);\n",
7560 stage, stage - 1, stage - 1, stage - 1);
7562 else if (settings->op[stage].projected == proj_count3)
7564 shader_addline(buffer, "tex%u = %s(ps_sampler%u, ffp_texcoord[%u].xyz);\n",
7565 stage, texture_function, stage, stage);
7567 else
7569 shader_addline(buffer, "tex%u = %s(ps_sampler%u, ffp_texcoord[%u].%s);\n",
7570 stage, texture_function, stage, stage, coord_mask);
7573 string_buffer_sprintf(tex_reg_name, "tex%u", stage);
7574 shader_glsl_color_correction_ext(buffer, tex_reg_name->buffer, WINED3DSP_WRITEMASK_ALL,
7575 settings->op[stage].color_fixup);
7578 if (settings->color_key_enabled)
7580 shader_addline(buffer, "if (all(greaterThanEqual(tex0, color_key[0])) && all(lessThan(tex0, color_key[1])))\n");
7581 shader_addline(buffer, " discard;\n");
7584 shader_addline(buffer, "ret = ffp_varying_diffuse;\n");
7586 /* Generate the main shader */
7587 for (stage = 0; stage < MAX_TEXTURES; ++stage)
7589 BOOL op_equal;
7591 if (settings->op[stage].cop == WINED3D_TOP_DISABLE)
7592 break;
7594 if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG1
7595 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG1)
7596 op_equal = settings->op[stage].carg1 == settings->op[stage].aarg1;
7597 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG1
7598 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG2)
7599 op_equal = settings->op[stage].carg1 == settings->op[stage].aarg2;
7600 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG2
7601 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG1)
7602 op_equal = settings->op[stage].carg2 == settings->op[stage].aarg1;
7603 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG2
7604 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG2)
7605 op_equal = settings->op[stage].carg2 == settings->op[stage].aarg2;
7606 else
7607 op_equal = settings->op[stage].aop == settings->op[stage].cop
7608 && settings->op[stage].carg0 == settings->op[stage].aarg0
7609 && settings->op[stage].carg1 == settings->op[stage].aarg1
7610 && settings->op[stage].carg2 == settings->op[stage].aarg2;
7612 if (settings->op[stage].aop == WINED3D_TOP_DISABLE)
7614 shader_glsl_ffp_fragment_op(buffer, stage, TRUE, FALSE, settings->op[stage].dst,
7615 settings->op[stage].cop, settings->op[stage].carg0,
7616 settings->op[stage].carg1, settings->op[stage].carg2);
7618 else if (op_equal)
7620 shader_glsl_ffp_fragment_op(buffer, stage, TRUE, TRUE, settings->op[stage].dst,
7621 settings->op[stage].cop, settings->op[stage].carg0,
7622 settings->op[stage].carg1, settings->op[stage].carg2);
7624 else if (settings->op[stage].cop != WINED3D_TOP_BUMPENVMAP
7625 && settings->op[stage].cop != WINED3D_TOP_BUMPENVMAP_LUMINANCE)
7627 shader_glsl_ffp_fragment_op(buffer, stage, TRUE, FALSE, settings->op[stage].dst,
7628 settings->op[stage].cop, settings->op[stage].carg0,
7629 settings->op[stage].carg1, settings->op[stage].carg2);
7630 shader_glsl_ffp_fragment_op(buffer, stage, FALSE, TRUE, settings->op[stage].dst,
7631 settings->op[stage].aop, settings->op[stage].aarg0,
7632 settings->op[stage].aarg1, settings->op[stage].aarg2);
7636 shader_addline(buffer, "%s[0] = ffp_varying_specular * specular_enable + ret;\n",
7637 get_fragment_output(gl_info));
7639 if (settings->sRGB_write)
7640 shader_glsl_generate_srgb_write_correction(buffer, gl_info);
7642 shader_glsl_generate_fog_code(buffer, gl_info, settings->fog);
7644 shader_glsl_generate_alpha_test(buffer, gl_info, alpha_test_func);
7646 shader_addline(buffer, "}\n");
7648 shader_id = GL_EXTCALL(glCreateShader(GL_FRAGMENT_SHADER));
7649 shader_glsl_compile(gl_info, shader_id, buffer->buffer);
7651 string_buffer_release(&priv->string_buffers, tex_reg_name);
7652 return shader_id;
7655 static struct glsl_ffp_vertex_shader *shader_glsl_find_ffp_vertex_shader(struct shader_glsl_priv *priv,
7656 const struct wined3d_gl_info *gl_info, const struct wined3d_ffp_vs_settings *settings)
7658 struct glsl_ffp_vertex_shader *shader;
7659 const struct wine_rb_entry *entry;
7661 if ((entry = wine_rb_get(&priv->ffp_vertex_shaders, settings)))
7662 return WINE_RB_ENTRY_VALUE(entry, struct glsl_ffp_vertex_shader, desc.entry);
7664 if (!(shader = HeapAlloc(GetProcessHeap(), 0, sizeof(*shader))))
7665 return NULL;
7667 shader->desc.settings = *settings;
7668 shader->id = shader_glsl_generate_ffp_vertex_shader(priv, settings, gl_info);
7669 list_init(&shader->linked_programs);
7670 if (wine_rb_put(&priv->ffp_vertex_shaders, &shader->desc.settings, &shader->desc.entry) == -1)
7671 ERR("Failed to insert ffp vertex shader.\n");
7673 return shader;
7676 static struct glsl_ffp_fragment_shader *shader_glsl_find_ffp_fragment_shader(struct shader_glsl_priv *priv,
7677 const struct wined3d_gl_info *gl_info, const struct ffp_frag_settings *args)
7679 struct glsl_ffp_fragment_shader *glsl_desc;
7680 const struct ffp_frag_desc *desc;
7682 if ((desc = find_ffp_frag_shader(&priv->ffp_fragment_shaders, args)))
7683 return CONTAINING_RECORD(desc, struct glsl_ffp_fragment_shader, entry);
7685 if (!(glsl_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*glsl_desc))))
7686 return NULL;
7688 glsl_desc->entry.settings = *args;
7689 glsl_desc->id = shader_glsl_generate_ffp_fragment_shader(priv, args, gl_info);
7690 list_init(&glsl_desc->linked_programs);
7691 add_ffp_frag_shader(&priv->ffp_fragment_shaders, &glsl_desc->entry);
7693 return glsl_desc;
7697 static void shader_glsl_init_vs_uniform_locations(const struct wined3d_gl_info *gl_info,
7698 struct shader_glsl_priv *priv, GLuint program_id, struct glsl_vs_program *vs, unsigned int vs_c_count)
7700 unsigned int i;
7701 struct wined3d_string_buffer *name = string_buffer_get(&priv->string_buffers);
7703 for (i = 0; i < vs_c_count; ++i)
7705 string_buffer_sprintf(name, "vs_c[%u]", i);
7706 vs->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7708 memset(&vs->uniform_f_locations[vs_c_count], 0xff, (WINED3D_MAX_VS_CONSTS_F - vs_c_count) * sizeof(GLuint));
7710 for (i = 0; i < WINED3D_MAX_CONSTS_I; ++i)
7712 string_buffer_sprintf(name, "vs_i[%u]", i);
7713 vs->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7716 for (i = 0; i < WINED3D_MAX_CONSTS_B; ++i)
7718 string_buffer_sprintf(name, "vs_b[%u]", i);
7719 vs->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7722 vs->pos_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "pos_fixup"));
7724 for (i = 0; i < MAX_VERTEX_BLENDS; ++i)
7726 string_buffer_sprintf(name, "ffp_modelview_matrix[%u]", i);
7727 vs->modelview_matrix_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7729 vs->projection_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_projection_matrix"));
7730 vs->normal_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_normal_matrix"));
7731 for (i = 0; i < MAX_TEXTURES; ++i)
7733 string_buffer_sprintf(name, "ffp_texture_matrix[%u]", i);
7734 vs->texture_matrix_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7736 vs->material_ambient_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_material.ambient"));
7737 vs->material_diffuse_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_material.diffuse"));
7738 vs->material_specular_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_material.specular"));
7739 vs->material_emissive_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_material.emissive"));
7740 vs->material_shininess_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_material.shininess"));
7741 vs->light_ambient_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_light_ambient"));
7742 for (i = 0; i < MAX_ACTIVE_LIGHTS; ++i)
7744 string_buffer_sprintf(name, "ffp_light[%u].diffuse", i);
7745 vs->light_location[i].diffuse = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7746 string_buffer_sprintf(name, "ffp_light[%u].specular", i);
7747 vs->light_location[i].specular = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7748 string_buffer_sprintf(name, "ffp_light[%u].ambient", i);
7749 vs->light_location[i].ambient = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7750 string_buffer_sprintf(name, "ffp_light[%u].position", i);
7751 vs->light_location[i].position = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7752 string_buffer_sprintf(name, "ffp_light[%u].direction", i);
7753 vs->light_location[i].direction = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7754 string_buffer_sprintf(name, "ffp_light[%u].range", i);
7755 vs->light_location[i].range = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7756 string_buffer_sprintf(name, "ffp_light[%u].falloff", i);
7757 vs->light_location[i].falloff = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7758 string_buffer_sprintf(name, "ffp_light[%u].c_att", i);
7759 vs->light_location[i].c_att = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7760 string_buffer_sprintf(name, "ffp_light[%u].l_att", i);
7761 vs->light_location[i].l_att = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7762 string_buffer_sprintf(name, "ffp_light[%u].q_att", i);
7763 vs->light_location[i].q_att = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7764 string_buffer_sprintf(name, "ffp_light[%u].cos_htheta", i);
7765 vs->light_location[i].cos_htheta = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7766 string_buffer_sprintf(name, "ffp_light[%u].cos_hphi", i);
7767 vs->light_location[i].cos_hphi = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7769 vs->pointsize_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.size"));
7770 vs->pointsize_min_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.size_min"));
7771 vs->pointsize_max_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.size_max"));
7772 vs->pointsize_c_att_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.c_att"));
7773 vs->pointsize_l_att_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.l_att"));
7774 vs->pointsize_q_att_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_point.q_att"));
7775 vs->clip_planes_location = GL_EXTCALL(glGetUniformLocation(program_id, "clip_planes"));
7777 string_buffer_release(&priv->string_buffers, name);
7780 static void shader_glsl_init_gs_uniform_locations(const struct wined3d_gl_info *gl_info,
7781 struct shader_glsl_priv *priv, GLuint program_id, struct glsl_gs_program *gs)
7783 gs->pos_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "pos_fixup"));
7786 static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *gl_info,
7787 struct shader_glsl_priv *priv, GLuint program_id, struct glsl_ps_program *ps, unsigned int ps_c_count)
7789 unsigned int i;
7790 struct wined3d_string_buffer *name = string_buffer_get(&priv->string_buffers);
7792 for (i = 0; i < ps_c_count; ++i)
7794 string_buffer_sprintf(name, "ps_c[%u]", i);
7795 ps->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7797 memset(&ps->uniform_f_locations[ps_c_count], 0xff, (WINED3D_MAX_PS_CONSTS_F - ps_c_count) * sizeof(GLuint));
7799 for (i = 0; i < WINED3D_MAX_CONSTS_I; ++i)
7801 string_buffer_sprintf(name, "ps_i[%u]", i);
7802 ps->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7805 for (i = 0; i < WINED3D_MAX_CONSTS_B; ++i)
7807 string_buffer_sprintf(name, "ps_b[%u]", i);
7808 ps->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7811 for (i = 0; i < MAX_TEXTURES; ++i)
7813 string_buffer_sprintf(name, "bumpenv_mat%u", i);
7814 ps->bumpenv_mat_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7815 string_buffer_sprintf(name, "bumpenv_lum_scale%u", i);
7816 ps->bumpenv_lum_scale_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7817 string_buffer_sprintf(name, "bumpenv_lum_offset%u", i);
7818 ps->bumpenv_lum_offset_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7819 string_buffer_sprintf(name, "tss_const%u", i);
7820 ps->tss_constant_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
7823 ps->tex_factor_location = GL_EXTCALL(glGetUniformLocation(program_id, "tex_factor"));
7824 ps->specular_enable_location = GL_EXTCALL(glGetUniformLocation(program_id, "specular_enable"));
7826 ps->fog_color_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.color"));
7827 ps->fog_density_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.density"));
7828 ps->fog_end_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.end"));
7829 ps->fog_scale_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.scale"));
7831 ps->alpha_test_ref_location = GL_EXTCALL(glGetUniformLocation(program_id, "alpha_test_ref"));
7833 ps->np2_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "ps_samplerNP2Fixup"));
7834 ps->ycorrection_location = GL_EXTCALL(glGetUniformLocation(program_id, "ycorrection"));
7835 ps->color_key_location = GL_EXTCALL(glGetUniformLocation(program_id, "color_key"));
7837 string_buffer_release(&priv->string_buffers, name);
7840 static void shader_glsl_init_uniform_block_bindings(const struct wined3d_gl_info *gl_info,
7841 struct shader_glsl_priv *priv, GLuint program_id,
7842 const struct wined3d_shader_reg_maps *reg_maps)
7844 struct wined3d_string_buffer *name = string_buffer_get(&priv->string_buffers);
7845 const char *prefix = shader_glsl_get_prefix(reg_maps->shader_version.type);
7846 unsigned int i, base, count;
7847 GLuint block_idx;
7849 wined3d_gl_limits_get_uniform_block_range(&gl_info->limits, reg_maps->shader_version.type, &base, &count);
7850 for (i = 0; i < count; ++i)
7852 if (!reg_maps->cb_sizes[i])
7853 continue;
7855 string_buffer_sprintf(name, "block_%s_cb%u", prefix, i);
7856 block_idx = GL_EXTCALL(glGetUniformBlockIndex(program_id, name->buffer));
7857 GL_EXTCALL(glUniformBlockBinding(program_id, block_idx, base + i));
7859 checkGLcall("glUniformBlockBinding");
7860 string_buffer_release(&priv->string_buffers, name);
7863 /* Context activation is done by the caller. */
7864 static void set_glsl_shader_program(const struct wined3d_context *context, const struct wined3d_state *state,
7865 struct shader_glsl_priv *priv, struct glsl_context_data *ctx_data)
7867 const struct wined3d_gl_info *gl_info = context->gl_info;
7868 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
7869 const struct ps_np2fixup_info *np2fixup_info = NULL;
7870 struct glsl_shader_prog_link *entry = NULL;
7871 struct wined3d_shader *vshader = NULL;
7872 struct wined3d_shader *gshader = NULL;
7873 struct wined3d_shader *pshader = NULL;
7874 GLuint program_id;
7875 GLuint reorder_shader_id = 0;
7876 unsigned int i;
7877 GLuint vs_id = 0;
7878 GLuint gs_id = 0;
7879 GLuint ps_id = 0;
7880 struct list *ps_list, *vs_list;
7881 WORD attribs_map;
7882 struct wined3d_string_buffer *tmp_name;
7884 if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_VERTEX)) && ctx_data->glsl_program)
7886 vs_id = ctx_data->glsl_program->vs.id;
7887 vs_list = &ctx_data->glsl_program->vs.shader_entry;
7889 if (use_vs(state))
7891 vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
7892 gshader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
7894 if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_GEOMETRY))
7895 && ctx_data->glsl_program->gs.id)
7897 gs_id = ctx_data->glsl_program->gs.id;
7899 else if (gshader)
7901 struct gs_compile_args args;
7903 find_gs_compile_args(state, gshader, &args);
7904 gs_id = find_glsl_geometry_shader(context, priv, gshader, &args);
7908 else if (use_vs(state))
7910 struct vs_compile_args vs_compile_args;
7912 vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
7913 gshader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
7915 find_vs_compile_args(state, vshader, context->stream_info.swizzle_map, &vs_compile_args, d3d_info);
7916 vs_id = find_glsl_vshader(context, priv, vshader, &vs_compile_args);
7917 vs_list = &vshader->linked_programs;
7919 if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_GEOMETRY))
7920 && ctx_data->glsl_program->gs.id)
7922 gs_id = ctx_data->glsl_program->gs.id;
7924 else if (gshader)
7926 struct gs_compile_args gs_compile_args;
7928 find_gs_compile_args(state, gshader, &gs_compile_args);
7929 gs_id = find_glsl_geometry_shader(context, priv, gshader, &gs_compile_args);
7932 else if (priv->vertex_pipe == &glsl_vertex_pipe)
7934 struct glsl_ffp_vertex_shader *ffp_shader;
7935 struct wined3d_ffp_vs_settings settings;
7937 wined3d_ffp_get_vs_settings(context, state, &settings);
7938 ffp_shader = shader_glsl_find_ffp_vertex_shader(priv, gl_info, &settings);
7939 vs_id = ffp_shader->id;
7940 vs_list = &ffp_shader->linked_programs;
7943 if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_PIXEL)) && ctx_data->glsl_program)
7945 ps_id = ctx_data->glsl_program->ps.id;
7946 ps_list = &ctx_data->glsl_program->ps.shader_entry;
7948 if (use_ps(state))
7949 pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
7951 else if (use_ps(state))
7953 struct ps_compile_args ps_compile_args;
7954 pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
7955 find_ps_compile_args(state, pshader, context->stream_info.position_transformed, &ps_compile_args, context);
7956 ps_id = find_glsl_pshader(context, &priv->shader_buffer, &priv->string_buffers,
7957 pshader, &ps_compile_args, &np2fixup_info);
7958 ps_list = &pshader->linked_programs;
7960 else if (priv->fragment_pipe == &glsl_fragment_pipe)
7962 struct glsl_ffp_fragment_shader *ffp_shader;
7963 struct ffp_frag_settings settings;
7965 gen_ffp_frag_op(context, state, &settings, FALSE);
7966 ffp_shader = shader_glsl_find_ffp_fragment_shader(priv, gl_info, &settings);
7967 ps_id = ffp_shader->id;
7968 ps_list = &ffp_shader->linked_programs;
7971 if ((!vs_id && !gs_id && !ps_id) || (entry = get_glsl_program_entry(priv, vs_id, gs_id, ps_id)))
7973 ctx_data->glsl_program = entry;
7974 return;
7977 /* If we get to this point, then no matching program exists, so we create one */
7978 program_id = GL_EXTCALL(glCreateProgram());
7979 TRACE("Created new GLSL shader program %u.\n", program_id);
7981 /* Create the entry */
7982 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
7983 entry->id = program_id;
7984 entry->vs.id = vs_id;
7985 entry->gs.id = gs_id;
7986 entry->ps.id = ps_id;
7987 entry->constant_version = 0;
7988 entry->ps.np2_fixup_info = np2fixup_info;
7989 /* Add the hash table entry */
7990 add_glsl_program_entry(priv, entry);
7992 /* Set the current program */
7993 ctx_data->glsl_program = entry;
7995 /* Attach GLSL vshader */
7996 if (vs_id)
7998 TRACE("Attaching GLSL shader object %u to program %u.\n", vs_id, program_id);
7999 GL_EXTCALL(glAttachShader(program_id, vs_id));
8000 checkGLcall("glAttachShader");
8002 list_add_head(vs_list, &entry->vs.shader_entry);
8005 if (vshader)
8007 attribs_map = vshader->reg_maps.input_registers;
8008 if (vshader->reg_maps.shader_version.major < 4)
8010 reorder_shader_id = shader_glsl_generate_vs3_rasterizer_input_setup(priv, vshader, pshader,
8011 state->gl_primitive_type == GL_POINTS && vshader->reg_maps.point_size,
8012 d3d_info->emulated_flatshading
8013 && state->render_states[WINED3D_RS_SHADEMODE] == WINED3D_SHADE_FLAT, gl_info);
8014 TRACE("Attaching GLSL shader object %u to program %u.\n", reorder_shader_id, program_id);
8015 GL_EXTCALL(glAttachShader(program_id, reorder_shader_id));
8016 checkGLcall("glAttachShader");
8017 /* Flag the reorder function for deletion, it will be freed
8018 * automatically when the program is destroyed. */
8019 GL_EXTCALL(glDeleteShader(reorder_shader_id));
8022 else
8024 attribs_map = (1u << WINED3D_FFP_ATTRIBS_COUNT) - 1;
8027 if (!shader_glsl_use_explicit_attrib_location(gl_info))
8029 /* Bind vertex attributes to a corresponding index number to match
8030 * the same index numbers as ARB_vertex_programs (makes loading
8031 * vertex attributes simpler). With this method, we can use the
8032 * exact same code to load the attributes later for both ARB and
8033 * GLSL shaders.
8035 * We have to do this here because we need to know the Program ID
8036 * in order to make the bindings work, and it has to be done prior
8037 * to linking the GLSL program. */
8038 tmp_name = string_buffer_get(&priv->string_buffers);
8039 for (i = 0; attribs_map; attribs_map >>= 1, ++i)
8041 if (!(attribs_map & 1))
8042 continue;
8044 string_buffer_sprintf(tmp_name, "vs_in%u", i);
8045 GL_EXTCALL(glBindAttribLocation(program_id, i, tmp_name->buffer));
8046 if (vshader && vshader->reg_maps.shader_version.major >= 4)
8048 string_buffer_sprintf(tmp_name, "vs_in_uint%u", i);
8049 GL_EXTCALL(glBindAttribLocation(program_id, i, tmp_name->buffer));
8050 string_buffer_sprintf(tmp_name, "vs_in_int%u", i);
8051 GL_EXTCALL(glBindAttribLocation(program_id, i, tmp_name->buffer));
8054 checkGLcall("glBindAttribLocation");
8055 string_buffer_release(&priv->string_buffers, tmp_name);
8058 if (gshader)
8060 TRACE("Attaching GLSL geometry shader object %u to program %u.\n", gs_id, program_id);
8061 GL_EXTCALL(glAttachShader(program_id, gs_id));
8062 checkGLcall("glAttachShader");
8064 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
8066 TRACE("input type %s, output type %s, vertices out %u.\n",
8067 debug_d3dprimitivetype(gshader->u.gs.input_type),
8068 debug_d3dprimitivetype(gshader->u.gs.output_type),
8069 gshader->u.gs.vertices_out);
8070 GL_EXTCALL(glProgramParameteriARB(program_id, GL_GEOMETRY_INPUT_TYPE_ARB,
8071 gl_primitive_type_from_d3d(gshader->u.gs.input_type)));
8072 GL_EXTCALL(glProgramParameteriARB(program_id, GL_GEOMETRY_OUTPUT_TYPE_ARB,
8073 gl_primitive_type_from_d3d(gshader->u.gs.output_type)));
8074 GL_EXTCALL(glProgramParameteriARB(program_id, GL_GEOMETRY_VERTICES_OUT_ARB,
8075 gshader->u.gs.vertices_out));
8076 checkGLcall("glProgramParameteriARB");
8079 list_add_head(&gshader->linked_programs, &entry->gs.shader_entry);
8082 /* Attach GLSL pshader */
8083 if (ps_id)
8085 TRACE("Attaching GLSL shader object %u to program %u.\n", ps_id, program_id);
8086 GL_EXTCALL(glAttachShader(program_id, ps_id));
8087 checkGLcall("glAttachShader");
8089 list_add_head(ps_list, &entry->ps.shader_entry);
8092 /* Link the program */
8093 TRACE("Linking GLSL shader program %u.\n", program_id);
8094 GL_EXTCALL(glLinkProgram(program_id));
8095 shader_glsl_validate_link(gl_info, program_id);
8097 shader_glsl_init_vs_uniform_locations(gl_info, priv, program_id, &entry->vs,
8098 vshader ? vshader->limits->constant_float : 0);
8099 shader_glsl_init_gs_uniform_locations(gl_info, priv, program_id, &entry->gs);
8100 shader_glsl_init_ps_uniform_locations(gl_info, priv, program_id, &entry->ps,
8101 pshader ? pshader->limits->constant_float : 0);
8102 checkGLcall("Find glsl program uniform locations");
8104 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
8106 if (pshader && pshader->reg_maps.shader_version.major >= 3
8107 && pshader->u.ps.declared_in_count > vec4_varyings(3, gl_info))
8109 TRACE("Shader %d needs vertex color clamping disabled.\n", program_id);
8110 entry->vs.vertex_color_clamp = GL_FALSE;
8112 else
8114 entry->vs.vertex_color_clamp = GL_FIXED_ONLY_ARB;
8117 else
8119 /* With core profile we never change vertex_color_clamp from
8120 * GL_FIXED_ONLY_MODE (which is also the initial value) so we never call
8121 * glClampColorARB(). */
8122 entry->vs.vertex_color_clamp = GL_FIXED_ONLY_ARB;
8125 /* Set the shader to allow uniform loading on it */
8126 GL_EXTCALL(glUseProgram(program_id));
8127 checkGLcall("glUseProgram");
8129 /* Texture unit mapping is set up to be the same each time the shader
8130 * program is used so we can hardcode the sampler uniform values. */
8131 shader_glsl_load_samplers(gl_info, priv, context->tex_unit_map, program_id);
8133 entry->constant_update_mask = 0;
8134 if (vshader)
8136 entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_F;
8137 if (vshader->reg_maps.integer_constants)
8138 entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_I;
8139 if (vshader->reg_maps.boolean_constants)
8140 entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_B;
8141 if (entry->vs.pos_fixup_location != -1)
8142 entry->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP;
8144 shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &vshader->reg_maps);
8145 shader_glsl_load_icb(gl_info, priv, program_id, &vshader->reg_maps);
8147 else
8149 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_MODELVIEW
8150 | WINED3D_SHADER_CONST_FFP_PROJ;
8152 for (i = 1; i < MAX_VERTEX_BLENDS; ++i)
8154 if (entry->vs.modelview_matrix_location[i] != -1)
8156 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_VERTEXBLEND;
8157 break;
8161 for (i = 0; i < MAX_TEXTURES; ++i)
8163 if (entry->vs.texture_matrix_location[i] != -1)
8165 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_TEXMATRIX;
8166 break;
8169 if (entry->vs.material_ambient_location != -1 || entry->vs.material_diffuse_location != -1
8170 || entry->vs.material_specular_location != -1
8171 || entry->vs.material_emissive_location != -1
8172 || entry->vs.material_shininess_location != -1)
8173 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_MATERIAL;
8174 if (entry->vs.light_ambient_location != -1)
8175 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_LIGHTS;
8177 if (entry->vs.clip_planes_location != -1)
8178 entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_CLIP_PLANES;
8179 if (entry->vs.pointsize_min_location != -1)
8180 entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_POINTSIZE;
8182 if (gshader)
8184 if (entry->gs.pos_fixup_location != -1)
8185 entry->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP;
8186 shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &gshader->reg_maps);
8187 shader_glsl_load_icb(gl_info, priv, program_id, &gshader->reg_maps);
8190 if (ps_id)
8192 if (pshader)
8194 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_F;
8195 if (pshader->reg_maps.integer_constants)
8196 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_I;
8197 if (pshader->reg_maps.boolean_constants)
8198 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_B;
8199 if (entry->ps.ycorrection_location != -1)
8200 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_Y_CORR;
8202 shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &pshader->reg_maps);
8203 shader_glsl_load_icb(gl_info, priv, program_id, &pshader->reg_maps);
8204 shader_glsl_load_images(gl_info, priv, program_id, &pshader->reg_maps);
8206 else
8208 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_PS;
8211 for (i = 0; i < MAX_TEXTURES; ++i)
8213 if (entry->ps.bumpenv_mat_location[i] != -1)
8215 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_BUMP_ENV;
8216 break;
8220 if (entry->ps.fog_color_location != -1)
8221 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_FOG;
8222 if (entry->ps.alpha_test_ref_location != -1)
8223 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_ALPHA_TEST;
8224 if (entry->ps.np2_fixup_location != -1)
8225 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_NP2_FIXUP;
8226 if (entry->ps.color_key_location != -1)
8227 entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_COLOR_KEY;
8231 /* Context activation is done by the caller. */
8232 static GLuint create_glsl_blt_shader(const struct wined3d_gl_info *gl_info, enum wined3d_gl_resource_type tex_type,
8233 BOOL masked)
8235 GLuint program_id;
8236 GLuint vshader_id, pshader_id;
8237 const char *blt_pshader;
8239 static const char blt_vshader[] =
8240 "#version 120\n"
8241 "void main(void)\n"
8242 "{\n"
8243 " gl_Position = gl_Vertex;\n"
8244 " gl_FrontColor = vec4(1.0);\n"
8245 " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
8246 "}\n";
8248 static const char * const blt_pshaders_full[WINED3D_GL_RES_TYPE_COUNT] =
8250 /* WINED3D_GL_RES_TYPE_TEX_1D */
8251 NULL,
8252 /* WINED3D_GL_RES_TYPE_TEX_2D */
8253 "#version 120\n"
8254 "uniform sampler2D sampler;\n"
8255 "void main(void)\n"
8256 "{\n"
8257 " gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n"
8258 "}\n",
8259 /* WINED3D_GL_RES_TYPE_TEX_3D */
8260 NULL,
8261 /* WINED3D_GL_RES_TYPE_TEX_CUBE */
8262 "#version 120\n"
8263 "uniform samplerCube sampler;\n"
8264 "void main(void)\n"
8265 "{\n"
8266 " gl_FragDepth = textureCube(sampler, gl_TexCoord[0].xyz).x;\n"
8267 "}\n",
8268 /* WINED3D_GL_RES_TYPE_TEX_RECT */
8269 "#version 120\n"
8270 "#extension GL_ARB_texture_rectangle : enable\n"
8271 "uniform sampler2DRect sampler;\n"
8272 "void main(void)\n"
8273 "{\n"
8274 " gl_FragDepth = texture2DRect(sampler, gl_TexCoord[0].xy).x;\n"
8275 "}\n",
8276 /* WINED3D_GL_RES_TYPE_BUFFER */
8277 NULL,
8278 /* WINED3D_GL_RES_TYPE_RB */
8279 NULL,
8282 static const char * const blt_pshaders_masked[WINED3D_GL_RES_TYPE_COUNT] =
8284 /* WINED3D_GL_RES_TYPE_TEX_1D */
8285 NULL,
8286 /* WINED3D_GL_RES_TYPE_TEX_2D */
8287 "#version 120\n"
8288 "uniform sampler2D sampler;\n"
8289 "uniform vec4 mask;\n"
8290 "void main(void)\n"
8291 "{\n"
8292 " if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
8293 " gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n"
8294 "}\n",
8295 /* WINED3D_GL_RES_TYPE_TEX_3D */
8296 NULL,
8297 /* WINED3D_GL_RES_TYPE_TEX_CUBE */
8298 "#version 120\n"
8299 "uniform samplerCube sampler;\n"
8300 "uniform vec4 mask;\n"
8301 "void main(void)\n"
8302 "{\n"
8303 " if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
8304 " gl_FragDepth = textureCube(sampler, gl_TexCoord[0].xyz).x;\n"
8305 "}\n",
8306 /* WINED3D_GL_RES_TYPE_TEX_RECT */
8307 "#version 120\n"
8308 "#extension GL_ARB_texture_rectangle : enable\n"
8309 "uniform sampler2DRect sampler;\n"
8310 "uniform vec4 mask;\n"
8311 "void main(void)\n"
8312 "{\n"
8313 " if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
8314 " gl_FragDepth = texture2DRect(sampler, gl_TexCoord[0].xy).x;\n"
8315 "}\n",
8316 /* WINED3D_GL_RES_TYPE_BUFFER */
8317 NULL,
8318 /* WINED3D_GL_RES_TYPE_RB */
8319 NULL,
8322 blt_pshader = masked ? blt_pshaders_masked[tex_type] : blt_pshaders_full[tex_type];
8323 if (!blt_pshader)
8325 FIXME("tex_type %#x not supported\n", tex_type);
8326 return 0;
8329 vshader_id = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER));
8330 shader_glsl_compile(gl_info, vshader_id, blt_vshader);
8332 pshader_id = GL_EXTCALL(glCreateShader(GL_FRAGMENT_SHADER));
8333 shader_glsl_compile(gl_info, pshader_id, blt_pshader);
8335 program_id = GL_EXTCALL(glCreateProgram());
8336 GL_EXTCALL(glAttachShader(program_id, vshader_id));
8337 GL_EXTCALL(glAttachShader(program_id, pshader_id));
8338 GL_EXTCALL(glLinkProgram(program_id));
8340 shader_glsl_validate_link(gl_info, program_id);
8342 /* Once linked we can mark the shaders for deletion. They will be deleted once the program
8343 * is destroyed
8345 GL_EXTCALL(glDeleteShader(vshader_id));
8346 GL_EXTCALL(glDeleteShader(pshader_id));
8347 return program_id;
8350 /* Context activation is done by the caller. */
8351 static void shader_glsl_select(void *shader_priv, struct wined3d_context *context,
8352 const struct wined3d_state *state)
8354 struct glsl_context_data *ctx_data = context->shader_backend_data;
8355 const struct wined3d_gl_info *gl_info = context->gl_info;
8356 struct shader_glsl_priv *priv = shader_priv;
8357 GLuint program_id = 0, prev_id = 0;
8358 GLenum old_vertex_color_clamp, current_vertex_color_clamp;
8360 priv->vertex_pipe->vp_enable(gl_info, !use_vs(state));
8361 priv->fragment_pipe->enable_extension(gl_info, !use_ps(state));
8363 if (ctx_data->glsl_program)
8365 prev_id = ctx_data->glsl_program->id;
8366 old_vertex_color_clamp = ctx_data->glsl_program->vs.vertex_color_clamp;
8368 else
8370 prev_id = 0;
8371 old_vertex_color_clamp = GL_FIXED_ONLY_ARB;
8374 set_glsl_shader_program(context, state, priv, ctx_data);
8376 if (ctx_data->glsl_program)
8378 program_id = ctx_data->glsl_program->id;
8379 current_vertex_color_clamp = ctx_data->glsl_program->vs.vertex_color_clamp;
8381 else
8383 program_id = 0;
8384 current_vertex_color_clamp = GL_FIXED_ONLY_ARB;
8387 if (old_vertex_color_clamp != current_vertex_color_clamp)
8389 if (gl_info->supported[ARB_COLOR_BUFFER_FLOAT])
8391 GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, current_vertex_color_clamp));
8392 checkGLcall("glClampColorARB");
8394 else
8396 FIXME("vertex color clamp needs to be changed, but extension not supported.\n");
8400 TRACE("Using GLSL program %u.\n", program_id);
8402 if (prev_id != program_id)
8404 GL_EXTCALL(glUseProgram(program_id));
8405 checkGLcall("glUseProgram");
8407 if (program_id)
8408 context->constant_update_mask |= ctx_data->glsl_program->constant_update_mask;
8412 /* "context" is not necessarily the currently active context. */
8413 static void shader_glsl_invalidate_current_program(struct wined3d_context *context)
8415 struct glsl_context_data *ctx_data = context->shader_backend_data;
8417 ctx_data->glsl_program = NULL;
8418 context->shader_update_mask = (1u << WINED3D_SHADER_TYPE_PIXEL)
8419 | (1u << WINED3D_SHADER_TYPE_VERTEX)
8420 | (1u << WINED3D_SHADER_TYPE_GEOMETRY)
8421 | (1u << WINED3D_SHADER_TYPE_HULL)
8422 | (1u << WINED3D_SHADER_TYPE_DOMAIN)
8423 | (1u << WINED3D_SHADER_TYPE_COMPUTE);
8426 /* Context activation is done by the caller. */
8427 static void shader_glsl_disable(void *shader_priv, struct wined3d_context *context)
8429 const struct wined3d_gl_info *gl_info = context->gl_info;
8430 struct shader_glsl_priv *priv = shader_priv;
8432 shader_glsl_invalidate_current_program(context);
8433 GL_EXTCALL(glUseProgram(0));
8434 checkGLcall("glUseProgram");
8436 priv->vertex_pipe->vp_enable(gl_info, FALSE);
8437 priv->fragment_pipe->enable_extension(gl_info, FALSE);
8439 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_COLOR_BUFFER_FLOAT])
8441 GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FIXED_ONLY_ARB));
8442 checkGLcall("glClampColorARB");
8446 /* Context activation is done by the caller. */
8447 static void shader_glsl_select_depth_blt(void *shader_priv, const struct wined3d_gl_info *gl_info,
8448 enum wined3d_gl_resource_type tex_type, const SIZE *ds_mask_size)
8450 BOOL masked = ds_mask_size->cx && ds_mask_size->cy;
8451 struct shader_glsl_priv *priv = shader_priv;
8452 GLuint *blt_program;
8453 GLint loc;
8455 blt_program = masked ? &priv->depth_blt_program_masked[tex_type] : &priv->depth_blt_program_full[tex_type];
8456 if (!*blt_program)
8458 *blt_program = create_glsl_blt_shader(gl_info, tex_type, masked);
8459 loc = GL_EXTCALL(glGetUniformLocation(*blt_program, "sampler"));
8460 GL_EXTCALL(glUseProgram(*blt_program));
8461 GL_EXTCALL(glUniform1i(loc, 0));
8463 else
8465 GL_EXTCALL(glUseProgram(*blt_program));
8468 if (masked)
8470 loc = GL_EXTCALL(glGetUniformLocation(*blt_program, "mask"));
8471 GL_EXTCALL(glUniform4f(loc, 0.0f, 0.0f, (float)ds_mask_size->cx, (float)ds_mask_size->cy));
8475 /* Context activation is done by the caller. */
8476 static void shader_glsl_deselect_depth_blt(void *shader_priv, const struct wined3d_gl_info *gl_info)
8478 const struct glsl_context_data *ctx_data = context_get_current()->shader_backend_data;
8479 GLuint program_id;
8481 program_id = ctx_data->glsl_program ? ctx_data->glsl_program->id : 0;
8482 if (program_id) TRACE("Using GLSL program %u\n", program_id);
8484 GL_EXTCALL(glUseProgram(program_id));
8485 checkGLcall("glUseProgram");
8488 static void shader_glsl_invalidate_contexts_program(struct wined3d_device *device,
8489 const struct glsl_shader_prog_link *program)
8491 const struct glsl_context_data *ctx_data;
8492 struct wined3d_context *context;
8493 unsigned int i;
8495 for (i = 0; i < device->context_count; ++i)
8497 context = device->contexts[i];
8498 ctx_data = context->shader_backend_data;
8500 if (ctx_data->glsl_program == program)
8501 shader_glsl_invalidate_current_program(context);
8505 static void shader_glsl_destroy(struct wined3d_shader *shader)
8507 struct glsl_shader_private *shader_data = shader->backend_data;
8508 struct wined3d_device *device = shader->device;
8509 struct shader_glsl_priv *priv = device->shader_priv;
8510 const struct wined3d_gl_info *gl_info;
8511 const struct list *linked_programs;
8512 struct wined3d_context *context;
8514 if (!shader_data || !shader_data->num_gl_shaders)
8516 HeapFree(GetProcessHeap(), 0, shader_data);
8517 shader->backend_data = NULL;
8518 return;
8521 context = context_acquire(device, NULL);
8522 gl_info = context->gl_info;
8524 TRACE("Deleting linked programs.\n");
8525 linked_programs = &shader->linked_programs;
8526 if (linked_programs->next)
8528 struct glsl_shader_prog_link *entry, *entry2;
8529 UINT i;
8531 switch (shader->reg_maps.shader_version.type)
8533 case WINED3D_SHADER_TYPE_PIXEL:
8535 struct glsl_ps_compiled_shader *gl_shaders = shader_data->gl_shaders.ps;
8537 for (i = 0; i < shader_data->num_gl_shaders; ++i)
8539 TRACE("Deleting pixel shader %u.\n", gl_shaders[i].id);
8540 GL_EXTCALL(glDeleteShader(gl_shaders[i].id));
8541 checkGLcall("glDeleteShader");
8543 HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.ps);
8545 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs,
8546 struct glsl_shader_prog_link, ps.shader_entry)
8548 shader_glsl_invalidate_contexts_program(device, entry);
8549 delete_glsl_program_entry(priv, gl_info, entry);
8552 break;
8555 case WINED3D_SHADER_TYPE_VERTEX:
8557 struct glsl_vs_compiled_shader *gl_shaders = shader_data->gl_shaders.vs;
8559 for (i = 0; i < shader_data->num_gl_shaders; ++i)
8561 TRACE("Deleting vertex shader %u.\n", gl_shaders[i].id);
8562 GL_EXTCALL(glDeleteShader(gl_shaders[i].id));
8563 checkGLcall("glDeleteShader");
8565 HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.vs);
8567 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs,
8568 struct glsl_shader_prog_link, vs.shader_entry)
8570 shader_glsl_invalidate_contexts_program(device, entry);
8571 delete_glsl_program_entry(priv, gl_info, entry);
8574 break;
8577 case WINED3D_SHADER_TYPE_GEOMETRY:
8579 struct glsl_gs_compiled_shader *gl_shaders = shader_data->gl_shaders.gs;
8581 for (i = 0; i < shader_data->num_gl_shaders; ++i)
8583 TRACE("Deleting geometry shader %u.\n", gl_shaders[i].id);
8584 GL_EXTCALL(glDeleteShader(gl_shaders[i].id));
8585 checkGLcall("glDeleteShader");
8587 HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.gs);
8589 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs,
8590 struct glsl_shader_prog_link, gs.shader_entry)
8592 shader_glsl_invalidate_contexts_program(device, entry);
8593 delete_glsl_program_entry(priv, gl_info, entry);
8596 break;
8599 default:
8600 ERR("Unhandled shader type %#x.\n", shader->reg_maps.shader_version.type);
8601 break;
8605 HeapFree(GetProcessHeap(), 0, shader->backend_data);
8606 shader->backend_data = NULL;
8608 context_release(context);
8611 static int glsl_program_key_compare(const void *key, const struct wine_rb_entry *entry)
8613 const struct glsl_program_key *k = key;
8614 const struct glsl_shader_prog_link *prog = WINE_RB_ENTRY_VALUE(entry,
8615 const struct glsl_shader_prog_link, program_lookup_entry);
8617 if (k->vs_id > prog->vs.id) return 1;
8618 else if (k->vs_id < prog->vs.id) return -1;
8620 if (k->gs_id > prog->gs.id) return 1;
8621 else if (k->gs_id < prog->gs.id) return -1;
8623 if (k->ps_id > prog->ps.id) return 1;
8624 else if (k->ps_id < prog->ps.id) return -1;
8626 return 0;
8629 static BOOL constant_heap_init(struct constant_heap *heap, unsigned int constant_count)
8631 SIZE_T size = (constant_count + 1) * sizeof(*heap->entries)
8632 + constant_count * sizeof(*heap->contained)
8633 + constant_count * sizeof(*heap->positions);
8634 void *mem = HeapAlloc(GetProcessHeap(), 0, size);
8636 if (!mem)
8638 ERR("Failed to allocate memory\n");
8639 return FALSE;
8642 heap->entries = mem;
8643 heap->entries[1].version = 0;
8644 heap->contained = (BOOL *)(heap->entries + constant_count + 1);
8645 memset(heap->contained, 0, constant_count * sizeof(*heap->contained));
8646 heap->positions = (unsigned int *)(heap->contained + constant_count);
8647 heap->size = 1;
8649 return TRUE;
8652 static void constant_heap_free(struct constant_heap *heap)
8654 HeapFree(GetProcessHeap(), 0, heap->entries);
8657 static HRESULT shader_glsl_alloc(struct wined3d_device *device, const struct wined3d_vertex_pipe_ops *vertex_pipe,
8658 const struct fragment_pipeline *fragment_pipe)
8660 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
8661 struct shader_glsl_priv *priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct shader_glsl_priv));
8662 SIZE_T stack_size = wined3d_log2i(max(WINED3D_MAX_VS_CONSTS_F, WINED3D_MAX_PS_CONSTS_F)) + 1;
8663 struct fragment_caps fragment_caps;
8664 void *vertex_priv, *fragment_priv;
8666 string_buffer_list_init(&priv->string_buffers);
8668 if (!(vertex_priv = vertex_pipe->vp_alloc(&glsl_shader_backend, priv)))
8670 ERR("Failed to initialize vertex pipe.\n");
8671 HeapFree(GetProcessHeap(), 0, priv);
8672 return E_FAIL;
8675 if (!(fragment_priv = fragment_pipe->alloc_private(&glsl_shader_backend, priv)))
8677 ERR("Failed to initialize fragment pipe.\n");
8678 vertex_pipe->vp_free(device);
8679 HeapFree(GetProcessHeap(), 0, priv);
8680 return E_FAIL;
8683 if (!string_buffer_init(&priv->shader_buffer))
8685 ERR("Failed to initialize shader buffer.\n");
8686 goto fail;
8689 if (!(priv->stack = wined3d_calloc(stack_size, sizeof(*priv->stack))))
8691 ERR("Failed to allocate memory.\n");
8692 goto fail;
8695 if (!constant_heap_init(&priv->vconst_heap, WINED3D_MAX_VS_CONSTS_F))
8697 ERR("Failed to initialize vertex shader constant heap\n");
8698 goto fail;
8701 if (!constant_heap_init(&priv->pconst_heap, WINED3D_MAX_PS_CONSTS_F))
8703 ERR("Failed to initialize pixel shader constant heap\n");
8704 goto fail;
8707 wine_rb_init(&priv->program_lookup, glsl_program_key_compare);
8709 priv->next_constant_version = 1;
8710 priv->vertex_pipe = vertex_pipe;
8711 priv->fragment_pipe = fragment_pipe;
8712 fragment_pipe->get_caps(gl_info, &fragment_caps);
8713 priv->ffp_proj_control = fragment_caps.wined3d_caps & WINED3D_FRAGMENT_CAP_PROJ_CONTROL;
8714 priv->legacy_lighting = device->wined3d->flags & WINED3D_LEGACY_FFP_LIGHTING;
8716 device->vertex_priv = vertex_priv;
8717 device->fragment_priv = fragment_priv;
8718 device->shader_priv = priv;
8720 return WINED3D_OK;
8722 fail:
8723 constant_heap_free(&priv->pconst_heap);
8724 constant_heap_free(&priv->vconst_heap);
8725 HeapFree(GetProcessHeap(), 0, priv->stack);
8726 string_buffer_free(&priv->shader_buffer);
8727 fragment_pipe->free_private(device);
8728 vertex_pipe->vp_free(device);
8729 HeapFree(GetProcessHeap(), 0, priv);
8730 return E_OUTOFMEMORY;
8733 /* Context activation is done by the caller. */
8734 static void shader_glsl_free(struct wined3d_device *device)
8736 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
8737 struct shader_glsl_priv *priv = device->shader_priv;
8738 int i;
8740 for (i = 0; i < WINED3D_GL_RES_TYPE_COUNT; ++i)
8742 if (priv->depth_blt_program_full[i])
8744 GL_EXTCALL(glDeleteProgram(priv->depth_blt_program_full[i]));
8746 if (priv->depth_blt_program_masked[i])
8748 GL_EXTCALL(glDeleteProgram(priv->depth_blt_program_masked[i]));
8752 wine_rb_destroy(&priv->program_lookup, NULL, NULL);
8753 constant_heap_free(&priv->pconst_heap);
8754 constant_heap_free(&priv->vconst_heap);
8755 HeapFree(GetProcessHeap(), 0, priv->stack);
8756 string_buffer_list_cleanup(&priv->string_buffers);
8757 string_buffer_free(&priv->shader_buffer);
8758 priv->fragment_pipe->free_private(device);
8759 priv->vertex_pipe->vp_free(device);
8761 HeapFree(GetProcessHeap(), 0, device->shader_priv);
8762 device->shader_priv = NULL;
8765 static BOOL shader_glsl_allocate_context_data(struct wined3d_context *context)
8767 return !!(context->shader_backend_data = HeapAlloc(GetProcessHeap(),
8768 HEAP_ZERO_MEMORY, sizeof(struct glsl_context_data)));
8771 static void shader_glsl_free_context_data(struct wined3d_context *context)
8773 HeapFree(GetProcessHeap(), 0, context->shader_backend_data);
8776 static void shader_glsl_init_context_state(struct wined3d_context *context)
8778 const struct wined3d_gl_info *gl_info = context->gl_info;
8780 gl_info->gl_ops.gl.p_glEnable(GL_PROGRAM_POINT_SIZE);
8781 checkGLcall("GL_PROGRAM_POINT_SIZE");
8784 static void shader_glsl_get_caps(const struct wined3d_gl_info *gl_info, struct shader_caps *caps)
8786 UINT shader_model;
8788 /* FIXME: Check for the specific extensions required for SM5 support
8789 * (ARB_compute_shader, ARB_tessellation_shader, ARB_gpu_shader5, ...) as
8790 * soon as we introduce them, adjusting the GL / GLSL version checks
8791 * accordingly. */
8792 if (gl_info->glsl_version >= MAKEDWORD_VERSION(4, 30) && gl_info->supported[WINED3D_GL_VERSION_4_3]
8793 && gl_info->supported[ARB_DERIVATIVE_CONTROL]
8794 && gl_info->supported[ARB_SHADER_IMAGE_LOAD_STORE]
8795 && gl_info->supported[ARB_SHADER_IMAGE_SIZE])
8796 shader_model = 5;
8797 else if (gl_info->glsl_version >= MAKEDWORD_VERSION(1, 50) && gl_info->supported[WINED3D_GL_VERSION_3_2]
8798 && gl_info->supported[ARB_SHADER_BIT_ENCODING] && gl_info->supported[ARB_SAMPLER_OBJECTS]
8799 && gl_info->supported[ARB_TEXTURE_SWIZZLE])
8800 shader_model = 4;
8801 /* Support for texldd and texldl instructions in pixel shaders is required
8802 * for SM3. */
8803 else if (shader_glsl_has_core_grad(gl_info, NULL) || gl_info->supported[ARB_SHADER_TEXTURE_LOD])
8804 shader_model = 3;
8805 else
8806 shader_model = 2;
8807 TRACE("Shader model %u.\n", shader_model);
8809 caps->vs_version = min(wined3d_settings.max_sm_vs, shader_model);
8810 caps->hs_version = min(wined3d_settings.max_sm_hs, shader_model);
8811 caps->ds_version = min(wined3d_settings.max_sm_ds, shader_model);
8812 caps->gs_version = min(wined3d_settings.max_sm_gs, shader_model);
8813 caps->ps_version = min(wined3d_settings.max_sm_ps, shader_model);
8814 caps->cs_version = min(wined3d_settings.max_sm_cs, shader_model);
8816 caps->vs_uniform_count = min(WINED3D_MAX_VS_CONSTS_F, gl_info->limits.glsl_vs_float_constants);
8817 caps->ps_uniform_count = min(WINED3D_MAX_PS_CONSTS_F, gl_info->limits.glsl_ps_float_constants);
8818 caps->varying_count = gl_info->limits.glsl_varyings;
8820 /* FIXME: The following line is card dependent. -8.0 to 8.0 is the
8821 * Direct3D minimum requirement.
8823 * Both GL_ARB_fragment_program and GLSL require a "maximum representable magnitude"
8824 * of colors to be 2^10, and 2^32 for other floats. Should we use 1024 here?
8826 * The problem is that the refrast clamps temporary results in the shader to
8827 * [-MaxValue;+MaxValue]. If the card's max value is bigger than the one we advertize here,
8828 * then applications may miss the clamping behavior. On the other hand, if it is smaller,
8829 * the shader will generate incorrect results too. Unfortunately, GL deliberately doesn't
8830 * offer a way to query this.
8832 if (shader_model >= 4)
8833 caps->ps_1x_max_value = FLT_MAX;
8834 else
8835 caps->ps_1x_max_value = 1024.0f;
8837 /* Ideally we'd only set caps like sRGB writes here if supported by both
8838 * the shader backend and the fragment pipe, but we can get called before
8839 * shader_glsl_alloc(). */
8840 caps->wined3d_caps = WINED3D_SHADER_CAP_VS_CLIPPING
8841 | WINED3D_SHADER_CAP_SRGB_WRITE;
8844 static BOOL shader_glsl_color_fixup_supported(struct color_fixup_desc fixup)
8846 if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
8848 TRACE("Checking support for fixup:\n");
8849 dump_color_fixup_desc(fixup);
8852 /* We support everything except YUV conversions. */
8853 if (!is_complex_fixup(fixup))
8855 TRACE("[OK]\n");
8856 return TRUE;
8859 TRACE("[FAILED]\n");
8860 return FALSE;
8863 static const SHADER_HANDLER shader_glsl_instruction_handler_table[WINED3DSIH_TABLE_SIZE] =
8865 /* WINED3DSIH_ABS */ shader_glsl_map2gl,
8866 /* WINED3DSIH_ADD */ shader_glsl_binop,
8867 /* WINED3DSIH_AND */ shader_glsl_binop,
8868 /* WINED3DSIH_ATOMIC_AND */ NULL,
8869 /* WINED3DSIH_ATOMIC_IADD */ shader_glsl_atomic,
8870 /* WINED3DSIH_ATOMIC_OR */ NULL,
8871 /* WINED3DSIH_ATOMIC_XOR */ NULL,
8872 /* WINED3DSIH_BEM */ shader_glsl_bem,
8873 /* WINED3DSIH_BFI */ NULL,
8874 /* WINED3DSIH_BFREV */ NULL,
8875 /* WINED3DSIH_BREAK */ shader_glsl_break,
8876 /* WINED3DSIH_BREAKC */ shader_glsl_breakc,
8877 /* WINED3DSIH_BREAKP */ shader_glsl_breakp,
8878 /* WINED3DSIH_BUFINFO */ NULL,
8879 /* WINED3DSIH_CALL */ shader_glsl_call,
8880 /* WINED3DSIH_CALLNZ */ shader_glsl_callnz,
8881 /* WINED3DSIH_CASE */ shader_glsl_case,
8882 /* WINED3DSIH_CMP */ shader_glsl_conditional_move,
8883 /* WINED3DSIH_CND */ shader_glsl_cnd,
8884 /* WINED3DSIH_CONTINUE */ shader_glsl_continue,
8885 /* WINED3DSIH_CRS */ shader_glsl_cross,
8886 /* WINED3DSIH_CUT */ shader_glsl_cut,
8887 /* WINED3DSIH_CUT_STREAM */ shader_glsl_cut,
8888 /* WINED3DSIH_DCL */ shader_glsl_nop,
8889 /* WINED3DSIH_DCL_CONSTANT_BUFFER */ shader_glsl_nop,
8890 /* WINED3DSIH_DCL_GLOBAL_FLAGS */ shader_glsl_nop,
8891 /* WINED3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT */ NULL,
8892 /* WINED3DSIH_DCL_HS_MAX_TESSFACTOR */ NULL,
8893 /* WINED3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER */ shader_glsl_nop,
8894 /* WINED3DSIH_DCL_INDEXABLE_TEMP */ shader_glsl_nop,
8895 /* WINED3DSIH_DCL_INPUT */ shader_glsl_nop,
8896 /* WINED3DSIH_DCL_INPUT_CONTROL_POINT_COUNT */ NULL,
8897 /* WINED3DSIH_DCL_INPUT_PRIMITIVE */ shader_glsl_nop,
8898 /* WINED3DSIH_DCL_INPUT_PS */ NULL,
8899 /* WINED3DSIH_DCL_INPUT_PS_SGV */ NULL,
8900 /* WINED3DSIH_DCL_INPUT_PS_SIV */ NULL,
8901 /* WINED3DSIH_DCL_INPUT_SGV */ shader_glsl_nop,
8902 /* WINED3DSIH_DCL_INPUT_SIV */ shader_glsl_nop,
8903 /* WINED3DSIH_DCL_OUTPUT */ shader_glsl_nop,
8904 /* WINED3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT */ NULL,
8905 /* WINED3DSIH_DCL_OUTPUT_SIV */ shader_glsl_nop,
8906 /* WINED3DSIH_DCL_OUTPUT_TOPOLOGY */ shader_glsl_nop,
8907 /* WINED3DSIH_DCL_RESOURCE_STRUCTURED */ NULL,
8908 /* WINED3DSIH_DCL_SAMPLER */ shader_glsl_nop,
8909 /* WINED3DSIH_DCL_STREAM */ NULL,
8910 /* WINED3DSIH_DCL_TEMPS */ shader_glsl_nop,
8911 /* WINED3DSIH_DCL_TESSELLATOR_DOMAIN */ NULL,
8912 /* WINED3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE */ NULL,
8913 /* WINED3DSIH_DCL_TESSELLATOR_PARTITIONING */ NULL,
8914 /* WINED3DSIH_DCL_TGSM_RAW */ NULL,
8915 /* WINED3DSIH_DCL_TGSM_STRUCTURED */ NULL,
8916 /* WINED3DSIH_DCL_THREAD_GROUP */ NULL,
8917 /* WINED3DSIH_DCL_UAV_RAW */ NULL,
8918 /* WINED3DSIH_DCL_UAV_STRUCTURED */ NULL,
8919 /* WINED3DSIH_DCL_UAV_TYPED */ shader_glsl_nop,
8920 /* WINED3DSIH_DCL_VERTICES_OUT */ shader_glsl_nop,
8921 /* WINED3DSIH_DEF */ shader_glsl_nop,
8922 /* WINED3DSIH_DEFAULT */ shader_glsl_default,
8923 /* WINED3DSIH_DEFB */ shader_glsl_nop,
8924 /* WINED3DSIH_DEFI */ shader_glsl_nop,
8925 /* WINED3DSIH_DIV */ shader_glsl_binop,
8926 /* WINED3DSIH_DP2 */ shader_glsl_dot,
8927 /* WINED3DSIH_DP2ADD */ shader_glsl_dp2add,
8928 /* WINED3DSIH_DP3 */ shader_glsl_dot,
8929 /* WINED3DSIH_DP4 */ shader_glsl_dot,
8930 /* WINED3DSIH_DST */ shader_glsl_dst,
8931 /* WINED3DSIH_DSX */ shader_glsl_map2gl,
8932 /* WINED3DSIH_DSX_COARSE */ shader_glsl_map2gl,
8933 /* WINED3DSIH_DSX_FINE */ shader_glsl_map2gl,
8934 /* WINED3DSIH_DSY */ shader_glsl_map2gl,
8935 /* WINED3DSIH_DSY_COARSE */ shader_glsl_map2gl,
8936 /* WINED3DSIH_DSY_FINE */ shader_glsl_map2gl,
8937 /* WINED3DSIH_ELSE */ shader_glsl_else,
8938 /* WINED3DSIH_EMIT */ shader_glsl_emit,
8939 /* WINED3DSIH_EMIT_STREAM */ shader_glsl_emit,
8940 /* WINED3DSIH_ENDIF */ shader_glsl_end,
8941 /* WINED3DSIH_ENDLOOP */ shader_glsl_end,
8942 /* WINED3DSIH_ENDREP */ shader_glsl_end,
8943 /* WINED3DSIH_ENDSWITCH */ shader_glsl_end,
8944 /* WINED3DSIH_EQ */ shader_glsl_relop,
8945 /* WINED3DSIH_EXP */ shader_glsl_scalar_op,
8946 /* WINED3DSIH_EXPP */ shader_glsl_expp,
8947 /* WINED3DSIH_FRC */ shader_glsl_map2gl,
8948 /* WINED3DSIH_FTOI */ shader_glsl_to_int,
8949 /* WINED3DSIH_FTOU */ shader_glsl_to_uint,
8950 /* WINED3DSIH_GATHER4 */ NULL,
8951 /* WINED3DSIH_GATHER4_C */ NULL,
8952 /* WINED3DSIH_GE */ shader_glsl_relop,
8953 /* WINED3DSIH_HS_CONTROL_POINT_PHASE */ NULL,
8954 /* WINED3DSIH_HS_DECLS */ shader_glsl_nop,
8955 /* WINED3DSIH_HS_FORK_PHASE */ NULL,
8956 /* WINED3DSIH_HS_JOIN_PHASE */ NULL,
8957 /* WINED3DSIH_IADD */ shader_glsl_binop,
8958 /* WINED3DSIH_IEQ */ shader_glsl_relop,
8959 /* WINED3DSIH_IF */ shader_glsl_if,
8960 /* WINED3DSIH_IFC */ shader_glsl_ifc,
8961 /* WINED3DSIH_IGE */ shader_glsl_relop,
8962 /* WINED3DSIH_ILT */ shader_glsl_relop,
8963 /* WINED3DSIH_IMAD */ shader_glsl_mad,
8964 /* WINED3DSIH_IMAX */ shader_glsl_map2gl,
8965 /* WINED3DSIH_IMIN */ shader_glsl_map2gl,
8966 /* WINED3DSIH_IMM_ATOMIC_ALLOC */ NULL,
8967 /* WINED3DSIH_IMM_ATOMIC_AND */ NULL,
8968 /* WINED3DSIH_IMM_ATOMIC_CONSUME */ NULL,
8969 /* WINED3DSIH_IMM_ATOMIC_OR */ NULL,
8970 /* WINED3DSIH_IMM_ATOMIC_XOR */ NULL,
8971 /* WINED3DSIH_IMUL */ shader_glsl_imul,
8972 /* WINED3DSIH_INE */ shader_glsl_relop,
8973 /* WINED3DSIH_INEG */ shader_glsl_unary_op,
8974 /* WINED3DSIH_ISHL */ shader_glsl_binop,
8975 /* WINED3DSIH_ISHR */ shader_glsl_binop,
8976 /* WINED3DSIH_ITOF */ shader_glsl_to_float,
8977 /* WINED3DSIH_LABEL */ shader_glsl_label,
8978 /* WINED3DSIH_LD */ shader_glsl_ld,
8979 /* WINED3DSIH_LD2DMS */ NULL,
8980 /* WINED3DSIH_LD_RAW */ NULL,
8981 /* WINED3DSIH_LD_STRUCTURED */ NULL,
8982 /* WINED3DSIH_LD_UAV_TYPED */ shader_glsl_ld_uav,
8983 /* WINED3DSIH_LIT */ shader_glsl_lit,
8984 /* WINED3DSIH_LOD */ NULL,
8985 /* WINED3DSIH_LOG */ shader_glsl_scalar_op,
8986 /* WINED3DSIH_LOGP */ shader_glsl_scalar_op,
8987 /* WINED3DSIH_LOOP */ shader_glsl_loop,
8988 /* WINED3DSIH_LRP */ shader_glsl_lrp,
8989 /* WINED3DSIH_LT */ shader_glsl_relop,
8990 /* WINED3DSIH_M3x2 */ shader_glsl_mnxn,
8991 /* WINED3DSIH_M3x3 */ shader_glsl_mnxn,
8992 /* WINED3DSIH_M3x4 */ shader_glsl_mnxn,
8993 /* WINED3DSIH_M4x3 */ shader_glsl_mnxn,
8994 /* WINED3DSIH_M4x4 */ shader_glsl_mnxn,
8995 /* WINED3DSIH_MAD */ shader_glsl_mad,
8996 /* WINED3DSIH_MAX */ shader_glsl_map2gl,
8997 /* WINED3DSIH_MIN */ shader_glsl_map2gl,
8998 /* WINED3DSIH_MOV */ shader_glsl_mov,
8999 /* WINED3DSIH_MOVA */ shader_glsl_mov,
9000 /* WINED3DSIH_MOVC */ shader_glsl_conditional_move,
9001 /* WINED3DSIH_MUL */ shader_glsl_binop,
9002 /* WINED3DSIH_NE */ shader_glsl_relop,
9003 /* WINED3DSIH_NOP */ shader_glsl_nop,
9004 /* WINED3DSIH_NOT */ shader_glsl_unary_op,
9005 /* WINED3DSIH_NRM */ shader_glsl_nrm,
9006 /* WINED3DSIH_OR */ shader_glsl_binop,
9007 /* WINED3DSIH_PHASE */ shader_glsl_nop,
9008 /* WINED3DSIH_POW */ shader_glsl_pow,
9009 /* WINED3DSIH_RCP */ shader_glsl_scalar_op,
9010 /* WINED3DSIH_REP */ shader_glsl_rep,
9011 /* WINED3DSIH_RESINFO */ shader_glsl_resinfo,
9012 /* WINED3DSIH_RET */ shader_glsl_ret,
9013 /* WINED3DSIH_ROUND_NE */ shader_glsl_map2gl,
9014 /* WINED3DSIH_ROUND_NI */ shader_glsl_map2gl,
9015 /* WINED3DSIH_ROUND_PI */ shader_glsl_map2gl,
9016 /* WINED3DSIH_ROUND_Z */ shader_glsl_map2gl,
9017 /* WINED3DSIH_RSQ */ shader_glsl_scalar_op,
9018 /* WINED3DSIH_SAMPLE */ shader_glsl_sample,
9019 /* WINED3DSIH_SAMPLE_B */ shader_glsl_sample,
9020 /* WINED3DSIH_SAMPLE_C */ shader_glsl_sample_c,
9021 /* WINED3DSIH_SAMPLE_C_LZ */ shader_glsl_sample_c,
9022 /* WINED3DSIH_SAMPLE_GRAD */ shader_glsl_sample,
9023 /* WINED3DSIH_SAMPLE_INFO */ NULL,
9024 /* WINED3DSIH_SAMPLE_LOD */ shader_glsl_sample,
9025 /* WINED3DSIH_SAMPLE_POS */ NULL,
9026 /* WINED3DSIH_SETP */ NULL,
9027 /* WINED3DSIH_SGE */ shader_glsl_compare,
9028 /* WINED3DSIH_SGN */ shader_glsl_sgn,
9029 /* WINED3DSIH_SINCOS */ shader_glsl_sincos,
9030 /* WINED3DSIH_SLT */ shader_glsl_compare,
9031 /* WINED3DSIH_SQRT */ shader_glsl_map2gl,
9032 /* WINED3DSIH_STORE_RAW */ NULL,
9033 /* WINED3DSIH_STORE_STRUCTURED */ NULL,
9034 /* WINED3DSIH_STORE_UAV_TYPED */ NULL,
9035 /* WINED3DSIH_SUB */ shader_glsl_binop,
9036 /* WINED3DSIH_SWAPC */ NULL,
9037 /* WINED3DSIH_SWITCH */ shader_glsl_switch,
9038 /* WINED3DSIH_SYNC */ NULL,
9039 /* WINED3DSIH_TEX */ shader_glsl_tex,
9040 /* WINED3DSIH_TEXBEM */ shader_glsl_texbem,
9041 /* WINED3DSIH_TEXBEML */ shader_glsl_texbem,
9042 /* WINED3DSIH_TEXCOORD */ shader_glsl_texcoord,
9043 /* WINED3DSIH_TEXDEPTH */ shader_glsl_texdepth,
9044 /* WINED3DSIH_TEXDP3 */ shader_glsl_texdp3,
9045 /* WINED3DSIH_TEXDP3TEX */ shader_glsl_texdp3tex,
9046 /* WINED3DSIH_TEXKILL */ shader_glsl_texkill,
9047 /* WINED3DSIH_TEXLDD */ shader_glsl_texldd,
9048 /* WINED3DSIH_TEXLDL */ shader_glsl_texldl,
9049 /* WINED3DSIH_TEXM3x2DEPTH */ shader_glsl_texm3x2depth,
9050 /* WINED3DSIH_TEXM3x2PAD */ shader_glsl_texm3x2pad,
9051 /* WINED3DSIH_TEXM3x2TEX */ shader_glsl_texm3x2tex,
9052 /* WINED3DSIH_TEXM3x3 */ shader_glsl_texm3x3,
9053 /* WINED3DSIH_TEXM3x3DIFF */ NULL,
9054 /* WINED3DSIH_TEXM3x3PAD */ shader_glsl_texm3x3pad,
9055 /* WINED3DSIH_TEXM3x3SPEC */ shader_glsl_texm3x3spec,
9056 /* WINED3DSIH_TEXM3x3TEX */ shader_glsl_texm3x3tex,
9057 /* WINED3DSIH_TEXM3x3VSPEC */ shader_glsl_texm3x3vspec,
9058 /* WINED3DSIH_TEXREG2AR */ shader_glsl_texreg2ar,
9059 /* WINED3DSIH_TEXREG2GB */ shader_glsl_texreg2gb,
9060 /* WINED3DSIH_TEXREG2RGB */ shader_glsl_texreg2rgb,
9061 /* WINED3DSIH_UBFE */ NULL,
9062 /* WINED3DSIH_UDIV */ shader_glsl_udiv,
9063 /* WINED3DSIH_UGE */ shader_glsl_relop,
9064 /* WINED3DSIH_ULT */ shader_glsl_relop,
9065 /* WINED3DSIH_UMAX */ shader_glsl_map2gl,
9066 /* WINED3DSIH_UMIN */ shader_glsl_map2gl,
9067 /* WINED3DSIH_USHR */ shader_glsl_binop,
9068 /* WINED3DSIH_UTOF */ shader_glsl_to_float,
9069 /* WINED3DSIH_XOR */ shader_glsl_binop,
9072 static void shader_glsl_handle_instruction(const struct wined3d_shader_instruction *ins) {
9073 SHADER_HANDLER hw_fct;
9075 /* Select handler */
9076 hw_fct = shader_glsl_instruction_handler_table[ins->handler_idx];
9078 /* Unhandled opcode */
9079 if (!hw_fct)
9081 FIXME("Backend can't handle opcode %s.\n", debug_d3dshaderinstructionhandler(ins->handler_idx));
9082 return;
9084 hw_fct(ins);
9086 shader_glsl_add_instruction_modifiers(ins);
9089 static BOOL shader_glsl_has_ffp_proj_control(void *shader_priv)
9091 struct shader_glsl_priv *priv = shader_priv;
9093 return priv->ffp_proj_control;
9096 const struct wined3d_shader_backend_ops glsl_shader_backend =
9098 shader_glsl_handle_instruction,
9099 shader_glsl_select,
9100 shader_glsl_disable,
9101 shader_glsl_select_depth_blt,
9102 shader_glsl_deselect_depth_blt,
9103 shader_glsl_update_float_vertex_constants,
9104 shader_glsl_update_float_pixel_constants,
9105 shader_glsl_load_constants,
9106 shader_glsl_destroy,
9107 shader_glsl_alloc,
9108 shader_glsl_free,
9109 shader_glsl_allocate_context_data,
9110 shader_glsl_free_context_data,
9111 shader_glsl_init_context_state,
9112 shader_glsl_get_caps,
9113 shader_glsl_color_fixup_supported,
9114 shader_glsl_has_ffp_proj_control,
9117 static void glsl_vertex_pipe_vp_enable(const struct wined3d_gl_info *gl_info, BOOL enable) {}
9119 static void glsl_vertex_pipe_vp_get_caps(const struct wined3d_gl_info *gl_info, struct wined3d_vertex_caps *caps)
9121 caps->xyzrhw = TRUE;
9122 caps->emulated_flatshading = !gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
9123 caps->ffp_generic_attributes = TRUE;
9124 caps->max_active_lights = MAX_ACTIVE_LIGHTS;
9125 caps->max_vertex_blend_matrices = MAX_VERTEX_BLENDS;
9126 caps->max_vertex_blend_matrix_index = 0;
9127 caps->vertex_processing_caps = WINED3DVTXPCAPS_TEXGEN
9128 | WINED3DVTXPCAPS_MATERIALSOURCE7
9129 | WINED3DVTXPCAPS_VERTEXFOG
9130 | WINED3DVTXPCAPS_DIRECTIONALLIGHTS
9131 | WINED3DVTXPCAPS_POSITIONALLIGHTS
9132 | WINED3DVTXPCAPS_LOCALVIEWER
9133 | WINED3DVTXPCAPS_TEXGEN_SPHEREMAP;
9134 caps->fvf_caps = WINED3DFVFCAPS_PSIZE | 8; /* 8 texture coordinates. */
9135 caps->max_user_clip_planes = gl_info->limits.user_clip_distances;
9136 caps->raster_caps = WINED3DPRASTERCAPS_FOGRANGE;
9139 static DWORD glsl_vertex_pipe_vp_get_emul_mask(const struct wined3d_gl_info *gl_info)
9141 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
9142 return GL_EXT_EMUL_ARB_MULTITEXTURE;
9143 return 0;
9146 static void *glsl_vertex_pipe_vp_alloc(const struct wined3d_shader_backend_ops *shader_backend, void *shader_priv)
9148 struct shader_glsl_priv *priv;
9150 if (shader_backend == &glsl_shader_backend)
9152 priv = shader_priv;
9153 wine_rb_init(&priv->ffp_vertex_shaders, wined3d_ffp_vertex_program_key_compare);
9154 return priv;
9157 FIXME("GLSL vertex pipe without GLSL shader backend not implemented.\n");
9159 return NULL;
9162 static void shader_glsl_free_ffp_vertex_shader(struct wine_rb_entry *entry, void *context)
9164 struct glsl_ffp_vertex_shader *shader = WINE_RB_ENTRY_VALUE(entry,
9165 struct glsl_ffp_vertex_shader, desc.entry);
9166 struct glsl_shader_prog_link *program, *program2;
9167 struct glsl_ffp_destroy_ctx *ctx = context;
9169 LIST_FOR_EACH_ENTRY_SAFE(program, program2, &shader->linked_programs,
9170 struct glsl_shader_prog_link, vs.shader_entry)
9172 delete_glsl_program_entry(ctx->priv, ctx->gl_info, program);
9174 ctx->gl_info->gl_ops.ext.p_glDeleteShader(shader->id);
9175 HeapFree(GetProcessHeap(), 0, shader);
9178 /* Context activation is done by the caller. */
9179 static void glsl_vertex_pipe_vp_free(struct wined3d_device *device)
9181 struct shader_glsl_priv *priv = device->vertex_priv;
9182 struct glsl_ffp_destroy_ctx ctx;
9184 ctx.priv = priv;
9185 ctx.gl_info = &device->adapter->gl_info;
9186 wine_rb_destroy(&priv->ffp_vertex_shaders, shader_glsl_free_ffp_vertex_shader, &ctx);
9189 static void glsl_vertex_pipe_nop(struct wined3d_context *context,
9190 const struct wined3d_state *state, DWORD state_id) {}
9192 static void glsl_vertex_pipe_shader(struct wined3d_context *context,
9193 const struct wined3d_state *state, DWORD state_id)
9195 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9198 static void glsl_vertex_pipe_vdecl(struct wined3d_context *context,
9199 const struct wined3d_state *state, DWORD state_id)
9201 const struct wined3d_gl_info *gl_info = context->gl_info;
9202 BOOL normal = !!(context->stream_info.use_map & (1u << WINED3D_FFP_NORMAL));
9203 BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
9204 BOOL transformed = context->stream_info.position_transformed;
9205 BOOL wasrhw = context->last_was_rhw;
9206 unsigned int i;
9208 context->last_was_rhw = transformed;
9210 /* If the vertex declaration contains a transformed position attribute,
9211 * the draw uses the fixed function vertex pipeline regardless of any
9212 * vertex shader set by the application. */
9213 if (transformed != wasrhw
9214 || context->stream_info.swizzle_map != context->last_swizzle_map)
9215 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9217 context->last_swizzle_map = context->stream_info.swizzle_map;
9219 if (!use_vs(state))
9221 if (context->last_was_vshader)
9223 if (legacy_context)
9224 for (i = 0; i < gl_info->limits.user_clip_distances; ++i)
9225 clipplane(context, state, STATE_CLIPPLANE(i));
9226 else
9227 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_CLIP_PLANES;
9230 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_TEXMATRIX;
9232 /* Because of settings->texcoords, we have to regenerate the vertex
9233 * shader on a vdecl change if there aren't enough varyings to just
9234 * always output all the texture coordinates. */
9235 if (gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(gl_info)
9236 || normal != context->last_was_normal)
9237 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9239 if (use_ps(state)
9240 && state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.shader_version.major == 1
9241 && state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.shader_version.minor <= 3)
9242 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9244 else
9246 if (!context->last_was_vshader)
9248 /* Vertex shader clipping ignores the view matrix. Update all clip planes. */
9249 if (legacy_context)
9250 for (i = 0; i < gl_info->limits.user_clip_distances; ++i)
9251 clipplane(context, state, STATE_CLIPPLANE(i));
9252 else
9253 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_CLIP_PLANES;
9257 context->last_was_vshader = use_vs(state);
9258 context->last_was_normal = normal;
9261 static void glsl_vertex_pipe_vs(struct wined3d_context *context,
9262 const struct wined3d_state *state, DWORD state_id)
9264 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9265 /* Different vertex shaders potentially require a different vertex attributes setup. */
9266 if (!isStateDirty(context, STATE_VDECL))
9267 context_apply_state(context, state, STATE_VDECL);
9270 static void glsl_vertex_pipe_geometry_shader(struct wined3d_context *context,
9271 const struct wined3d_state *state, DWORD state_id)
9273 if (state->shader[WINED3D_SHADER_TYPE_VERTEX]
9274 && state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.shader_version.major >= 4)
9275 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9278 static void glsl_vertex_pipe_pixel_shader(struct wined3d_context *context,
9279 const struct wined3d_state *state, DWORD state_id)
9281 if (state->shader[WINED3D_SHADER_TYPE_GEOMETRY])
9282 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_GEOMETRY;
9283 else if (state->shader[WINED3D_SHADER_TYPE_VERTEX]
9284 && state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.shader_version.major >= 4)
9285 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9288 static void glsl_vertex_pipe_world(struct wined3d_context *context,
9289 const struct wined3d_state *state, DWORD state_id)
9291 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_MODELVIEW;
9294 static void glsl_vertex_pipe_vertexblend(struct wined3d_context *context,
9295 const struct wined3d_state *state, DWORD state_id)
9297 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_VERTEXBLEND;
9300 static void glsl_vertex_pipe_view(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
9302 const struct wined3d_gl_info *gl_info = context->gl_info;
9303 unsigned int k;
9305 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_MODELVIEW
9306 | WINED3D_SHADER_CONST_FFP_LIGHTS
9307 | WINED3D_SHADER_CONST_FFP_VERTEXBLEND;
9309 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
9311 for (k = 0; k < gl_info->limits.user_clip_distances; ++k)
9313 if (!isStateDirty(context, STATE_CLIPPLANE(k)))
9314 clipplane(context, state, STATE_CLIPPLANE(k));
9317 else
9319 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_CLIP_PLANES;
9323 static void glsl_vertex_pipe_projection(struct wined3d_context *context,
9324 const struct wined3d_state *state, DWORD state_id)
9326 /* Table fog behavior depends on the projection matrix. */
9327 if (state->render_states[WINED3D_RS_FOGENABLE]
9328 && state->render_states[WINED3D_RS_FOGTABLEMODE] != WINED3D_FOG_NONE)
9329 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9330 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_PROJ;
9333 static void glsl_vertex_pipe_viewport(struct wined3d_context *context,
9334 const struct wined3d_state *state, DWORD state_id)
9336 if (!isStateDirty(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION)))
9337 glsl_vertex_pipe_projection(context, state, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
9338 if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_POINTSCALEENABLE))
9339 && state->render_states[WINED3D_RS_POINTSCALEENABLE])
9340 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_POINTSIZE;
9341 context->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP;
9344 static void glsl_vertex_pipe_texmatrix(struct wined3d_context *context,
9345 const struct wined3d_state *state, DWORD state_id)
9347 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_TEXMATRIX;
9350 static void glsl_vertex_pipe_texmatrix_np2(struct wined3d_context *context,
9351 const struct wined3d_state *state, DWORD state_id)
9353 DWORD sampler = state_id - STATE_SAMPLER(0);
9354 const struct wined3d_texture *texture = state->textures[sampler];
9355 BOOL np2;
9357 if (!texture)
9358 return;
9360 if (sampler >= MAX_TEXTURES)
9361 return;
9363 if ((np2 = !(texture->flags & WINED3D_TEXTURE_POW2_MAT_IDENT))
9364 || context->lastWasPow2Texture & (1u << sampler))
9366 if (np2)
9367 context->lastWasPow2Texture |= 1u << sampler;
9368 else
9369 context->lastWasPow2Texture &= ~(1u << sampler);
9371 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_TEXMATRIX;
9375 static void glsl_vertex_pipe_material(struct wined3d_context *context,
9376 const struct wined3d_state *state, DWORD state_id)
9378 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_MATERIAL;
9381 static void glsl_vertex_pipe_light(struct wined3d_context *context,
9382 const struct wined3d_state *state, DWORD state_id)
9384 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_LIGHTS;
9387 static void glsl_vertex_pipe_pointsize(struct wined3d_context *context,
9388 const struct wined3d_state *state, DWORD state_id)
9390 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_POINTSIZE;
9393 static void glsl_vertex_pipe_pointscale(struct wined3d_context *context,
9394 const struct wined3d_state *state, DWORD state_id)
9396 if (!use_vs(state))
9397 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_POINTSIZE;
9400 static void glsl_vertex_pointsprite_core(struct wined3d_context *context,
9401 const struct wined3d_state *state, DWORD state_id)
9403 static unsigned int once;
9405 if (state->gl_primitive_type == GL_POINTS && !state->render_states[WINED3D_RS_POINTSPRITEENABLE] && !once++)
9406 FIXME("Non-point sprite points not supported in core profile.\n");
9409 static void glsl_vertex_pipe_shademode(struct wined3d_context *context,
9410 const struct wined3d_state *state, DWORD state_id)
9412 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_VERTEX;
9415 static void glsl_vertex_pipe_clip_plane(struct wined3d_context *context,
9416 const struct wined3d_state *state, DWORD state_id)
9418 const struct wined3d_gl_info *gl_info = context->gl_info;
9419 UINT index = state_id - STATE_CLIPPLANE(0);
9421 if (index >= gl_info->limits.user_clip_distances)
9422 return;
9424 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_CLIP_PLANES;
9427 static const struct StateEntryTemplate glsl_vertex_pipe_vp_states[] =
9429 {STATE_VDECL, {STATE_VDECL, glsl_vertex_pipe_vdecl }, WINED3D_GL_EXT_NONE },
9430 {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), glsl_vertex_pipe_vs }, WINED3D_GL_EXT_NONE },
9431 {STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY), {STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY), glsl_vertex_pipe_geometry_shader}, WINED3D_GL_EXT_NONE },
9432 {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), glsl_vertex_pipe_pixel_shader}, WINED3D_GL_EXT_NONE },
9433 {STATE_MATERIAL, {STATE_RENDER(WINED3D_RS_SPECULARENABLE), NULL }, WINED3D_GL_EXT_NONE },
9434 {STATE_RENDER(WINED3D_RS_SPECULARENABLE), {STATE_RENDER(WINED3D_RS_SPECULARENABLE), glsl_vertex_pipe_material}, WINED3D_GL_EXT_NONE },
9435 /* Clip planes */
9436 {STATE_CLIPPLANE(0), {STATE_CLIPPLANE(0), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9437 {STATE_CLIPPLANE(0), {STATE_CLIPPLANE(0), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9438 {STATE_CLIPPLANE(1), {STATE_CLIPPLANE(1), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9439 {STATE_CLIPPLANE(1), {STATE_CLIPPLANE(1), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9440 {STATE_CLIPPLANE(2), {STATE_CLIPPLANE(2), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9441 {STATE_CLIPPLANE(2), {STATE_CLIPPLANE(2), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9442 {STATE_CLIPPLANE(3), {STATE_CLIPPLANE(3), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9443 {STATE_CLIPPLANE(3), {STATE_CLIPPLANE(3), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9444 {STATE_CLIPPLANE(4), {STATE_CLIPPLANE(4), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9445 {STATE_CLIPPLANE(4), {STATE_CLIPPLANE(4), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9446 {STATE_CLIPPLANE(5), {STATE_CLIPPLANE(5), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9447 {STATE_CLIPPLANE(5), {STATE_CLIPPLANE(5), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9448 {STATE_CLIPPLANE(6), {STATE_CLIPPLANE(6), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9449 {STATE_CLIPPLANE(6), {STATE_CLIPPLANE(6), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9450 {STATE_CLIPPLANE(7), {STATE_CLIPPLANE(7), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9451 {STATE_CLIPPLANE(7), {STATE_CLIPPLANE(7), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9452 {STATE_CLIPPLANE(8), {STATE_CLIPPLANE(8), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9453 {STATE_CLIPPLANE(8), {STATE_CLIPPLANE(8), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9454 {STATE_CLIPPLANE(9), {STATE_CLIPPLANE(9), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9455 {STATE_CLIPPLANE(9), {STATE_CLIPPLANE(9), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9456 {STATE_CLIPPLANE(10), {STATE_CLIPPLANE(10), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9457 {STATE_CLIPPLANE(10), {STATE_CLIPPLANE(10), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9458 {STATE_CLIPPLANE(11), {STATE_CLIPPLANE(11), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9459 {STATE_CLIPPLANE(11), {STATE_CLIPPLANE(11), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9460 {STATE_CLIPPLANE(12), {STATE_CLIPPLANE(12), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9461 {STATE_CLIPPLANE(12), {STATE_CLIPPLANE(12), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9462 {STATE_CLIPPLANE(13), {STATE_CLIPPLANE(13), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9463 {STATE_CLIPPLANE(13), {STATE_CLIPPLANE(13), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9464 {STATE_CLIPPLANE(14), {STATE_CLIPPLANE(14), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9465 {STATE_CLIPPLANE(14), {STATE_CLIPPLANE(14), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9466 {STATE_CLIPPLANE(15), {STATE_CLIPPLANE(15), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9467 {STATE_CLIPPLANE(15), {STATE_CLIPPLANE(15), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9468 {STATE_CLIPPLANE(16), {STATE_CLIPPLANE(16), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9469 {STATE_CLIPPLANE(16), {STATE_CLIPPLANE(16), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9470 {STATE_CLIPPLANE(17), {STATE_CLIPPLANE(17), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9471 {STATE_CLIPPLANE(17), {STATE_CLIPPLANE(17), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9472 {STATE_CLIPPLANE(18), {STATE_CLIPPLANE(18), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9473 {STATE_CLIPPLANE(18), {STATE_CLIPPLANE(18), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9474 {STATE_CLIPPLANE(19), {STATE_CLIPPLANE(19), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9475 {STATE_CLIPPLANE(19), {STATE_CLIPPLANE(19), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9476 {STATE_CLIPPLANE(20), {STATE_CLIPPLANE(20), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9477 {STATE_CLIPPLANE(20), {STATE_CLIPPLANE(20), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9478 {STATE_CLIPPLANE(21), {STATE_CLIPPLANE(21), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9479 {STATE_CLIPPLANE(21), {STATE_CLIPPLANE(21), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9480 {STATE_CLIPPLANE(22), {STATE_CLIPPLANE(22), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9481 {STATE_CLIPPLANE(22), {STATE_CLIPPLANE(22), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9482 {STATE_CLIPPLANE(23), {STATE_CLIPPLANE(23), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9483 {STATE_CLIPPLANE(23), {STATE_CLIPPLANE(23), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9484 {STATE_CLIPPLANE(24), {STATE_CLIPPLANE(24), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9485 {STATE_CLIPPLANE(24), {STATE_CLIPPLANE(24), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9486 {STATE_CLIPPLANE(25), {STATE_CLIPPLANE(25), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9487 {STATE_CLIPPLANE(25), {STATE_CLIPPLANE(25), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9488 {STATE_CLIPPLANE(26), {STATE_CLIPPLANE(26), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9489 {STATE_CLIPPLANE(26), {STATE_CLIPPLANE(26), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9490 {STATE_CLIPPLANE(27), {STATE_CLIPPLANE(27), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9491 {STATE_CLIPPLANE(27), {STATE_CLIPPLANE(27), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9492 {STATE_CLIPPLANE(28), {STATE_CLIPPLANE(28), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9493 {STATE_CLIPPLANE(28), {STATE_CLIPPLANE(28), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9494 {STATE_CLIPPLANE(29), {STATE_CLIPPLANE(29), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9495 {STATE_CLIPPLANE(29), {STATE_CLIPPLANE(29), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9496 {STATE_CLIPPLANE(30), {STATE_CLIPPLANE(30), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9497 {STATE_CLIPPLANE(30), {STATE_CLIPPLANE(30), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9498 {STATE_CLIPPLANE(31), {STATE_CLIPPLANE(31), clipplane }, WINED3D_GL_LEGACY_CONTEXT },
9499 {STATE_CLIPPLANE(31), {STATE_CLIPPLANE(31), glsl_vertex_pipe_clip_plane}, WINED3D_GL_EXT_NONE },
9500 /* Lights */
9501 {STATE_LIGHT_TYPE, {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9502 {STATE_ACTIVELIGHT(0), {STATE_ACTIVELIGHT(0), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9503 {STATE_ACTIVELIGHT(1), {STATE_ACTIVELIGHT(1), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9504 {STATE_ACTIVELIGHT(2), {STATE_ACTIVELIGHT(2), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9505 {STATE_ACTIVELIGHT(3), {STATE_ACTIVELIGHT(3), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9506 {STATE_ACTIVELIGHT(4), {STATE_ACTIVELIGHT(4), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9507 {STATE_ACTIVELIGHT(5), {STATE_ACTIVELIGHT(5), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9508 {STATE_ACTIVELIGHT(6), {STATE_ACTIVELIGHT(6), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9509 {STATE_ACTIVELIGHT(7), {STATE_ACTIVELIGHT(7), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9510 /* Viewport */
9511 {STATE_VIEWPORT, {STATE_VIEWPORT, glsl_vertex_pipe_viewport}, WINED3D_GL_EXT_NONE },
9512 /* Transform states */
9513 {STATE_TRANSFORM(WINED3D_TS_VIEW), {STATE_TRANSFORM(WINED3D_TS_VIEW), glsl_vertex_pipe_view }, WINED3D_GL_EXT_NONE },
9514 {STATE_TRANSFORM(WINED3D_TS_PROJECTION), {STATE_TRANSFORM(WINED3D_TS_PROJECTION), glsl_vertex_pipe_projection}, WINED3D_GL_EXT_NONE },
9515 {STATE_TRANSFORM(WINED3D_TS_TEXTURE0), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9516 {STATE_TRANSFORM(WINED3D_TS_TEXTURE1), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9517 {STATE_TRANSFORM(WINED3D_TS_TEXTURE2), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9518 {STATE_TRANSFORM(WINED3D_TS_TEXTURE3), {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9519 {STATE_TRANSFORM(WINED3D_TS_TEXTURE4), {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9520 {STATE_TRANSFORM(WINED3D_TS_TEXTURE5), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9521 {STATE_TRANSFORM(WINED3D_TS_TEXTURE6), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9522 {STATE_TRANSFORM(WINED3D_TS_TEXTURE7), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), NULL }, WINED3D_GL_EXT_NONE },
9523 {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)), {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)), glsl_vertex_pipe_world }, WINED3D_GL_EXT_NONE },
9524 {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(1)), {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(1)), glsl_vertex_pipe_vertexblend }, WINED3D_GL_EXT_NONE },
9525 {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(2)), {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(2)), glsl_vertex_pipe_vertexblend }, WINED3D_GL_EXT_NONE },
9526 {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(3)), {STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(3)), glsl_vertex_pipe_vertexblend }, WINED3D_GL_EXT_NONE },
9527 {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9528 {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9529 {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9530 {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9531 {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9532 {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9533 {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9534 {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_vertex_pipe_texmatrix}, WINED3D_GL_EXT_NONE },
9535 {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9536 {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9537 {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9538 {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9539 {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9540 {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9541 {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9542 {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXCOORD_INDEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9543 /* Fog */
9544 {STATE_RENDER(WINED3D_RS_FOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), glsl_vertex_pipe_shader}, WINED3D_GL_EXT_NONE },
9545 {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9546 {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9547 {STATE_RENDER(WINED3D_RS_RANGEFOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9548 {STATE_RENDER(WINED3D_RS_CLIPPING), {STATE_RENDER(WINED3D_RS_CLIPPING), state_clipping }, WINED3D_GL_EXT_NONE },
9549 {STATE_RENDER(WINED3D_RS_CLIPPLANEENABLE), {STATE_RENDER(WINED3D_RS_CLIPPING), NULL }, WINED3D_GL_EXT_NONE },
9550 {STATE_RENDER(WINED3D_RS_LIGHTING), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9551 {STATE_RENDER(WINED3D_RS_AMBIENT), {STATE_RENDER(WINED3D_RS_AMBIENT), glsl_vertex_pipe_light }, WINED3D_GL_EXT_NONE },
9552 {STATE_RENDER(WINED3D_RS_COLORVERTEX), {STATE_RENDER(WINED3D_RS_COLORVERTEX), glsl_vertex_pipe_shader}, WINED3D_GL_EXT_NONE },
9553 {STATE_RENDER(WINED3D_RS_LOCALVIEWER), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9554 {STATE_RENDER(WINED3D_RS_NORMALIZENORMALS), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9555 {STATE_RENDER(WINED3D_RS_DIFFUSEMATERIALSOURCE), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9556 {STATE_RENDER(WINED3D_RS_SPECULARMATERIALSOURCE), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9557 {STATE_RENDER(WINED3D_RS_AMBIENTMATERIALSOURCE), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9558 {STATE_RENDER(WINED3D_RS_EMISSIVEMATERIALSOURCE), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9559 {STATE_RENDER(WINED3D_RS_VERTEXBLEND), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9560 {STATE_RENDER(WINED3D_RS_POINTSIZE), {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), NULL }, WINED3D_GL_EXT_NONE },
9561 {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), glsl_vertex_pipe_pointsize}, WINED3D_GL_EXT_NONE },
9562 {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), state_pointsprite }, ARB_POINT_SPRITE },
9563 {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), state_pointsprite_w }, WINED3D_GL_LEGACY_CONTEXT },
9564 {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), glsl_vertex_pointsprite_core}, WINED3D_GL_EXT_NONE },
9565 {STATE_RENDER(WINED3D_RS_POINTSCALEENABLE), {STATE_RENDER(WINED3D_RS_POINTSCALEENABLE), glsl_vertex_pipe_pointscale}, WINED3D_GL_EXT_NONE },
9566 {STATE_RENDER(WINED3D_RS_POINTSCALE_A), {STATE_RENDER(WINED3D_RS_POINTSCALEENABLE), NULL }, WINED3D_GL_EXT_NONE },
9567 {STATE_RENDER(WINED3D_RS_POINTSCALE_B), {STATE_RENDER(WINED3D_RS_POINTSCALEENABLE), NULL }, WINED3D_GL_EXT_NONE },
9568 {STATE_RENDER(WINED3D_RS_POINTSCALE_C), {STATE_RENDER(WINED3D_RS_POINTSCALEENABLE), NULL }, WINED3D_GL_EXT_NONE },
9569 {STATE_RENDER(WINED3D_RS_POINTSIZE_MAX), {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), NULL }, WINED3D_GL_EXT_NONE },
9570 {STATE_RENDER(WINED3D_RS_TWEENFACTOR), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9571 {STATE_RENDER(WINED3D_RS_INDEXEDVERTEXBLENDENABLE), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), NULL }, WINED3D_GL_EXT_NONE },
9572 /* NP2 texture matrix fixups. They are not needed if
9573 * GL_ARB_texture_non_power_of_two is supported. Otherwise, register
9574 * glsl_vertex_pipe_texmatrix(), which takes care of updating the texture
9575 * matrix. */
9576 {STATE_SAMPLER(0), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9577 {STATE_SAMPLER(0), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9578 {STATE_SAMPLER(0), {STATE_SAMPLER(0), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9579 {STATE_SAMPLER(1), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9580 {STATE_SAMPLER(1), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9581 {STATE_SAMPLER(1), {STATE_SAMPLER(1), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9582 {STATE_SAMPLER(2), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9583 {STATE_SAMPLER(2), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9584 {STATE_SAMPLER(2), {STATE_SAMPLER(2), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9585 {STATE_SAMPLER(3), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9586 {STATE_SAMPLER(3), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9587 {STATE_SAMPLER(3), {STATE_SAMPLER(3), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9588 {STATE_SAMPLER(4), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9589 {STATE_SAMPLER(4), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9590 {STATE_SAMPLER(4), {STATE_SAMPLER(4), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9591 {STATE_SAMPLER(5), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9592 {STATE_SAMPLER(5), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9593 {STATE_SAMPLER(5), {STATE_SAMPLER(5), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9594 {STATE_SAMPLER(6), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9595 {STATE_SAMPLER(6), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9596 {STATE_SAMPLER(6), {STATE_SAMPLER(6), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9597 {STATE_SAMPLER(7), {0, NULL }, ARB_TEXTURE_NON_POWER_OF_TWO },
9598 {STATE_SAMPLER(7), {0, NULL }, WINED3D_GL_NORMALIZED_TEXRECT},
9599 {STATE_SAMPLER(7), {STATE_SAMPLER(7), glsl_vertex_pipe_texmatrix_np2}, WINED3D_GL_EXT_NONE },
9600 {STATE_POINT_ENABLE, {STATE_POINT_ENABLE, glsl_vertex_pipe_shader}, WINED3D_GL_EXT_NONE },
9601 {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), glsl_vertex_pipe_nop }, WINED3D_GL_LEGACY_CONTEXT },
9602 {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), glsl_vertex_pipe_shademode}, WINED3D_GL_EXT_NONE },
9603 {0 /* Terminate */, {0, NULL }, WINED3D_GL_EXT_NONE },
9606 /* TODO:
9607 * - Implement vertex tweening. */
9608 const struct wined3d_vertex_pipe_ops glsl_vertex_pipe =
9610 glsl_vertex_pipe_vp_enable,
9611 glsl_vertex_pipe_vp_get_caps,
9612 glsl_vertex_pipe_vp_get_emul_mask,
9613 glsl_vertex_pipe_vp_alloc,
9614 glsl_vertex_pipe_vp_free,
9615 glsl_vertex_pipe_vp_states,
9618 static void glsl_fragment_pipe_enable(const struct wined3d_gl_info *gl_info, BOOL enable)
9620 /* Nothing to do. */
9623 static void glsl_fragment_pipe_get_caps(const struct wined3d_gl_info *gl_info, struct fragment_caps *caps)
9625 caps->wined3d_caps = WINED3D_FRAGMENT_CAP_PROJ_CONTROL
9626 | WINED3D_FRAGMENT_CAP_SRGB_WRITE
9627 | WINED3D_FRAGMENT_CAP_COLOR_KEY;
9628 caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP
9629 | WINED3DPMISCCAPS_PERSTAGECONSTANT;
9630 caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE
9631 | WINED3DTEXOPCAPS_SELECTARG1
9632 | WINED3DTEXOPCAPS_SELECTARG2
9633 | WINED3DTEXOPCAPS_MODULATE4X
9634 | WINED3DTEXOPCAPS_MODULATE2X
9635 | WINED3DTEXOPCAPS_MODULATE
9636 | WINED3DTEXOPCAPS_ADDSIGNED2X
9637 | WINED3DTEXOPCAPS_ADDSIGNED
9638 | WINED3DTEXOPCAPS_ADD
9639 | WINED3DTEXOPCAPS_SUBTRACT
9640 | WINED3DTEXOPCAPS_ADDSMOOTH
9641 | WINED3DTEXOPCAPS_BLENDCURRENTALPHA
9642 | WINED3DTEXOPCAPS_BLENDFACTORALPHA
9643 | WINED3DTEXOPCAPS_BLENDTEXTUREALPHA
9644 | WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA
9645 | WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM
9646 | WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
9647 | WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
9648 | WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
9649 | WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
9650 | WINED3DTEXOPCAPS_DOTPRODUCT3
9651 | WINED3DTEXOPCAPS_MULTIPLYADD
9652 | WINED3DTEXOPCAPS_LERP
9653 | WINED3DTEXOPCAPS_BUMPENVMAP
9654 | WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE;
9655 caps->MaxTextureBlendStages = MAX_TEXTURES;
9656 caps->MaxSimultaneousTextures = min(gl_info->limits.fragment_samplers, MAX_TEXTURES);
9659 static DWORD glsl_fragment_pipe_get_emul_mask(const struct wined3d_gl_info *gl_info)
9661 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
9662 return GL_EXT_EMUL_ARB_MULTITEXTURE;
9663 return 0;
9666 static void *glsl_fragment_pipe_alloc(const struct wined3d_shader_backend_ops *shader_backend, void *shader_priv)
9668 struct shader_glsl_priv *priv;
9670 if (shader_backend == &glsl_shader_backend)
9672 priv = shader_priv;
9673 wine_rb_init(&priv->ffp_fragment_shaders, wined3d_ffp_frag_program_key_compare);
9674 return priv;
9677 FIXME("GLSL fragment pipe without GLSL shader backend not implemented.\n");
9679 return NULL;
9682 static void shader_glsl_free_ffp_fragment_shader(struct wine_rb_entry *entry, void *context)
9684 struct glsl_ffp_fragment_shader *shader = WINE_RB_ENTRY_VALUE(entry,
9685 struct glsl_ffp_fragment_shader, entry.entry);
9686 struct glsl_shader_prog_link *program, *program2;
9687 struct glsl_ffp_destroy_ctx *ctx = context;
9689 LIST_FOR_EACH_ENTRY_SAFE(program, program2, &shader->linked_programs,
9690 struct glsl_shader_prog_link, ps.shader_entry)
9692 delete_glsl_program_entry(ctx->priv, ctx->gl_info, program);
9694 ctx->gl_info->gl_ops.ext.p_glDeleteShader(shader->id);
9695 HeapFree(GetProcessHeap(), 0, shader);
9698 /* Context activation is done by the caller. */
9699 static void glsl_fragment_pipe_free(struct wined3d_device *device)
9701 struct shader_glsl_priv *priv = device->fragment_priv;
9702 struct glsl_ffp_destroy_ctx ctx;
9704 ctx.priv = priv;
9705 ctx.gl_info = &device->adapter->gl_info;
9706 wine_rb_destroy(&priv->ffp_fragment_shaders, shader_glsl_free_ffp_fragment_shader, &ctx);
9709 static void glsl_fragment_pipe_shader(struct wined3d_context *context,
9710 const struct wined3d_state *state, DWORD state_id)
9712 context->last_was_pshader = use_ps(state);
9714 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9717 static void glsl_fragment_pipe_fogparams(struct wined3d_context *context,
9718 const struct wined3d_state *state, DWORD state_id)
9720 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_FOG;
9723 static void glsl_fragment_pipe_fog(struct wined3d_context *context,
9724 const struct wined3d_state *state, DWORD state_id)
9726 BOOL use_vshader = use_vs(state);
9727 enum fogsource new_source;
9728 DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART];
9729 DWORD fogend = state->render_states[WINED3D_RS_FOGEND];
9731 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9733 if (!state->render_states[WINED3D_RS_FOGENABLE])
9734 return;
9736 if (state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE)
9738 if (use_vshader)
9739 new_source = FOGSOURCE_VS;
9740 else if (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE || context->stream_info.position_transformed)
9741 new_source = FOGSOURCE_COORD;
9742 else
9743 new_source = FOGSOURCE_FFP;
9745 else
9747 new_source = FOGSOURCE_FFP;
9750 if (new_source != context->fog_source || fogstart == fogend)
9752 context->fog_source = new_source;
9753 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_FOG;
9757 static void glsl_fragment_pipe_vdecl(struct wined3d_context *context,
9758 const struct wined3d_state *state, DWORD state_id)
9760 /* Because of settings->texcoords_initialized and args->texcoords_initialized. */
9761 if (context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info))
9762 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9764 if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_FOGENABLE)))
9765 glsl_fragment_pipe_fog(context, state, state_id);
9768 static void glsl_fragment_pipe_vs(struct wined3d_context *context,
9769 const struct wined3d_state *state, DWORD state_id)
9771 /* Because of settings->texcoords_initialized and args->texcoords_initialized. */
9772 if (context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info))
9773 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9776 static void glsl_fragment_pipe_tex_transform(struct wined3d_context *context,
9777 const struct wined3d_state *state, DWORD state_id)
9779 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9782 static void glsl_fragment_pipe_invalidate_constants(struct wined3d_context *context,
9783 const struct wined3d_state *state, DWORD state_id)
9785 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_PS;
9788 static void glsl_fragment_pipe_alpha_test_func(struct wined3d_context *context,
9789 const struct wined3d_state *state, DWORD state_id)
9791 const struct wined3d_gl_info *gl_info = context->gl_info;
9792 GLint func = wined3d_gl_compare_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
9793 float ref = state->render_states[WINED3D_RS_ALPHAREF] / 255.0f;
9795 if (func)
9797 gl_info->gl_ops.gl.p_glAlphaFunc(func, ref);
9798 checkGLcall("glAlphaFunc");
9802 static void glsl_fragment_pipe_core_alpha_test(struct wined3d_context *context,
9803 const struct wined3d_state *state, DWORD state_id)
9805 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9808 static void glsl_fragment_pipe_alpha_test(struct wined3d_context *context,
9809 const struct wined3d_state *state, DWORD state_id)
9811 const struct wined3d_gl_info *gl_info = context->gl_info;
9813 if (state->render_states[WINED3D_RS_ALPHATESTENABLE])
9815 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
9816 checkGLcall("glEnable(GL_ALPHA_TEST)");
9818 else
9820 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
9821 checkGLcall("glDisable(GL_ALPHA_TEST)");
9825 static void glsl_fragment_pipe_core_alpha_test_ref(struct wined3d_context *context,
9826 const struct wined3d_state *state, DWORD state_id)
9828 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_ALPHA_TEST;
9831 static void glsl_fragment_pipe_color_key(struct wined3d_context *context,
9832 const struct wined3d_state *state, DWORD state_id)
9834 context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_COLOR_KEY;
9837 static void glsl_fragment_pipe_shademode(struct wined3d_context *context,
9838 const struct wined3d_state *state, DWORD state_id)
9840 context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
9843 static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] =
9845 {STATE_VDECL, {STATE_VDECL, glsl_fragment_pipe_vdecl }, WINED3D_GL_EXT_NONE },
9846 {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), glsl_fragment_pipe_vs }, WINED3D_GL_EXT_NONE },
9847 {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9848 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9849 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9850 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9851 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9852 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9853 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9854 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9855 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9856 {STATE_TEXTURESTAGE(0, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9857 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9858 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9859 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9860 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9861 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9862 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9863 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9864 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9865 {STATE_TEXTURESTAGE(1, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9866 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9867 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9868 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9869 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9870 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9871 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9872 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9873 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9874 {STATE_TEXTURESTAGE(2, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9875 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9876 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9877 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9878 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9879 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9880 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9881 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9882 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9883 {STATE_TEXTURESTAGE(3, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9884 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9885 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9886 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9887 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9888 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9889 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9890 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9891 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9892 {STATE_TEXTURESTAGE(4, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9893 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9894 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9895 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9896 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9897 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9898 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9899 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9900 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9901 {STATE_TEXTURESTAGE(5, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9902 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9903 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9904 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9905 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9906 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9907 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9908 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9909 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9910 {STATE_TEXTURESTAGE(6, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9911 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9912 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9913 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9914 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9915 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9916 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9917 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG2), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9918 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG0), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9919 {STATE_TEXTURESTAGE(7, WINED3D_TSS_RESULT_ARG), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9920 {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), glsl_fragment_pipe_shader }, WINED3D_GL_EXT_NONE },
9921 {STATE_RENDER(WINED3D_RS_ALPHAFUNC), {STATE_RENDER(WINED3D_RS_ALPHAFUNC), glsl_fragment_pipe_alpha_test_func }, WINED3D_GL_LEGACY_CONTEXT},
9922 {STATE_RENDER(WINED3D_RS_ALPHAFUNC), {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), NULL }, WINED3D_GL_EXT_NONE },
9923 {STATE_RENDER(WINED3D_RS_ALPHAREF), {STATE_RENDER(WINED3D_RS_ALPHAFUNC), NULL }, WINED3D_GL_LEGACY_CONTEXT},
9924 {STATE_RENDER(WINED3D_RS_ALPHAREF), {STATE_RENDER(WINED3D_RS_ALPHAREF), glsl_fragment_pipe_core_alpha_test_ref }, WINED3D_GL_EXT_NONE },
9925 {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), glsl_fragment_pipe_alpha_test }, WINED3D_GL_LEGACY_CONTEXT},
9926 {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), glsl_fragment_pipe_core_alpha_test }, WINED3D_GL_EXT_NONE },
9927 {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9928 {STATE_COLOR_KEY, { STATE_COLOR_KEY, glsl_fragment_pipe_color_key }, WINED3D_GL_EXT_NONE },
9929 {STATE_RENDER(WINED3D_RS_FOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), glsl_fragment_pipe_fog }, WINED3D_GL_EXT_NONE },
9930 {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9931 {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
9932 {STATE_RENDER(WINED3D_RS_FOGSTART), {STATE_RENDER(WINED3D_RS_FOGSTART), glsl_fragment_pipe_fogparams }, WINED3D_GL_EXT_NONE },
9933 {STATE_RENDER(WINED3D_RS_FOGEND), {STATE_RENDER(WINED3D_RS_FOGSTART), NULL }, WINED3D_GL_EXT_NONE },
9934 {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), state_srgbwrite }, ARB_FRAMEBUFFER_SRGB},
9935 {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
9936 {STATE_RENDER(WINED3D_RS_FOGCOLOR), {STATE_RENDER(WINED3D_RS_FOGCOLOR), glsl_fragment_pipe_fogparams }, WINED3D_GL_EXT_NONE },
9937 {STATE_RENDER(WINED3D_RS_FOGDENSITY), {STATE_RENDER(WINED3D_RS_FOGDENSITY), glsl_fragment_pipe_fogparams }, WINED3D_GL_EXT_NONE },
9938 {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), glsl_fragment_pipe_shader }, ARB_POINT_SPRITE },
9939 {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), glsl_fragment_pipe_shader }, WINED3D_GL_VERSION_2_0},
9940 {STATE_TEXTURESTAGE(0,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9941 {STATE_TEXTURESTAGE(1,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9942 {STATE_TEXTURESTAGE(2,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9943 {STATE_TEXTURESTAGE(3,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9944 {STATE_TEXTURESTAGE(4,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9945 {STATE_TEXTURESTAGE(5,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9946 {STATE_TEXTURESTAGE(6,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9947 {STATE_TEXTURESTAGE(7,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE },
9948 {STATE_TEXTURESTAGE(0, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(0, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9949 {STATE_TEXTURESTAGE(1, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(1, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9950 {STATE_TEXTURESTAGE(2, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(2, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9951 {STATE_TEXTURESTAGE(3, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(3, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9952 {STATE_TEXTURESTAGE(4, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(4, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9953 {STATE_TEXTURESTAGE(5, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(5, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9954 {STATE_TEXTURESTAGE(6, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(6, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9955 {STATE_TEXTURESTAGE(7, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(7, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9956 {STATE_RENDER(WINED3D_RS_SPECULARENABLE), {STATE_RENDER(WINED3D_RS_SPECULARENABLE), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE },
9957 {STATE_POINT_ENABLE, {STATE_POINT_ENABLE, glsl_fragment_pipe_shader }, WINED3D_GL_EXT_NONE },
9958 {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), state_shademode }, WINED3D_GL_LEGACY_CONTEXT},
9959 {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), glsl_fragment_pipe_shademode }, WINED3D_GL_EXT_NONE },
9960 {0 /* Terminate */, {0, 0 }, WINED3D_GL_EXT_NONE },
9963 static BOOL glsl_fragment_pipe_alloc_context_data(struct wined3d_context *context)
9965 return TRUE;
9968 static void glsl_fragment_pipe_free_context_data(struct wined3d_context *context)
9972 const struct fragment_pipeline glsl_fragment_pipe =
9974 glsl_fragment_pipe_enable,
9975 glsl_fragment_pipe_get_caps,
9976 glsl_fragment_pipe_get_emul_mask,
9977 glsl_fragment_pipe_alloc,
9978 glsl_fragment_pipe_free,
9979 glsl_fragment_pipe_alloc_context_data,
9980 glsl_fragment_pipe_free_context_data,
9981 shader_glsl_color_fixup_supported,
9982 glsl_fragment_pipe_state_template,