1 /* 2 * Pixel and vertex shaders implementation using ARB_vertex_program 3 * and ARB_fragment_program GL extensions. 4 * 5 * Copyright 2002-2003 Jason Edmeades 6 * Copyright 2002-2003 Raphael Junqueira 7 * Copyright 2004 Christian Costa 8 * Copyright 2005 Oliver Stieber 9 * Copyright 2006 Ivan Gyurdiev 10 * Copyright 2006 Jason Green 11 * Copyright 2006 Henri Verbeet 12 * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers 13 * Copyright 2009 Henri Verbeet for CodeWeavers 14 * 15 * This library is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU Lesser General Public 17 * License as published by the Free Software Foundation; either 18 * version 2.1 of the License, or (at your option) any later version. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 * Lesser General Public License for more details. 24 * 25 * You should have received a copy of the GNU Lesser General Public 26 * License along with this library; if not, write to the Free Software 27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 28 */ 29 30 #include "wined3d_private.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); 33 WINE_DECLARE_DEBUG_CHANNEL(d3d_constants); 34 WINE_DECLARE_DEBUG_CHANNEL(d3d); 35 36 static BOOL shader_is_pshader_version(enum wined3d_shader_type type) 37 { 38 return type == WINED3D_SHADER_TYPE_PIXEL; 39 } 40 41 static BOOL shader_is_vshader_version(enum wined3d_shader_type type) 42 { 43 return type == WINED3D_SHADER_TYPE_VERTEX; 44 } 45 46 /* Extract a line. Note that this modifies the source string. */ 47 static char *get_line(char **ptr) 48 { 49 char *p, *q; 50 51 p = *ptr; 52 if (!(q = strstr(p, "\n"))) 53 { 54 if (!*p) return NULL; 55 *ptr += strlen(p); 56 return p; 57 } 58 *q = '\0'; 59 *ptr = q + 1; 60 61 return p; 62 } 63 64 static void shader_arb_dump_program_source(const char *source) 65 { 66 ULONG source_size; 67 char *ptr, *line, *tmp; 68 69 source_size = strlen(source) + 1; 70 tmp = HeapAlloc(GetProcessHeap(), 0, source_size); 71 if (!tmp) 72 { 73 ERR("Failed to allocate %u bytes for shader source.\n", source_size); 74 return; 75 } 76 memcpy(tmp, source, source_size); 77 78 ptr = tmp; 79 while ((line = get_line(&ptr))) FIXME(" %s\n", line); 80 FIXME("\n"); 81 82 HeapFree(GetProcessHeap(), 0, tmp); 83 } 84 85 enum arb_helper_value 86 { 87 ARB_ZERO, 88 ARB_ONE, 89 ARB_TWO, 90 ARB_0001, 91 ARB_EPS, 92 93 ARB_VS_REL_OFFSET 94 }; 95 96 static const char *arb_get_helper_value(enum wined3d_shader_type shader, enum arb_helper_value value) 97 { 98 if (shader == WINED3D_SHADER_TYPE_GEOMETRY) 99 { 100 ERR("Geometry shaders are unsupported\n"); 101 return "bad"; 102 } 103 104 if (shader == WINED3D_SHADER_TYPE_PIXEL) 105 { 106 switch (value) 107 { 108 case ARB_ZERO: return "ps_helper_const.x"; 109 case ARB_ONE: return "ps_helper_const.y"; 110 case ARB_TWO: return "coefmul.x"; 111 case ARB_0001: return "ps_helper_const.xxxy"; 112 case ARB_EPS: return "ps_helper_const.z"; 113 default: break; 114 } 115 } 116 else 117 { 118 switch (value) 119 { 120 case ARB_ZERO: return "helper_const.x"; 121 case ARB_ONE: return "helper_const.y"; 122 case ARB_TWO: return "helper_const.z"; 123 case ARB_EPS: return "helper_const.w"; 124 case ARB_0001: return "helper_const.xxxy"; 125 case ARB_VS_REL_OFFSET: return "rel_addr_const.y"; 126 } 127 } 128 FIXME("Unmanaged %s shader helper constant requested: %u\n", 129 shader == WINED3D_SHADER_TYPE_PIXEL ? "pixel" : "vertex", value); 130 switch (value) 131 { 132 case ARB_ZERO: return "0.0"; 133 case ARB_ONE: return "1.0"; 134 case ARB_TWO: return "2.0"; 135 case ARB_0001: return "{0.0, 0.0, 0.0, 1.0}"; 136 case ARB_EPS: return "1e-8"; 137 default: return "bad"; 138 } 139 } 140 141 static inline BOOL ffp_clip_emul(const struct wined3d_context *context) 142 { 143 return context->lowest_disabled_stage < 7; 144 } 145 146 /* ARB_program_shader private data */ 147 148 struct control_frame 149 { 150 struct list entry; 151 enum 152 { 153 IF, 154 IFC, 155 LOOP, 156 REP 157 } type; 158 BOOL muting; 159 BOOL outer_loop; 160 union 161 { 162 unsigned int loop; 163 unsigned int ifc; 164 } no; 165 struct wined3d_shader_loop_control loop_control; 166 BOOL had_else; 167 }; 168 169 struct arb_ps_np2fixup_info 170 { 171 struct ps_np2fixup_info super; 172 /* For ARB we need an offset value: 173 * With both GLSL and ARB mode the NP2 fixup information (the texture dimensions) are stored in a 174 * consecutive way (GLSL uses a uniform array). Since ARB doesn't know the notion of a "standalone" 175 * array we need an offset to the index inside the program local parameter array. */ 176 UINT offset; 177 }; 178 179 struct arb_ps_compile_args 180 { 181 struct ps_compile_args super; 182 WORD bools; 183 WORD clip; /* only a boolean, use a WORD for alignment */ 184 unsigned char loop_ctrl[MAX_CONST_I][3]; 185 }; 186 187 struct stb_const_desc 188 { 189 unsigned char texunit; 190 UINT const_num; 191 }; 192 193 struct arb_ps_compiled_shader 194 { 195 struct arb_ps_compile_args args; 196 struct arb_ps_np2fixup_info np2fixup_info; 197 struct stb_const_desc bumpenvmatconst[MAX_TEXTURES]; 198 struct stb_const_desc luminanceconst[MAX_TEXTURES]; 199 UINT int_consts[MAX_CONST_I]; 200 GLuint prgId; 201 UINT ycorrection; 202 unsigned char numbumpenvmatconsts; 203 char num_int_consts; 204 }; 205 206 struct arb_vs_compile_args 207 { 208 struct vs_compile_args super; 209 union 210 { 211 struct 212 { 213 WORD bools; 214 unsigned char clip_texcoord; 215 unsigned char clipplane_mask; 216 } boolclip; 217 DWORD boolclip_compare; 218 } clip; 219 DWORD ps_signature; 220 union 221 { 222 unsigned char samplers[4]; 223 DWORD samplers_compare; 224 } vertex; 225 unsigned char loop_ctrl[MAX_CONST_I][3]; 226 }; 227 228 struct arb_vs_compiled_shader 229 { 230 struct arb_vs_compile_args args; 231 GLuint prgId; 232 UINT int_consts[MAX_CONST_I]; 233 char num_int_consts; 234 char need_color_unclamp; 235 UINT pos_fixup; 236 }; 237 238 struct recorded_instruction 239 { 240 struct wined3d_shader_instruction ins; 241 struct list entry; 242 }; 243 244 struct shader_arb_ctx_priv 245 { 246 char addr_reg[20]; 247 enum 248 { 249 /* plain GL_ARB_vertex_program or GL_ARB_fragment_program */ 250 ARB, 251 /* GL_NV_vertex_progam2_option or GL_NV_fragment_program_option */ 252 NV2, 253 /* GL_NV_vertex_program3 or GL_NV_fragment_program2 */ 254 NV3 255 } target_version; 256 257 const struct arb_vs_compile_args *cur_vs_args; 258 const struct arb_ps_compile_args *cur_ps_args; 259 const struct arb_ps_compiled_shader *compiled_fprog; 260 const struct arb_vs_compiled_shader *compiled_vprog; 261 struct arb_ps_np2fixup_info *cur_np2fixup_info; 262 struct list control_frames; 263 struct list record; 264 BOOL recording; 265 BOOL muted; 266 unsigned int num_loops, loop_depth, num_ifcs; 267 int aL; 268 BOOL ps_post_process; 269 270 unsigned int vs_clipplanes; 271 BOOL footer_written; 272 BOOL in_main_func; 273 274 /* For 3.0 vertex shaders */ 275 const char *vs_output[MAX_REG_OUTPUT]; 276 /* For 2.x and earlier vertex shaders */ 277 const char *texcrd_output[8], *color_output[2], *fog_output; 278 279 /* 3.0 pshader input for compatibility with fixed function */ 280 const char *ps_input[MAX_REG_INPUT]; 281 }; 282 283 struct ps_signature 284 { 285 struct wined3d_shader_signature_element *sig; 286 DWORD idx; 287 struct wine_rb_entry entry; 288 }; 289 290 struct arb_pshader_private { 291 struct arb_ps_compiled_shader *gl_shaders; 292 UINT num_gl_shaders, shader_array_size; 293 DWORD input_signature_idx; 294 DWORD clipplane_emulation; 295 BOOL clamp_consts; 296 }; 297 298 struct arb_vshader_private { 299 struct arb_vs_compiled_shader *gl_shaders; 300 UINT num_gl_shaders, shader_array_size; 301 UINT rel_offset; 302 }; 303 304 struct shader_arb_priv 305 { 306 GLuint current_vprogram_id; 307 GLuint current_fprogram_id; 308 const struct arb_ps_compiled_shader *compiled_fprog; 309 const struct arb_vs_compiled_shader *compiled_vprog; 310 GLuint depth_blt_vprogram_id; 311 GLuint depth_blt_fprogram_id_full[tex_type_count]; 312 GLuint depth_blt_fprogram_id_masked[tex_type_count]; 313 BOOL use_arbfp_fixed_func; 314 struct wine_rb_tree fragment_shaders; 315 BOOL last_ps_const_clamped; 316 BOOL last_vs_color_unclamp; 317 318 struct wine_rb_tree signature_tree; 319 DWORD ps_sig_number; 320 321 unsigned int highest_dirty_ps_const, highest_dirty_vs_const; 322 char *vshader_const_dirty, *pshader_const_dirty; 323 const struct wined3d_context *last_context; 324 325 const struct wined3d_vertex_pipe_ops *vertex_pipe; 326 const struct fragment_pipeline *fragment_pipe; 327 BOOL ffp_proj_control; 328 }; 329 330 /* Context activation for state handlers is done by the caller. */ 331 332 static BOOL need_rel_addr_const(const struct arb_vshader_private *shader_data, 333 const struct wined3d_shader_reg_maps *reg_maps, const struct wined3d_gl_info *gl_info) 334 { 335 if (shader_data->rel_offset) return TRUE; 336 if (!reg_maps->usesmova) return FALSE; 337 return !gl_info->supported[NV_VERTEX_PROGRAM2_OPTION]; 338 } 339 340 /* Returns TRUE if result.clip from GL_NV_vertex_program2 should be used and FALSE otherwise */ 341 static inline BOOL use_nv_clip(const struct wined3d_gl_info *gl_info) 342 { 343 return gl_info->supported[NV_VERTEX_PROGRAM2_OPTION] 344 && !(gl_info->quirks & WINED3D_QUIRK_NV_CLIP_BROKEN); 345 } 346 347 static BOOL need_helper_const(const struct arb_vshader_private *shader_data, 348 const struct wined3d_shader_reg_maps *reg_maps, const struct wined3d_gl_info *gl_info) 349 { 350 if (need_rel_addr_const(shader_data, reg_maps, gl_info)) return TRUE; 351 if (!gl_info->supported[NV_VERTEX_PROGRAM]) return TRUE; /* Need to init colors. */ 352 if (gl_info->quirks & WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT) return TRUE; /* Load the immval offset. */ 353 if (gl_info->quirks & WINED3D_QUIRK_SET_TEXCOORD_W) return TRUE; /* Have to init texcoords. */ 354 if (!use_nv_clip(gl_info)) return TRUE; /* Init the clip texcoord */ 355 if (reg_maps->usesnrm) return TRUE; /* 0.0 */ 356 if (reg_maps->usespow) return TRUE; /* EPS, 0.0 and 1.0 */ 357 if (reg_maps->fog) return TRUE; /* Clamping fog coord, 0.0 and 1.0 */ 358 return FALSE; 359 } 360 361 static unsigned int reserved_vs_const(const struct arb_vshader_private *shader_data, 362 const struct wined3d_shader_reg_maps *reg_maps, const struct wined3d_gl_info *gl_info) 363 { 364 unsigned int ret = 1; 365 /* We use one PARAM for the pos fixup, and in some cases one to load 366 * some immediate values into the shader. */ 367 if (need_helper_const(shader_data, reg_maps, gl_info)) ++ret; 368 if (need_rel_addr_const(shader_data, reg_maps, gl_info)) ++ret; 369 return ret; 370 } 371 372 /* Loads floating point constants into the currently set ARB_vertex/fragment_program. 373 * When constant_list == NULL, it will load all the constants. 374 * 375 * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders) 376 * or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders) 377 */ 378 /* Context activation is done by the caller. */ 379 static unsigned int shader_arb_load_constantsF(const struct wined3d_shader *shader, 380 const struct wined3d_gl_info *gl_info, GLuint target_type, unsigned int max_constants, 381 const float *constants, char *dirty_consts) 382 { 383 struct wined3d_shader_lconst *lconst; 384 DWORD i, j; 385 unsigned int ret; 386 387 if (TRACE_ON(d3d_constants)) 388 { 389 for(i = 0; i < max_constants; i++) { 390 if(!dirty_consts[i]) continue; 391 TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i, 392 constants[i * 4 + 0], constants[i * 4 + 1], 393 constants[i * 4 + 2], constants[i * 4 + 3]); 394 } 395 } 396 397 i = 0; 398 399 /* In 1.X pixel shaders constants are implicitly clamped in the range [-1;1] */ 400 if (target_type == GL_FRAGMENT_PROGRAM_ARB && shader->reg_maps.shader_version.major == 1) 401 { 402 float lcl_const[4]; 403 /* ps 1.x supports only 8 constants, clamp only those. When switching between 1.x and higher 404 * shaders, the first 8 constants are marked dirty for reload 405 */ 406 for(; i < min(8, max_constants); i++) { 407 if(!dirty_consts[i]) continue; 408 dirty_consts[i] = 0; 409 410 j = 4 * i; 411 if (constants[j + 0] > 1.0f) lcl_const[0] = 1.0f; 412 else if (constants[j + 0] < -1.0f) lcl_const[0] = -1.0f; 413 else lcl_const[0] = constants[j + 0]; 414 415 if (constants[j + 1] > 1.0f) lcl_const[1] = 1.0f; 416 else if (constants[j + 1] < -1.0f) lcl_const[1] = -1.0f; 417 else lcl_const[1] = constants[j + 1]; 418 419 if (constants[j + 2] > 1.0f) lcl_const[2] = 1.0f; 420 else if (constants[j + 2] < -1.0f) lcl_const[2] = -1.0f; 421 else lcl_const[2] = constants[j + 2]; 422 423 if (constants[j + 3] > 1.0f) lcl_const[3] = 1.0f; 424 else if (constants[j + 3] < -1.0f) lcl_const[3] = -1.0f; 425 else lcl_const[3] = constants[j + 3]; 426 427 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, lcl_const)); 428 } 429 430 /* If further constants are dirty, reload them without clamping. 431 * 432 * The alternative is not to touch them, but then we cannot reset the dirty constant count 433 * to zero. That's bad for apps that only use PS 1.x shaders, because in that case the code 434 * above would always re-check the first 8 constants since max_constant remains at the init 435 * value 436 */ 437 } 438 439 if (gl_info->supported[EXT_GPU_PROGRAM_PARAMETERS]) 440 { 441 /* TODO: Benchmark if we're better of with finding the dirty constants ourselves, 442 * or just reloading *all* constants at once 443 * 444 GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, i, max_constants, constants + (i * 4))); 445 */ 446 for(; i < max_constants; i++) { 447 if(!dirty_consts[i]) continue; 448 449 /* Find the next block of dirty constants */ 450 dirty_consts[i] = 0; 451 j = i; 452 for(i++; (i < max_constants) && dirty_consts[i]; i++) { 453 dirty_consts[i] = 0; 454 } 455 456 GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, j, i - j, constants + (j * 4))); 457 } 458 } else { 459 for(; i < max_constants; i++) { 460 if(dirty_consts[i]) { 461 dirty_consts[i] = 0; 462 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4))); 463 } 464 } 465 } 466 checkGLcall("glProgramEnvParameter4fvARB()"); 467 468 /* Load immediate constants */ 469 if (shader->load_local_constsF) 470 { 471 if (TRACE_ON(d3d_shader)) 472 { 473 LIST_FOR_EACH_ENTRY(lconst, &shader->constantsF, struct wined3d_shader_lconst, entry) 474 { 475 GLfloat* values = (GLfloat*)lconst->value; 476 TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx, 477 values[0], values[1], values[2], values[3]); 478 } 479 } 480 /* Immediate constants are clamped for 1.X shaders at loading times */ 481 ret = 0; 482 LIST_FOR_EACH_ENTRY(lconst, &shader->constantsF, struct wined3d_shader_lconst, entry) 483 { 484 dirty_consts[lconst->idx] = 1; /* Dirtify so the non-immediate constant overwrites it next time */ 485 ret = max(ret, lconst->idx + 1); 486 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value)); 487 } 488 checkGLcall("glProgramEnvParameter4fvARB()"); 489 return ret; /* The loaded immediate constants need reloading for the next shader */ 490 } else { 491 return 0; /* No constants are dirty now */ 492 } 493 } 494 495 /* Loads the texture dimensions for NP2 fixup into the currently set 496 * ARB_[vertex/fragment]_programs. */ 497 static void shader_arb_load_np2fixup_constants(const struct arb_ps_np2fixup_info *fixup, 498 const struct wined3d_gl_info *gl_info, const struct wined3d_state *state) 499 { 500 GLfloat np2fixup_constants[4 * MAX_FRAGMENT_SAMPLERS]; 501 WORD active = fixup->super.active; 502 UINT i; 503 504 if (!active) 505 return; 506 507 for (i = 0; active; active >>= 1, ++i) 508 { 509 const struct wined3d_texture *tex = state->textures[i]; 510 unsigned char idx = fixup->super.idx[i]; 511 GLfloat *tex_dim = &np2fixup_constants[(idx >> 1) * 4]; 512 513 if (!(active & 1)) 514 continue; 515 516 if (!tex) 517 { 518 ERR("Nonexistent texture is flagged for NP2 texcoord fixup.\n"); 519 continue; 520 } 521 522 if (idx % 2) 523 { 524 tex_dim[2] = tex->pow2_matrix[0]; 525 tex_dim[3] = tex->pow2_matrix[5]; 526 } 527 else 528 { 529 tex_dim[0] = tex->pow2_matrix[0]; 530 tex_dim[1] = tex->pow2_matrix[5]; 531 } 532 } 533 534 for (i = 0; i < fixup->super.num_consts; ++i) 535 { 536 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 537 fixup->offset + i, &np2fixup_constants[i * 4])); 538 } 539 } 540 541 /* Context activation is done by the caller. */ 542 static void shader_arb_ps_local_constants(const struct arb_ps_compiled_shader *gl_shader, 543 const struct wined3d_context *context, const struct wined3d_state *state, UINT rt_height) 544 { 545 const struct wined3d_gl_info *gl_info = context->gl_info; 546 unsigned char i; 547 548 for(i = 0; i < gl_shader->numbumpenvmatconsts; i++) 549 { 550 int texunit = gl_shader->bumpenvmatconst[i].texunit; 551 552 /* The state manager takes care that this function is always called if the bump env matrix changes */ 553 const float *data = (const float *)&state->texture_states[texunit][WINED3D_TSS_BUMPENV_MAT00]; 554 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 555 gl_shader->bumpenvmatconst[i].const_num, data)); 556 557 if (gl_shader->luminanceconst[i].const_num != WINED3D_CONST_NUM_UNUSED) 558 { 559 /* WINED3D_TSS_BUMPENVLSCALE and WINED3D_TSS_BUMPENVLOFFSET are next to each other. 560 * point gl to the scale, and load 4 floats. x = scale, y = offset, z and w are junk, we 561 * don't care about them. The pointers are valid for sure because the stateblock is bigger. 562 * (they're WINED3D_TSS_TEXTURETRANSFORMFLAGS and WINED3D_TSS_ADDRESSW, so most likely 0 or NaN 563 */ 564 const float *scale = (const float *)&state->texture_states[texunit][WINED3D_TSS_BUMPENV_LSCALE]; 565 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 566 gl_shader->luminanceconst[i].const_num, scale)); 567 } 568 } 569 checkGLcall("Load bumpmap consts"); 570 571 if(gl_shader->ycorrection != WINED3D_CONST_NUM_UNUSED) 572 { 573 /* ycorrection.x: Backbuffer height(onscreen) or 0(offscreen). 574 * ycorrection.y: -1.0(onscreen), 1.0(offscreen) 575 * ycorrection.z: 1.0 576 * ycorrection.w: 0.0 577 */ 578 float val[4]; 579 val[0] = context->render_offscreen ? 0.0f : (float) rt_height; 580 val[1] = context->render_offscreen ? 1.0f : -1.0f; 581 val[2] = 1.0f; 582 val[3] = 0.0f; 583 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, gl_shader->ycorrection, val)); 584 checkGLcall("y correction loading"); 585 } 586 587 if (!gl_shader->num_int_consts) return; 588 589 for(i = 0; i < MAX_CONST_I; i++) 590 { 591 if(gl_shader->int_consts[i] != WINED3D_CONST_NUM_UNUSED) 592 { 593 float val[4]; 594 val[0] = (float)state->ps_consts_i[4 * i]; 595 val[1] = (float)state->ps_consts_i[4 * i + 1]; 596 val[2] = (float)state->ps_consts_i[4 * i + 2]; 597 val[3] = -1.0f; 598 599 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, gl_shader->int_consts[i], val)); 600 } 601 } 602 checkGLcall("Load ps int consts"); 603 } 604 605 /* Context activation is done by the caller. */ 606 static void shader_arb_vs_local_constants(const struct arb_vs_compiled_shader *gl_shader, 607 const struct wined3d_context *context, const struct wined3d_state *state) 608 { 609 const struct wined3d_gl_info *gl_info = context->gl_info; 610 float position_fixup[4]; 611 unsigned char i; 612 613 /* Upload the position fixup */ 614 shader_get_position_fixup(context, state, position_fixup); 615 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, gl_shader->pos_fixup, position_fixup)); 616 617 if (!gl_shader->num_int_consts) return; 618 619 for(i = 0; i < MAX_CONST_I; i++) 620 { 621 if(gl_shader->int_consts[i] != WINED3D_CONST_NUM_UNUSED) 622 { 623 float val[4]; 624 val[0] = (float)state->vs_consts_i[4 * i]; 625 val[1] = (float)state->vs_consts_i[4 * i + 1]; 626 val[2] = (float)state->vs_consts_i[4 * i + 2]; 627 val[3] = -1.0f; 628 629 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, gl_shader->int_consts[i], val)); 630 } 631 } 632 checkGLcall("Load vs int consts"); 633 } 634 635 static void shader_arb_select(void *shader_priv, struct wined3d_context *context, 636 const struct wined3d_state *state); 637 638 /** 639 * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs. 640 * 641 * We only support float constants in ARB at the moment, so don't 642 * worry about the Integers or Booleans 643 */ 644 /* Context activation is done by the caller (state handler). */ 645 static void shader_arb_load_constants_internal(struct shader_arb_priv *priv, 646 struct wined3d_context *context, const struct wined3d_state *state, 647 BOOL usePixelShader, BOOL useVertexShader, BOOL from_shader_select) 648 { 649 const struct wined3d_d3d_info *d3d_info = context->d3d_info; 650 const struct wined3d_gl_info *gl_info = context->gl_info; 651 652 if (!from_shader_select) 653 { 654 const struct wined3d_shader *vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX]; 655 const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL]; 656 657 if (vshader 658 && (vshader->reg_maps.boolean_constants 659 || (!gl_info->supported[NV_VERTEX_PROGRAM2_OPTION] 660 && (vshader->reg_maps.integer_constants & ~vshader->reg_maps.local_int_consts)))) 661 { 662 TRACE("bool/integer vertex shader constants potentially modified, forcing shader reselection.\n"); 663 shader_arb_select(priv, context, state); 664 } 665 else if (pshader 666 && (pshader->reg_maps.boolean_constants 667 || (!gl_info->supported[NV_FRAGMENT_PROGRAM_OPTION] 668 && (pshader->reg_maps.integer_constants & ~pshader->reg_maps.local_int_consts)))) 669 { 670 TRACE("bool/integer pixel shader constants potentially modified, forcing shader reselection.\n"); 671 shader_arb_select(priv, context, state); 672 } 673 } 674 675 if (context != priv->last_context) 676 { 677 memset(priv->vshader_const_dirty, 1, 678 sizeof(*priv->vshader_const_dirty) * d3d_info->limits.vs_uniform_count); 679 priv->highest_dirty_vs_const = d3d_info->limits.vs_uniform_count; 680 681 memset(priv->pshader_const_dirty, 1, 682 sizeof(*priv->pshader_const_dirty) * d3d_info->limits.ps_uniform_count); 683 priv->highest_dirty_ps_const = d3d_info->limits.ps_uniform_count; 684 685 priv->last_context = context; 686 } 687 688 if (useVertexShader) 689 { 690 const struct wined3d_shader *vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX]; 691 const struct arb_vs_compiled_shader *gl_shader = priv->compiled_vprog; 692 693 /* Load DirectX 9 float constants for vertex shader */ 694 priv->highest_dirty_vs_const = shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB, 695 priv->highest_dirty_vs_const, state->vs_consts_f, priv->vshader_const_dirty); 696 shader_arb_vs_local_constants(gl_shader, context, state); 697 } 698 699 if (usePixelShader) 700 { 701 const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL]; 702 const struct arb_ps_compiled_shader *gl_shader = priv->compiled_fprog; 703 UINT rt_height = state->fb->render_targets[0]->resource.height; 704 705 /* Load DirectX 9 float constants for pixel shader */ 706 priv->highest_dirty_ps_const = shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, 707 priv->highest_dirty_ps_const, state->ps_consts_f, priv->pshader_const_dirty); 708 shader_arb_ps_local_constants(gl_shader, context, state, rt_height); 709 710 if (context->constant_update_mask & WINED3D_SHADER_CONST_PS_NP2_FIXUP) 711 shader_arb_load_np2fixup_constants(&gl_shader->np2fixup_info, gl_info, state); 712 } 713 } 714 715 static void shader_arb_load_constants(void *shader_priv, struct wined3d_context *context, 716 const struct wined3d_state *state) 717 { 718 BOOL vs = use_vs(state); 719 BOOL ps = use_ps(state); 720 721 shader_arb_load_constants_internal(shader_priv, context, state, ps, vs, FALSE); 722 } 723 724 static void shader_arb_update_float_vertex_constants(struct wined3d_device *device, UINT start, UINT count) 725 { 726 struct wined3d_context *context = context_get_current(); 727 struct shader_arb_priv *priv = device->shader_priv; 728 unsigned int i; 729 730 for (i = 0; i < device->context_count; ++i) 731 { 732 device->contexts[i]->constant_update_mask |= WINED3D_SHADER_CONST_VS_F; 733 } 734 735 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active 736 * context. On a context switch the old context will be fully dirtified */ 737 if (!context || context->swapchain->device != device) return; 738 739 memset(priv->vshader_const_dirty + start, 1, sizeof(*priv->vshader_const_dirty) * count); 740 priv->highest_dirty_vs_const = max(priv->highest_dirty_vs_const, start + count); 741 } 742 743 static void shader_arb_update_float_pixel_constants(struct wined3d_device *device, UINT start, UINT count) 744 { 745 struct wined3d_context *context = context_get_current(); 746 struct shader_arb_priv *priv = device->shader_priv; 747 unsigned int i; 748 749 for (i = 0; i < device->context_count; ++i) 750 { 751 device->contexts[i]->constant_update_mask |= WINED3D_SHADER_CONST_PS_F; 752 } 753 754 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active 755 * context. On a context switch the old context will be fully dirtified */ 756 if (!context || context->swapchain->device != device) return; 757 758 memset(priv->pshader_const_dirty + start, 1, sizeof(*priv->pshader_const_dirty) * count); 759 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, start + count); 760 } 761 762 static void shader_arb_append_imm_vec4(struct wined3d_shader_buffer *buffer, const float *values) 763 { 764 char str[4][17]; 765 766 wined3d_ftoa(values[0], str[0]); 767 wined3d_ftoa(values[1], str[1]); 768 wined3d_ftoa(values[2], str[2]); 769 wined3d_ftoa(values[3], str[3]); 770 shader_addline(buffer, "{%s, %s, %s, %s}", str[0], str[1], str[2], str[3]); 771 } 772 773 /* Generate the variable & register declarations for the ARB_vertex_program output target */ 774 static void shader_generate_arb_declarations(const struct wined3d_shader *shader, 775 const struct wined3d_shader_reg_maps *reg_maps, struct wined3d_shader_buffer *buffer, 776 const struct wined3d_gl_info *gl_info, DWORD *num_clipplanes, 777 const struct shader_arb_ctx_priv *ctx) 778 { 779 DWORD i; 780 char pshader = shader_is_pshader_version(reg_maps->shader_version.type); 781 const struct wined3d_shader_lconst *lconst; 782 unsigned max_constantsF; 783 DWORD map; 784 785 /* In pixel shaders, all private constants are program local, we don't need anything 786 * from program.env. Thus we can advertise the full set of constants in pixel shaders. 787 * If we need a private constant the GL implementation will squeeze it in somewhere 788 * 789 * With vertex shaders we need the posFixup and on some GL implementations 4 helper 790 * immediate values. The posFixup is loaded using program.env for now, so always 791 * subtract one from the number of constants. If the shader uses indirect addressing, 792 * account for the helper const too because we have to declare all available d3d constants 793 * and don't know which are actually used. 794 */ 795 if (pshader) 796 { 797 max_constantsF = gl_info->limits.arb_ps_native_constants; 798 /* 24 is the minimum MAX_PROGRAM_ENV_PARAMETERS_ARB value. */ 799 if (max_constantsF < 24) 800 max_constantsF = gl_info->limits.arb_ps_float_constants; 801 } 802 else 803 { 804 const struct arb_vshader_private *shader_data = shader->backend_data; 805 max_constantsF = gl_info->limits.arb_vs_native_constants; 806 /* 96 is the minimum MAX_PROGRAM_ENV_PARAMETERS_ARB value. 807 * Also prevents max_constantsF from becoming less than 0 and 808 * wrapping . */ 809 if (max_constantsF < 96) 810 max_constantsF = gl_info->limits.arb_vs_float_constants; 811 812 if (reg_maps->usesrelconstF) 813 { 814 DWORD highest_constf = 0, clip_limit; 815 816 max_constantsF -= reserved_vs_const(shader_data, reg_maps, gl_info); 817 max_constantsF -= count_bits(reg_maps->integer_constants); 818 max_constantsF -= gl_info->reserved_arb_constants; 819 820 for (i = 0; i < shader->limits.constant_float; ++i) 821 { 822 DWORD idx = i >> 5; 823 DWORD shift = i & 0x1f; 824 if(reg_maps->constf[idx] & (1 << shift)) highest_constf = i; 825 } 826 827 if(use_nv_clip(gl_info) && ctx->target_version >= NV2) 828 { 829 if(ctx->cur_vs_args->super.clip_enabled) 830 clip_limit = gl_info->limits.clipplanes; 831 else 832 clip_limit = 0; 833 } 834 else 835 { 836 unsigned int mask = ctx->cur_vs_args->clip.boolclip.clipplane_mask; 837 clip_limit = min(count_bits(mask), 4); 838 } 839 *num_clipplanes = min(clip_limit, max_constantsF - highest_constf - 1); 840 max_constantsF -= *num_clipplanes; 841 if(*num_clipplanes < clip_limit) 842 { 843 WARN("Only %u clipplanes out of %u enabled\n", *num_clipplanes, gl_info->limits.clipplanes); 844 } 845 } 846 else 847 { 848 if (ctx->target_version >= NV2) *num_clipplanes = gl_info->limits.clipplanes; 849 else *num_clipplanes = min(gl_info->limits.clipplanes, 4); 850 } 851 } 852 853 for (i = 0, map = reg_maps->temporary; map; map >>= 1, ++i) 854 { 855 if (map & 1) shader_addline(buffer, "TEMP R%u;\n", i); 856 } 857 858 for (i = 0, map = reg_maps->address; map; map >>= 1, ++i) 859 { 860 if (map & 1) shader_addline(buffer, "ADDRESS A%u;\n", i); 861 } 862 863 if (pshader && reg_maps->shader_version.major == 1 && reg_maps->shader_version.minor <= 3) 864 { 865 for (i = 0, map = reg_maps->texcoord; map; map >>= 1, ++i) 866 { 867 if (map & 1) shader_addline(buffer, "TEMP T%u;\n", i); 868 } 869 } 870 871 if (!shader->load_local_constsF) 872 { 873 LIST_FOR_EACH_ENTRY(lconst, &shader->constantsF, struct wined3d_shader_lconst, entry) 874 { 875 const float *value; 876 value = (const float *)lconst->value; 877 shader_addline(buffer, "PARAM C%u = ", lconst->idx); 878 shader_arb_append_imm_vec4(buffer, value); 879 shader_addline(buffer, ";\n"); 880 } 881 } 882 883 /* After subtracting privately used constants from the hardware limit(they are loaded as 884 * local constants), make sure the shader doesn't violate the env constant limit 885 */ 886 if(pshader) 887 { 888 max_constantsF = min(max_constantsF, gl_info->limits.arb_ps_float_constants); 889 } 890 else 891 { 892 max_constantsF = min(max_constantsF, gl_info->limits.arb_vs_float_constants); 893 } 894 895 /* Avoid declaring more constants than needed */ 896 max_constantsF = min(max_constantsF, shader->limits.constant_float); 897 898 /* we use the array-based constants array if the local constants are marked for loading, 899 * because then we use indirect addressing, or when the local constant list is empty, 900 * because then we don't know if we're using indirect addressing or not. If we're hardcoding 901 * local constants do not declare the loaded constants as an array because ARB compilers usually 902 * do not optimize unused constants away 903 */ 904 if (reg_maps->usesrelconstF) 905 { 906 /* Need to PARAM the environment parameters (constants) so we can use relative addressing */ 907 shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n", 908 max_constantsF, max_constantsF - 1); 909 } else { 910 for(i = 0; i < max_constantsF; i++) { 911 DWORD idx, mask; 912 idx = i >> 5; 913 mask = 1 << (i & 0x1f); 914 if (!shader_constant_is_local(shader, i) && (reg_maps->constf[idx] & mask)) 915 { 916 shader_addline(buffer, "PARAM C%d = program.env[%d];\n",i, i); 917 } 918 } 919 } 920 } 921 922 static const char * const shift_tab[] = { 923 "dummy", /* 0 (none) */ 924 "coefmul.x", /* 1 (x2) */ 925 "coefmul.y", /* 2 (x4) */ 926 "coefmul.z", /* 3 (x8) */ 927 "coefmul.w", /* 4 (x16) */ 928 "dummy", /* 5 (x32) */ 929 "dummy", /* 6 (x64) */ 930 "dummy", /* 7 (x128) */ 931 "dummy", /* 8 (d256) */ 932 "dummy", /* 9 (d128) */ 933 "dummy", /* 10 (d64) */ 934 "dummy", /* 11 (d32) */ 935 "coefdiv.w", /* 12 (d16) */ 936 "coefdiv.z", /* 13 (d8) */ 937 "coefdiv.y", /* 14 (d4) */ 938 "coefdiv.x" /* 15 (d2) */ 939 }; 940 941 static void shader_arb_get_write_mask(const struct wined3d_shader_instruction *ins, 942 const struct wined3d_shader_dst_param *dst, char *write_mask) 943 { 944 char *ptr = write_mask; 945 946 if (dst->write_mask != WINED3DSP_WRITEMASK_ALL) 947 { 948 *ptr++ = '.'; 949 if (dst->write_mask & WINED3DSP_WRITEMASK_0) *ptr++ = 'x'; 950 if (dst->write_mask & WINED3DSP_WRITEMASK_1) *ptr++ = 'y'; 951 if (dst->write_mask & WINED3DSP_WRITEMASK_2) *ptr++ = 'z'; 952 if (dst->write_mask & WINED3DSP_WRITEMASK_3) *ptr++ = 'w'; 953 } 954 955 *ptr = '\0'; 956 } 957 958 static void shader_arb_get_swizzle(const struct wined3d_shader_src_param *param, BOOL fixup, char *swizzle_str) 959 { 960 /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra", 961 * but addressed as "rgba". To fix this we need to swap the register's x 962 * and z components. */ 963 const char *swizzle_chars = fixup ? "zyxw" : "xyzw"; 964 char *ptr = swizzle_str; 965 966 /* swizzle bits fields: wwzzyyxx */ 967 DWORD swizzle = param->swizzle; 968 DWORD swizzle_x = swizzle & 0x03; 969 DWORD swizzle_y = (swizzle >> 2) & 0x03; 970 DWORD swizzle_z = (swizzle >> 4) & 0x03; 971 DWORD swizzle_w = (swizzle >> 6) & 0x03; 972 973 /* If the swizzle is the default swizzle (ie, "xyzw"), we don't need to 974 * generate a swizzle string. Unless we need to our own swizzling. */ 975 if (swizzle != WINED3DSP_NOSWIZZLE || fixup) 976 { 977 *ptr++ = '.'; 978 if (swizzle_x == swizzle_y && swizzle_x == swizzle_z && swizzle_x == swizzle_w) { 979 *ptr++ = swizzle_chars[swizzle_x]; 980 } else { 981 *ptr++ = swizzle_chars[swizzle_x]; 982 *ptr++ = swizzle_chars[swizzle_y]; 983 *ptr++ = swizzle_chars[swizzle_z]; 984 *ptr++ = swizzle_chars[swizzle_w]; 985 } 986 } 987 988 *ptr = '\0'; 989 } 990 991 static void shader_arb_request_a0(const struct wined3d_shader_instruction *ins, const char *src) 992 { 993 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 994 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 995 996 if (!strcmp(priv->addr_reg, src)) return; 997 998 strcpy(priv->addr_reg, src); 999 shader_addline(buffer, "ARL A0.x, %s;\n", src); 1000 } 1001 1002 static void shader_arb_get_src_param(const struct wined3d_shader_instruction *ins, 1003 const struct wined3d_shader_src_param *src, unsigned int tmpreg, char *outregstr); 1004 1005 static void shader_arb_get_register_name(const struct wined3d_shader_instruction *ins, 1006 const struct wined3d_shader_register *reg, char *register_name, BOOL *is_color) 1007 { 1008 /* oPos, oFog and oPts in D3D */ 1009 static const char * const rastout_reg_names[] = {"TMP_OUT", "TMP_FOGCOORD", "result.pointsize"}; 1010 const struct wined3d_shader *shader = ins->ctx->shader; 1011 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps; 1012 BOOL pshader = shader_is_pshader_version(reg_maps->shader_version.type); 1013 struct shader_arb_ctx_priv *ctx = ins->ctx->backend_data; 1014 1015 *is_color = FALSE; 1016 1017 switch (reg->type) 1018 { 1019 case WINED3DSPR_TEMP: 1020 sprintf(register_name, "R%u", reg->idx[0].offset); 1021 break; 1022 1023 case WINED3DSPR_INPUT: 1024 if (pshader) 1025 { 1026 if (reg_maps->shader_version.major < 3) 1027 { 1028 if (!reg->idx[0].offset) 1029 strcpy(register_name, "fragment.color.primary"); 1030 else 1031 strcpy(register_name, "fragment.color.secondary"); 1032 } 1033 else 1034 { 1035 if (reg->idx[0].rel_addr) 1036 { 1037 char rel_reg[50]; 1038 shader_arb_get_src_param(ins, reg->idx[0].rel_addr, 0, rel_reg); 1039 1040 if (!strcmp(rel_reg, "**aL_emul**")) 1041 { 1042 DWORD idx = ctx->aL + reg->idx[0].offset; 1043 if(idx < MAX_REG_INPUT) 1044 { 1045 strcpy(register_name, ctx->ps_input[idx]); 1046 } 1047 else 1048 { 1049 ERR("Pixel shader input register out of bounds: %u\n", idx); 1050 sprintf(register_name, "out_of_bounds_%u", idx); 1051 } 1052 } 1053 else if (reg_maps->input_registers & 0x0300) 1054 { 1055 /* There are two ways basically: 1056 * 1057 * 1) Use the unrolling code that is used for loop emulation and unroll the loop. 1058 * That means trouble if the loop also contains a breakc or if the control values 1059 * aren't local constants. 1060 * 2) Generate an if block that checks if aL.y < 8, == 8 or == 9 and selects the 1061 * source dynamically. The trouble is that we cannot simply read aL.y because it 1062 * is an ADDRESS register. We could however push it, load .zw with a value and use 1063 * ADAC to load the condition code register and pop it again afterwards 1064 */ 1065 FIXME("Relative input register addressing with more than 8 registers\n"); 1066 1067 /* This is better than nothing for now */ 1068 sprintf(register_name, "fragment.texcoord[%s + %u]", rel_reg, reg->idx[0].offset); 1069 } 1070 else if(ctx->cur_ps_args->super.vp_mode != vertexshader) 1071 { 1072 /* This is problematic because we'd have to consult the ctx->ps_input strings 1073 * for where to find the varying. Some may be "0.0", others can be texcoords or 1074 * colors. This needs either a pipeline replacement to make the vertex shader feed 1075 * proper varyings, or loop unrolling 1076 * 1077 * For now use the texcoords and hope for the best 1078 */ 1079 FIXME("Non-vertex shader varying input with indirect addressing\n"); 1080 sprintf(register_name, "fragment.texcoord[%s + %u]", rel_reg, reg->idx[0].offset); 1081 } 1082 else 1083 { 1084 /* D3D supports indirect addressing only with aL in loop registers. The loop instruction 1085 * pulls GL_NV_fragment_program2 in 1086 */ 1087 sprintf(register_name, "fragment.texcoord[%s + %u]", rel_reg, reg->idx[0].offset); 1088 } 1089 } 1090 else 1091 { 1092 if (reg->idx[0].offset < MAX_REG_INPUT) 1093 { 1094 strcpy(register_name, ctx->ps_input[reg->idx[0].offset]); 1095 } 1096 else 1097 { 1098 ERR("Pixel shader input register out of bounds: %u\n", reg->idx[0].offset); 1099 sprintf(register_name, "out_of_bounds_%u", reg->idx[0].offset); 1100 } 1101 } 1102 } 1103 } 1104 else 1105 { 1106 if (ctx->cur_vs_args->super.swizzle_map & (1 << reg->idx[0].offset)) 1107 *is_color = TRUE; 1108 sprintf(register_name, "vertex.attrib[%u]", reg->idx[0].offset); 1109 } 1110 break; 1111 1112 case WINED3DSPR_CONST: 1113 if (!pshader && reg->idx[0].rel_addr) 1114 { 1115 const struct arb_vshader_private *shader_data = shader->backend_data; 1116 UINT rel_offset = ctx->target_version == ARB ? shader_data->rel_offset : 0; 1117 BOOL aL = FALSE; 1118 char rel_reg[50]; 1119 if (reg_maps->shader_version.major < 2) 1120 { 1121 sprintf(rel_reg, "A0.x"); 1122 } 1123 else 1124 { 1125 shader_arb_get_src_param(ins, reg->idx[0].rel_addr, 0, rel_reg); 1126 if (ctx->target_version == ARB) 1127 { 1128 if (!strcmp(rel_reg, "**aL_emul**")) 1129 { 1130 aL = TRUE; 1131 } else { 1132 shader_arb_request_a0(ins, rel_reg); 1133 sprintf(rel_reg, "A0.x"); 1134 } 1135 } 1136 } 1137 if (aL) 1138 sprintf(register_name, "C[%u]", ctx->aL + reg->idx[0].offset); 1139 else if (reg->idx[0].offset >= rel_offset) 1140 sprintf(register_name, "C[%s + %u]", rel_reg, reg->idx[0].offset - rel_offset); 1141 else 1142 sprintf(register_name, "C[%s - %u]", rel_reg, rel_offset - reg->idx[0].offset); 1143 } 1144 else 1145 { 1146 if (reg_maps->usesrelconstF) 1147 sprintf(register_name, "C[%u]", reg->idx[0].offset); 1148 else 1149 sprintf(register_name, "C%u", reg->idx[0].offset); 1150 } 1151 break; 1152 1153 case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */ 1154 if (pshader) 1155 { 1156 if (reg_maps->shader_version.major == 1 1157 && reg_maps->shader_version.minor <= 3) 1158 /* In ps <= 1.3, Tx is a temporary register as destination 1159 * to all instructions, and as source to most instructions. 1160 * For some instructions it is the texcoord input. Those 1161 * instructions know about the special use. */ 1162 sprintf(register_name, "T%u", reg->idx[0].offset); 1163 else 1164 /* In ps 1.4 and 2.x Tx is always a (read-only) varying. */ 1165 sprintf(register_name, "fragment.texcoord[%u]", reg->idx[0].offset); 1166 } 1167 else 1168 { 1169 if (reg_maps->shader_version.major == 1 || ctx->target_version >= NV2) 1170 sprintf(register_name, "A%u", reg->idx[0].offset); 1171 else 1172 sprintf(register_name, "A%u_SHADOW", reg->idx[0].offset); 1173 } 1174 break; 1175 1176 case WINED3DSPR_COLOROUT: 1177 if (ctx->ps_post_process && !reg->idx[0].offset) 1178 { 1179 strcpy(register_name, "TMP_COLOR"); 1180 } 1181 else 1182 { 1183 if (ctx->cur_ps_args->super.srgb_correction) 1184 FIXME("sRGB correction on higher render targets.\n"); 1185 if (reg_maps->rt_mask > 1) 1186 sprintf(register_name, "result.color[%u]", reg->idx[0].offset); 1187 else 1188 strcpy(register_name, "result.color"); 1189 } 1190 break; 1191 1192 case WINED3DSPR_RASTOUT: 1193 if (reg->idx[0].offset == 1) 1194 sprintf(register_name, "%s", ctx->fog_output); 1195 else 1196 sprintf(register_name, "%s", rastout_reg_names[reg->idx[0].offset]); 1197 break; 1198 1199 case WINED3DSPR_DEPTHOUT: 1200 strcpy(register_name, "result.depth"); 1201 break; 1202 1203 case WINED3DSPR_ATTROUT: 1204 /* case WINED3DSPR_OUTPUT: */ 1205 if (pshader) 1206 sprintf(register_name, "oD[%u]", reg->idx[0].offset); 1207 else 1208 strcpy(register_name, ctx->color_output[reg->idx[0].offset]); 1209 break; 1210 1211 case WINED3DSPR_TEXCRDOUT: 1212 if (pshader) 1213 sprintf(register_name, "oT[%u]", reg->idx[0].offset); 1214 else if (reg_maps->shader_version.major < 3) 1215 strcpy(register_name, ctx->texcrd_output[reg->idx[0].offset]); 1216 else 1217 strcpy(register_name, ctx->vs_output[reg->idx[0].offset]); 1218 break; 1219 1220 case WINED3DSPR_LOOP: 1221 if(ctx->target_version >= NV2) 1222 { 1223 /* Pshader has an implicitly declared loop index counter A0.x that cannot be renamed */ 1224 if(pshader) sprintf(register_name, "A0.x"); 1225 else sprintf(register_name, "aL.y"); 1226 } 1227 else 1228 { 1229 /* Unfortunately this code cannot return the value of ctx->aL here. An immediate value 1230 * would be valid, but if aL is used for indexing(its only use), there's likely an offset, 1231 * thus the result would be something like C[15 + 30], which is not valid in the ARB program 1232 * grammar. So return a marker for the emulated aL and intercept it in constant and varying 1233 * indexing 1234 */ 1235 sprintf(register_name, "**aL_emul**"); 1236 } 1237 1238 break; 1239 1240 case WINED3DSPR_CONSTINT: 1241 sprintf(register_name, "I%u", reg->idx[0].offset); 1242 break; 1243 1244 case WINED3DSPR_MISCTYPE: 1245 if (!reg->idx[0].offset) 1246 sprintf(register_name, "vpos"); 1247 else if (reg->idx[0].offset == 1) 1248 sprintf(register_name, "fragment.facing.x"); 1249 else 1250 FIXME("Unknown MISCTYPE register index %u.\n", reg->idx[0].offset); 1251 break; 1252 1253 default: 1254 FIXME("Unhandled register type %#x[%u].\n", reg->type, reg->idx[0].offset); 1255 sprintf(register_name, "unrecognized_register[%u]", reg->idx[0].offset); 1256 break; 1257 } 1258 } 1259 1260 static void shader_arb_get_dst_param(const struct wined3d_shader_instruction *ins, 1261 const struct wined3d_shader_dst_param *wined3d_dst, char *str) 1262 { 1263 char register_name[255]; 1264 char write_mask[6]; 1265 BOOL is_color; 1266 1267 shader_arb_get_register_name(ins, &wined3d_dst->reg, register_name, &is_color); 1268 strcpy(str, register_name); 1269 1270 shader_arb_get_write_mask(ins, wined3d_dst, write_mask); 1271 strcat(str, write_mask); 1272 } 1273 1274 static const char *shader_arb_get_fixup_swizzle(enum fixup_channel_source channel_source) 1275 { 1276 switch(channel_source) 1277 { 1278 case CHANNEL_SOURCE_ZERO: return "0"; 1279 case CHANNEL_SOURCE_ONE: return "1"; 1280 case CHANNEL_SOURCE_X: return "x"; 1281 case CHANNEL_SOURCE_Y: return "y"; 1282 case CHANNEL_SOURCE_Z: return "z"; 1283 case CHANNEL_SOURCE_W: return "w"; 1284 default: 1285 FIXME("Unhandled channel source %#x\n", channel_source); 1286 return "undefined"; 1287 } 1288 } 1289 1290 static void gen_color_correction(struct wined3d_shader_buffer *buffer, const char *reg, 1291 DWORD dst_mask, const char *one, const char *two, struct color_fixup_desc fixup) 1292 { 1293 DWORD mask; 1294 1295 if (is_complex_fixup(fixup)) 1296 { 1297 enum complex_fixup complex_fixup = get_complex_fixup(fixup); 1298 FIXME("Complex fixup (%#x) not supported\n", complex_fixup); 1299 return; 1300 } 1301 1302 mask = 0; 1303 if (fixup.x_source != CHANNEL_SOURCE_X) mask |= WINED3DSP_WRITEMASK_0; 1304 if (fixup.y_source != CHANNEL_SOURCE_Y) mask |= WINED3DSP_WRITEMASK_1; 1305 if (fixup.z_source != CHANNEL_SOURCE_Z) mask |= WINED3DSP_WRITEMASK_2; 1306 if (fixup.w_source != CHANNEL_SOURCE_W) mask |= WINED3DSP_WRITEMASK_3; 1307 mask &= dst_mask; 1308 1309 if (mask) 1310 { 1311 shader_addline(buffer, "SWZ %s, %s, %s, %s, %s, %s;\n", reg, reg, 1312 shader_arb_get_fixup_swizzle(fixup.x_source), shader_arb_get_fixup_swizzle(fixup.y_source), 1313 shader_arb_get_fixup_swizzle(fixup.z_source), shader_arb_get_fixup_swizzle(fixup.w_source)); 1314 } 1315 1316 mask = 0; 1317 if (fixup.x_sign_fixup) mask |= WINED3DSP_WRITEMASK_0; 1318 if (fixup.y_sign_fixup) mask |= WINED3DSP_WRITEMASK_1; 1319 if (fixup.z_sign_fixup) mask |= WINED3DSP_WRITEMASK_2; 1320 if (fixup.w_sign_fixup) mask |= WINED3DSP_WRITEMASK_3; 1321 mask &= dst_mask; 1322 1323 if (mask) 1324 { 1325 char reg_mask[6]; 1326 char *ptr = reg_mask; 1327 1328 if (mask != WINED3DSP_WRITEMASK_ALL) 1329 { 1330 *ptr++ = '.'; 1331 if (mask & WINED3DSP_WRITEMASK_0) *ptr++ = 'x'; 1332 if (mask & WINED3DSP_WRITEMASK_1) *ptr++ = 'y'; 1333 if (mask & WINED3DSP_WRITEMASK_2) *ptr++ = 'z'; 1334 if (mask & WINED3DSP_WRITEMASK_3) *ptr++ = 'w'; 1335 } 1336 *ptr = '\0'; 1337 1338 shader_addline(buffer, "MAD %s%s, %s, %s, -%s;\n", reg, reg_mask, reg, two, one); 1339 } 1340 } 1341 1342 static const char *shader_arb_get_modifier(const struct wined3d_shader_instruction *ins) 1343 { 1344 DWORD mod; 1345 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 1346 if (!ins->dst_count) return ""; 1347 1348 mod = ins->dst[0].modifiers; 1349 1350 /* Silently ignore PARTIALPRECISION if its not supported */ 1351 if(priv->target_version == ARB) mod &= ~WINED3DSPDM_PARTIALPRECISION; 1352 1353 if(mod & WINED3DSPDM_MSAMPCENTROID) 1354 { 1355 FIXME("Unhandled modifier WINED3DSPDM_MSAMPCENTROID\n"); 1356 mod &= ~WINED3DSPDM_MSAMPCENTROID; 1357 } 1358 1359 switch(mod) 1360 { 1361 case WINED3DSPDM_SATURATE | WINED3DSPDM_PARTIALPRECISION: 1362 return "H_SAT"; 1363 1364 case WINED3DSPDM_SATURATE: 1365 return "_SAT"; 1366 1367 case WINED3DSPDM_PARTIALPRECISION: 1368 return "H"; 1369 1370 case 0: 1371 return ""; 1372 1373 default: 1374 FIXME("Unknown modifiers 0x%08x\n", mod); 1375 return ""; 1376 } 1377 } 1378 1379 #define TEX_PROJ 0x1 1380 #define TEX_BIAS 0x2 1381 #define TEX_LOD 0x4 1382 #define TEX_DERIV 0x10 1383 1384 static void shader_hw_sample(const struct wined3d_shader_instruction *ins, DWORD sampler_idx, 1385 const char *dst_str, const char *coord_reg, WORD flags, const char *dsx, const char *dsy) 1386 { 1387 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1388 DWORD sampler_type = ins->ctx->reg_maps->sampler_type[sampler_idx]; 1389 const char *tex_type; 1390 BOOL np2_fixup = FALSE; 1391 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 1392 const char *mod; 1393 BOOL pshader = shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type); 1394 const struct wined3d_shader *shader; 1395 const struct wined3d_device *device; 1396 const struct wined3d_gl_info *gl_info; 1397 1398 /* D3D vertex shader sampler IDs are vertex samplers(0-3), not global d3d samplers */ 1399 if(!pshader) sampler_idx += MAX_FRAGMENT_SAMPLERS; 1400 1401 switch(sampler_type) { 1402 case WINED3DSTT_1D: 1403 tex_type = "1D"; 1404 break; 1405 1406 case WINED3DSTT_2D: 1407 shader = ins->ctx->shader; 1408 device = shader->device; 1409 gl_info = &device->adapter->gl_info; 1410 1411 if (pshader && priv->cur_ps_args->super.np2_fixup & (1 << sampler_idx) 1412 && gl_info->supported[ARB_TEXTURE_RECTANGLE]) 1413 tex_type = "RECT"; 1414 else 1415 tex_type = "2D"; 1416 if (shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type)) 1417 { 1418 if (priv->cur_np2fixup_info->super.active & (1 << sampler_idx)) 1419 { 1420 if (flags) FIXME("Only ordinary sampling from NP2 textures is supported.\n"); 1421 else np2_fixup = TRUE; 1422 } 1423 } 1424 break; 1425 1426 case WINED3DSTT_VOLUME: 1427 tex_type = "3D"; 1428 break; 1429 1430 case WINED3DSTT_CUBE: 1431 tex_type = "CUBE"; 1432 break; 1433 1434 default: 1435 ERR("Unexpected texture type %d\n", sampler_type); 1436 tex_type = ""; 1437 } 1438 1439 /* TEX, TXL, TXD and TXP do not support the "H" modifier, 1440 * so don't use shader_arb_get_modifier 1441 */ 1442 if(ins->dst[0].modifiers & WINED3DSPDM_SATURATE) mod = "_SAT"; 1443 else mod = ""; 1444 1445 /* Fragment samplers always have indentity mapping */ 1446 if(sampler_idx >= MAX_FRAGMENT_SAMPLERS) 1447 { 1448 sampler_idx = priv->cur_vs_args->vertex.samplers[sampler_idx - MAX_FRAGMENT_SAMPLERS]; 1449 } 1450 1451 if (flags & TEX_DERIV) 1452 { 1453 if(flags & TEX_PROJ) FIXME("Projected texture sampling with custom derivatives\n"); 1454 if(flags & TEX_BIAS) FIXME("Biased texture sampling with custom derivatives\n"); 1455 shader_addline(buffer, "TXD%s %s, %s, %s, %s, texture[%u], %s;\n", mod, dst_str, coord_reg, 1456 dsx, dsy,sampler_idx, tex_type); 1457 } 1458 else if(flags & TEX_LOD) 1459 { 1460 if(flags & TEX_PROJ) FIXME("Projected texture sampling with explicit lod\n"); 1461 if(flags & TEX_BIAS) FIXME("Biased texture sampling with explicit lod\n"); 1462 shader_addline(buffer, "TXL%s %s, %s, texture[%u], %s;\n", mod, dst_str, coord_reg, 1463 sampler_idx, tex_type); 1464 } 1465 else if (flags & TEX_BIAS) 1466 { 1467 /* Shouldn't be possible, but let's check for it */ 1468 if(flags & TEX_PROJ) FIXME("Biased and Projected texture sampling\n"); 1469 /* TXB takes the 4th component of the source vector automatically, as d3d. Nothing more to do */ 1470 shader_addline(buffer, "TXB%s %s, %s, texture[%u], %s;\n", mod, dst_str, coord_reg, sampler_idx, tex_type); 1471 } 1472 else if (flags & TEX_PROJ) 1473 { 1474 shader_addline(buffer, "TXP%s %s, %s, texture[%u], %s;\n", mod, dst_str, coord_reg, sampler_idx, tex_type); 1475 } 1476 else 1477 { 1478 if (np2_fixup) 1479 { 1480 const unsigned char idx = priv->cur_np2fixup_info->super.idx[sampler_idx]; 1481 shader_addline(buffer, "MUL TA, np2fixup[%u].%s, %s;\n", idx >> 1, 1482 (idx % 2) ? "zwxy" : "xyzw", coord_reg); 1483 1484 shader_addline(buffer, "TEX%s %s, TA, texture[%u], %s;\n", mod, dst_str, sampler_idx, tex_type); 1485 } 1486 else 1487 shader_addline(buffer, "TEX%s %s, %s, texture[%u], %s;\n", mod, dst_str, coord_reg, sampler_idx, tex_type); 1488 } 1489 1490 if (pshader) 1491 { 1492 gen_color_correction(buffer, dst_str, ins->dst[0].write_mask, 1493 arb_get_helper_value(WINED3D_SHADER_TYPE_PIXEL, ARB_ONE), 1494 arb_get_helper_value(WINED3D_SHADER_TYPE_PIXEL, ARB_TWO), 1495 priv->cur_ps_args->super.color_fixup[sampler_idx]); 1496 } 1497 } 1498 1499 static void shader_arb_get_src_param(const struct wined3d_shader_instruction *ins, 1500 const struct wined3d_shader_src_param *src, unsigned int tmpreg, char *outregstr) 1501 { 1502 /* Generate a line that does the input modifier computation and return the input register to use */ 1503 BOOL is_color = FALSE, insert_line; 1504 char regstr[256]; 1505 char swzstr[20]; 1506 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1507 struct shader_arb_ctx_priv *ctx = ins->ctx->backend_data; 1508 const char *one = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ONE); 1509 const char *two = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_TWO); 1510 1511 /* Assume a new line will be added */ 1512 insert_line = TRUE; 1513 1514 /* Get register name */ 1515 shader_arb_get_register_name(ins, &src->reg, regstr, &is_color); 1516 shader_arb_get_swizzle(src, is_color, swzstr); 1517 1518 switch (src->modifiers) 1519 { 1520 case WINED3DSPSM_NONE: 1521 sprintf(outregstr, "%s%s", regstr, swzstr); 1522 insert_line = FALSE; 1523 break; 1524 case WINED3DSPSM_NEG: 1525 sprintf(outregstr, "-%s%s", regstr, swzstr); 1526 insert_line = FALSE; 1527 break; 1528 case WINED3DSPSM_BIAS: 1529 shader_addline(buffer, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg, regstr); 1530 break; 1531 case WINED3DSPSM_BIASNEG: 1532 shader_addline(buffer, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg, regstr); 1533 break; 1534 case WINED3DSPSM_SIGN: 1535 shader_addline(buffer, "MAD T%c, %s, %s, -%s;\n", 'A' + tmpreg, regstr, two, one); 1536 break; 1537 case WINED3DSPSM_SIGNNEG: 1538 shader_addline(buffer, "MAD T%c, %s, -%s, %s;\n", 'A' + tmpreg, regstr, two, one); 1539 break; 1540 case WINED3DSPSM_COMP: 1541 shader_addline(buffer, "SUB T%c, %s, %s;\n", 'A' + tmpreg, one, regstr); 1542 break; 1543 case WINED3DSPSM_X2: 1544 shader_addline(buffer, "ADD T%c, %s, %s;\n", 'A' + tmpreg, regstr, regstr); 1545 break; 1546 case WINED3DSPSM_X2NEG: 1547 shader_addline(buffer, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg, regstr, regstr); 1548 break; 1549 case WINED3DSPSM_DZ: 1550 shader_addline(buffer, "RCP T%c, %s.z;\n", 'A' + tmpreg, regstr); 1551 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg); 1552 break; 1553 case WINED3DSPSM_DW: 1554 shader_addline(buffer, "RCP T%c, %s.w;\n", 'A' + tmpreg, regstr); 1555 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg); 1556 break; 1557 case WINED3DSPSM_ABS: 1558 if(ctx->target_version >= NV2) { 1559 sprintf(outregstr, "|%s%s|", regstr, swzstr); 1560 insert_line = FALSE; 1561 } else { 1562 shader_addline(buffer, "ABS T%c, %s;\n", 'A' + tmpreg, regstr); 1563 } 1564 break; 1565 case WINED3DSPSM_ABSNEG: 1566 if(ctx->target_version >= NV2) { 1567 sprintf(outregstr, "-|%s%s|", regstr, swzstr); 1568 } else { 1569 shader_addline(buffer, "ABS T%c, %s;\n", 'A' + tmpreg, regstr); 1570 sprintf(outregstr, "-T%c%s", 'A' + tmpreg, swzstr); 1571 } 1572 insert_line = FALSE; 1573 break; 1574 default: 1575 sprintf(outregstr, "%s%s", regstr, swzstr); 1576 insert_line = FALSE; 1577 } 1578 1579 /* Return modified or original register, with swizzle */ 1580 if (insert_line) 1581 sprintf(outregstr, "T%c%s", 'A' + tmpreg, swzstr); 1582 } 1583 1584 static void pshader_hw_bem(const struct wined3d_shader_instruction *ins) 1585 { 1586 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1587 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1588 DWORD sampler_code = dst->reg.idx[0].offset; 1589 char dst_name[50]; 1590 char src_name[2][50]; 1591 1592 shader_arb_get_dst_param(ins, dst, dst_name); 1593 1594 /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed 1595 * 1596 * Keep in mind that src_name[1] can be "TB" and src_name[0] can be "TA" because modifiers like _x2 are valid 1597 * with bem. So delay loading the first parameter until after the perturbation calculation which needs two 1598 * temps is done. 1599 */ 1600 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 1601 shader_addline(buffer, "SWZ TA, bumpenvmat%d, x, z, 0, 0;\n", sampler_code); 1602 shader_addline(buffer, "DP3 TC.r, TA, %s;\n", src_name[1]); 1603 shader_addline(buffer, "SWZ TA, bumpenvmat%d, y, w, 0, 0;\n", sampler_code); 1604 shader_addline(buffer, "DP3 TC.g, TA, %s;\n", src_name[1]); 1605 1606 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name[0]); 1607 shader_addline(buffer, "ADD %s, %s, TC;\n", dst_name, src_name[0]); 1608 } 1609 1610 static DWORD negate_modifiers(DWORD mod, char *extra_char) 1611 { 1612 *extra_char = ' '; 1613 switch(mod) 1614 { 1615 case WINED3DSPSM_NONE: return WINED3DSPSM_NEG; 1616 case WINED3DSPSM_NEG: return WINED3DSPSM_NONE; 1617 case WINED3DSPSM_BIAS: return WINED3DSPSM_BIASNEG; 1618 case WINED3DSPSM_BIASNEG: return WINED3DSPSM_BIAS; 1619 case WINED3DSPSM_SIGN: return WINED3DSPSM_SIGNNEG; 1620 case WINED3DSPSM_SIGNNEG: return WINED3DSPSM_SIGN; 1621 case WINED3DSPSM_COMP: *extra_char = '-'; return WINED3DSPSM_COMP; 1622 case WINED3DSPSM_X2: return WINED3DSPSM_X2NEG; 1623 case WINED3DSPSM_X2NEG: return WINED3DSPSM_X2; 1624 case WINED3DSPSM_DZ: *extra_char = '-'; return WINED3DSPSM_DZ; 1625 case WINED3DSPSM_DW: *extra_char = '-'; return WINED3DSPSM_DW; 1626 case WINED3DSPSM_ABS: return WINED3DSPSM_ABSNEG; 1627 case WINED3DSPSM_ABSNEG: return WINED3DSPSM_ABS; 1628 } 1629 FIXME("Unknown modifier %u\n", mod); 1630 return mod; 1631 } 1632 1633 static void pshader_hw_cnd(const struct wined3d_shader_instruction *ins) 1634 { 1635 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1636 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1637 char dst_name[50]; 1638 char src_name[3][50]; 1639 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major, 1640 ins->ctx->reg_maps->shader_version.minor); 1641 1642 shader_arb_get_dst_param(ins, dst, dst_name); 1643 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 1644 1645 if (shader_version <= WINED3D_SHADER_VERSION(1, 3) && ins->coissue 1646 && ins->dst->write_mask != WINED3DSP_WRITEMASK_3) 1647 { 1648 shader_addline(buffer, "MOV%s %s, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name[1]); 1649 } 1650 else 1651 { 1652 struct wined3d_shader_src_param src0_copy = ins->src[0]; 1653 char extra_neg; 1654 1655 /* src0 may have a negate srcmod set, so we can't blindly add "-" to the name */ 1656 src0_copy.modifiers = negate_modifiers(src0_copy.modifiers, &extra_neg); 1657 1658 shader_arb_get_src_param(ins, &src0_copy, 0, src_name[0]); 1659 shader_arb_get_src_param(ins, &ins->src[2], 2, src_name[2]); 1660 shader_addline(buffer, "ADD TA, %c%s, coefdiv.x;\n", extra_neg, src_name[0]); 1661 shader_addline(buffer, "CMP%s %s, TA, %s, %s;\n", shader_arb_get_modifier(ins), 1662 dst_name, src_name[1], src_name[2]); 1663 } 1664 } 1665 1666 static void pshader_hw_cmp(const struct wined3d_shader_instruction *ins) 1667 { 1668 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1669 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1670 char dst_name[50]; 1671 char src_name[3][50]; 1672 1673 shader_arb_get_dst_param(ins, dst, dst_name); 1674 1675 /* Generate input register names (with modifiers) */ 1676 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name[0]); 1677 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 1678 shader_arb_get_src_param(ins, &ins->src[2], 2, src_name[2]); 1679 1680 shader_addline(buffer, "CMP%s %s, %s, %s, %s;\n", shader_arb_get_modifier(ins), 1681 dst_name, src_name[0], src_name[2], src_name[1]); 1682 } 1683 1684 /** Process the WINED3DSIO_DP2ADD instruction in ARB. 1685 * dst = dot2(src0, src1) + src2 */ 1686 static void pshader_hw_dp2add(const struct wined3d_shader_instruction *ins) 1687 { 1688 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1689 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1690 char dst_name[50]; 1691 char src_name[3][50]; 1692 struct shader_arb_ctx_priv *ctx = ins->ctx->backend_data; 1693 1694 shader_arb_get_dst_param(ins, dst, dst_name); 1695 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name[0]); 1696 shader_arb_get_src_param(ins, &ins->src[2], 2, src_name[2]); 1697 1698 if(ctx->target_version >= NV3) 1699 { 1700 /* GL_NV_fragment_program2 has a 1:1 matching instruction */ 1701 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 1702 shader_addline(buffer, "DP2A%s %s, %s, %s, %s;\n", shader_arb_get_modifier(ins), 1703 dst_name, src_name[0], src_name[1], src_name[2]); 1704 } 1705 else if(ctx->target_version >= NV2) 1706 { 1707 /* dst.x = src2.?, src0.x, src1.x + src0.y * src1.y 1708 * dst.y = src2.?, src0.x, src1.z + src0.y * src1.w 1709 * dst.z = src2.?, src0.x, src1.x + src0.y * src1.y 1710 * dst.z = src2.?, src0.x, src1.z + src0.y * src1.w 1711 * 1712 * Make sure that src1.zw = src1.xy, then we get a classic dp2add 1713 * 1714 * .xyxy and other swizzles that we could get with this are not valid in 1715 * plain ARBfp, but luckily the NV extension grammar lifts this limitation. 1716 */ 1717 struct wined3d_shader_src_param tmp_param = ins->src[1]; 1718 DWORD swizzle = tmp_param.swizzle & 0xf; /* Selects .xy */ 1719 tmp_param.swizzle = swizzle | (swizzle << 4); /* Creates .xyxy */ 1720 1721 shader_arb_get_src_param(ins, &tmp_param, 1, src_name[1]); 1722 1723 shader_addline(buffer, "X2D%s %s, %s, %s, %s;\n", shader_arb_get_modifier(ins), 1724 dst_name, src_name[2], src_name[0], src_name[1]); 1725 } 1726 else 1727 { 1728 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 1729 /* Emulate a DP2 with a DP3 and 0.0. Don't use the dest as temp register, it could be src[1] or src[2] 1730 * src_name[0] can be TA, but TA is a private temp for modifiers, so it is save to overwrite 1731 */ 1732 shader_addline(buffer, "MOV TA, %s;\n", src_name[0]); 1733 shader_addline(buffer, "MOV TA.z, 0.0;\n"); 1734 shader_addline(buffer, "DP3 TA, TA, %s;\n", src_name[1]); 1735 shader_addline(buffer, "ADD%s %s, TA, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name[2]); 1736 } 1737 } 1738 1739 /* Map the opcode 1-to-1 to the GL code */ 1740 static void shader_hw_map2gl(const struct wined3d_shader_instruction *ins) 1741 { 1742 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1743 const char *instruction; 1744 char arguments[256], dst_str[50]; 1745 unsigned int i; 1746 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1747 1748 switch (ins->handler_idx) 1749 { 1750 case WINED3DSIH_ABS: instruction = "ABS"; break; 1751 case WINED3DSIH_ADD: instruction = "ADD"; break; 1752 case WINED3DSIH_CRS: instruction = "XPD"; break; 1753 case WINED3DSIH_DP3: instruction = "DP3"; break; 1754 case WINED3DSIH_DP4: instruction = "DP4"; break; 1755 case WINED3DSIH_DST: instruction = "DST"; break; 1756 case WINED3DSIH_FRC: instruction = "FRC"; break; 1757 case WINED3DSIH_LIT: instruction = "LIT"; break; 1758 case WINED3DSIH_LRP: instruction = "LRP"; break; 1759 case WINED3DSIH_MAD: instruction = "MAD"; break; 1760 case WINED3DSIH_MAX: instruction = "MAX"; break; 1761 case WINED3DSIH_MIN: instruction = "MIN"; break; 1762 case WINED3DSIH_MOV: instruction = "MOV"; break; 1763 case WINED3DSIH_MUL: instruction = "MUL"; break; 1764 case WINED3DSIH_SGE: instruction = "SGE"; break; 1765 case WINED3DSIH_SLT: instruction = "SLT"; break; 1766 case WINED3DSIH_SUB: instruction = "SUB"; break; 1767 case WINED3DSIH_MOVA:instruction = "ARR"; break; 1768 case WINED3DSIH_DSX: instruction = "DDX"; break; 1769 default: instruction = ""; 1770 FIXME("Unhandled opcode %#x\n", ins->handler_idx); 1771 break; 1772 } 1773 1774 /* Note that shader_arb_add_dst_param() adds spaces. */ 1775 arguments[0] = '\0'; 1776 shader_arb_get_dst_param(ins, dst, dst_str); 1777 for (i = 0; i < ins->src_count; ++i) 1778 { 1779 char operand[100]; 1780 strcat(arguments, ", "); 1781 shader_arb_get_src_param(ins, &ins->src[i], i, operand); 1782 strcat(arguments, operand); 1783 } 1784 shader_addline(buffer, "%s%s %s%s;\n", instruction, shader_arb_get_modifier(ins), dst_str, arguments); 1785 } 1786 1787 static void shader_hw_nop(const struct wined3d_shader_instruction *ins) {} 1788 1789 static void shader_hw_mov(const struct wined3d_shader_instruction *ins) 1790 { 1791 const struct wined3d_shader *shader = ins->ctx->shader; 1792 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps; 1793 BOOL pshader = shader_is_pshader_version(reg_maps->shader_version.type); 1794 struct shader_arb_ctx_priv *ctx = ins->ctx->backend_data; 1795 const char *zero = arb_get_helper_value(reg_maps->shader_version.type, ARB_ZERO); 1796 const char *one = arb_get_helper_value(reg_maps->shader_version.type, ARB_ONE); 1797 const char *two = arb_get_helper_value(reg_maps->shader_version.type, ARB_TWO); 1798 1799 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1800 char src0_param[256]; 1801 1802 if (ins->handler_idx == WINED3DSIH_MOVA) 1803 { 1804 const struct arb_vshader_private *shader_data = shader->backend_data; 1805 char write_mask[6]; 1806 const char *offset = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_VS_REL_OFFSET); 1807 1808 if(ctx->target_version >= NV2) { 1809 shader_hw_map2gl(ins); 1810 return; 1811 } 1812 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_param); 1813 shader_arb_get_write_mask(ins, &ins->dst[0], write_mask); 1814 1815 /* This implements the mova formula used in GLSL. The first two instructions 1816 * prepare the sign() part. Note that it is fine to have my_sign(0.0) = 1.0 1817 * in this case: 1818 * mova A0.x, 0.0 1819 * 1820 * A0.x = arl(floor(abs(0.0) + 0.5) * 1.0) = floor(0.5) = 0.0 since arl does a floor 1821 * 1822 * The ARL is performed when A0 is used - the requested component is read from A0_SHADOW into 1823 * A0.x. We can use the overwritten component of A0_shadow as temporary storage for the sign. 1824 */ 1825 shader_addline(buffer, "SGE A0_SHADOW%s, %s, %s;\n", write_mask, src0_param, zero); 1826 shader_addline(buffer, "MAD A0_SHADOW%s, A0_SHADOW, %s, -%s;\n", write_mask, two, one); 1827 1828 shader_addline(buffer, "ABS TA%s, %s;\n", write_mask, src0_param); 1829 shader_addline(buffer, "ADD TA%s, TA, rel_addr_const.x;\n", write_mask); 1830 shader_addline(buffer, "FLR TA%s, TA;\n", write_mask); 1831 if (shader_data->rel_offset) 1832 { 1833 shader_addline(buffer, "ADD TA%s, TA, %s;\n", write_mask, offset); 1834 } 1835 shader_addline(buffer, "MUL A0_SHADOW%s, TA, A0_SHADOW;\n", write_mask); 1836 1837 ((struct shader_arb_ctx_priv *)ins->ctx->backend_data)->addr_reg[0] = '\0'; 1838 } 1839 else if (reg_maps->shader_version.major == 1 1840 && !shader_is_pshader_version(reg_maps->shader_version.type) 1841 && ins->dst[0].reg.type == WINED3DSPR_ADDR) 1842 { 1843 const struct arb_vshader_private *shader_data = shader->backend_data; 1844 src0_param[0] = '\0'; 1845 1846 if (shader_data->rel_offset && ctx->target_version == ARB) 1847 { 1848 const char *offset = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_VS_REL_OFFSET); 1849 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_param); 1850 shader_addline(buffer, "ADD TA.x, %s, %s;\n", src0_param, offset); 1851 shader_addline(buffer, "ARL A0.x, TA.x;\n"); 1852 } 1853 else 1854 { 1855 /* Apple's ARB_vertex_program implementation does not accept an ARL source argument 1856 * with more than one component. Thus replicate the first source argument over all 1857 * 4 components. For example, .xyzw -> .x (or better: .xxxx), .zwxy -> .z, etc) */ 1858 struct wined3d_shader_src_param tmp_src = ins->src[0]; 1859 tmp_src.swizzle = (tmp_src.swizzle & 0x3) * 0x55; 1860 shader_arb_get_src_param(ins, &tmp_src, 0, src0_param); 1861 shader_addline(buffer, "ARL A0.x, %s;\n", src0_param); 1862 } 1863 } 1864 else if (ins->dst[0].reg.type == WINED3DSPR_COLOROUT && !ins->dst[0].reg.idx[0].offset && pshader) 1865 { 1866 if (ctx->ps_post_process && shader->u.ps.color0_mov) 1867 { 1868 shader_addline(buffer, "#mov handled in srgb write or fog code\n"); 1869 return; 1870 } 1871 shader_hw_map2gl(ins); 1872 } 1873 else 1874 { 1875 shader_hw_map2gl(ins); 1876 } 1877 } 1878 1879 static void pshader_hw_texkill(const struct wined3d_shader_instruction *ins) 1880 { 1881 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1882 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 1883 char reg_dest[40]; 1884 1885 /* No swizzles are allowed in d3d's texkill. PS 1.x ignores the 4th component as documented, 1886 * but >= 2.0 honors it (undocumented, but tested by the d3d9 testsuite) 1887 */ 1888 shader_arb_get_dst_param(ins, dst, reg_dest); 1889 1890 if (ins->ctx->reg_maps->shader_version.major >= 2) 1891 { 1892 const char *kilsrc = "TA"; 1893 BOOL is_color; 1894 1895 shader_arb_get_register_name(ins, &dst->reg, reg_dest, &is_color); 1896 if(dst->write_mask == WINED3DSP_WRITEMASK_ALL) 1897 { 1898 kilsrc = reg_dest; 1899 } 1900 else 1901 { 1902 /* Sigh. KIL doesn't support swizzles/writemasks. KIL passes a writemask, but ".xy" for example 1903 * is not valid as a swizzle in ARB (needs ".xyyy"). Use SWZ to load the register properly, and set 1904 * masked out components to 0(won't kill) 1905 */ 1906 char x = '0', y = '0', z = '0', w = '0'; 1907 if(dst->write_mask & WINED3DSP_WRITEMASK_0) x = 'x'; 1908 if(dst->write_mask & WINED3DSP_WRITEMASK_1) y = 'y'; 1909 if(dst->write_mask & WINED3DSP_WRITEMASK_2) z = 'z'; 1910 if(dst->write_mask & WINED3DSP_WRITEMASK_3) w = 'w'; 1911 shader_addline(buffer, "SWZ TA, %s, %c, %c, %c, %c;\n", reg_dest, x, y, z, w); 1912 } 1913 shader_addline(buffer, "KIL %s;\n", kilsrc); 1914 } 1915 else 1916 { 1917 /* ARB fp doesn't like swizzles on the parameter of the KIL instruction. To mask the 4th component, 1918 * copy the register into our general purpose TMP variable, overwrite .w and pass TMP to KIL 1919 * 1920 * ps_1_3 shaders use the texcoord incarnation of the Tx register. ps_1_4 shaders can use the same, 1921 * or pass in any temporary register(in shader phase 2) 1922 */ 1923 if (ins->ctx->reg_maps->shader_version.minor <= 3) 1924 sprintf(reg_dest, "fragment.texcoord[%u]", dst->reg.idx[0].offset); 1925 else 1926 shader_arb_get_dst_param(ins, dst, reg_dest); 1927 shader_addline(buffer, "SWZ TA, %s, x, y, z, 1;\n", reg_dest); 1928 shader_addline(buffer, "KIL TA;\n"); 1929 } 1930 } 1931 1932 static void pshader_hw_tex(const struct wined3d_shader_instruction *ins) 1933 { 1934 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 1935 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 1936 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major, 1937 ins->ctx->reg_maps->shader_version.minor); 1938 struct wined3d_shader_src_param src; 1939 1940 char reg_dest[40]; 1941 char reg_coord[40]; 1942 DWORD reg_sampler_code; 1943 WORD myflags = 0; 1944 BOOL swizzle_coord = FALSE; 1945 1946 /* All versions have a destination register */ 1947 shader_arb_get_dst_param(ins, dst, reg_dest); 1948 1949 /* 1.0-1.4: Use destination register number as texture code. 1950 2.0+: Use provided sampler number as texure code. */ 1951 if (shader_version < WINED3D_SHADER_VERSION(2,0)) 1952 reg_sampler_code = dst->reg.idx[0].offset; 1953 else 1954 reg_sampler_code = ins->src[1].reg.idx[0].offset; 1955 1956 /* 1.0-1.3: Use the texcoord varying. 1957 1.4+: Use provided coordinate source register. */ 1958 if (shader_version < WINED3D_SHADER_VERSION(1,4)) 1959 sprintf(reg_coord, "fragment.texcoord[%u]", reg_sampler_code); 1960 else { 1961 /* TEX is the only instruction that can handle DW and DZ natively */ 1962 src = ins->src[0]; 1963 if(src.modifiers == WINED3DSPSM_DW) src.modifiers = WINED3DSPSM_NONE; 1964 if(src.modifiers == WINED3DSPSM_DZ) src.modifiers = WINED3DSPSM_NONE; 1965 shader_arb_get_src_param(ins, &src, 0, reg_coord); 1966 } 1967 1968 /* projection flag: 1969 * 1.1, 1.2, 1.3: Use WINED3D_TSS_TEXTURETRANSFORMFLAGS 1970 * 1.4: Use WINED3DSPSM_DZ or WINED3DSPSM_DW on src[0] 1971 * 2.0+: Use WINED3DSI_TEXLD_PROJECT on the opcode 1972 */ 1973 if (shader_version < WINED3D_SHADER_VERSION(1,4)) 1974 { 1975 DWORD flags = 0; 1976 if (reg_sampler_code < MAX_TEXTURES) 1977 flags = priv->cur_ps_args->super.tex_transform >> reg_sampler_code * WINED3D_PSARGS_TEXTRANSFORM_SHIFT; 1978 if (flags & WINED3D_PSARGS_PROJECTED) 1979 { 1980 myflags |= TEX_PROJ; 1981 if ((flags & ~WINED3D_PSARGS_PROJECTED) == WINED3D_TTFF_COUNT3) 1982 swizzle_coord = TRUE; 1983 } 1984 } 1985 else if (shader_version < WINED3D_SHADER_VERSION(2,0)) 1986 { 1987 enum wined3d_shader_src_modifier src_mod = ins->src[0].modifiers; 1988 if (src_mod == WINED3DSPSM_DZ) 1989 { 1990 swizzle_coord = TRUE; 1991 myflags |= TEX_PROJ; 1992 } else if(src_mod == WINED3DSPSM_DW) { 1993 myflags |= TEX_PROJ; 1994 } 1995 } else { 1996 if (ins->flags & WINED3DSI_TEXLD_PROJECT) myflags |= TEX_PROJ; 1997 if (ins->flags & WINED3DSI_TEXLD_BIAS) myflags |= TEX_BIAS; 1998 } 1999 2000 if (swizzle_coord) 2001 { 2002 /* TXP cannot handle DZ natively, so move the z coordinate to .w. 2003 * reg_coord is a read-only varying register, so we need a temp reg */ 2004 shader_addline(ins->ctx->buffer, "SWZ TA, %s, x, y, z, z;\n", reg_coord); 2005 strcpy(reg_coord, "TA"); 2006 } 2007 2008 shader_hw_sample(ins, reg_sampler_code, reg_dest, reg_coord, myflags, NULL, NULL); 2009 } 2010 2011 static void pshader_hw_texcoord(const struct wined3d_shader_instruction *ins) 2012 { 2013 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2014 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2015 DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major, 2016 ins->ctx->reg_maps->shader_version.minor); 2017 char dst_str[50]; 2018 2019 if (shader_version < WINED3D_SHADER_VERSION(1,4)) 2020 { 2021 DWORD reg = dst->reg.idx[0].offset; 2022 2023 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2024 shader_addline(buffer, "MOV_SAT %s, fragment.texcoord[%u];\n", dst_str, reg); 2025 } else { 2026 char reg_src[40]; 2027 2028 shader_arb_get_src_param(ins, &ins->src[0], 0, reg_src); 2029 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2030 shader_addline(buffer, "MOV %s, %s;\n", dst_str, reg_src); 2031 } 2032 } 2033 2034 static void pshader_hw_texreg2ar(const struct wined3d_shader_instruction *ins) 2035 { 2036 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2037 DWORD flags = 0; 2038 2039 DWORD reg1 = ins->dst[0].reg.idx[0].offset; 2040 char dst_str[50]; 2041 char src_str[50]; 2042 2043 /* Note that texreg2ar treats Tx as a temporary register, not as a varying */ 2044 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2045 shader_arb_get_src_param(ins, &ins->src[0], 0, src_str); 2046 /* Move .x first in case src_str is "TA" */ 2047 shader_addline(buffer, "MOV TA.y, %s.x;\n", src_str); 2048 shader_addline(buffer, "MOV TA.x, %s.w;\n", src_str); 2049 if (reg1 < MAX_TEXTURES) 2050 { 2051 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2052 flags = priv->cur_ps_args->super.tex_transform >> reg1 * WINED3D_PSARGS_TEXTRANSFORM_SHIFT; 2053 } 2054 shader_hw_sample(ins, reg1, dst_str, "TA", flags & WINED3D_PSARGS_PROJECTED ? TEX_PROJ : 0, NULL, NULL); 2055 } 2056 2057 static void pshader_hw_texreg2gb(const struct wined3d_shader_instruction *ins) 2058 { 2059 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2060 2061 DWORD reg1 = ins->dst[0].reg.idx[0].offset; 2062 char dst_str[50]; 2063 char src_str[50]; 2064 2065 /* Note that texreg2gb treats Tx as a temporary register, not as a varying */ 2066 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2067 shader_arb_get_src_param(ins, &ins->src[0], 0, src_str); 2068 shader_addline(buffer, "MOV TA.x, %s.y;\n", src_str); 2069 shader_addline(buffer, "MOV TA.y, %s.z;\n", src_str); 2070 shader_hw_sample(ins, reg1, dst_str, "TA", 0, NULL, NULL); 2071 } 2072 2073 static void pshader_hw_texreg2rgb(const struct wined3d_shader_instruction *ins) 2074 { 2075 DWORD reg1 = ins->dst[0].reg.idx[0].offset; 2076 char dst_str[50]; 2077 char src_str[50]; 2078 2079 /* Note that texreg2rg treats Tx as a temporary register, not as a varying */ 2080 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2081 shader_arb_get_src_param(ins, &ins->src[0], 0, src_str); 2082 shader_hw_sample(ins, reg1, dst_str, src_str, 0, NULL, NULL); 2083 } 2084 2085 static void pshader_hw_texbem(const struct wined3d_shader_instruction *ins) 2086 { 2087 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2088 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2089 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2090 char reg_coord[40], dst_reg[50], src_reg[50]; 2091 DWORD reg_dest_code; 2092 2093 /* All versions have a destination register. The Tx where the texture coordinates come 2094 * from is the varying incarnation of the texture register 2095 */ 2096 reg_dest_code = dst->reg.idx[0].offset; 2097 shader_arb_get_dst_param(ins, &ins->dst[0], dst_reg); 2098 shader_arb_get_src_param(ins, &ins->src[0], 0, src_reg); 2099 sprintf(reg_coord, "fragment.texcoord[%u]", reg_dest_code); 2100 2101 /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed 2102 * The Tx in which the perturbation map is stored is the tempreg incarnation of the texture register 2103 * 2104 * GL_NV_fragment_program_option could handle this in one instruction via X2D: 2105 * X2D TA.xy, fragment.texcoord, T%u, bumpenvmat%u.xzyw 2106 * 2107 * However, the NV extensions are never enabled for <= 2.0 shaders because of the performance penalty that 2108 * comes with it, and texbem is an 1.x only instruction. No 1.x instruction forces us to enable the NV 2109 * extension. 2110 */ 2111 shader_addline(buffer, "SWZ TB, bumpenvmat%d, x, z, 0, 0;\n", reg_dest_code); 2112 shader_addline(buffer, "DP3 TA.x, TB, %s;\n", src_reg); 2113 shader_addline(buffer, "SWZ TB, bumpenvmat%d, y, w, 0, 0;\n", reg_dest_code); 2114 shader_addline(buffer, "DP3 TA.y, TB, %s;\n", src_reg); 2115 2116 /* with projective textures, texbem only divides the static texture coord, not the displacement, 2117 * so we can't let the GL handle this. 2118 */ 2119 if ((priv->cur_ps_args->super.tex_transform >> reg_dest_code * WINED3D_PSARGS_TEXTRANSFORM_SHIFT) 2120 & WINED3D_PSARGS_PROJECTED) 2121 { 2122 shader_addline(buffer, "RCP TB.w, %s.w;\n", reg_coord); 2123 shader_addline(buffer, "MUL TB.xy, %s, TB.w;\n", reg_coord); 2124 shader_addline(buffer, "ADD TA.xy, TA, TB;\n"); 2125 } else { 2126 shader_addline(buffer, "ADD TA.xy, TA, %s;\n", reg_coord); 2127 } 2128 2129 shader_hw_sample(ins, reg_dest_code, dst_reg, "TA", 0, NULL, NULL); 2130 2131 if (ins->handler_idx == WINED3DSIH_TEXBEML) 2132 { 2133 /* No src swizzles are allowed, so this is ok */ 2134 shader_addline(buffer, "MAD TA, %s.z, luminance%d.x, luminance%d.y;\n", 2135 src_reg, reg_dest_code, reg_dest_code); 2136 shader_addline(buffer, "MUL %s, %s, TA;\n", dst_reg, dst_reg); 2137 } 2138 } 2139 2140 static void pshader_hw_texm3x2pad(const struct wined3d_shader_instruction *ins) 2141 { 2142 DWORD reg = ins->dst[0].reg.idx[0].offset; 2143 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2144 char src0_name[50], dst_name[50]; 2145 BOOL is_color; 2146 struct wined3d_shader_register tmp_reg = ins->dst[0].reg; 2147 2148 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2149 /* The next instruction will be a texm3x2tex or texm3x2depth that writes to the uninitialized 2150 * T<reg+1> register. Use this register to store the calculated vector 2151 */ 2152 tmp_reg.idx[0].offset = reg + 1; 2153 shader_arb_get_register_name(ins, &tmp_reg, dst_name, &is_color); 2154 shader_addline(buffer, "DP3 %s.x, fragment.texcoord[%u], %s;\n", dst_name, reg, src0_name); 2155 } 2156 2157 static void pshader_hw_texm3x2tex(const struct wined3d_shader_instruction *ins) 2158 { 2159 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2160 DWORD flags; 2161 DWORD reg = ins->dst[0].reg.idx[0].offset; 2162 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2163 char dst_str[50]; 2164 char src0_name[50]; 2165 char dst_reg[50]; 2166 BOOL is_color; 2167 2168 /* We know that we're writing to the uninitialized T<reg> register, so use it for temporary storage */ 2169 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_reg, &is_color); 2170 2171 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2172 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2173 shader_addline(buffer, "DP3 %s.y, fragment.texcoord[%u], %s;\n", dst_reg, reg, src0_name); 2174 flags = reg < MAX_TEXTURES ? priv->cur_ps_args->super.tex_transform >> reg * WINED3D_PSARGS_TEXTRANSFORM_SHIFT : 0; 2175 shader_hw_sample(ins, reg, dst_str, dst_reg, flags & WINED3D_PSARGS_PROJECTED ? TEX_PROJ : 0, NULL, NULL); 2176 } 2177 2178 static void pshader_hw_texm3x3pad(const struct wined3d_shader_instruction *ins) 2179 { 2180 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx; 2181 DWORD reg = ins->dst[0].reg.idx[0].offset; 2182 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2183 char src0_name[50], dst_name[50]; 2184 struct wined3d_shader_register tmp_reg = ins->dst[0].reg; 2185 BOOL is_color; 2186 2187 /* There are always 2 texm3x3pad instructions followed by one texm3x3[tex,vspec, ...] instruction, with 2188 * incrementing ins->dst[0].register_idx numbers. So the pad instruction already knows the final destination 2189 * register, and this register is uninitialized(otherwise the assembler complains that it is 'redeclared') 2190 */ 2191 tmp_reg.idx[0].offset = reg + 2 - tex_mx->current_row; 2192 shader_arb_get_register_name(ins, &tmp_reg, dst_name, &is_color); 2193 2194 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2195 shader_addline(buffer, "DP3 %s.%c, fragment.texcoord[%u], %s;\n", 2196 dst_name, 'x' + tex_mx->current_row, reg, src0_name); 2197 tex_mx->texcoord_w[tex_mx->current_row++] = reg; 2198 } 2199 2200 static void pshader_hw_texm3x3tex(const struct wined3d_shader_instruction *ins) 2201 { 2202 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2203 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx; 2204 DWORD flags; 2205 DWORD reg = ins->dst[0].reg.idx[0].offset; 2206 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2207 char dst_str[50]; 2208 char src0_name[50], dst_name[50]; 2209 BOOL is_color; 2210 2211 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_name, &is_color); 2212 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2213 shader_addline(buffer, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_name, reg, src0_name); 2214 2215 /* Sample the texture using the calculated coordinates */ 2216 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2217 flags = reg < MAX_TEXTURES ? priv->cur_ps_args->super.tex_transform >> reg * WINED3D_PSARGS_TEXTRANSFORM_SHIFT : 0; 2218 shader_hw_sample(ins, reg, dst_str, dst_name, flags & WINED3D_PSARGS_PROJECTED ? TEX_PROJ : 0, NULL, NULL); 2219 tex_mx->current_row = 0; 2220 } 2221 2222 static void pshader_hw_texm3x3vspec(const struct wined3d_shader_instruction *ins) 2223 { 2224 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2225 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx; 2226 DWORD flags; 2227 DWORD reg = ins->dst[0].reg.idx[0].offset; 2228 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2229 char dst_str[50]; 2230 char src0_name[50]; 2231 char dst_reg[50]; 2232 BOOL is_color; 2233 2234 /* Get the dst reg without writemask strings. We know this register is uninitialized, so we can use all 2235 * components for temporary data storage 2236 */ 2237 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_reg, &is_color); 2238 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2239 shader_addline(buffer, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_reg, reg, src0_name); 2240 2241 /* Construct the eye-ray vector from w coordinates */ 2242 shader_addline(buffer, "MOV TB.x, fragment.texcoord[%u].w;\n", tex_mx->texcoord_w[0]); 2243 shader_addline(buffer, "MOV TB.y, fragment.texcoord[%u].w;\n", tex_mx->texcoord_w[1]); 2244 shader_addline(buffer, "MOV TB.z, fragment.texcoord[%u].w;\n", reg); 2245 2246 /* Calculate reflection vector 2247 */ 2248 shader_addline(buffer, "DP3 %s.w, %s, TB;\n", dst_reg, dst_reg); 2249 /* The .w is ignored when sampling, so I can use TB.w to calculate dot(N, N) */ 2250 shader_addline(buffer, "DP3 TB.w, %s, %s;\n", dst_reg, dst_reg); 2251 shader_addline(buffer, "RCP TB.w, TB.w;\n"); 2252 shader_addline(buffer, "MUL %s.w, %s.w, TB.w;\n", dst_reg, dst_reg); 2253 shader_addline(buffer, "MUL %s, %s.w, %s;\n", dst_reg, dst_reg, dst_reg); 2254 shader_addline(buffer, "MAD %s, coefmul.x, %s, -TB;\n", dst_reg, dst_reg); 2255 2256 /* Sample the texture using the calculated coordinates */ 2257 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2258 flags = reg < MAX_TEXTURES ? priv->cur_ps_args->super.tex_transform >> reg * WINED3D_PSARGS_TEXTRANSFORM_SHIFT : 0; 2259 shader_hw_sample(ins, reg, dst_str, dst_reg, flags & WINED3D_PSARGS_PROJECTED ? TEX_PROJ : 0, NULL, NULL); 2260 tex_mx->current_row = 0; 2261 } 2262 2263 static void pshader_hw_texm3x3spec(const struct wined3d_shader_instruction *ins) 2264 { 2265 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2266 struct wined3d_shader_tex_mx *tex_mx = ins->ctx->tex_mx; 2267 DWORD flags; 2268 DWORD reg = ins->dst[0].reg.idx[0].offset; 2269 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2270 char dst_str[50]; 2271 char src0_name[50]; 2272 char src1_name[50]; 2273 char dst_reg[50]; 2274 BOOL is_color; 2275 2276 shader_arb_get_src_param(ins, &ins->src[0], 0, src0_name); 2277 shader_arb_get_src_param(ins, &ins->src[0], 1, src1_name); 2278 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_reg, &is_color); 2279 /* Note: dst_reg.xy is input here, generated by two texm3x3pad instructions */ 2280 shader_addline(buffer, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_reg, reg, src0_name); 2281 2282 /* Calculate reflection vector. 2283 * 2284 * dot(N, E) 2285 * dst_reg.xyz = 2 * --------- * N - E 2286 * dot(N, N) 2287 * 2288 * Which normalizes the normal vector 2289 */ 2290 shader_addline(buffer, "DP3 %s.w, %s, %s;\n", dst_reg, dst_reg, src1_name); 2291 shader_addline(buffer, "DP3 TC.w, %s, %s;\n", dst_reg, dst_reg); 2292 shader_addline(buffer, "RCP TC.w, TC.w;\n"); 2293 shader_addline(buffer, "MUL %s.w, %s.w, TC.w;\n", dst_reg, dst_reg); 2294 shader_addline(buffer, "MUL %s, %s.w, %s;\n", dst_reg, dst_reg, dst_reg); 2295 shader_addline(buffer, "MAD %s, coefmul.x, %s, -%s;\n", dst_reg, dst_reg, src1_name); 2296 2297 /* Sample the texture using the calculated coordinates */ 2298 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2299 flags = reg < MAX_TEXTURES ? priv->cur_ps_args->super.tex_transform >> reg * WINED3D_PSARGS_TEXTRANSFORM_SHIFT : 0; 2300 shader_hw_sample(ins, reg, dst_str, dst_reg, flags & WINED3D_PSARGS_PROJECTED ? TEX_PROJ : 0, NULL, NULL); 2301 tex_mx->current_row = 0; 2302 } 2303 2304 static void pshader_hw_texdepth(const struct wined3d_shader_instruction *ins) 2305 { 2306 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2307 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2308 char dst_name[50]; 2309 const char *zero = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ZERO); 2310 const char *one = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ONE); 2311 2312 /* texdepth has an implicit destination, the fragment depth value. It's only parameter, 2313 * which is essentially an input, is the destination register because it is the first 2314 * parameter. According to the msdn, this must be register r5, but let's keep it more flexible 2315 * here(writemasks/swizzles are not valid on texdepth) 2316 */ 2317 shader_arb_get_dst_param(ins, dst, dst_name); 2318 2319 /* According to the msdn, the source register(must be r5) is unusable after 2320 * the texdepth instruction, so we're free to modify it 2321 */ 2322 shader_addline(buffer, "MIN %s.y, %s.y, %s;\n", dst_name, dst_name, one); 2323 2324 /* How to deal with the special case dst_name.g == 0? if r != 0, then 2325 * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct 2326 * result. But if r = 0.0, then 0 * inf = 0, which is incorrect. 2327 */ 2328 shader_addline(buffer, "RCP %s.y, %s.y;\n", dst_name, dst_name); 2329 shader_addline(buffer, "MUL TA.x, %s.x, %s.y;\n", dst_name, dst_name); 2330 shader_addline(buffer, "MIN TA.x, TA.x, %s;\n", one); 2331 shader_addline(buffer, "MAX result.depth, TA.x, %s;\n", zero); 2332 } 2333 2334 /** Process the WINED3DSIO_TEXDP3TEX instruction in ARB: 2335 * Take a 3-component dot product of the TexCoord[dstreg] and src, 2336 * then perform a 1D texture lookup from stage dstregnum, place into dst. */ 2337 static void pshader_hw_texdp3tex(const struct wined3d_shader_instruction *ins) 2338 { 2339 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2340 DWORD sampler_idx = ins->dst[0].reg.idx[0].offset; 2341 char src0[50]; 2342 char dst_str[50]; 2343 2344 shader_arb_get_src_param(ins, &ins->src[0], 0, src0); 2345 shader_addline(buffer, "MOV TB, 0.0;\n"); 2346 shader_addline(buffer, "DP3 TB.x, fragment.texcoord[%u], %s;\n", sampler_idx, src0); 2347 2348 shader_arb_get_dst_param(ins, &ins->dst[0], dst_str); 2349 shader_hw_sample(ins, sampler_idx, dst_str, "TB", 0 /* Only one coord, can't be projected */, NULL, NULL); 2350 } 2351 2352 /** Process the WINED3DSIO_TEXDP3 instruction in ARB: 2353 * Take a 3-component dot product of the TexCoord[dstreg] and src. */ 2354 static void pshader_hw_texdp3(const struct wined3d_shader_instruction *ins) 2355 { 2356 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2357 char src0[50]; 2358 char dst_str[50]; 2359 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2360 2361 /* Handle output register */ 2362 shader_arb_get_dst_param(ins, dst, dst_str); 2363 shader_arb_get_src_param(ins, &ins->src[0], 0, src0); 2364 shader_addline(buffer, "DP3 %s, fragment.texcoord[%u], %s;\n", dst_str, dst->reg.idx[0].offset, src0); 2365 } 2366 2367 /** Process the WINED3DSIO_TEXM3X3 instruction in ARB 2368 * Perform the 3rd row of a 3x3 matrix multiply */ 2369 static void pshader_hw_texm3x3(const struct wined3d_shader_instruction *ins) 2370 { 2371 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2372 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2373 char dst_str[50], dst_name[50]; 2374 char src0[50]; 2375 BOOL is_color; 2376 2377 shader_arb_get_dst_param(ins, dst, dst_str); 2378 shader_arb_get_src_param(ins, &ins->src[0], 0, src0); 2379 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_name, &is_color); 2380 shader_addline(buffer, "DP3 %s.z, fragment.texcoord[%u], %s;\n", dst_name, dst->reg.idx[0].offset, src0); 2381 shader_addline(buffer, "MOV %s, %s;\n", dst_str, dst_name); 2382 } 2383 2384 /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in ARB: 2385 * Last row of a 3x2 matrix multiply, use the result to calculate the depth: 2386 * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated) 2387 * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y 2388 */ 2389 static void pshader_hw_texm3x2depth(const struct wined3d_shader_instruction *ins) 2390 { 2391 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2392 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2393 char src0[50], dst_name[50]; 2394 BOOL is_color; 2395 const char *zero = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ZERO); 2396 const char *one = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ONE); 2397 2398 shader_arb_get_src_param(ins, &ins->src[0], 0, src0); 2399 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_name, &is_color); 2400 shader_addline(buffer, "DP3 %s.y, fragment.texcoord[%u], %s;\n", dst_name, dst->reg.idx[0].offset, src0); 2401 2402 /* How to deal with the special case dst_name.g == 0? if r != 0, then 2403 * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct 2404 * result. But if r = 0.0, then 0 * inf = 0, which is incorrect. 2405 */ 2406 shader_addline(buffer, "RCP %s.y, %s.y;\n", dst_name, dst_name); 2407 shader_addline(buffer, "MUL %s.x, %s.x, %s.y;\n", dst_name, dst_name, dst_name); 2408 shader_addline(buffer, "MIN %s.x, %s.x, %s;\n", dst_name, dst_name, one); 2409 shader_addline(buffer, "MAX result.depth, %s.x, %s;\n", dst_name, zero); 2410 } 2411 2412 /** Handles transforming all WINED3DSIO_M?x? opcodes for 2413 Vertex/Pixel shaders to ARB_vertex_program codes */ 2414 static void shader_hw_mnxn(const struct wined3d_shader_instruction *ins) 2415 { 2416 int i; 2417 int nComponents = 0; 2418 struct wined3d_shader_dst_param tmp_dst = {{0}}; 2419 struct wined3d_shader_src_param tmp_src[2] = {{{0}}}; 2420 struct wined3d_shader_instruction tmp_ins; 2421 2422 memset(&tmp_ins, 0, sizeof(tmp_ins)); 2423 2424 /* Set constants for the temporary argument */ 2425 tmp_ins.ctx = ins->ctx; 2426 tmp_ins.dst_count = 1; 2427 tmp_ins.dst = &tmp_dst; 2428 tmp_ins.src_count = 2; 2429 tmp_ins.src = tmp_src; 2430 2431 switch(ins->handler_idx) 2432 { 2433 case WINED3DSIH_M4x4: 2434 nComponents = 4; 2435 tmp_ins.handler_idx = WINED3DSIH_DP4; 2436 break; 2437 case WINED3DSIH_M4x3: 2438 nComponents = 3; 2439 tmp_ins.handler_idx = WINED3DSIH_DP4; 2440 break; 2441 case WINED3DSIH_M3x4: 2442 nComponents = 4; 2443 tmp_ins.handler_idx = WINED3DSIH_DP3; 2444 break; 2445 case WINED3DSIH_M3x3: 2446 nComponents = 3; 2447 tmp_ins.handler_idx = WINED3DSIH_DP3; 2448 break; 2449 case WINED3DSIH_M3x2: 2450 nComponents = 2; 2451 tmp_ins.handler_idx = WINED3DSIH_DP3; 2452 break; 2453 default: 2454 FIXME("Unhandled opcode %#x\n", ins->handler_idx); 2455 break; 2456 } 2457 2458 tmp_dst = ins->dst[0]; 2459 tmp_src[0] = ins->src[0]; 2460 tmp_src[1] = ins->src[1]; 2461 for (i = 0; i < nComponents; ++i) 2462 { 2463 tmp_dst.write_mask = WINED3DSP_WRITEMASK_0 << i; 2464 shader_hw_map2gl(&tmp_ins); 2465 ++tmp_src[1].reg.idx[0].offset; 2466 } 2467 } 2468 2469 static void shader_hw_rcp(const struct wined3d_shader_instruction *ins) 2470 { 2471 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2472 2473 char dst[50]; 2474 char src[50]; 2475 2476 shader_arb_get_dst_param(ins, &ins->dst[0], dst); /* Destination */ 2477 shader_arb_get_src_param(ins, &ins->src[0], 0, src); 2478 if (ins->src[0].swizzle == WINED3DSP_NOSWIZZLE) 2479 { 2480 /* Dx sdk says .x is used if no swizzle is given, but our test shows that 2481 * .w is used 2482 */ 2483 strcat(src, ".w"); 2484 } 2485 2486 shader_addline(buffer, "RCP%s %s, %s;\n", shader_arb_get_modifier(ins), dst, src); 2487 } 2488 2489 static void shader_hw_scalar_op(const struct wined3d_shader_instruction *ins) 2490 { 2491 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2492 const char *instruction; 2493 2494 char dst[50]; 2495 char src[50]; 2496 2497 switch(ins->handler_idx) 2498 { 2499 case WINED3DSIH_RSQ: instruction = "RSQ"; break; 2500 case WINED3DSIH_RCP: instruction = "RCP"; break; 2501 case WINED3DSIH_EXP: instruction = "EX2"; break; 2502 case WINED3DSIH_EXPP: instruction = "EXP"; break; 2503 default: instruction = ""; 2504 FIXME("Unhandled opcode %#x\n", ins->handler_idx); 2505 break; 2506 } 2507 2508 shader_arb_get_dst_param(ins, &ins->dst[0], dst); /* Destination */ 2509 shader_arb_get_src_param(ins, &ins->src[0], 0, src); 2510 if (ins->src[0].swizzle == WINED3DSP_NOSWIZZLE) 2511 { 2512 /* Dx sdk says .x is used if no swizzle is given, but our test shows that 2513 * .w is used 2514 */ 2515 strcat(src, ".w"); 2516 } 2517 2518 shader_addline(buffer, "%s%s %s, %s;\n", instruction, shader_arb_get_modifier(ins), dst, src); 2519 } 2520 2521 static void shader_hw_nrm(const struct wined3d_shader_instruction *ins) 2522 { 2523 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2524 char dst_name[50]; 2525 char src_name[50]; 2526 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2527 BOOL pshader = shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type); 2528 const char *zero = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ZERO); 2529 2530 shader_arb_get_dst_param(ins, &ins->dst[0], dst_name); 2531 shader_arb_get_src_param(ins, &ins->src[0], 1 /* Use TB */, src_name); 2532 2533 /* In D3D, NRM of a vector with length zero returns zero. Catch this situation, as 2534 * otherwise NRM or RSQ would return NaN */ 2535 if(pshader && priv->target_version >= NV3) 2536 { 2537 /* GL_NV_fragment_program2's NRM needs protection against length zero vectors too 2538 * 2539 * TODO: Find out if DP3+NRM+MOV is really faster than DP3+RSQ+MUL 2540 */ 2541 shader_addline(buffer, "DP3C TA, %s, %s;\n", src_name, src_name); 2542 shader_addline(buffer, "NRM%s %s, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name); 2543 shader_addline(buffer, "MOV %s (EQ), %s;\n", dst_name, zero); 2544 } 2545 else if(priv->target_version >= NV2) 2546 { 2547 shader_addline(buffer, "DP3C TA.x, %s, %s;\n", src_name, src_name); 2548 shader_addline(buffer, "RSQ TA.x (NE), TA.x;\n"); 2549 shader_addline(buffer, "MUL%s %s, %s, TA.x;\n", shader_arb_get_modifier(ins), dst_name, 2550 src_name); 2551 } 2552 else 2553 { 2554 const char *one = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ONE); 2555 2556 shader_addline(buffer, "DP3 TA.x, %s, %s;\n", src_name, src_name); 2557 /* Pass any non-zero value to RSQ if the input vector has a length of zero. The 2558 * RSQ result doesn't matter, as long as multiplying it by 0 returns 0. 2559 */ 2560 shader_addline(buffer, "SGE TA.y, -TA.x, %s;\n", zero); 2561 shader_addline(buffer, "MAD TA.x, %s, TA.y, TA.x;\n", one); 2562 2563 shader_addline(buffer, "RSQ TA.x, TA.x;\n"); 2564 /* dst.w = src[0].w * 1 / (src.x^2 + src.y^2 + src.z^2)^(1/2) according to msdn*/ 2565 shader_addline(buffer, "MUL%s %s, %s, TA.x;\n", shader_arb_get_modifier(ins), dst_name, 2566 src_name); 2567 } 2568 } 2569 2570 static void shader_hw_lrp(const struct wined3d_shader_instruction *ins) 2571 { 2572 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2573 char dst_name[50]; 2574 char src_name[3][50]; 2575 2576 /* ARB_fragment_program has a convenient LRP instruction */ 2577 if(shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type)) { 2578 shader_hw_map2gl(ins); 2579 return; 2580 } 2581 2582 shader_arb_get_dst_param(ins, &ins->dst[0], dst_name); 2583 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name[0]); 2584 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name[1]); 2585 shader_arb_get_src_param(ins, &ins->src[2], 2, src_name[2]); 2586 2587 shader_addline(buffer, "SUB TA, %s, %s;\n", src_name[1], src_name[2]); 2588 shader_addline(buffer, "MAD%s %s, %s, TA, %s;\n", shader_arb_get_modifier(ins), 2589 dst_name, src_name[0], src_name[2]); 2590 } 2591 2592 static void shader_hw_sincos(const struct wined3d_shader_instruction *ins) 2593 { 2594 /* This instruction exists in ARB, but the d3d instruction takes two extra parameters which 2595 * must contain fixed constants. So we need a separate function to filter those constants and 2596 * can't use map2gl 2597 */ 2598 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2599 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2600 const struct wined3d_shader_dst_param *dst = &ins->dst[0]; 2601 char dst_name[50]; 2602 char src_name0[50], src_name1[50], src_name2[50]; 2603 BOOL is_color; 2604 2605 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name0); 2606 if(shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type)) { 2607 shader_arb_get_dst_param(ins, &ins->dst[0], dst_name); 2608 /* No modifiers are supported on SCS */ 2609 shader_addline(buffer, "SCS %s, %s;\n", dst_name, src_name0); 2610 2611 if(ins->dst[0].modifiers & WINED3DSPDM_SATURATE) 2612 { 2613 shader_arb_get_register_name(ins, &dst->reg, src_name0, &is_color); 2614 shader_addline(buffer, "MOV_SAT %s, %s;\n", dst_name, src_name0); 2615 } 2616 } else if(priv->target_version >= NV2) { 2617 shader_arb_get_register_name(ins, &dst->reg, dst_name, &is_color); 2618 2619 /* Sincos writemask must be .x, .y or .xy */ 2620 if(dst->write_mask & WINED3DSP_WRITEMASK_0) 2621 shader_addline(buffer, "COS%s %s.x, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name0); 2622 if(dst->write_mask & WINED3DSP_WRITEMASK_1) 2623 shader_addline(buffer, "SIN%s %s.y, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name0); 2624 } else { 2625 /* Approximate sine and cosine with a taylor series, as per math textbook. The application passes 8 2626 * helper constants(D3DSINCOSCONST1 and D3DSINCOSCONST2) in src1 and src2. 2627 * 2628 * sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ... 2629 * cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + ... 2630 * 2631 * The constants we get are: 2632 * 2633 * +1 +1, -1 -1 +1 +1 -1 -1 2634 * ---- , ---- , ---- , ----- , ----- , ----- , ------ 2635 * 1!*2 2!*4 3!*8 4!*16 5!*32 6!*64 7!*128 2636 * 2637 * If used with x^2, x^3, x^4 etc they calculate sin(x/2) and cos(x/2): 2638 * 2639 * (x/2)^2 = x^2 / 4 2640 * (x/2)^3 = x^3 / 8 2641 * (x/2)^4 = x^4 / 16 2642 * (x/2)^5 = x^5 / 32 2643 * etc 2644 * 2645 * To get the final result: 2646 * sin(x) = 2 * sin(x/2) * cos(x/2) 2647 * cos(x) = cos(x/2)^2 - sin(x/2)^2 2648 * (from sin(x+y) and cos(x+y) rules) 2649 * 2650 * As per MSDN, dst.z is undefined after the operation, and so is 2651 * dst.x and dst.y if they're masked out by the writemask. Ie 2652 * sincos dst.y, src1, c0, c1 2653 * returns the sine in dst.y. dst.x and dst.z are undefined, dst.w is not touched. The assembler 2654 * vsa.exe also stops with an error if the dest register is the same register as the source 2655 * register. This means we can use dest.xyz as temporary storage. The assembler vsa.exe output also 2656 * indicates that sincos consumes 8 instruction slots in vs_2_0(and, strangely, in vs_3_0). 2657 */ 2658 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name1); 2659 shader_arb_get_src_param(ins, &ins->src[2], 2, src_name2); 2660 shader_arb_get_register_name(ins, &dst->reg, dst_name, &is_color); 2661 2662 shader_addline(buffer, "MUL %s.x, %s, %s;\n", dst_name, src_name0, src_name0); /* x ^ 2 */ 2663 shader_addline(buffer, "MUL TA.y, %s.x, %s;\n", dst_name, src_name0); /* x ^ 3 */ 2664 shader_addline(buffer, "MUL %s.y, TA.y, %s;\n", dst_name, src_name0); /* x ^ 4 */ 2665 shader_addline(buffer, "MUL TA.z, %s.y, %s;\n", dst_name, src_name0); /* x ^ 5 */ 2666 shader_addline(buffer, "MUL %s.z, TA.z, %s;\n", dst_name, src_name0); /* x ^ 6 */ 2667 shader_addline(buffer, "MUL TA.w, %s.z, %s;\n", dst_name, src_name0); /* x ^ 7 */ 2668 2669 /* sin(x/2) 2670 * 2671 * Unfortunately we don't get the constants in a DP4-capable form. Is there a way to 2672 * properly merge that with MULs in the code above? 2673 * The swizzles .yz and xw however fit into the .yzxw swizzle added to ps_2_0. Maybe 2674 * we can merge the sine and cosine MAD rows to calculate them together. 2675 */ 2676 shader_addline(buffer, "MUL TA.x, %s, %s.w;\n", src_name0, src_name2); /* x^1, +1/(1!*2) */ 2677 shader_addline(buffer, "MAD TA.x, TA.y, %s.x, TA.x;\n", src_name2); /* -1/(3!*8) */ 2678 shader_addline(buffer, "MAD TA.x, TA.z, %s.w, TA.x;\n", src_name1); /* +1/(5!*32) */ 2679 shader_addline(buffer, "MAD TA.x, TA.w, %s.x, TA.x;\n", src_name1); /* -1/(7!*128) */ 2680 2681 /* cos(x/2) */ 2682 shader_addline(buffer, "MAD TA.y, %s.x, %s.y, %s.z;\n", dst_name, src_name2, src_name2); /* -1/(2!*4), +1.0 */ 2683 shader_addline(buffer, "MAD TA.y, %s.y, %s.z, TA.y;\n", dst_name, src_name1); /* +1/(4!*16) */ 2684 shader_addline(buffer, "MAD TA.y, %s.z, %s.y, TA.y;\n", dst_name, src_name1); /* -1/(6!*64) */ 2685 2686 if(dst->write_mask & WINED3DSP_WRITEMASK_0) { 2687 /* cos x */ 2688 shader_addline(buffer, "MUL TA.z, TA.y, TA.y;\n"); 2689 shader_addline(buffer, "MAD %s.x, -TA.x, TA.x, TA.z;\n", dst_name); 2690 } 2691 if(dst->write_mask & WINED3DSP_WRITEMASK_1) { 2692 /* sin x */ 2693 shader_addline(buffer, "MUL %s.y, TA.x, TA.y;\n", dst_name); 2694 shader_addline(buffer, "ADD %s.y, %s.y, %s.y;\n", dst_name, dst_name, dst_name); 2695 } 2696 } 2697 } 2698 2699 static void shader_hw_sgn(const struct wined3d_shader_instruction *ins) 2700 { 2701 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2702 char dst_name[50]; 2703 char src_name[50]; 2704 struct shader_arb_ctx_priv *ctx = ins->ctx->backend_data; 2705 2706 shader_arb_get_dst_param(ins, &ins->dst[0], dst_name); 2707 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name); 2708 2709 /* SGN is only valid in vertex shaders */ 2710 if(ctx->target_version >= NV2) { 2711 shader_addline(buffer, "SSG%s %s, %s;\n", shader_arb_get_modifier(ins), dst_name, src_name); 2712 return; 2713 } 2714 2715 /* If SRC > 0.0, -SRC < SRC = TRUE, otherwise false. 2716 * if SRC < 0.0, SRC < -SRC = TRUE. If neither is true, src = 0.0 2717 */ 2718 if(ins->dst[0].modifiers & WINED3DSPDM_SATURATE) { 2719 shader_addline(buffer, "SLT %s, -%s, %s;\n", dst_name, src_name, src_name); 2720 } else { 2721 /* src contains TA? Write to the dest first. This won't overwrite our destination. 2722 * Then use TA, and calculate the final result 2723 * 2724 * Not reading from TA? Store the first result in TA to avoid overwriting the 2725 * destination if src reg = dst reg 2726 */ 2727 if(strstr(src_name, "TA")) 2728 { 2729 shader_addline(buffer, "SLT %s, %s, -%s;\n", dst_name, src_name, src_name); 2730 shader_addline(buffer, "SLT TA, -%s, %s;\n", src_name, src_name); 2731 shader_addline(buffer, "ADD %s, %s, -TA;\n", dst_name, dst_name); 2732 } 2733 else 2734 { 2735 shader_addline(buffer, "SLT TA, -%s, %s;\n", src_name, src_name); 2736 shader_addline(buffer, "SLT %s, %s, -%s;\n", dst_name, src_name, src_name); 2737 shader_addline(buffer, "ADD %s, TA, -%s;\n", dst_name, dst_name); 2738 } 2739 } 2740 } 2741 2742 static void shader_hw_dsy(const struct wined3d_shader_instruction *ins) 2743 { 2744 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2745 char src[50]; 2746 char dst[50]; 2747 char dst_name[50]; 2748 BOOL is_color; 2749 2750 shader_arb_get_dst_param(ins, &ins->dst[0], dst); 2751 shader_arb_get_src_param(ins, &ins->src[0], 0, src); 2752 shader_arb_get_register_name(ins, &ins->dst[0].reg, dst_name, &is_color); 2753 2754 shader_addline(buffer, "DDY %s, %s;\n", dst, src); 2755 shader_addline(buffer, "MUL%s %s, %s, ycorrection.y;\n", shader_arb_get_modifier(ins), dst, dst_name); 2756 } 2757 2758 static DWORD abs_modifier(DWORD mod, BOOL *need_abs) 2759 { 2760 *need_abs = FALSE; 2761 2762 switch(mod) 2763 { 2764 case WINED3DSPSM_NONE: return WINED3DSPSM_ABS; 2765 case WINED3DSPSM_NEG: return WINED3DSPSM_ABS; 2766 case WINED3DSPSM_BIAS: *need_abs = TRUE; return WINED3DSPSM_BIAS; 2767 case WINED3DSPSM_BIASNEG: *need_abs = TRUE; return WINED3DSPSM_BIASNEG; 2768 case WINED3DSPSM_SIGN: *need_abs = TRUE; return WINED3DSPSM_SIGN; 2769 case WINED3DSPSM_SIGNNEG: *need_abs = TRUE; return WINED3DSPSM_SIGNNEG; 2770 case WINED3DSPSM_COMP: *need_abs = TRUE; return WINED3DSPSM_COMP; 2771 case WINED3DSPSM_X2: *need_abs = TRUE; return WINED3DSPSM_X2; 2772 case WINED3DSPSM_X2NEG: *need_abs = TRUE; return WINED3DSPSM_X2NEG; 2773 case WINED3DSPSM_DZ: *need_abs = TRUE; return WINED3DSPSM_DZ; 2774 case WINED3DSPSM_DW: *need_abs = TRUE; return WINED3DSPSM_DW; 2775 case WINED3DSPSM_ABS: return WINED3DSPSM_ABS; 2776 case WINED3DSPSM_ABSNEG: return WINED3DSPSM_ABS; 2777 } 2778 FIXME("Unknown modifier %u\n", mod); 2779 return mod; 2780 } 2781 2782 static void shader_hw_log(const struct wined3d_shader_instruction *ins) 2783 { 2784 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2785 char src0[50], dst[50]; 2786 struct wined3d_shader_src_param src0_copy = ins->src[0]; 2787 BOOL need_abs = FALSE; 2788 const char *instr; 2789 2790 switch(ins->handler_idx) 2791 { 2792 case WINED3DSIH_LOG: instr = "LG2"; break; 2793 case WINED3DSIH_LOGP: instr = "LOG"; break; 2794 default: 2795 ERR("Unexpected instruction %d\n", ins->handler_idx); 2796 return; 2797 } 2798 2799 /* LOG and LOGP operate on the absolute value of the input */ 2800 src0_copy.modifiers = abs_modifier(src0_copy.modifiers, &need_abs); 2801 2802 shader_arb_get_dst_param(ins, &ins->dst[0], dst); 2803 shader_arb_get_src_param(ins, &src0_copy, 0, src0); 2804 2805 if(need_abs) 2806 { 2807 shader_addline(buffer, "ABS TA, %s;\n", src0); 2808 shader_addline(buffer, "%s%s %s, TA;\n", instr, shader_arb_get_modifier(ins), dst); 2809 } 2810 else 2811 { 2812 shader_addline(buffer, "%s%s %s, %s;\n", instr, shader_arb_get_modifier(ins), dst, src0); 2813 } 2814 } 2815 2816 static void shader_hw_pow(const struct wined3d_shader_instruction *ins) 2817 { 2818 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2819 char src0[50], src1[50], dst[50]; 2820 struct wined3d_shader_src_param src0_copy = ins->src[0]; 2821 BOOL need_abs = FALSE; 2822 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2823 const char *one = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ONE); 2824 2825 /* POW operates on the absolute value of the input */ 2826 src0_copy.modifiers = abs_modifier(src0_copy.modifiers, &need_abs); 2827 2828 shader_arb_get_dst_param(ins, &ins->dst[0], dst); 2829 shader_arb_get_src_param(ins, &src0_copy, 0, src0); 2830 shader_arb_get_src_param(ins, &ins->src[1], 1, src1); 2831 2832 if (need_abs) 2833 shader_addline(buffer, "ABS TA.x, %s;\n", src0); 2834 else 2835 shader_addline(buffer, "MOV TA.x, %s;\n", src0); 2836 2837 if (priv->target_version >= NV2) 2838 { 2839 shader_addline(buffer, "MOVC TA.y, %s;\n", src1); 2840 shader_addline(buffer, "POW%s %s, TA.x, TA.y;\n", shader_arb_get_modifier(ins), dst); 2841 shader_addline(buffer, "MOV %s (EQ.y), %s;\n", dst, one); 2842 } 2843 else 2844 { 2845 const char *zero = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_ZERO); 2846 const char *flt_eps = arb_get_helper_value(ins->ctx->reg_maps->shader_version.type, ARB_EPS); 2847 2848 shader_addline(buffer, "ABS TA.y, %s;\n", src1); 2849 shader_addline(buffer, "SGE TA.y, -TA.y, %s;\n", zero); 2850 /* Possibly add flt_eps to avoid getting float special values */ 2851 shader_addline(buffer, "MAD TA.z, TA.y, %s, %s;\n", flt_eps, src1); 2852 shader_addline(buffer, "POW%s TA.x, TA.x, TA.z;\n", shader_arb_get_modifier(ins)); 2853 shader_addline(buffer, "MAD TA.x, -TA.x, TA.y, TA.x;\n"); 2854 shader_addline(buffer, "MAD %s, TA.y, %s, TA.x;\n", dst, one); 2855 } 2856 } 2857 2858 static void shader_hw_loop(const struct wined3d_shader_instruction *ins) 2859 { 2860 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2861 char src_name[50]; 2862 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 2863 2864 /* src0 is aL */ 2865 shader_arb_get_src_param(ins, &ins->src[1], 0, src_name); 2866 2867 if(vshader) 2868 { 2869 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2870 struct list *e = list_head(&priv->control_frames); 2871 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 2872 2873 if(priv->loop_depth > 1) shader_addline(buffer, "PUSHA aL;\n"); 2874 /* The constant loader makes sure to load -1 into iX.w */ 2875 shader_addline(buffer, "ARLC aL, %s.xywz;\n", src_name); 2876 shader_addline(buffer, "BRA loop_%u_end (LE.x);\n", control_frame->no.loop); 2877 shader_addline(buffer, "loop_%u_start:\n", control_frame->no.loop); 2878 } 2879 else 2880 { 2881 shader_addline(buffer, "LOOP %s;\n", src_name); 2882 } 2883 } 2884 2885 static void shader_hw_rep(const struct wined3d_shader_instruction *ins) 2886 { 2887 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2888 char src_name[50]; 2889 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 2890 2891 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name); 2892 2893 /* The constant loader makes sure to load -1 into iX.w */ 2894 if(vshader) 2895 { 2896 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2897 struct list *e = list_head(&priv->control_frames); 2898 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 2899 2900 if(priv->loop_depth > 1) shader_addline(buffer, "PUSHA aL;\n"); 2901 2902 shader_addline(buffer, "ARLC aL, %s.xywz;\n", src_name); 2903 shader_addline(buffer, "BRA loop_%u_end (LE.x);\n", control_frame->no.loop); 2904 shader_addline(buffer, "loop_%u_start:\n", control_frame->no.loop); 2905 } 2906 else 2907 { 2908 shader_addline(buffer, "REP %s;\n", src_name); 2909 } 2910 } 2911 2912 static void shader_hw_endloop(const struct wined3d_shader_instruction *ins) 2913 { 2914 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2915 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 2916 2917 if(vshader) 2918 { 2919 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2920 struct list *e = list_head(&priv->control_frames); 2921 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 2922 2923 shader_addline(buffer, "ARAC aL.xy, aL;\n"); 2924 shader_addline(buffer, "BRA loop_%u_start (GT.x);\n", control_frame->no.loop); 2925 shader_addline(buffer, "loop_%u_end:\n", control_frame->no.loop); 2926 2927 if(priv->loop_depth > 1) shader_addline(buffer, "POPA aL;\n"); 2928 } 2929 else 2930 { 2931 shader_addline(buffer, "ENDLOOP;\n"); 2932 } 2933 } 2934 2935 static void shader_hw_endrep(const struct wined3d_shader_instruction *ins) 2936 { 2937 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2938 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 2939 2940 if(vshader) 2941 { 2942 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 2943 struct list *e = list_head(&priv->control_frames); 2944 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 2945 2946 shader_addline(buffer, "ARAC aL.xy, aL;\n"); 2947 shader_addline(buffer, "BRA loop_%u_start (GT.x);\n", control_frame->no.loop); 2948 shader_addline(buffer, "loop_%u_end:\n", control_frame->no.loop); 2949 2950 if(priv->loop_depth > 1) shader_addline(buffer, "POPA aL;\n"); 2951 } 2952 else 2953 { 2954 shader_addline(buffer, "ENDREP;\n"); 2955 } 2956 } 2957 2958 static const struct control_frame *find_last_loop(const struct shader_arb_ctx_priv *priv) 2959 { 2960 struct control_frame *control_frame; 2961 2962 LIST_FOR_EACH_ENTRY(control_frame, &priv->control_frames, struct control_frame, entry) 2963 { 2964 if(control_frame->type == LOOP || control_frame->type == REP) return control_frame; 2965 } 2966 ERR("Could not find loop for break\n"); 2967 return NULL; 2968 } 2969 2970 static void shader_hw_break(const struct wined3d_shader_instruction *ins) 2971 { 2972 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 2973 const struct control_frame *control_frame = find_last_loop(ins->ctx->backend_data); 2974 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 2975 2976 if(vshader) 2977 { 2978 shader_addline(buffer, "BRA loop_%u_end;\n", control_frame->no.loop); 2979 } 2980 else 2981 { 2982 shader_addline(buffer, "BRK;\n"); 2983 } 2984 } 2985 2986 static const char *get_compare(enum wined3d_shader_rel_op op) 2987 { 2988 switch (op) 2989 { 2990 case WINED3D_SHADER_REL_OP_GT: return "GT"; 2991 case WINED3D_SHADER_REL_OP_EQ: return "EQ"; 2992 case WINED3D_SHADER_REL_OP_GE: return "GE"; 2993 case WINED3D_SHADER_REL_OP_LT: return "LT"; 2994 case WINED3D_SHADER_REL_OP_NE: return "NE"; 2995 case WINED3D_SHADER_REL_OP_LE: return "LE"; 2996 default: 2997 FIXME("Unrecognized operator %#x.\n", op); 2998 return "(\?\?)"; 2999 } 3000 } 3001 3002 static enum wined3d_shader_rel_op invert_compare(enum wined3d_shader_rel_op op) 3003 { 3004 switch (op) 3005 { 3006 case WINED3D_SHADER_REL_OP_GT: return WINED3D_SHADER_REL_OP_LE; 3007 case WINED3D_SHADER_REL_OP_EQ: return WINED3D_SHADER_REL_OP_NE; 3008 case WINED3D_SHADER_REL_OP_GE: return WINED3D_SHADER_REL_OP_LT; 3009 case WINED3D_SHADER_REL_OP_LT: return WINED3D_SHADER_REL_OP_GE; 3010 case WINED3D_SHADER_REL_OP_NE: return WINED3D_SHADER_REL_OP_EQ; 3011 case WINED3D_SHADER_REL_OP_LE: return WINED3D_SHADER_REL_OP_GT; 3012 default: 3013 FIXME("Unrecognized operator %#x.\n", op); 3014 return -1; 3015 } 3016 } 3017 3018 static void shader_hw_breakc(const struct wined3d_shader_instruction *ins) 3019 { 3020 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3021 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 3022 const struct control_frame *control_frame = find_last_loop(ins->ctx->backend_data); 3023 char src_name0[50]; 3024 char src_name1[50]; 3025 const char *comp = get_compare(ins->flags); 3026 3027 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name0); 3028 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name1); 3029 3030 if(vshader) 3031 { 3032 /* SUBC CC, src0, src1" works only in pixel shaders, so use TA to throw 3033 * away the subtraction result 3034 */ 3035 shader_addline(buffer, "SUBC TA, %s, %s;\n", src_name0, src_name1); 3036 shader_addline(buffer, "BRA loop_%u_end (%s.x);\n", control_frame->no.loop, comp); 3037 } 3038 else 3039 { 3040 shader_addline(buffer, "SUBC TA, %s, %s;\n", src_name0, src_name1); 3041 shader_addline(buffer, "BRK (%s.x);\n", comp); 3042 } 3043 } 3044 3045 static void shader_hw_ifc(const struct wined3d_shader_instruction *ins) 3046 { 3047 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3048 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 3049 struct list *e = list_head(&priv->control_frames); 3050 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 3051 const char *comp; 3052 char src_name0[50]; 3053 char src_name1[50]; 3054 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 3055 3056 shader_arb_get_src_param(ins, &ins->src[0], 0, src_name0); 3057 shader_arb_get_src_param(ins, &ins->src[1], 1, src_name1); 3058 3059 if(vshader) 3060 { 3061 /* Invert the flag. We jump to the else label if the condition is NOT true */ 3062 comp = get_compare(invert_compare(ins->flags)); 3063 shader_addline(buffer, "SUBC TA, %s, %s;\n", src_name0, src_name1); 3064 shader_addline(buffer, "BRA ifc_%u_else (%s.x);\n", control_frame->no.ifc, comp); 3065 } 3066 else 3067 { 3068 comp = get_compare(ins->flags); 3069 shader_addline(buffer, "SUBC TA, %s, %s;\n", src_name0, src_name1); 3070 shader_addline(buffer, "IF %s.x;\n", comp); 3071 } 3072 } 3073 3074 static void shader_hw_else(const struct wined3d_shader_instruction *ins) 3075 { 3076 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3077 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 3078 struct list *e = list_head(&priv->control_frames); 3079 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 3080 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 3081 3082 if(vshader) 3083 { 3084 shader_addline(buffer, "BRA ifc_%u_endif;\n", control_frame->no.ifc); 3085 shader_addline(buffer, "ifc_%u_else:\n", control_frame->no.ifc); 3086 control_frame->had_else = TRUE; 3087 } 3088 else 3089 { 3090 shader_addline(buffer, "ELSE;\n"); 3091 } 3092 } 3093 3094 static void shader_hw_endif(const struct wined3d_shader_instruction *ins) 3095 { 3096 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3097 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 3098 struct list *e = list_head(&priv->control_frames); 3099 struct control_frame *control_frame = LIST_ENTRY(e, struct control_frame, entry); 3100 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 3101 3102 if(vshader) 3103 { 3104 if(control_frame->had_else) 3105 { 3106 shader_addline(buffer, "ifc_%u_endif:\n", control_frame->no.ifc); 3107 } 3108 else 3109 { 3110 shader_addline(buffer, "#No else branch. else is endif\n"); 3111 shader_addline(buffer, "ifc_%u_else:\n", control_frame->no.ifc); 3112 } 3113 } 3114 else 3115 { 3116 shader_addline(buffer, "ENDIF;\n"); 3117 } 3118 } 3119 3120 static void shader_hw_texldd(const struct wined3d_shader_instruction *ins) 3121 { 3122 DWORD sampler_idx = ins->src[1].reg.idx[0].offset; 3123 char reg_dest[40]; 3124 char reg_src[3][40]; 3125 WORD flags = TEX_DERIV; 3126 3127 shader_arb_get_dst_param(ins, &ins->dst[0], reg_dest); 3128 shader_arb_get_src_param(ins, &ins->src[0], 0, reg_src[0]); 3129 shader_arb_get_src_param(ins, &ins->src[2], 1, reg_src[1]); 3130 shader_arb_get_src_param(ins, &ins->src[3], 2, reg_src[2]); 3131 3132 if (ins->flags & WINED3DSI_TEXLD_PROJECT) flags |= TEX_PROJ; 3133 if (ins->flags & WINED3DSI_TEXLD_BIAS) flags |= TEX_BIAS; 3134 3135 shader_hw_sample(ins, sampler_idx, reg_dest, reg_src[0], flags, reg_src[1], reg_src[2]); 3136 } 3137 3138 static void shader_hw_texldl(const struct wined3d_shader_instruction *ins) 3139 { 3140 DWORD sampler_idx = ins->src[1].reg.idx[0].offset; 3141 char reg_dest[40]; 3142 char reg_coord[40]; 3143 WORD flags = TEX_LOD; 3144 3145 shader_arb_get_dst_param(ins, &ins->dst[0], reg_dest); 3146 shader_arb_get_src_param(ins, &ins->src[0], 0, reg_coord); 3147 3148 if (ins->flags & WINED3DSI_TEXLD_PROJECT) flags |= TEX_PROJ; 3149 if (ins->flags & WINED3DSI_TEXLD_BIAS) flags |= TEX_BIAS; 3150 3151 shader_hw_sample(ins, sampler_idx, reg_dest, reg_coord, flags, NULL, NULL); 3152 } 3153 3154 static void shader_hw_label(const struct wined3d_shader_instruction *ins) 3155 { 3156 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3157 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 3158 3159 priv->in_main_func = FALSE; 3160 /* Call instructions activate the NV extensions, not labels and rets. If there is an uncalled 3161 * subroutine, don't generate a label that will make GL complain 3162 */ 3163 if(priv->target_version == ARB) return; 3164 3165 shader_addline(buffer, "l%u:\n", ins->src[0].reg.idx[0].offset); 3166 } 3167 3168 static void vshader_add_footer(struct shader_arb_ctx_priv *priv_ctx, 3169 const struct arb_vshader_private *shader_data, const struct arb_vs_compile_args *args, 3170 const struct wined3d_shader_reg_maps *reg_maps, const struct wined3d_gl_info *gl_info, 3171 struct wined3d_shader_buffer *buffer) 3172 { 3173 unsigned int i; 3174 3175 /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used 3176 * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE), 3177 * the fog frag coord is thrown away. If the fog frag coord is used, but not written by 3178 * the shader, it is set to 0.0(fully fogged, since start = 1.0, end = 0.0) 3179 */ 3180 if (args->super.fog_src == VS_FOG_Z) 3181 { 3182 shader_addline(buffer, "MOV result.fogcoord, TMP_OUT.z;\n"); 3183 } 3184 else 3185 { 3186 if (!reg_maps->fog) 3187 { 3188 /* posFixup.x is always 1.0, so we can safely use it */ 3189 shader_addline(buffer, "ADD result.fogcoord, posFixup.x, -posFixup.x;\n"); 3190 } 3191 else 3192 { 3193 /* Clamp fogcoord */ 3194 const char *zero = arb_get_helper_value(reg_maps->shader_version.type, ARB_ZERO); 3195 const char *one = arb_get_helper_value(reg_maps->shader_version.type, ARB_ONE); 3196 3197 shader_addline(buffer, "MIN TMP_FOGCOORD.x, TMP_FOGCOORD.x, %s;\n", one); 3198 shader_addline(buffer, "MAX result.fogcoord.x, TMP_FOGCOORD.x, %s;\n", zero); 3199 } 3200 } 3201 3202 /* Clipplanes are always stored without y inversion */ 3203 if (use_nv_clip(gl_info) && priv_ctx->target_version >= NV2) 3204 { 3205 if (args->super.clip_enabled) 3206 { 3207 for (i = 0; i < priv_ctx->vs_clipplanes; i++) 3208 { 3209 shader_addline(buffer, "DP4 result.clip[%u].x, TMP_OUT, state.clip[%u].plane;\n", i, i); 3210 } 3211 } 3212 } 3213 else if (args->clip.boolclip.clip_texcoord) 3214 { 3215 unsigned int cur_clip = 0; 3216 char component[4] = {'x', 'y', 'z', 'w'}; 3217 const char *zero = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_ZERO); 3218 3219 for (i = 0; i < gl_info->limits.clipplanes; ++i) 3220 { 3221 if (args->clip.boolclip.clipplane_mask & (1 << i)) 3222 { 3223 shader_addline(buffer, "DP4 TA.%c, TMP_OUT, state.clip[%u].plane;\n", 3224 component[cur_clip++], i); 3225 } 3226 } 3227 switch (cur_clip) 3228 { 3229 case 0: 3230 shader_addline(buffer, "MOV TA, %s;\n", zero); 3231 break; 3232 case 1: 3233 shader_addline(buffer, "MOV TA.yzw, %s;\n", zero); 3234 break; 3235 case 2: 3236 shader_addline(buffer, "MOV TA.zw, %s;\n", zero); 3237 break; 3238 case 3: 3239 shader_addline(buffer, "MOV TA.w, %s;\n", zero); 3240 break; 3241 } 3242 shader_addline(buffer, "MOV result.texcoord[%u], TA;\n", 3243 args->clip.boolclip.clip_texcoord - 1); 3244 } 3245 3246 /* Write the final position. 3247 * 3248 * OpenGL coordinates specify the center of the pixel while d3d coords specify 3249 * the corner. The offsets are stored in z and w in posFixup. posFixup.y contains 3250 * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x 3251 * contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that. 3252 */ 3253 shader_addline(buffer, "MUL TA, posFixup, TMP_OUT.w;\n"); 3254 shader_addline(buffer, "ADD TMP_OUT.x, TMP_OUT.x, TA.z;\n"); 3255 shader_addline(buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TA.w;\n"); 3256 3257 /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c 3258 * and the glsl equivalent 3259 */ 3260 if (need_helper_const(shader_data, reg_maps, gl_info)) 3261 { 3262 const char *two = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_TWO); 3263 shader_addline(buffer, "MAD TMP_OUT.z, TMP_OUT.z, %s, -TMP_OUT.w;\n", two); 3264 } 3265 else 3266 { 3267 shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, TMP_OUT.z;\n"); 3268 shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, -TMP_OUT.w;\n"); 3269 } 3270 3271 shader_addline(buffer, "MOV result.position, TMP_OUT;\n"); 3272 3273 priv_ctx->footer_written = TRUE; 3274 } 3275 3276 static void shader_hw_ret(const struct wined3d_shader_instruction *ins) 3277 { 3278 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3279 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 3280 const struct wined3d_shader *shader = ins->ctx->shader; 3281 BOOL vshader = shader_is_vshader_version(ins->ctx->reg_maps->shader_version.type); 3282 3283 if(priv->target_version == ARB) return; 3284 3285 if(vshader) 3286 { 3287 if (priv->in_main_func) vshader_add_footer(priv, shader->backend_data, 3288 priv->cur_vs_args, ins->ctx->reg_maps, ins->ctx->gl_info, buffer); 3289 } 3290 3291 shader_addline(buffer, "RET;\n"); 3292 } 3293 3294 static void shader_hw_call(const struct wined3d_shader_instruction *ins) 3295 { 3296 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 3297 shader_addline(buffer, "CAL l%u;\n", ins->src[0].reg.idx[0].offset); 3298 } 3299 3300 /* Context activation is done by the caller. */ 3301 static GLuint create_arb_blt_vertex_program(const struct wined3d_gl_info *gl_info) 3302 { 3303 GLuint program_id = 0; 3304 GLint pos; 3305 3306 const char *blt_vprogram = 3307 "!!ARBvp1.0\n" 3308 "PARAM c[1] = { { 1, 0.5 } };\n" 3309 "MOV result.position, vertex.position;\n" 3310 "MOV result.color, c[0].x;\n" 3311 "MOV result.texcoord[0], vertex.texcoord[0];\n" 3312 "END\n"; 3313 3314 GL_EXTCALL(glGenProgramsARB(1, &program_id)); 3315 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program_id)); 3316 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 3317 strlen(blt_vprogram), blt_vprogram)); 3318 checkGLcall("glProgramStringARB()"); 3319 3320 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); 3321 if (pos != -1) 3322 { 3323 FIXME("Vertex program error at position %d: %s\n\n", pos, 3324 debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 3325 shader_arb_dump_program_source(blt_vprogram); 3326 } 3327 else 3328 { 3329 GLint native; 3330 3331 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 3332 checkGLcall("glGetProgramivARB()"); 3333 if (!native) WARN("Program exceeds native resource limits.\n"); 3334 } 3335 3336 return program_id; 3337 } 3338 3339 /* Context activation is done by the caller. */ 3340 static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_info, 3341 enum tex_types tex_type, BOOL masked) 3342 { 3343 GLuint program_id = 0; 3344 const char *fprogram; 3345 GLint pos; 3346 3347 static const char * const blt_fprograms_full[tex_type_count] = 3348 { 3349 /* tex_1d */ 3350 NULL, 3351 /* tex_2d */ 3352 "!!ARBfp1.0\n" 3353 "TEMP R0;\n" 3354 "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n" 3355 "MOV result.depth.z, R0.x;\n" 3356 "END\n", 3357 /* tex_3d */ 3358 NULL, 3359 /* tex_cube */ 3360 "!!ARBfp1.0\n" 3361 "TEMP R0;\n" 3362 "TEX R0.x, fragment.texcoord[0], texture[0], CUBE;\n" 3363 "MOV result.depth.z, R0.x;\n" 3364 "END\n", 3365 /* tex_rect */ 3366 "!!ARBfp1.0\n" 3367 "TEMP R0;\n" 3368 "TEX R0.x, fragment.texcoord[0], texture[0], RECT;\n" 3369 "MOV result.depth.z, R0.x;\n" 3370 "END\n", 3371 }; 3372 3373 static const char * const blt_fprograms_masked[tex_type_count] = 3374 { 3375 /* tex_1d */ 3376 NULL, 3377 /* tex_2d */ 3378 "!!ARBfp1.0\n" 3379 "PARAM mask = program.local[0];\n" 3380 "TEMP R0;\n" 3381 "SLT R0.xy, fragment.position, mask.zwzw;\n" 3382 "MUL R0.x, R0.x, R0.y;\n" 3383 "KIL -R0.x;\n" 3384 "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n" 3385 "MOV result.depth.z, R0.x;\n" 3386 "END\n", 3387 /* tex_3d */ 3388 NULL, 3389 /* tex_cube */ 3390 "!!ARBfp1.0\n" 3391 "PARAM mask = program.local[0];\n" 3392 "TEMP R0;\n" 3393 "SLT R0.xy, fragment.position, mask.zwzw;\n" 3394 "MUL R0.x, R0.x, R0.y;\n" 3395 "KIL -R0.x;\n" 3396 "TEX R0.x, fragment.texcoord[0], texture[0], CUBE;\n" 3397 "MOV result.depth.z, R0.x;\n" 3398 "END\n", 3399 /* tex_rect */ 3400 "!!ARBfp1.0\n" 3401 "PARAM mask = program.local[0];\n" 3402 "TEMP R0;\n" 3403 "SLT R0.xy, fragment.position, mask.zwzw;\n" 3404 "MUL R0.x, R0.x, R0.y;\n" 3405 "KIL -R0.x;\n" 3406 "TEX R0.x, fragment.texcoord[0], texture[0], RECT;\n" 3407 "MOV result.depth.z, R0.x;\n" 3408 "END\n", 3409 }; 3410 3411 fprogram = masked ? blt_fprograms_masked[tex_type] : blt_fprograms_full[tex_type]; 3412 if (!fprogram) 3413 { 3414 FIXME("tex_type %#x not supported, falling back to tex_2d\n", tex_type); 3415 tex_type = tex_2d; 3416 fprogram = masked ? blt_fprograms_masked[tex_type] : blt_fprograms_full[tex_type]; 3417 } 3418 3419 GL_EXTCALL(glGenProgramsARB(1, &program_id)); 3420 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id)); 3421 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fprogram), fprogram)); 3422 checkGLcall("glProgramStringARB()"); 3423 3424 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); 3425 if (pos != -1) 3426 { 3427 FIXME("Fragment program error at position %d: %s\n\n", pos, 3428 debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 3429 shader_arb_dump_program_source(fprogram); 3430 } 3431 else 3432 { 3433 GLint native; 3434 3435 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 3436 checkGLcall("glGetProgramivARB()"); 3437 if (!native) WARN("Program exceeds native resource limits.\n"); 3438 } 3439 3440 return program_id; 3441 } 3442 3443 static void arbfp_add_sRGB_correction(struct wined3d_shader_buffer *buffer, const char *fragcolor, 3444 const char *tmp1, const char *tmp2, const char *tmp3, const char *tmp4, BOOL condcode) 3445 { 3446 /* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */ 3447 3448 if(condcode) 3449 { 3450 /* Sigh. MOVC CC doesn't work, so use one of the temps as dummy dest */ 3451 shader_addline(buffer, "SUBC %s, %s.x, srgb_consts1.x;\n", tmp1, fragcolor); 3452 /* Calculate the > 0.0031308 case */ 3453 shader_addline(buffer, "POW %s.x (GE), %s.x, srgb_consts0.x;\n", fragcolor, fragcolor); 3454 shader_addline(buffer, "POW %s.y (GE), %s.y, srgb_consts0.x;\n", fragcolor, fragcolor); 3455 shader_addline(buffer, "POW %s.z (GE), %s.z, srgb_consts0.x;\n", fragcolor, fragcolor); 3456 shader_addline(buffer, "MUL %s.xyz (GE), %s, srgb_consts0.y;\n", fragcolor, fragcolor); 3457 shader_addline(buffer, "SUB %s.xyz (GE), %s, srgb_consts0.z;\n", fragcolor, fragcolor); 3458 /* Calculate the < case */ 3459 shader_addline(buffer, "MUL %s.xyz (LT), srgb_consts0.w, %s;\n", fragcolor, fragcolor); 3460 } 3461 else 3462 { 3463 /* Calculate the > 0.0031308 case */ 3464 shader_addline(buffer, "POW %s.x, %s.x, srgb_consts0.x;\n", tmp1, fragcolor); 3465 shader_addline(buffer, "POW %s.y, %s.y, srgb_consts0.x;\n", tmp1, fragcolor); 3466 shader_addline(buffer, "POW %s.z, %s.z, srgb_consts0.x;\n", tmp1, fragcolor); 3467 shader_addline(buffer, "MUL %s, %s, srgb_consts0.y;\n", tmp1, tmp1); 3468 shader_addline(buffer, "SUB %s, %s, srgb_consts0.z;\n", tmp1, tmp1); 3469 /* Calculate the < case */ 3470 shader_addline(buffer, "MUL %s, srgb_consts0.w, %s;\n", tmp2, fragcolor); 3471 /* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */ 3472 shader_addline(buffer, "SLT %s, srgb_consts1.x, %s;\n", tmp3, fragcolor); 3473 shader_addline(buffer, "SGE %s, srgb_consts1.x, %s;\n", tmp4, fragcolor); 3474 /* Store the components > 0.0031308 in the destination */ 3475 shader_addline(buffer, "MUL %s.xyz, %s, %s;\n", fragcolor, tmp1, tmp3); 3476 /* Add the components that are < 0.0031308 */ 3477 shader_addline(buffer, "MAD %s.xyz, %s, %s, %s;\n", fragcolor, tmp2, tmp4, fragcolor); 3478 /* Move everything into result.color at once. Nvidia hardware cannot handle partial 3479 * result.color writes(.rgb first, then .a), or handle overwriting already written 3480 * components. The assembler uses a temporary register in this case, which is usually 3481 * not allocated from one of our registers that were used earlier. 3482 */ 3483 } 3484 /* [0.0;1.0] clamping. Not needed, this is done implicitly */ 3485 } 3486 3487 static const DWORD *find_loop_control_values(const struct wined3d_shader *shader, DWORD idx) 3488 { 3489 const struct wined3d_shader_lconst *constant; 3490 3491 LIST_FOR_EACH_ENTRY(constant, &shader->constantsI, struct wined3d_shader_lconst, entry) 3492 { 3493 if (constant->idx == idx) 3494 { 3495 return constant->value; 3496 } 3497 } 3498 return NULL; 3499 } 3500 3501 static void init_ps_input(const struct wined3d_shader *shader, 3502 const struct arb_ps_compile_args *args, struct shader_arb_ctx_priv *priv) 3503 { 3504 static const char * const texcoords[8] = 3505 { 3506 "fragment.texcoord[0]", "fragment.texcoord[1]", "fragment.texcoord[2]", "fragment.texcoord[3]", 3507 "fragment.texcoord[4]", "fragment.texcoord[5]", "fragment.texcoord[6]", "fragment.texcoord[7]" 3508 }; 3509 unsigned int i; 3510 const struct wined3d_shader_signature_element *sig = shader->input_signature; 3511 const char *semantic_name; 3512 DWORD semantic_idx; 3513 3514 switch(args->super.vp_mode) 3515 { 3516 case pretransformed: 3517 case fixedfunction: 3518 /* The pixelshader has to collect the varyings on its own. In any case properly load 3519 * color0 and color1. In the case of pretransformed vertices also load texcoords. Set 3520 * other attribs to 0.0. 3521 * 3522 * For fixedfunction this behavior is correct, according to the tests. For pretransformed 3523 * we'd either need a replacement shader that can load other attribs like BINORMAL, or 3524 * load the texcoord attrib pointers to match the pixel shader signature 3525 */ 3526 for(i = 0; i < MAX_REG_INPUT; i++) 3527 { 3528 semantic_name = sig[i].semantic_name; 3529 semantic_idx = sig[i].semantic_idx; 3530 if (!semantic_name) continue; 3531 3532 if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_COLOR)) 3533 { 3534 if (!semantic_idx) priv->ps_input[i] = "fragment.color.primary"; 3535 else if(semantic_idx == 1) priv->ps_input[i] = "fragment.color.secondary"; 3536 else priv->ps_input[i] = "0.0"; 3537 } 3538 else if(args->super.vp_mode == fixedfunction) 3539 { 3540 priv->ps_input[i] = "0.0"; 3541 } 3542 else if(shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD)) 3543 { 3544 if(semantic_idx < 8) priv->ps_input[i] = texcoords[semantic_idx]; 3545 else priv->ps_input[i] = "0.0"; 3546 } 3547 else if(shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_FOG)) 3548 { 3549 if (!semantic_idx) priv->ps_input[i] = "fragment.fogcoord"; 3550 else priv->ps_input[i] = "0.0"; 3551 } 3552 else 3553 { 3554 priv->ps_input[i] = "0.0"; 3555 } 3556 3557 TRACE("v%u, semantic %s%u is %s\n", i, semantic_name, semantic_idx, priv->ps_input[i]); 3558 } 3559 break; 3560 3561 case vertexshader: 3562 /* That one is easy. The vertex shaders provide v0-v7 in fragment.texcoord and v8 and v9 in 3563 * fragment.color 3564 */ 3565 for(i = 0; i < 8; i++) 3566 { 3567 priv->ps_input[i] = texcoords[i]; 3568 } 3569 priv->ps_input[8] = "fragment.color.primary"; 3570 priv->ps_input[9] = "fragment.color.secondary"; 3571 break; 3572 } 3573 } 3574 3575 static void arbfp_add_linear_fog(struct wined3d_shader_buffer *buffer, 3576 const char *fragcolor, const char *tmp) 3577 { 3578 shader_addline(buffer, "SUB %s.x, state.fog.params.z, fragment.fogcoord.x;\n", tmp); 3579 shader_addline(buffer, "MUL_SAT %s.x, %s.x, state.fog.params.w;\n", tmp, tmp); 3580 shader_addline(buffer, "LRP %s.rgb, %s.x, %s, state.fog.color;\n", fragcolor, tmp, fragcolor); 3581 } 3582 3583 /* Context activation is done by the caller. */ 3584 static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, 3585 const struct wined3d_gl_info *gl_info, struct wined3d_shader_buffer *buffer, 3586 const struct arb_ps_compile_args *args, struct arb_ps_compiled_shader *compiled) 3587 { 3588 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; 3589 const DWORD *function = shader->function; 3590 GLuint retval; 3591 char fragcolor[16]; 3592 DWORD next_local = 0; 3593 struct shader_arb_ctx_priv priv_ctx; 3594 BOOL dcl_td = FALSE; 3595 BOOL want_nv_prog = FALSE; 3596 struct arb_pshader_private *shader_priv = shader->backend_data; 3597 GLint errPos; 3598 DWORD map; 3599 BOOL custom_linear_fog = FALSE; 3600 3601 char srgbtmp[4][4]; 3602 char ftoa_tmp[17]; 3603 unsigned int i, found = 0; 3604 3605 for (i = 0, map = reg_maps->temporary; map; map >>= 1, ++i) 3606 { 3607 if (!(map & 1) 3608 || (shader->u.ps.color0_mov && i == shader->u.ps.color0_reg) 3609 || (reg_maps->shader_version.major < 2 && !i)) 3610 continue; 3611 3612 sprintf(srgbtmp[found], "R%u", i); 3613 ++found; 3614 if (found == 4) break; 3615 } 3616 3617 switch(found) { 3618 case 0: 3619 sprintf(srgbtmp[0], "TA"); 3620 sprintf(srgbtmp[1], "TB"); 3621 sprintf(srgbtmp[2], "TC"); 3622 sprintf(srgbtmp[3], "TD"); 3623 dcl_td = TRUE; 3624 break; 3625 case 1: 3626 sprintf(srgbtmp[1], "TA"); 3627 sprintf(srgbtmp[2], "TB"); 3628 sprintf(srgbtmp[3], "TC"); 3629 break; 3630 case 2: 3631 sprintf(srgbtmp[2], "TA"); 3632 sprintf(srgbtmp[3], "TB"); 3633 break; 3634 case 3: 3635 sprintf(srgbtmp[3], "TA"); 3636 break; 3637 case 4: 3638 break; 3639 } 3640 3641 /* Create the hw ARB shader */ 3642 memset(&priv_ctx, 0, sizeof(priv_ctx)); 3643 priv_ctx.cur_ps_args = args; 3644 priv_ctx.compiled_fprog = compiled; 3645 priv_ctx.cur_np2fixup_info = &compiled->np2fixup_info; 3646 init_ps_input(shader, args, &priv_ctx); 3647 list_init(&priv_ctx.control_frames); 3648 priv_ctx.ps_post_process = args->super.srgb_correction; 3649 3650 /* Avoid enabling NV_fragment_program* if we do not need it. 3651 * 3652 * Enabling GL_NV_fragment_program_option causes the driver to occupy a temporary register, 3653 * and it slows down the shader execution noticeably(about 5%). Usually our instruction emulation 3654 * is faster than what we gain from using higher native instructions. There are some things though 3655 * that cannot be emulated. In that case enable the extensions. 3656 * If the extension is enabled, instruction handlers that support both ways will use it. 3657 * 3658 * Testing shows no performance difference between OPTION NV_fragment_program2 and NV_fragment_program. 3659 * So enable the best we can get. 3660 */ 3661 if(reg_maps->usesdsx || reg_maps->usesdsy || reg_maps->loop_depth > 0 || reg_maps->usestexldd || 3662 reg_maps->usestexldl || reg_maps->usesfacing || reg_maps->usesifc || reg_maps->usescall) 3663 { 3664 want_nv_prog = TRUE; 3665 } 3666 3667 shader_addline(buffer, "!!ARBfp1.0\n"); 3668 if (want_nv_prog && gl_info->supported[NV_FRAGMENT_PROGRAM2]) 3669 { 3670 shader_addline(buffer, "OPTION NV_fragment_program2;\n"); 3671 priv_ctx.target_version = NV3; 3672 } 3673 else if (want_nv_prog && gl_info->supported[NV_FRAGMENT_PROGRAM_OPTION]) 3674 { 3675 shader_addline(buffer, "OPTION NV_fragment_program;\n"); 3676 priv_ctx.target_version = NV2; 3677 } else { 3678 if(want_nv_prog) 3679 { 3680 /* This is an error - either we're advertising the wrong shader version, or aren't enforcing some 3681 * limits properly 3682 */ 3683 ERR("The shader requires instructions that are not available in plain GL_ARB_fragment_program\n"); 3684 ERR("Try GLSL\n"); 3685 } 3686 priv_ctx.target_version = ARB; 3687 } 3688 3689 if (reg_maps->rt_mask > 1) 3690 { 3691 shader_addline(buffer, "OPTION ARB_draw_buffers;\n"); 3692 } 3693 3694 if (reg_maps->shader_version.major < 3) 3695 { 3696 switch (args->super.fog) 3697 { 3698 case WINED3D_FFP_PS_FOG_OFF: 3699 break; 3700 case WINED3D_FFP_PS_FOG_LINEAR: 3701 if (gl_info->quirks & WINED3D_QUIRK_BROKEN_ARB_FOG) 3702 { 3703 custom_linear_fog = TRUE; 3704 priv_ctx.ps_post_process = TRUE; 3705 break; 3706 } 3707 shader_addline(buffer, "OPTION ARB_fog_linear;\n"); 3708 break; 3709 case WINED3D_FFP_PS_FOG_EXP: 3710 shader_addline(buffer, "OPTION ARB_fog_exp;\n"); 3711 break; 3712 case WINED3D_FFP_PS_FOG_EXP2: 3713 shader_addline(buffer, "OPTION ARB_fog_exp2;\n"); 3714 break; 3715 } 3716 } 3717 3718 /* For now always declare the temps. At least the Nvidia assembler optimizes completely 3719 * unused temps away(but occupies them for the whole shader if they're used once). Always 3720 * declaring them avoids tricky bookkeeping work 3721 */ 3722 shader_addline(buffer, "TEMP TA;\n"); /* Used for modifiers */ 3723 shader_addline(buffer, "TEMP TB;\n"); /* Used for modifiers */ 3724 shader_addline(buffer, "TEMP TC;\n"); /* Used for modifiers */ 3725 if(dcl_td) shader_addline(buffer, "TEMP TD;\n"); /* Used for sRGB writing */ 3726 shader_addline(buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n"); 3727 shader_addline(buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n"); 3728 wined3d_ftoa(eps, ftoa_tmp); 3729 shader_addline(buffer, "PARAM ps_helper_const = { 0.0, 1.0, %s, 0.0 };\n", ftoa_tmp); 3730 3731 if (reg_maps->shader_version.major < 2) 3732 { 3733 strcpy(fragcolor, "R0"); 3734 } 3735 else 3736 { 3737 if (priv_ctx.ps_post_process) 3738 { 3739 if (shader->u.ps.color0_mov) 3740 { 3741 sprintf(fragcolor, "R%u", shader->u.ps.color0_reg); 3742 } 3743 else 3744 { 3745 shader_addline(buffer, "TEMP TMP_COLOR;\n"); 3746 strcpy(fragcolor, "TMP_COLOR"); 3747 } 3748 } else { 3749 strcpy(fragcolor, "result.color"); 3750 } 3751 } 3752 3753 if (args->super.srgb_correction) 3754 { 3755 shader_addline(buffer, "PARAM srgb_consts0 = "); 3756 shader_arb_append_imm_vec4(buffer, wined3d_srgb_const0); 3757 shader_addline(buffer, ";\n"); 3758 shader_addline(buffer, "PARAM srgb_consts1 = "); 3759 shader_arb_append_imm_vec4(buffer, wined3d_srgb_const1); 3760 shader_addline(buffer, ";\n"); 3761 } 3762 3763 /* Base Declarations */ 3764 shader_generate_arb_declarations(shader, reg_maps, buffer, gl_info, NULL, &priv_ctx); 3765 3766 for (i = 0, map = reg_maps->bumpmat; map; map >>= 1, ++i) 3767 { 3768 unsigned char bump_const; 3769 3770 if (!(map & 1)) continue; 3771 3772 bump_const = compiled->numbumpenvmatconsts; 3773 compiled->bumpenvmatconst[bump_const].const_num = WINED3D_CONST_NUM_UNUSED; 3774 compiled->bumpenvmatconst[bump_const].texunit = i; 3775 compiled->luminanceconst[bump_const].const_num = WINED3D_CONST_NUM_UNUSED; 3776 compiled->luminanceconst[bump_const].texunit = i; 3777 3778 /* We can fit the constants into the constant limit for sure because texbem, texbeml, bem and beml are only supported 3779 * in 1.x shaders, and GL_ARB_fragment_program has a constant limit of 24 constants. So in the worst case we're loading 3780 * 8 shader constants, 8 bump matrices and 8 luminance parameters and are perfectly fine. (No NP2 fixup on bumpmapped 3781 * textures due to conditional NP2 restrictions) 3782 * 3783 * Use local constants to load the bump env parameters, not program.env. This avoids collisions with d3d constants of 3784 * shaders in newer shader models. Since the bump env parameters have to share their space with NP2 fixup constants, 3785 * their location is shader dependent anyway and they cannot be loaded globally. 3786 */ 3787 compiled->bumpenvmatconst[bump_const].const_num = next_local++; 3788 shader_addline(buffer, "PARAM bumpenvmat%d = program.local[%d];\n", 3789 i, compiled->bumpenvmatconst[bump_const].const_num); 3790 compiled->numbumpenvmatconsts = bump_const + 1; 3791 3792 if (!(reg_maps->luminanceparams & (1 << i))) continue; 3793 3794 compiled->luminanceconst[bump_const].const_num = next_local++; 3795 shader_addline(buffer, "PARAM luminance%d = program.local[%d];\n", 3796 i, compiled->luminanceconst[bump_const].const_num); 3797 } 3798 3799 for(i = 0; i < MAX_CONST_I; i++) 3800 { 3801 compiled->int_consts[i] = WINED3D_CONST_NUM_UNUSED; 3802 if (reg_maps->integer_constants & (1 << i) && priv_ctx.target_version >= NV2) 3803 { 3804 const DWORD *control_values = find_loop_control_values(shader, i); 3805 3806 if(control_values) 3807 { 3808 shader_addline(buffer, "PARAM I%u = {%u, %u, %u, -1};\n", i, 3809 control_values[0], control_values[1], control_values[2]); 3810 } 3811 else 3812 { 3813 compiled->int_consts[i] = next_local; 3814 compiled->num_int_consts++; 3815 shader_addline(buffer, "PARAM I%u = program.local[%u];\n", i, next_local++); 3816 } 3817 } 3818 } 3819 3820 if(reg_maps->vpos || reg_maps->usesdsy) 3821 { 3822 compiled->ycorrection = next_local; 3823 shader_addline(buffer, "PARAM ycorrection = program.local[%u];\n", next_local++); 3824 3825 if(reg_maps->vpos) 3826 { 3827 shader_addline(buffer, "TEMP vpos;\n"); 3828 /* ycorrection.x: Backbuffer height(onscreen) or 0(offscreen). 3829 * ycorrection.y: -1.0(onscreen), 1.0(offscreen) 3830 * ycorrection.z: 1.0 3831 * ycorrection.w: 0.0 3832 */ 3833 shader_addline(buffer, "MAD vpos, fragment.position, ycorrection.zyww, ycorrection.wxww;\n"); 3834 shader_addline(buffer, "FLR vpos.xy, vpos;\n"); 3835 } 3836 } 3837 else 3838 { 3839 compiled->ycorrection = WINED3D_CONST_NUM_UNUSED; 3840 } 3841 3842 /* Load constants to fixup NP2 texcoords if there are still free constants left: 3843 * Constants (texture dimensions) for the NP2 fixup are loaded as local program parameters. This will consume 3844 * at most 8 (MAX_FRAGMENT_SAMPLERS / 2) parameters, which is highly unlikely, since the application had to 3845 * use 16 NP2 textures at the same time. In case that we run out of constants the fixup is simply not 3846 * applied / activated. This will probably result in wrong rendering of the texture, but will save us from 3847 * shader compilation errors and the subsequent errors when drawing with this shader. */ 3848 if (priv_ctx.cur_ps_args->super.np2_fixup) { 3849 unsigned char cur_fixup_sampler = 0; 3850 3851 struct arb_ps_np2fixup_info* const fixup = priv_ctx.cur_np2fixup_info; 3852 const WORD map = priv_ctx.cur_ps_args->super.np2_fixup; 3853 const UINT max_lconsts = gl_info->limits.arb_ps_local_constants; 3854 3855 fixup->offset = next_local; 3856 fixup->super.active = 0; 3857 3858 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) { 3859 if (!(map & (1 << i))) continue; 3860 3861 if (fixup->offset + (cur_fixup_sampler >> 1) < max_lconsts) { 3862 fixup->super.active |= (1 << i); 3863 fixup->super.idx[i] = cur_fixup_sampler++; 3864 } else { 3865 FIXME("No free constant found to load NP2 fixup data into shader. " 3866 "Sampling from this texture will probably look wrong.\n"); 3867 break; 3868 } 3869 } 3870 3871 fixup->super.num_consts = (cur_fixup_sampler + 1) >> 1; 3872 if (fixup->super.num_consts) { 3873 shader_addline(buffer, "PARAM np2fixup[%u] = { program.env[%u..%u] };\n", 3874 fixup->super.num_consts, fixup->offset, fixup->super.num_consts + fixup->offset - 1); 3875 } 3876 } 3877 3878 if (shader_priv->clipplane_emulation != ~0U && args->clip) 3879 { 3880 shader_addline(buffer, "KIL fragment.texcoord[%u];\n", shader_priv->clipplane_emulation); 3881 } 3882 3883 /* Base Shader Body */ 3884 shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx); 3885 3886 if(args->super.srgb_correction) { 3887 arbfp_add_sRGB_correction(buffer, fragcolor, srgbtmp[0], srgbtmp[1], srgbtmp[2], srgbtmp[3], 3888 priv_ctx.target_version >= NV2); 3889 } 3890 3891 if (custom_linear_fog) 3892 arbfp_add_linear_fog(buffer, fragcolor, "TA"); 3893 3894 if(strcmp(fragcolor, "result.color")) { 3895 shader_addline(buffer, "MOV result.color, %s;\n", fragcolor); 3896 } 3897 shader_addline(buffer, "END\n"); 3898 3899 /* TODO: change to resource.glObjectHandle or something like that */ 3900 GL_EXTCALL(glGenProgramsARB(1, &retval)); 3901 3902 TRACE("Creating a hw pixel shader, prg=%d\n", retval); 3903 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, retval)); 3904 3905 TRACE("Created hw pixel shader, prg=%d\n", retval); 3906 /* Create the program and check for errors */ 3907 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 3908 buffer->content_size, buffer->buffer)); 3909 checkGLcall("glProgramStringARB()"); 3910 3911 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); 3912 if (errPos != -1) 3913 { 3914 FIXME("HW PixelShader Error at position %d: %s\n\n", 3915 errPos, debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 3916 shader_arb_dump_program_source(buffer->buffer); 3917 retval = 0; 3918 } 3919 else 3920 { 3921 GLint native; 3922 3923 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 3924 checkGLcall("glGetProgramivARB()"); 3925 if (!native) WARN("Program exceeds native resource limits.\n"); 3926 } 3927 3928 return retval; 3929 } 3930 3931 static int compare_sig(const struct wined3d_shader_signature_element *sig1, const struct wined3d_shader_signature_element *sig2) 3932 { 3933 unsigned int i; 3934 int ret; 3935 3936 for(i = 0; i < MAX_REG_INPUT; i++) 3937 { 3938 if (!sig1[i].semantic_name || !sig2[i].semantic_name) 3939 { 3940 /* Compare pointers, not contents. One string is NULL(element does not exist), the other one is not NULL */ 3941 if(sig1[i].semantic_name != sig2[i].semantic_name) return sig1[i].semantic_name < sig2[i].semantic_name ? -1 : 1; 3942 continue; 3943 } 3944 3945 if ((ret = strcmp(sig1[i].semantic_name, sig2[i].semantic_name))) return ret; 3946 if(sig1[i].semantic_idx != sig2[i].semantic_idx) return sig1[i].semantic_idx < sig2[i].semantic_idx ? -1 : 1; 3947 if(sig1[i].sysval_semantic != sig2[i].sysval_semantic) return sig1[i].sysval_semantic < sig2[i].sysval_semantic ? -1 : 1; 3948 if(sig1[i].component_type != sig2[i].component_type) return sig1[i].component_type < sig2[i].component_type ? -1 : 1; 3949 if(sig1[i].register_idx != sig2[i].register_idx) return sig1[i].register_idx < sig2[i].register_idx ? -1 : 1; 3950 if(sig1[i].mask != sig2[i].mask) return sig1[i].mask < sig2[i].mask ? -1 : 1; 3951 } 3952 return 0; 3953 } 3954 3955 static struct wined3d_shader_signature_element *clone_sig(const struct wined3d_shader_signature_element *sig) 3956 { 3957 struct wined3d_shader_signature_element *new; 3958 int i; 3959 char *name; 3960 3961 new = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*new) * MAX_REG_INPUT); 3962 for(i = 0; i < MAX_REG_INPUT; i++) 3963 { 3964 if (!sig[i].semantic_name) continue; 3965 3966 new[i] = sig[i]; 3967 /* Clone the semantic string */ 3968 name = HeapAlloc(GetProcessHeap(), 0, strlen(sig[i].semantic_name) + 1); 3969 strcpy(name, sig[i].semantic_name); 3970 new[i].semantic_name = name; 3971 } 3972 return new; 3973 } 3974 3975 static DWORD find_input_signature(struct shader_arb_priv *priv, const struct wined3d_shader_signature_element *sig) 3976 { 3977 struct wine_rb_entry *entry = wine_rb_get(&priv->signature_tree, sig); 3978 struct ps_signature *found_sig; 3979 3980 if (entry) 3981 { 3982 found_sig = WINE_RB_ENTRY_VALUE(entry, struct ps_signature, entry); 3983 TRACE("Found existing signature %u\n", found_sig->idx); 3984 return found_sig->idx; 3985 } 3986 found_sig = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*found_sig)); 3987 found_sig->sig = clone_sig(sig); 3988 found_sig->idx = priv->ps_sig_number++; 3989 TRACE("New signature stored and assigned number %u\n", found_sig->idx); 3990 if(wine_rb_put(&priv->signature_tree, sig, &found_sig->entry) == -1) 3991 { 3992 ERR("Failed to insert program entry.\n"); 3993 } 3994 return found_sig->idx; 3995 } 3996 3997 static void init_output_registers(const struct wined3d_shader *shader, 3998 const struct wined3d_shader_signature_element *ps_input_sig, 3999 struct shader_arb_ctx_priv *priv_ctx, struct arb_vs_compiled_shader *compiled) 4000 { 4001 unsigned int i, j; 4002 static const char * const texcoords[8] = 4003 { 4004 "result.texcoord[0]", "result.texcoord[1]", "result.texcoord[2]", "result.texcoord[3]", 4005 "result.texcoord[4]", "result.texcoord[5]", "result.texcoord[6]", "result.texcoord[7]" 4006 }; 4007 const char *semantic_name; 4008 DWORD semantic_idx, reg_idx; 4009 4010 /* Write generic input varyings 0 to 7 to result.texcoord[], varying 8 to result.color.primary 4011 * and varying 9 to result.color.secondary 4012 */ 4013 static const char * const decl_idx_to_string[MAX_REG_INPUT] = 4014 { 4015 "result.texcoord[0]", "result.texcoord[1]", "result.texcoord[2]", "result.texcoord[3]", 4016 "result.texcoord[4]", "result.texcoord[5]", "result.texcoord[6]", "result.texcoord[7]", 4017 "result.color.primary", "result.color.secondary" 4018 }; 4019 4020 if (!ps_input_sig) 4021 { 4022 TRACE("Pixel shader uses builtin varyings\n"); 4023 /* Map builtins to builtins */ 4024 for(i = 0; i < 8; i++) 4025 { 4026 priv_ctx->texcrd_output[i] = texcoords[i]; 4027 } 4028 priv_ctx->color_output[0] = "result.color.primary"; 4029 priv_ctx->color_output[1] = "result.color.secondary"; 4030 priv_ctx->fog_output = "TMP_FOGCOORD"; 4031 4032 /* Map declared regs to builtins. Use "TA" to /dev/null unread output */ 4033 for (i = 0; i < (sizeof(shader->output_signature) / sizeof(*shader->output_signature)); ++i) 4034 { 4035 semantic_name = shader->output_signature[i].semantic_name; 4036 if (!semantic_name) continue; 4037 4038 if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_POSITION)) 4039 { 4040 TRACE("o%u is TMP_OUT\n", i); 4041 if (!shader->output_signature[i].semantic_idx) priv_ctx->vs_output[i] = "TMP_OUT"; 4042 else priv_ctx->vs_output[i] = "TA"; 4043 } 4044 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_PSIZE)) 4045 { 4046 TRACE("o%u is result.pointsize\n", i); 4047 if (!shader->output_signature[i].semantic_idx) priv_ctx->vs_output[i] = "result.pointsize"; 4048 else priv_ctx->vs_output[i] = "TA"; 4049 } 4050 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_COLOR)) 4051 { 4052 TRACE("o%u is result.color.?, idx %u\n", i, shader->output_signature[i].semantic_idx); 4053 if (!shader->output_signature[i].semantic_idx) 4054 priv_ctx->vs_output[i] = "result.color.primary"; 4055 else if (shader->output_signature[i].semantic_idx == 1) 4056 priv_ctx->vs_output[i] = "result.color.secondary"; 4057 else priv_ctx->vs_output[i] = "TA"; 4058 } 4059 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD)) 4060 { 4061 TRACE("o%u is %s\n", i, texcoords[shader->output_signature[i].semantic_idx]); 4062 if (shader->output_signature[i].semantic_idx >= 8) priv_ctx->vs_output[i] = "TA"; 4063 else priv_ctx->vs_output[i] = texcoords[shader->output_signature[i].semantic_idx]; 4064 } 4065 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_FOG)) 4066 { 4067 TRACE("o%u is result.fogcoord\n", i); 4068 if (shader->output_signature[i].semantic_idx > 0) priv_ctx->vs_output[i] = "TA"; 4069 else priv_ctx->vs_output[i] = "result.fogcoord"; 4070 } 4071 else 4072 { 4073 priv_ctx->vs_output[i] = "TA"; 4074 } 4075 } 4076 return; 4077 } 4078 4079 TRACE("Pixel shader uses declared varyings\n"); 4080 4081 /* Map builtin to declared. /dev/null the results by default to the TA temp reg */ 4082 for(i = 0; i < 8; i++) 4083 { 4084 priv_ctx->texcrd_output[i] = "TA"; 4085 } 4086 priv_ctx->color_output[0] = "TA"; 4087 priv_ctx->color_output[1] = "TA"; 4088 priv_ctx->fog_output = "TA"; 4089 4090 for(i = 0; i < MAX_REG_INPUT; i++) 4091 { 4092 semantic_name = ps_input_sig[i].semantic_name; 4093 semantic_idx = ps_input_sig[i].semantic_idx; 4094 reg_idx = ps_input_sig[i].register_idx; 4095 if (!semantic_name) continue; 4096 4097 /* If a declared input register is not written by builtin arguments, don't write to it. 4098 * GL_NV_vertex_program makes sure the input defaults to 0.0, which is correct with D3D 4099 * 4100 * Don't care about POSITION and PSIZE here - this is a builtin vertex shader, position goes 4101 * to TMP_OUT in any case 4102 */ 4103 if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD)) 4104 { 4105 if (semantic_idx < 8) 4106 priv_ctx->texcrd_output[semantic_idx] = decl_idx_to_string[reg_idx]; 4107 } 4108 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_COLOR)) 4109 { 4110 if (semantic_idx < 2) 4111 priv_ctx->color_output[semantic_idx] = decl_idx_to_string[reg_idx]; 4112 } 4113 else if(shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_FOG)) 4114 { 4115 if (!semantic_idx) 4116 priv_ctx->fog_output = decl_idx_to_string[reg_idx]; 4117 } 4118 else 4119 { 4120 continue; 4121 } 4122 4123 if (!strcmp(decl_idx_to_string[reg_idx], "result.color.primary") 4124 || !strcmp(decl_idx_to_string[reg_idx], "result.color.secondary")) 4125 { 4126 compiled->need_color_unclamp = TRUE; 4127 } 4128 } 4129 4130 /* Map declared to declared */ 4131 for (i = 0; i < (sizeof(shader->output_signature) / sizeof(*shader->output_signature)); ++i) 4132 { 4133 /* Write unread output to TA to throw them away */ 4134 priv_ctx->vs_output[i] = "TA"; 4135 semantic_name = shader->output_signature[i].semantic_name; 4136 if (!semantic_name) continue; 4137 4138 if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_POSITION) 4139 && !shader->output_signature[i].semantic_idx) 4140 { 4141 priv_ctx->vs_output[i] = "TMP_OUT"; 4142 continue; 4143 } 4144 else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_PSIZE) 4145 && !shader->output_signature[i].semantic_idx) 4146 { 4147 priv_ctx->vs_output[i] = "result.pointsize"; 4148 continue; 4149 } 4150 4151 for(j = 0; j < MAX_REG_INPUT; j++) 4152 { 4153 if (!ps_input_sig[j].semantic_name) continue; 4154 4155 if (!strcmp(ps_input_sig[j].semantic_name, semantic_name) 4156 && ps_input_sig[j].semantic_idx == shader->output_signature[i].semantic_idx) 4157 { 4158 priv_ctx->vs_output[i] = decl_idx_to_string[ps_input_sig[j].register_idx]; 4159 4160 if (!strcmp(priv_ctx->vs_output[i], "result.color.primary") 4161 || !strcmp(priv_ctx->vs_output[i], "result.color.secondary")) 4162 { 4163 compiled->need_color_unclamp = TRUE; 4164 } 4165 } 4166 } 4167 } 4168 } 4169 4170 /* Context activation is done by the caller. */ 4171 static GLuint shader_arb_generate_vshader(const struct wined3d_shader *shader, 4172 const struct wined3d_gl_info *gl_info, struct wined3d_shader_buffer *buffer, 4173 const struct arb_vs_compile_args *args, struct arb_vs_compiled_shader *compiled, 4174 const struct wined3d_shader_signature_element *ps_input_sig) 4175 { 4176 const struct arb_vshader_private *shader_data = shader->backend_data; 4177 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; 4178 struct shader_arb_priv *priv = shader->device->shader_priv; 4179 const DWORD *function = shader->function; 4180 GLuint ret; 4181 DWORD next_local = 0; 4182 struct shader_arb_ctx_priv priv_ctx; 4183 unsigned int i; 4184 GLint errPos; 4185 4186 memset(&priv_ctx, 0, sizeof(priv_ctx)); 4187 priv_ctx.cur_vs_args = args; 4188 list_init(&priv_ctx.control_frames); 4189 init_output_registers(shader, ps_input_sig, &priv_ctx, compiled); 4190 4191 /* Create the hw ARB shader */ 4192 shader_addline(buffer, "!!ARBvp1.0\n"); 4193 4194 /* Always enable the NV extension if available. Unlike fragment shaders, there is no 4195 * mesurable performance penalty, and we can always make use of it for clipplanes. 4196 */ 4197 if (gl_info->supported[NV_VERTEX_PROGRAM3]) 4198 { 4199 shader_addline(buffer, "OPTION NV_vertex_program3;\n"); 4200 priv_ctx.target_version = NV3; 4201 shader_addline(buffer, "ADDRESS aL;\n"); 4202 } 4203 else if (gl_info->supported[NV_VERTEX_PROGRAM2_OPTION]) 4204 { 4205 shader_addline(buffer, "OPTION NV_vertex_program2;\n"); 4206 priv_ctx.target_version = NV2; 4207 shader_addline(buffer, "ADDRESS aL;\n"); 4208 } else { 4209 priv_ctx.target_version = ARB; 4210 } 4211 4212 shader_addline(buffer, "TEMP TMP_OUT;\n"); 4213 if (reg_maps->fog) 4214 shader_addline(buffer, "TEMP TMP_FOGCOORD;\n"); 4215 if (need_helper_const(shader_data, reg_maps, gl_info)) 4216 { 4217 char ftoa_tmp[17]; 4218 wined3d_ftoa(eps, ftoa_tmp); 4219 shader_addline(buffer, "PARAM helper_const = { 0.0, 1.0, 2.0, %s};\n", ftoa_tmp); 4220 } 4221 if (need_rel_addr_const(shader_data, reg_maps, gl_info)) 4222 { 4223 shader_addline(buffer, "PARAM rel_addr_const = { 0.5, %d.0, 0.0, 0.0 };\n", shader_data->rel_offset); 4224 shader_addline(buffer, "TEMP A0_SHADOW;\n"); 4225 } 4226 4227 shader_addline(buffer, "TEMP TA;\n"); 4228 shader_addline(buffer, "TEMP TB;\n"); 4229 4230 /* Base Declarations */ 4231 shader_generate_arb_declarations(shader, reg_maps, buffer, gl_info, 4232 &priv_ctx.vs_clipplanes, &priv_ctx); 4233 4234 for(i = 0; i < MAX_CONST_I; i++) 4235 { 4236 compiled->int_consts[i] = WINED3D_CONST_NUM_UNUSED; 4237 if(reg_maps->integer_constants & (1 << i) && priv_ctx.target_version >= NV2) 4238 { 4239 const DWORD *control_values = find_loop_control_values(shader, i); 4240 4241 if(control_values) 4242 { 4243 shader_addline(buffer, "PARAM I%u = {%u, %u, %u, -1};\n", i, 4244 control_values[0], control_values[1], control_values[2]); 4245 } 4246 else 4247 { 4248 compiled->int_consts[i] = next_local; 4249 compiled->num_int_consts++; 4250 shader_addline(buffer, "PARAM I%u = program.local[%u];\n", i, next_local++); 4251 } 4252 } 4253 } 4254 4255 /* We need a constant to fixup the final position */ 4256 shader_addline(buffer, "PARAM posFixup = program.local[%u];\n", next_local); 4257 compiled->pos_fixup = next_local++; 4258 4259 /* Initialize output parameters. GL_ARB_vertex_program does not require special initialization values 4260 * for output parameters. D3D in theory does not do that either, but some applications depend on a 4261 * proper initialization of the secondary color, and programs using the fixed function pipeline without 4262 * a replacement shader depend on the texcoord.w being set properly. 4263 * 4264 * GL_NV_vertex_program defines that all output values are initialized to {0.0, 0.0, 0.0, 1.0}. This 4265 * assertion is in effect even when using GL_ARB_vertex_program without any NV specific additions. So 4266 * skip this if NV_vertex_program is supported. Otherwise, initialize the secondary color. For the tex- 4267 * coords, we have a flag in the opengl caps. Many cards do not require the texcoord being set, and 4268 * this can eat a number of instructions, so skip it unless this cap is set as well 4269 */ 4270 if (!gl_info->supported[NV_VERTEX_PROGRAM]) 4271 { 4272 const char *color_init = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_0001); 4273 shader_addline(buffer, "MOV result.color.secondary, %s;\n", color_init); 4274 4275 if (gl_info->quirks & WINED3D_QUIRK_SET_TEXCOORD_W && !priv->ffp_proj_control) 4276 { 4277 int i; 4278 const char *one = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_ONE); 4279 for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) 4280 { 4281 if (reg_maps->texcoord_mask[i] && reg_maps->texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) 4282 shader_addline(buffer, "MOV result.texcoord[%u].w, %s\n", i, one); 4283 } 4284 } 4285 } 4286 4287 /* The shader starts with the main function */ 4288 priv_ctx.in_main_func = TRUE; 4289 /* Base Shader Body */ 4290 shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx); 4291 4292 if (!priv_ctx.footer_written) vshader_add_footer(&priv_ctx, 4293 shader_data, args, reg_maps, gl_info, buffer); 4294 4295 shader_addline(buffer, "END\n"); 4296 4297 /* TODO: change to resource.glObjectHandle or something like that */ 4298 GL_EXTCALL(glGenProgramsARB(1, &ret)); 4299 4300 TRACE("Creating a hw vertex shader, prg=%d\n", ret); 4301 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ret)); 4302 4303 TRACE("Created hw vertex shader, prg=%d\n", ret); 4304 /* Create the program and check for errors */ 4305 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 4306 buffer->content_size, buffer->buffer)); 4307 checkGLcall("glProgramStringARB()"); 4308 4309 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); 4310 if (errPos != -1) 4311 { 4312 FIXME("HW VertexShader Error at position %d: %s\n\n", 4313 errPos, debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 4314 shader_arb_dump_program_source(buffer->buffer); 4315 ret = -1; 4316 } 4317 else 4318 { 4319 GLint native; 4320 4321 GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 4322 checkGLcall("glGetProgramivARB()"); 4323 if (!native) WARN("Program exceeds native resource limits.\n"); 4324 } 4325 4326 return ret; 4327 } 4328 4329 /* Context activation is done by the caller. */ 4330 static struct arb_ps_compiled_shader *find_arb_pshader(struct wined3d_shader *shader, 4331 const struct arb_ps_compile_args *args) 4332 { 4333 struct wined3d_device *device = shader->device; 4334 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 4335 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; 4336 UINT i; 4337 DWORD new_size; 4338 struct arb_ps_compiled_shader *new_array; 4339 struct wined3d_shader_buffer buffer; 4340 struct arb_pshader_private *shader_data; 4341 GLuint ret; 4342 4343 if (!shader->backend_data) 4344 { 4345 struct shader_arb_priv *priv = device->shader_priv; 4346 4347 shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data)); 4348 shader_data = shader->backend_data; 4349 shader_data->clamp_consts = shader->reg_maps.shader_version.major == 1; 4350 4351 if (shader->reg_maps.shader_version.major < 3) 4352 shader_data->input_signature_idx = ~0U; 4353 else 4354 shader_data->input_signature_idx = find_input_signature(priv, shader->input_signature); 4355 4356 TRACE("Shader got assigned input signature index %u\n", shader_data->input_signature_idx); 4357 4358 if (!d3d_info->vs_clipping) 4359 shader_data->clipplane_emulation = shader_find_free_input_register(&shader->reg_maps, 4360 d3d_info->limits.ffp_blend_stages - 1); 4361 else 4362 shader_data->clipplane_emulation = ~0U; 4363 } 4364 shader_data = shader->backend_data; 4365 4366 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2), 4367 * so a linear search is more performant than a hashmap or a binary search 4368 * (cache coherency etc) 4369 */ 4370 for (i = 0; i < shader_data->num_gl_shaders; ++i) 4371 { 4372 if (!memcmp(&shader_data->gl_shaders[i].args, args, sizeof(*args))) 4373 return &shader_data->gl_shaders[i]; 4374 } 4375 4376 TRACE("No matching GL shader found, compiling a new shader\n"); 4377 if(shader_data->shader_array_size == shader_data->num_gl_shaders) { 4378 if (shader_data->num_gl_shaders) 4379 { 4380 new_size = shader_data->shader_array_size + max(1, shader_data->shader_array_size / 2); 4381 new_array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, shader_data->gl_shaders, 4382 new_size * sizeof(*shader_data->gl_shaders)); 4383 } else { 4384 new_array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data->gl_shaders)); 4385 new_size = 1; 4386 } 4387 4388 if(!new_array) { 4389 ERR("Out of memory\n"); 4390 return 0; 4391 } 4392 shader_data->gl_shaders = new_array; 4393 shader_data->shader_array_size = new_size; 4394 } 4395 4396 shader_data->gl_shaders[shader_data->num_gl_shaders].args = *args; 4397 4398 pixelshader_update_samplers(shader, args->super.tex_types); 4399 4400 if (!shader_buffer_init(&buffer)) 4401 { 4402 ERR("Failed to initialize shader buffer.\n"); 4403 return 0; 4404 } 4405 4406 ret = shader_arb_generate_pshader(shader, gl_info, &buffer, args, 4407 &shader_data->gl_shaders[shader_data->num_gl_shaders]); 4408 shader_buffer_free(&buffer); 4409 shader_data->gl_shaders[shader_data->num_gl_shaders].prgId = ret; 4410 4411 return &shader_data->gl_shaders[shader_data->num_gl_shaders++]; 4412 } 4413 4414 static inline BOOL vs_args_equal(const struct arb_vs_compile_args *stored, const struct arb_vs_compile_args *new, 4415 const DWORD use_map, BOOL skip_int) { 4416 if((stored->super.swizzle_map & use_map) != new->super.swizzle_map) return FALSE; 4417 if(stored->super.clip_enabled != new->super.clip_enabled) return FALSE; 4418 if(stored->super.fog_src != new->super.fog_src) return FALSE; 4419 if(stored->clip.boolclip_compare != new->clip.boolclip_compare) return FALSE; 4420 if(stored->ps_signature != new->ps_signature) return FALSE; 4421 if(stored->vertex.samplers_compare != new->vertex.samplers_compare) return FALSE; 4422 if(skip_int) return TRUE; 4423 4424 return !memcmp(stored->loop_ctrl, new->loop_ctrl, sizeof(stored->loop_ctrl)); 4425 } 4426 4427 static struct arb_vs_compiled_shader *find_arb_vshader(struct wined3d_shader *shader, 4428 const struct wined3d_gl_info *gl_info, DWORD use_map, const struct arb_vs_compile_args *args, 4429 const struct wined3d_shader_signature_element *ps_input_sig) 4430 { 4431 UINT i; 4432 DWORD new_size; 4433 struct arb_vs_compiled_shader *new_array; 4434 struct wined3d_shader_buffer buffer; 4435 struct arb_vshader_private *shader_data; 4436 GLuint ret; 4437 4438 if (!shader->backend_data) 4439 { 4440 const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; 4441 4442 shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data)); 4443 shader_data = shader->backend_data; 4444 4445 if ((gl_info->quirks & WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT) 4446 && reg_maps->min_rel_offset <= reg_maps->max_rel_offset) 4447 { 4448 if (reg_maps->max_rel_offset - reg_maps->min_rel_offset > 127) 4449 { 4450 FIXME("The difference between the minimum and maximum relative offset is > 127.\n"); 4451 FIXME("Which this OpenGL implementation does not support. Try using GLSL.\n"); 4452 FIXME("Min: %u, Max: %u.\n", reg_maps->min_rel_offset, reg_maps->max_rel_offset); 4453 } 4454 else if (reg_maps->max_rel_offset - reg_maps->min_rel_offset > 63) 4455 shader_data->rel_offset = reg_maps->min_rel_offset + 63; 4456 else if (reg_maps->max_rel_offset > 63) 4457 shader_data->rel_offset = reg_maps->min_rel_offset; 4458 } 4459 } 4460 shader_data = shader->backend_data; 4461 4462 /* Usually we have very few GL shaders for each d3d shader(just 1 or maybe 2), 4463 * so a linear search is more performant than a hashmap or a binary search 4464 * (cache coherency etc) 4465 */ 4466 for(i = 0; i < shader_data->num_gl_shaders; i++) { 4467 if (vs_args_equal(&shader_data->gl_shaders[i].args, args, 4468 use_map, gl_info->supported[NV_VERTEX_PROGRAM2_OPTION])) 4469 { 4470 return &shader_data->gl_shaders[i]; 4471 } 4472 } 4473 4474 TRACE("No matching GL shader found, compiling a new shader\n"); 4475 4476 if(shader_data->shader_array_size == shader_data->num_gl_shaders) { 4477 if (shader_data->num_gl_shaders) 4478 { 4479 new_size = shader_data->shader_array_size + max(1, shader_data->shader_array_size / 2); 4480 new_array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, shader_data->gl_shaders, 4481 new_size * sizeof(*shader_data->gl_shaders)); 4482 } else { 4483 new_array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data->gl_shaders)); 4484 new_size = 1; 4485 } 4486 4487 if(!new_array) { 4488 ERR("Out of memory\n"); 4489 return 0; 4490 } 4491 shader_data->gl_shaders = new_array; 4492 shader_data->shader_array_size = new_size; 4493 } 4494 4495 shader_data->gl_shaders[shader_data->num_gl_shaders].args = *args; 4496 4497 if (!shader_buffer_init(&buffer)) 4498 { 4499 ERR("Failed to initialize shader buffer.\n"); 4500 return 0; 4501 } 4502 4503 ret = shader_arb_generate_vshader(shader, gl_info, &buffer, args, 4504 &shader_data->gl_shaders[shader_data->num_gl_shaders], 4505 ps_input_sig); 4506 shader_buffer_free(&buffer); 4507 shader_data->gl_shaders[shader_data->num_gl_shaders].prgId = ret; 4508 4509 return &shader_data->gl_shaders[shader_data->num_gl_shaders++]; 4510 } 4511 4512 static void find_arb_ps_compile_args(const struct wined3d_state *state, 4513 const struct wined3d_context *context, const struct wined3d_shader *shader, 4514 struct arb_ps_compile_args *args) 4515 { 4516 const struct wined3d_gl_info *gl_info = context->gl_info; 4517 const struct wined3d_d3d_info *d3d_info = context->d3d_info; 4518 int i; 4519 WORD int_skip; 4520 4521 find_ps_compile_args(state, shader, context->stream_info.position_transformed, &args->super, gl_info); 4522 4523 /* This forces all local boolean constants to 1 to make them stateblock independent */ 4524 args->bools = shader->reg_maps.local_bool_consts; 4525 4526 for(i = 0; i < MAX_CONST_B; i++) 4527 { 4528 if (state->ps_consts_b[i]) 4529 args->bools |= ( 1 << i); 4530 } 4531 4532 /* Only enable the clip plane emulation KIL if at least one clipplane is enabled. The KIL instruction 4533 * is quite expensive because it forces the driver to disable early Z discards. It is cheaper to 4534 * duplicate the shader than have a no-op KIL instruction in every shader 4535 */ 4536 if (!d3d_info->vs_clipping && use_vs(state) 4537 && state->render_states[WINED3D_RS_CLIPPING] 4538 && state->render_states[WINED3D_RS_CLIPPLANEENABLE]) 4539 args->clip = 1; 4540 else 4541 args->clip = 0; 4542 4543 /* Skip if unused or local, or supported natively */ 4544 int_skip = ~shader->reg_maps.integer_constants | shader->reg_maps.local_int_consts; 4545 if (int_skip == 0xffff || gl_info->supported[NV_FRAGMENT_PROGRAM_OPTION]) 4546 { 4547 memset(args->loop_ctrl, 0, sizeof(args->loop_ctrl)); 4548 return; 4549 } 4550 4551 for(i = 0; i < MAX_CONST_I; i++) 4552 { 4553 if(int_skip & (1 << i)) 4554 { 4555 args->loop_ctrl[i][0] = 0; 4556 args->loop_ctrl[i][1] = 0; 4557 args->loop_ctrl[i][2] = 0; 4558 } 4559 else 4560 { 4561 args->loop_ctrl[i][0] = state->ps_consts_i[i * 4]; 4562 args->loop_ctrl[i][1] = state->ps_consts_i[i * 4 + 1]; 4563 args->loop_ctrl[i][2] = state->ps_consts_i[i * 4 + 2]; 4564 } 4565 } 4566 } 4567 4568 static void find_arb_vs_compile_args(const struct wined3d_state *state, 4569 const struct wined3d_context *context, const struct wined3d_shader *shader, 4570 struct arb_vs_compile_args *args) 4571 { 4572 const struct wined3d_device *device = shader->device; 4573 const struct wined3d_adapter *adapter = device->adapter; 4574 const struct wined3d_gl_info *gl_info = context->gl_info; 4575 const struct wined3d_d3d_info *d3d_info = context->d3d_info; 4576 int i; 4577 WORD int_skip; 4578 4579 find_vs_compile_args(state, shader, context->stream_info.swizzle_map, &args->super); 4580 4581 args->clip.boolclip_compare = 0; 4582 if (use_ps(state)) 4583 { 4584 const struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL]; 4585 const struct arb_pshader_private *shader_priv = ps->backend_data; 4586 args->ps_signature = shader_priv->input_signature_idx; 4587 4588 args->clip.boolclip.clip_texcoord = shader_priv->clipplane_emulation + 1; 4589 } 4590 else 4591 { 4592 args->ps_signature = ~0; 4593 if (!d3d_info->vs_clipping && adapter->fragment_pipe == &arbfp_fragment_pipeline) 4594 args->clip.boolclip.clip_texcoord = ffp_clip_emul(context) ? d3d_info->limits.ffp_blend_stages : 0; 4595 /* Otherwise: Setting boolclip_compare set clip_texcoord to 0 */ 4596 } 4597 4598 if (args->clip.boolclip.clip_texcoord) 4599 { 4600 if (state->render_states[WINED3D_RS_CLIPPING]) 4601 args->clip.boolclip.clipplane_mask = (unsigned char)state->render_states[WINED3D_RS_CLIPPLANEENABLE]; 4602 /* clipplane_mask was set to 0 by setting boolclip_compare to 0 */ 4603 } 4604 4605 /* This forces all local boolean constants to 1 to make them stateblock independent */ 4606 args->clip.boolclip.bools = shader->reg_maps.local_bool_consts; 4607 /* TODO: Figure out if it would be better to store bool constants as bitmasks in the stateblock */ 4608 for(i = 0; i < MAX_CONST_B; i++) 4609 { 4610 if (state->vs_consts_b[i]) 4611 args->clip.boolclip.bools |= ( 1 << i); 4612 } 4613 4614 args->vertex.samplers[0] = context->tex_unit_map[MAX_FRAGMENT_SAMPLERS + 0]; 4615 args->vertex.samplers[1] = context->tex_unit_map[MAX_FRAGMENT_SAMPLERS + 1]; 4616 args->vertex.samplers[2] = context->tex_unit_map[MAX_FRAGMENT_SAMPLERS + 2]; 4617 args->vertex.samplers[3] = 0; 4618 4619 /* Skip if unused or local */ 4620 int_skip = ~shader->reg_maps.integer_constants | shader->reg_maps.local_int_consts; 4621 /* This is about flow control, not clipping. */ 4622 if (int_skip == 0xffff || gl_info->supported[NV_VERTEX_PROGRAM2_OPTION]) 4623 { 4624 memset(args->loop_ctrl, 0, sizeof(args->loop_ctrl)); 4625 return; 4626 } 4627 4628 for(i = 0; i < MAX_CONST_I; i++) 4629 { 4630 if(int_skip & (1 << i)) 4631 { 4632 args->loop_ctrl[i][0] = 0; 4633 args->loop_ctrl[i][1] = 0; 4634 args->loop_ctrl[i][2] = 0; 4635 } 4636 else 4637 { 4638 args->loop_ctrl[i][0] = state->vs_consts_i[i * 4]; 4639 args->loop_ctrl[i][1] = state->vs_consts_i[i * 4 + 1]; 4640 args->loop_ctrl[i][2] = state->vs_consts_i[i * 4 + 2]; 4641 } 4642 } 4643 } 4644 4645 /* Context activation is done by the caller. */ 4646 static void shader_arb_select(void *shader_priv, struct wined3d_context *context, 4647 const struct wined3d_state *state) 4648 { 4649 struct shader_arb_priv *priv = shader_priv; 4650 const struct wined3d_gl_info *gl_info = context->gl_info; 4651 int i; 4652 4653 /* Deal with pixel shaders first so the vertex shader arg function has the input signature ready */ 4654 if (use_ps(state)) 4655 { 4656 struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL]; 4657 struct arb_ps_compile_args compile_args; 4658 struct arb_ps_compiled_shader *compiled; 4659 4660 TRACE("Using pixel shader %p.\n", ps); 4661 find_arb_ps_compile_args(state, context, ps, &compile_args); 4662 compiled = find_arb_pshader(ps, &compile_args); 4663 priv->current_fprogram_id = compiled->prgId; 4664 priv->compiled_fprog = compiled; 4665 4666 /* Bind the fragment program */ 4667 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id)); 4668 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id);"); 4669 4670 if (!priv->use_arbfp_fixed_func) 4671 priv->fragment_pipe->enable_extension(gl_info, FALSE); 4672 4673 /* Enable OpenGL fragment programs. */ 4674 gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); 4675 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);"); 4676 4677 TRACE("Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", priv->current_fprogram_id); 4678 4679 /* Pixel Shader 1.x constants are clamped to [-1;1], Pixel Shader 2.0 constants are not. If switching between 4680 * a 1.x and newer shader, reload the first 8 constants 4681 */ 4682 if (priv->last_ps_const_clamped != ((struct arb_pshader_private *)ps->backend_data)->clamp_consts) 4683 { 4684 priv->last_ps_const_clamped = ((struct arb_pshader_private *)ps->backend_data)->clamp_consts; 4685 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, 8); 4686 for(i = 0; i < 8; i++) 4687 { 4688 priv->pshader_const_dirty[i] = 1; 4689 } 4690 /* Also takes care of loading local constants */ 4691 shader_arb_load_constants_internal(shader_priv, context, state, TRUE, FALSE, TRUE); 4692 } 4693 else 4694 { 4695 UINT rt_height = state->fb->render_targets[0]->resource.height; 4696 shader_arb_ps_local_constants(compiled, context, state, rt_height); 4697 } 4698 4699 /* Force constant reloading for the NP2 fixup (see comment in shader_glsl_select for more info) */ 4700 if (compiled->np2fixup_info.super.active) 4701 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_NP2_FIXUP; 4702 4703 if (ps->load_local_constsF) 4704 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_F; 4705 } 4706 else 4707 { 4708 if (gl_info->supported[ARB_FRAGMENT_PROGRAM] && !priv->use_arbfp_fixed_func) 4709 { 4710 /* Disable only if we're not using arbfp fixed function fragment 4711 * processing. If this is used, keep GL_FRAGMENT_PROGRAM_ARB 4712 * enabled, and the fixed function pipeline will bind the fixed 4713 * function replacement shader. */ 4714 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); 4715 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); 4716 priv->current_fprogram_id = 0; 4717 } 4718 priv->fragment_pipe->enable_extension(gl_info, TRUE); 4719 } 4720 4721 if (use_vs(state)) 4722 { 4723 struct wined3d_shader *vs = state->shader[WINED3D_SHADER_TYPE_VERTEX]; 4724 struct arb_vs_compile_args compile_args; 4725 struct arb_vs_compiled_shader *compiled; 4726 const struct wined3d_shader_signature_element *ps_input_sig; 4727 4728 TRACE("Using vertex shader %p\n", vs); 4729 find_arb_vs_compile_args(state, context, vs, &compile_args); 4730 4731 /* Instead of searching for the signature in the signature list, read the one from the 4732 * current pixel shader. It's maybe not the shader where the signature came from, but it 4733 * is the same signature and faster to find. */ 4734 if (compile_args.ps_signature == ~0U) 4735 ps_input_sig = NULL; 4736 else 4737 ps_input_sig = state->shader[WINED3D_SHADER_TYPE_PIXEL]->input_signature; 4738 4739 compiled = find_arb_vshader(vs, context->gl_info, context->stream_info.use_map, 4740 &compile_args, ps_input_sig); 4741 priv->current_vprogram_id = compiled->prgId; 4742 priv->compiled_vprog = compiled; 4743 4744 /* Bind the vertex program */ 4745 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id)); 4746 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id);"); 4747 4748 priv->vertex_pipe->vp_enable(gl_info, FALSE); 4749 4750 /* Enable OpenGL vertex programs */ 4751 gl_info->gl_ops.gl.p_glEnable(GL_VERTEX_PROGRAM_ARB); 4752 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);"); 4753 TRACE("Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", priv->current_vprogram_id); 4754 shader_arb_vs_local_constants(compiled, context, state); 4755 4756 if(priv->last_vs_color_unclamp != compiled->need_color_unclamp) { 4757 priv->last_vs_color_unclamp = compiled->need_color_unclamp; 4758 4759 if (gl_info->supported[ARB_COLOR_BUFFER_FLOAT]) 4760 { 4761 GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, !compiled->need_color_unclamp)); 4762 checkGLcall("glClampColorARB"); 4763 } else { 4764 FIXME("vertex color clamp needs to be changed, but extension not supported.\n"); 4765 } 4766 } 4767 4768 if (vs->load_local_constsF) 4769 context->constant_update_mask |= WINED3D_SHADER_CONST_VS_F; 4770 } 4771 else 4772 { 4773 if (gl_info->supported[ARB_VERTEX_PROGRAM]) 4774 { 4775 priv->current_vprogram_id = 0; 4776 gl_info->gl_ops.gl.p_glDisable(GL_VERTEX_PROGRAM_ARB); 4777 checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)"); 4778 } 4779 priv->vertex_pipe->vp_enable(gl_info, TRUE); 4780 } 4781 } 4782 4783 4784 /* Context activation is done by the caller. */ 4785 static void shader_arb_disable(void *shader_priv, struct wined3d_context *context) 4786 { 4787 const struct wined3d_gl_info *gl_info = context->gl_info; 4788 struct shader_arb_priv *priv = shader_priv; 4789 4790 if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) 4791 { 4792 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); 4793 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); 4794 priv->current_fprogram_id = 0; 4795 } 4796 priv->fragment_pipe->enable_extension(gl_info, FALSE); 4797 4798 if (gl_info->supported[ARB_VERTEX_PROGRAM]) 4799 { 4800 priv->current_vprogram_id = 0; 4801 gl_info->gl_ops.gl.p_glDisable(GL_VERTEX_PROGRAM_ARB); 4802 checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)"); 4803 } 4804 priv->vertex_pipe->vp_enable(gl_info, FALSE); 4805 4806 if (gl_info->supported[ARB_COLOR_BUFFER_FLOAT] && priv->last_vs_color_unclamp) 4807 { 4808 GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FIXED_ONLY_ARB)); 4809 checkGLcall("glClampColorARB"); 4810 priv->last_vs_color_unclamp = FALSE; 4811 } 4812 4813 context->shader_update_mask = (1 << WINED3D_SHADER_TYPE_PIXEL) 4814 | (1 << WINED3D_SHADER_TYPE_VERTEX) 4815 | (1 << WINED3D_SHADER_TYPE_GEOMETRY); 4816 } 4817 4818 /* Context activation is done by the caller. */ 4819 static void shader_arb_select_depth_blt(void *shader_priv, const struct wined3d_gl_info *gl_info, 4820 enum tex_types tex_type, const SIZE *ds_mask_size) 4821 { 4822 const float mask[] = {0.0f, 0.0f, (float)ds_mask_size->cx, (float)ds_mask_size->cy}; 4823 BOOL masked = ds_mask_size->cx && ds_mask_size->cy; 4824 struct shader_arb_priv *priv = shader_priv; 4825 GLuint *blt_fprogram; 4826 4827 if (!priv->depth_blt_vprogram_id) priv->depth_blt_vprogram_id = create_arb_blt_vertex_program(gl_info); 4828 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->depth_blt_vprogram_id)); 4829 gl_info->gl_ops.gl.p_glEnable(GL_VERTEX_PROGRAM_ARB); 4830 4831 blt_fprogram = masked ? &priv->depth_blt_fprogram_id_masked[tex_type] : &priv->depth_blt_fprogram_id_full[tex_type]; 4832 if (!*blt_fprogram) *blt_fprogram = create_arb_blt_fragment_program(gl_info, tex_type, masked); 4833 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, *blt_fprogram)); 4834 if (masked) GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, mask)); 4835 gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); 4836 } 4837 4838 /* Context activation is done by the caller. */ 4839 static void shader_arb_deselect_depth_blt(void *shader_priv, const struct wined3d_gl_info *gl_info) 4840 { 4841 struct shader_arb_priv *priv = shader_priv; 4842 4843 if (priv->current_vprogram_id) { 4844 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id)); 4845 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);"); 4846 4847 TRACE("Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB.\n", priv->current_vprogram_id); 4848 } 4849 else 4850 { 4851 gl_info->gl_ops.gl.p_glDisable(GL_VERTEX_PROGRAM_ARB); 4852 checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)"); 4853 } 4854 4855 if (priv->current_fprogram_id) { 4856 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id)); 4857 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);"); 4858 4859 TRACE("Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB.\n", priv->current_fprogram_id); 4860 } 4861 else if(!priv->use_arbfp_fixed_func) 4862 { 4863 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); 4864 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); 4865 } 4866 } 4867 4868 static void shader_arb_destroy(struct wined3d_shader *shader) 4869 { 4870 struct wined3d_device *device = shader->device; 4871 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 4872 4873 if (shader_is_pshader_version(shader->reg_maps.shader_version.type)) 4874 { 4875 struct arb_pshader_private *shader_data = shader->backend_data; 4876 UINT i; 4877 4878 if(!shader_data) return; /* This can happen if a shader was never compiled */ 4879 4880 if (shader_data->num_gl_shaders) 4881 { 4882 struct wined3d_context *context = context_acquire(device, NULL); 4883 4884 for (i = 0; i < shader_data->num_gl_shaders; ++i) 4885 { 4886 GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId)); 4887 checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId))"); 4888 } 4889 4890 context_release(context); 4891 } 4892 4893 HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders); 4894 HeapFree(GetProcessHeap(), 0, shader_data); 4895 shader->backend_data = NULL; 4896 } 4897 else 4898 { 4899 struct arb_vshader_private *shader_data = shader->backend_data; 4900 UINT i; 4901 4902 if(!shader_data) return; /* This can happen if a shader was never compiled */ 4903 4904 if (shader_data->num_gl_shaders) 4905 { 4906 struct wined3d_context *context = context_acquire(device, NULL); 4907 4908 for (i = 0; i < shader_data->num_gl_shaders; ++i) 4909 { 4910 GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId)); 4911 checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &shader_data->gl_shaders[i].prgId))"); 4912 } 4913 4914 context_release(context); 4915 } 4916 4917 HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders); 4918 HeapFree(GetProcessHeap(), 0, shader_data); 4919 shader->backend_data = NULL; 4920 } 4921 } 4922 4923 static int sig_tree_compare(const void *key, const struct wine_rb_entry *entry) 4924 { 4925 struct ps_signature *e = WINE_RB_ENTRY_VALUE(entry, struct ps_signature, entry); 4926 return compare_sig(key, e->sig); 4927 } 4928 4929 static const struct wine_rb_functions sig_tree_functions = 4930 { 4931 wined3d_rb_alloc, 4932 wined3d_rb_realloc, 4933 wined3d_rb_free, 4934 sig_tree_compare 4935 }; 4936 4937 static HRESULT shader_arb_alloc(struct wined3d_device *device, const struct wined3d_vertex_pipe_ops *vertex_pipe, 4938 const struct fragment_pipeline *fragment_pipe) 4939 { 4940 struct shader_arb_priv *priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv)); 4941 struct fragment_caps fragment_caps; 4942 void *vertex_priv, *fragment_priv; 4943 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; 4944 4945 if (!(vertex_priv = vertex_pipe->vp_alloc(&arb_program_shader_backend, priv))) 4946 { 4947 ERR("Failed to initialize vertex pipe.\n"); 4948 HeapFree(GetProcessHeap(), 0, priv); 4949 return E_FAIL; 4950 } 4951 4952 if (!(fragment_priv = fragment_pipe->alloc_private(&arb_program_shader_backend, priv))) 4953 { 4954 ERR("Failed to initialize fragment pipe.\n"); 4955 vertex_pipe->vp_free(device); 4956 HeapFree(GetProcessHeap(), 0, priv); 4957 return E_FAIL; 4958 } 4959 4960 priv->vshader_const_dirty = HeapAlloc(GetProcessHeap(), 0, 4961 sizeof(*priv->vshader_const_dirty) * d3d_info->limits.vs_uniform_count); 4962 if (!priv->vshader_const_dirty) 4963 goto fail; 4964 memset(priv->vshader_const_dirty, 1, 4965 sizeof(*priv->vshader_const_dirty) * d3d_info->limits.vs_uniform_count); 4966 4967 priv->pshader_const_dirty = HeapAlloc(GetProcessHeap(), 0, 4968 sizeof(*priv->pshader_const_dirty) * d3d_info->limits.ps_uniform_count); 4969 if (!priv->pshader_const_dirty) 4970 goto fail; 4971 memset(priv->pshader_const_dirty, 1, 4972 sizeof(*priv->pshader_const_dirty) * d3d_info->limits.ps_uniform_count); 4973 4974 if(wine_rb_init(&priv->signature_tree, &sig_tree_functions) == -1) 4975 { 4976 ERR("RB tree init failed\n"); 4977 goto fail; 4978 } 4979 4980 priv->vertex_pipe = vertex_pipe; 4981 priv->fragment_pipe = fragment_pipe; 4982 fragment_pipe->get_caps(&device->adapter->gl_info, &fragment_caps); 4983 priv->ffp_proj_control = fragment_caps.wined3d_caps & WINED3D_FRAGMENT_CAP_PROJ_CONTROL; 4984 4985 device->vertex_priv = vertex_priv; 4986 device->fragment_priv = fragment_priv; 4987 device->shader_priv = priv; 4988 4989 return WINED3D_OK; 4990 4991 fail: 4992 HeapFree(GetProcessHeap(), 0, priv->pshader_const_dirty); 4993 HeapFree(GetProcessHeap(), 0, priv->vshader_const_dirty); 4994 fragment_pipe->free_private(device); 4995 vertex_pipe->vp_free(device); 4996 HeapFree(GetProcessHeap(), 0, priv); 4997 return E_OUTOFMEMORY; 4998 } 4999 5000 static void release_signature(struct wine_rb_entry *entry, void *context) 5001 { 5002 struct ps_signature *sig = WINE_RB_ENTRY_VALUE(entry, struct ps_signature, entry); 5003 int i; 5004 for(i = 0; i < MAX_REG_INPUT; i++) 5005 { 5006 HeapFree(GetProcessHeap(), 0, (char *) sig->sig[i].semantic_name); 5007 } 5008 HeapFree(GetProcessHeap(), 0, sig->sig); 5009 HeapFree(GetProcessHeap(), 0, sig); 5010 } 5011 5012 /* Context activation is done by the caller. */ 5013 static void shader_arb_free(struct wined3d_device *device) 5014 { 5015 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 5016 struct shader_arb_priv *priv = device->shader_priv; 5017 int i; 5018 5019 if (priv->depth_blt_vprogram_id) 5020 GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_vprogram_id)); 5021 5022 for (i = 0; i < tex_type_count; ++i) 5023 { 5024 if (priv->depth_blt_fprogram_id_full[i]) 5025 { 5026 GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id_full[i])); 5027 } 5028 if (priv->depth_blt_fprogram_id_masked[i]) 5029 { 5030 GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id_masked[i])); 5031 } 5032 } 5033 5034 wine_rb_destroy(&priv->signature_tree, release_signature, NULL); 5035 HeapFree(GetProcessHeap(), 0, priv->pshader_const_dirty); 5036 HeapFree(GetProcessHeap(), 0, priv->vshader_const_dirty); 5037 priv->fragment_pipe->free_private(device); 5038 priv->vertex_pipe->vp_free(device); 5039 HeapFree(GetProcessHeap(), 0, device->shader_priv); 5040 } 5041 5042 static BOOL shader_arb_allocate_context_data(struct wined3d_context *context) 5043 { 5044 return TRUE; 5045 } 5046 5047 static void shader_arb_free_context_data(struct wined3d_context *context) 5048 { 5049 struct shader_arb_priv *priv = context->swapchain->device->shader_priv; 5050 5051 if (priv->last_context == context) 5052 priv->last_context = NULL; 5053 } 5054 5055 static void shader_arb_get_caps(const struct wined3d_gl_info *gl_info, struct shader_caps *caps) 5056 { 5057 if (gl_info->supported[ARB_VERTEX_PROGRAM]) 5058 { 5059 DWORD vs_consts; 5060 UINT vs_version; 5061 5062 /* 96 is the minimum allowed value of MAX_PROGRAM_ENV_PARAMETERS_ARB 5063 * for vertex programs. If the native limit is less than that it's 5064 * not very useful, and e.g. Mesa swrast returns 0, probably to 5065 * indicate it's a software implementation. */ 5066 if (gl_info->limits.arb_vs_native_constants < 96) 5067 vs_consts = gl_info->limits.arb_vs_float_constants; 5068 else 5069 vs_consts = min(gl_info->limits.arb_vs_float_constants, gl_info->limits.arb_vs_native_constants); 5070 5071 if (gl_info->supported[NV_VERTEX_PROGRAM3]) 5072 { 5073 vs_version = 3; 5074 TRACE("Hardware vertex shader version 3.0 enabled (NV_VERTEX_PROGRAM3)\n"); 5075 } 5076 else if (vs_consts >= 256) 5077 { 5078 /* Shader Model 2.0 requires at least 256 vertex shader constants */ 5079 vs_version = 2; 5080 TRACE("Hardware vertex shader version 2.0 enabled (ARB_PROGRAM)\n"); 5081 } 5082 else 5083 { 5084 vs_version = 1; 5085 TRACE("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); 5086 } 5087 caps->vs_version = min(wined3d_settings.max_sm_vs, vs_version); 5088 caps->vs_uniform_count = vs_consts; 5089 } 5090 else 5091 { 5092 caps->vs_version = 0; 5093 caps->vs_uniform_count = 0; 5094 } 5095 5096 caps->gs_version = 0; 5097 5098 if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) 5099 { 5100 DWORD ps_consts; 5101 UINT ps_version; 5102 5103 /* Similar as above for vertex programs, but the minimum for fragment 5104 * programs is 24. */ 5105 if (gl_info->limits.arb_ps_native_constants < 24) 5106 ps_consts = gl_info->limits.arb_ps_float_constants; 5107 else 5108 ps_consts = min(gl_info->limits.arb_ps_float_constants, gl_info->limits.arb_ps_native_constants); 5109 5110 if (gl_info->supported[NV_FRAGMENT_PROGRAM2]) 5111 { 5112 ps_version = 3; 5113 TRACE("Hardware pixel shader version 3.0 enabled (NV_FRAGMENT_PROGRAM2)\n"); 5114 } 5115 else if (ps_consts >= 32) 5116 { 5117 /* Shader Model 2.0 requires at least 32 pixel shader constants */ 5118 ps_version = 2; 5119 TRACE("Hardware pixel shader version 2.0 enabled (ARB_PROGRAM)\n"); 5120 } 5121 else 5122 { 5123 ps_version = 1; 5124 TRACE("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); 5125 } 5126 caps->ps_version = min(wined3d_settings.max_sm_ps, ps_version); 5127 caps->ps_uniform_count = ps_consts; 5128 caps->ps_1x_max_value = 8.0f; 5129 } 5130 else 5131 { 5132 caps->ps_version = 0; 5133 caps->ps_uniform_count = 0; 5134 caps->ps_1x_max_value = 0.0f; 5135 } 5136 5137 caps->wined3d_caps = WINED3D_SHADER_CAP_SRGB_WRITE; 5138 if (use_nv_clip(gl_info)) 5139 caps->wined3d_caps |= WINED3D_SHADER_CAP_VS_CLIPPING; 5140 } 5141 5142 static BOOL shader_arb_color_fixup_supported(struct color_fixup_desc fixup) 5143 { 5144 if (TRACE_ON(d3d_shader) && TRACE_ON(d3d)) 5145 { 5146 TRACE("Checking support for color_fixup:\n"); 5147 dump_color_fixup_desc(fixup); 5148 } 5149 5150 /* We support everything except complex conversions. */ 5151 if (!is_complex_fixup(fixup)) 5152 { 5153 TRACE("[OK]\n"); 5154 return TRUE; 5155 } 5156 5157 TRACE("[FAILED]\n"); 5158 return FALSE; 5159 } 5160 5161 static void shader_arb_add_instruction_modifiers(const struct wined3d_shader_instruction *ins) { 5162 DWORD shift; 5163 char write_mask[20], regstr[50]; 5164 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 5165 BOOL is_color = FALSE; 5166 const struct wined3d_shader_dst_param *dst; 5167 5168 if (!ins->dst_count) return; 5169 5170 dst = &ins->dst[0]; 5171 shift = dst->shift; 5172 if (!shift) return; /* Saturate alone is handled by the instructions */ 5173 5174 shader_arb_get_write_mask(ins, dst, write_mask); 5175 shader_arb_get_register_name(ins, &dst->reg, regstr, &is_color); 5176 5177 /* Generate a line that does the output modifier computation 5178 * FIXME: _SAT vs shift? _SAT alone is already handled in the instructions, if this 5179 * maps problems in e.g. _d4_sat modify shader_arb_get_modifier 5180 */ 5181 shader_addline(buffer, "MUL%s %s%s, %s, %s;\n", shader_arb_get_modifier(ins), 5182 regstr, write_mask, regstr, shift_tab[shift]); 5183 } 5184 5185 static const SHADER_HANDLER shader_arb_instruction_handler_table[WINED3DSIH_TABLE_SIZE] = 5186 { 5187 /* WINED3DSIH_ABS */ shader_hw_map2gl, 5188 /* WINED3DSIH_ADD */ shader_hw_map2gl, 5189 /* WINED3DSIH_AND */ NULL, 5190 /* WINED3DSIH_BEM */ pshader_hw_bem, 5191 /* WINED3DSIH_BREAK */ shader_hw_break, 5192 /* WINED3DSIH_BREAKC */ shader_hw_breakc, 5193 /* WINED3DSIH_BREAKP */ NULL, 5194 /* WINED3DSIH_CALL */ shader_hw_call, 5195 /* WINED3DSIH_CALLNZ */ NULL, 5196 /* WINED3DSIH_CMP */ pshader_hw_cmp, 5197 /* WINED3DSIH_CND */ pshader_hw_cnd, 5198 /* WINED3DSIH_CRS */ shader_hw_map2gl, 5199 /* WINED3DSIH_CUT */ NULL, 5200 /* WINED3DSIH_DCL */ shader_hw_nop, 5201 /* WINED3DSIH_DCL_CONSTANT_BUFFER */ shader_hw_nop, 5202 /* WINED3DSIH_DCL_INPUT_PRIMITIVE */ shader_hw_nop, 5203 /* WINED3DSIH_DCL_OUTPUT_TOPOLOGY */ shader_hw_nop, 5204 /* WINED3DSIH_DCL_VERTICES_OUT */ shader_hw_nop, 5205 /* WINED3DSIH_DEF */ shader_hw_nop, 5206 /* WINED3DSIH_DEFB */ shader_hw_nop, 5207 /* WINED3DSIH_DEFI */ shader_hw_nop, 5208 /* WINED3DSIH_DIV */ NULL, 5209 /* WINED3DSIH_DP2ADD */ pshader_hw_dp2add, 5210 /* WINED3DSIH_DP3 */ shader_hw_map2gl, 5211 /* WINED3DSIH_DP4 */ shader_hw_map2gl, 5212 /* WINED3DSIH_DST */ shader_hw_map2gl, 5213 /* WINED3DSIH_DSX */ shader_hw_map2gl, 5214 /* WINED3DSIH_DSY */ shader_hw_dsy, 5215 /* WINED3DSIH_ELSE */ shader_hw_else, 5216 /* WINED3DSIH_EMIT */ NULL, 5217 /* WINED3DSIH_ENDIF */ shader_hw_endif, 5218 /* WINED3DSIH_ENDLOOP */ shader_hw_endloop, 5219 /* WINED3DSIH_ENDREP */ shader_hw_endrep, 5220 /* WINED3DSIH_EQ */ NULL, 5221 /* WINED3DSIH_EXP */ shader_hw_scalar_op, 5222 /* WINED3DSIH_EXPP */ shader_hw_scalar_op, 5223 /* WINED3DSIH_FRC */ shader_hw_map2gl, 5224 /* WINED3DSIH_FTOI */ NULL, 5225 /* WINED3DSIH_GE */ NULL, 5226 /* WINED3DSIH_IADD */ NULL, 5227 /* WINED3DSIH_IEQ */ NULL, 5228 /* WINED3DSIH_IF */ NULL /* Hardcoded into the shader */, 5229 /* WINED3DSIH_IFC */ shader_hw_ifc, 5230 /* WINED3DSIH_IGE */ NULL, 5231 /* WINED3DSIH_IMUL */ NULL, 5232 /* WINED3DSIH_ITOF */ NULL, 5233 /* WINED3DSIH_LABEL */ shader_hw_label, 5234 /* WINED3DSIH_LD */ NULL, 5235 /* WINED3DSIH_LIT */ shader_hw_map2gl, 5236 /* WINED3DSIH_LOG */ shader_hw_log, 5237 /* WINED3DSIH_LOGP */ shader_hw_log, 5238 /* WINED3DSIH_LOOP */ shader_hw_loop, 5239 /* WINED3DSIH_LRP */ shader_hw_lrp, 5240 /* WINED3DSIH_LT */ NULL, 5241 /* WINED3DSIH_M3x2 */ shader_hw_mnxn, 5242 /* WINED3DSIH_M3x3 */ shader_hw_mnxn, 5243 /* WINED3DSIH_M3x4 */ shader_hw_mnxn, 5244 /* WINED3DSIH_M4x3 */ shader_hw_mnxn, 5245 /* WINED3DSIH_M4x4 */ shader_hw_mnxn, 5246 /* WINED3DSIH_MAD */ shader_hw_map2gl, 5247 /* WINED3DSIH_MAX */ shader_hw_map2gl, 5248 /* WINED3DSIH_MIN */ shader_hw_map2gl, 5249 /* WINED3DSIH_MOV */ shader_hw_mov, 5250 /* WINED3DSIH_MOVA */ shader_hw_mov, 5251 /* WINED3DSIH_MOVC */ NULL, 5252 /* WINED3DSIH_MUL */ shader_hw_map2gl, 5253 /* WINED3DSIH_NOP */ shader_hw_nop, 5254 /* WINED3DSIH_NRM */ shader_hw_nrm, 5255 /* WINED3DSIH_PHASE */ shader_hw_nop, 5256 /* WINED3DSIH_POW */ shader_hw_pow, 5257 /* WINED3DSIH_RCP */ shader_hw_rcp, 5258 /* WINED3DSIH_REP */ shader_hw_rep, 5259 /* WINED3DSIH_RET */ shader_hw_ret, 5260 /* WINED3DSIH_ROUND_NI */ NULL, 5261 /* WINED3DSIH_RSQ */ shader_hw_scalar_op, 5262 /* WINED3DSIH_SAMPLE */ NULL, 5263 /* WINED3DSIH_SAMPLE_GRAD */ NULL, 5264 /* WINED3DSIH_SAMPLE_LOD */ NULL, 5265 /* WINED3DSIH_SETP */ NULL, 5266 /* WINED3DSIH_SGE */ shader_hw_map2gl, 5267 /* WINED3DSIH_SGN */ shader_hw_sgn, 5268 /* WINED3DSIH_SINCOS */ shader_hw_sincos, 5269 /* WINED3DSIH_SLT */ shader_hw_map2gl, 5270 /* WINED3DSIH_SQRT */ NULL, 5271 /* WINED3DSIH_SUB */ shader_hw_map2gl, 5272 /* WINED3DSIH_TEX */ pshader_hw_tex, 5273 /* WINED3DSIH_TEXBEM */ pshader_hw_texbem, 5274 /* WINED3DSIH_TEXBEML */ pshader_hw_texbem, 5275 /* WINED3DSIH_TEXCOORD */ pshader_hw_texcoord, 5276 /* WINED3DSIH_TEXDEPTH */ pshader_hw_texdepth, 5277 /* WINED3DSIH_TEXDP3 */ pshader_hw_texdp3, 5278 /* WINED3DSIH_TEXDP3TEX */ pshader_hw_texdp3tex, 5279 /* WINED3DSIH_TEXKILL */ pshader_hw_texkill, 5280 /* WINED3DSIH_TEXLDD */ shader_hw_texldd, 5281 /* WINED3DSIH_TEXLDL */ shader_hw_texldl, 5282 /* WINED3DSIH_TEXM3x2DEPTH */ pshader_hw_texm3x2depth, 5283 /* WINED3DSIH_TEXM3x2PAD */ pshader_hw_texm3x2pad, 5284 /* WINED3DSIH_TEXM3x2TEX */ pshader_hw_texm3x2tex, 5285 /* WINED3DSIH_TEXM3x3 */ pshader_hw_texm3x3, 5286 /* WINED3DSIH_TEXM3x3DIFF */ NULL, 5287 /* WINED3DSIH_TEXM3x3PAD */ pshader_hw_texm3x3pad, 5288 /* WINED3DSIH_TEXM3x3SPEC */ pshader_hw_texm3x3spec, 5289 /* WINED3DSIH_TEXM3x3TEX */ pshader_hw_texm3x3tex, 5290 /* WINED3DSIH_TEXM3x3VSPEC */ pshader_hw_texm3x3vspec, 5291 /* WINED3DSIH_TEXREG2AR */ pshader_hw_texreg2ar, 5292 /* WINED3DSIH_TEXREG2GB */ pshader_hw_texreg2gb, 5293 /* WINED3DSIH_TEXREG2RGB */ pshader_hw_texreg2rgb, 5294 /* WINED3DSIH_UDIV */ NULL, 5295 /* WINED3DSIH_USHR */ NULL, 5296 /* WINED3DSIH_UTOF */ NULL, 5297 /* WINED3DSIH_XOR */ NULL, 5298 }; 5299 5300 static BOOL get_bool_const(const struct wined3d_shader_instruction *ins, 5301 const struct wined3d_shader *shader, DWORD idx) 5302 { 5303 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps; 5304 BOOL vshader = shader_is_vshader_version(reg_maps->shader_version.type); 5305 const struct wined3d_shader_lconst *constant; 5306 WORD bools = 0; 5307 WORD flag = (1 << idx); 5308 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 5309 5310 if (reg_maps->local_bool_consts & flag) 5311 { 5312 /* What good is an if(bool) with a hardcoded local constant? I don't know, but handle it */ 5313 LIST_FOR_EACH_ENTRY(constant, &shader->constantsB, struct wined3d_shader_lconst, entry) 5314 { 5315 if (constant->idx == idx) 5316 { 5317 return constant->value[0]; 5318 } 5319 } 5320 ERR("Local constant not found\n"); 5321 return FALSE; 5322 } 5323 else 5324 { 5325 if(vshader) bools = priv->cur_vs_args->clip.boolclip.bools; 5326 else bools = priv->cur_ps_args->bools; 5327 return bools & flag; 5328 } 5329 } 5330 5331 static void get_loop_control_const(const struct wined3d_shader_instruction *ins, 5332 const struct wined3d_shader *shader, UINT idx, struct wined3d_shader_loop_control *loop_control) 5333 { 5334 const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps; 5335 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 5336 5337 /* Integer constants can either be a local constant, or they can be stored in the shader 5338 * type specific compile args. */ 5339 if (reg_maps->local_int_consts & (1 << idx)) 5340 { 5341 const struct wined3d_shader_lconst *constant; 5342 5343 LIST_FOR_EACH_ENTRY(constant, &shader->constantsI, struct wined3d_shader_lconst, entry) 5344 { 5345 if (constant->idx == idx) 5346 { 5347 loop_control->count = constant->value[0]; 5348 loop_control->start = constant->value[1]; 5349 /* Step is signed. */ 5350 loop_control->step = (int)constant->value[2]; 5351 return; 5352 } 5353 } 5354 /* If this happens the flag was set incorrectly */ 5355 ERR("Local constant not found\n"); 5356 loop_control->count = 0; 5357 loop_control->start = 0; 5358 loop_control->step = 0; 5359 return; 5360 } 5361 5362 switch (reg_maps->shader_version.type) 5363 { 5364 case WINED3D_SHADER_TYPE_VERTEX: 5365 /* Count and aL start value are unsigned */ 5366 loop_control->count = priv->cur_vs_args->loop_ctrl[idx][0]; 5367 loop_control->start = priv->cur_vs_args->loop_ctrl[idx][1]; 5368 /* Step is signed. */ 5369 loop_control->step = ((char)priv->cur_vs_args->loop_ctrl[idx][2]); 5370 break; 5371 5372 case WINED3D_SHADER_TYPE_PIXEL: 5373 loop_control->count = priv->cur_ps_args->loop_ctrl[idx][0]; 5374 loop_control->start = priv->cur_ps_args->loop_ctrl[idx][1]; 5375 loop_control->step = ((char)priv->cur_ps_args->loop_ctrl[idx][2]); 5376 break; 5377 5378 default: 5379 FIXME("Unhandled shader type %#x.\n", reg_maps->shader_version.type); 5380 break; 5381 } 5382 } 5383 5384 static void record_instruction(struct list *list, const struct wined3d_shader_instruction *ins) 5385 { 5386 unsigned int i; 5387 struct wined3d_shader_dst_param *dst_param = NULL; 5388 struct wined3d_shader_src_param *src_param = NULL, *rel_addr = NULL; 5389 struct recorded_instruction *rec = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rec)); 5390 if(!rec) 5391 { 5392 ERR("Out of memory\n"); 5393 return; 5394 } 5395 5396 rec->ins = *ins; 5397 dst_param = HeapAlloc(GetProcessHeap(), 0, sizeof(*dst_param)); 5398 if(!dst_param) goto free; 5399 *dst_param = *ins->dst; 5400 if (ins->dst->reg.idx[0].rel_addr) 5401 { 5402 rel_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(*rel_addr)); 5403 if (!rel_addr) 5404 goto free; 5405 *rel_addr = *ins->dst->reg.idx[0].rel_addr; 5406 dst_param->reg.idx[0].rel_addr = rel_addr; 5407 } 5408 rec->ins.dst = dst_param; 5409 5410 src_param = HeapAlloc(GetProcessHeap(), 0, sizeof(*src_param) * ins->src_count); 5411 if (!src_param) 5412 goto free; 5413 for (i = 0; i < ins->src_count; ++i) 5414 { 5415 src_param[i] = ins->src[i]; 5416 if (ins->src[i].reg.idx[0].rel_addr) 5417 { 5418 rel_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(*rel_addr)); 5419 if (!rel_addr) 5420 goto free; 5421 *rel_addr = *ins->src[i].reg.idx[0].rel_addr; 5422 src_param[i].reg.idx[0].rel_addr = rel_addr; 5423 } 5424 } 5425 rec->ins.src = src_param; 5426 list_add_tail(list, &rec->entry); 5427 return; 5428 5429 free: 5430 ERR("Out of memory\n"); 5431 if(dst_param) 5432 { 5433 HeapFree(GetProcessHeap(), 0, (void *)dst_param->reg.idx[0].rel_addr); 5434 HeapFree(GetProcessHeap(), 0, dst_param); 5435 } 5436 if(src_param) 5437 { 5438 for(i = 0; i < ins->src_count; i++) 5439 { 5440 HeapFree(GetProcessHeap(), 0, (void *)src_param[i].reg.idx[0].rel_addr); 5441 } 5442 HeapFree(GetProcessHeap(), 0, src_param); 5443 } 5444 HeapFree(GetProcessHeap(), 0, rec); 5445 } 5446 5447 static void free_recorded_instruction(struct list *list) 5448 { 5449 struct recorded_instruction *rec_ins, *entry2; 5450 unsigned int i; 5451 5452 LIST_FOR_EACH_ENTRY_SAFE(rec_ins, entry2, list, struct recorded_instruction, entry) 5453 { 5454 list_remove(&rec_ins->entry); 5455 if (rec_ins->ins.dst) 5456 { 5457 HeapFree(GetProcessHeap(), 0, (void *)rec_ins->ins.dst->reg.idx[0].rel_addr); 5458 HeapFree(GetProcessHeap(), 0, (void *)rec_ins->ins.dst); 5459 } 5460 if (rec_ins->ins.src) 5461 { 5462 for (i = 0; i < rec_ins->ins.src_count; ++i) 5463 { 5464 HeapFree(GetProcessHeap(), 0, (void *)rec_ins->ins.src[i].reg.idx[0].rel_addr); 5465 } 5466 HeapFree(GetProcessHeap(), 0, (void *)rec_ins->ins.src); 5467 } 5468 HeapFree(GetProcessHeap(), 0, rec_ins); 5469 } 5470 } 5471 5472 static void pop_control_frame(const struct wined3d_shader_instruction *ins) 5473 { 5474 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 5475 struct control_frame *control_frame; 5476 5477 if (ins->handler_idx == WINED3DSIH_ENDLOOP || ins->handler_idx == WINED3DSIH_ENDREP) 5478 { 5479 struct list *e = list_head(&priv->control_frames); 5480 control_frame = LIST_ENTRY(e, struct control_frame, entry); 5481 list_remove(&control_frame->entry); 5482 HeapFree(GetProcessHeap(), 0, control_frame); 5483 priv->loop_depth--; 5484 } 5485 else if (ins->handler_idx == WINED3DSIH_ENDIF) 5486 { 5487 /* Non-ifc ENDIFs were already handled previously. */ 5488 struct list *e = list_head(&priv->control_frames); 5489 control_frame = LIST_ENTRY(e, struct control_frame, entry); 5490 list_remove(&control_frame->entry); 5491 HeapFree(GetProcessHeap(), 0, control_frame); 5492 } 5493 } 5494 5495 static void shader_arb_handle_instruction(const struct wined3d_shader_instruction *ins) { 5496 SHADER_HANDLER hw_fct; 5497 struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; 5498 const struct wined3d_shader *shader = ins->ctx->shader; 5499 struct control_frame *control_frame; 5500 struct wined3d_shader_buffer *buffer = ins->ctx->buffer; 5501 BOOL bool_const; 5502 5503 if(ins->handler_idx == WINED3DSIH_LOOP || ins->handler_idx == WINED3DSIH_REP) 5504 { 5505 control_frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*control_frame)); 5506 list_add_head(&priv->control_frames, &control_frame->entry); 5507 5508 if(ins->handler_idx == WINED3DSIH_LOOP) control_frame->type = LOOP; 5509 if(ins->handler_idx == WINED3DSIH_REP) control_frame->type = REP; 5510 5511 if(priv->target_version >= NV2) 5512 { 5513 control_frame->no.loop = priv->num_loops++; 5514 priv->loop_depth++; 5515 } 5516 else 5517 { 5518 /* Don't bother recording when we're in a not used if branch */ 5519 if(priv->muted) 5520 { 5521 return; 5522 } 5523 5524 if(!priv->recording) 5525 { 5526 list_init(&priv->record); 5527 priv->recording = TRUE; 5528 control_frame->outer_loop = TRUE; 5529 get_loop_control_const(ins, shader, ins->src[0].reg.idx[0].offset, &control_frame->loop_control); 5530 return; /* Instruction is handled */ 5531 } 5532 /* Record this loop in the outer loop's recording */ 5533 } 5534 } 5535 else if(ins->handler_idx == WINED3DSIH_ENDLOOP || ins->handler_idx == WINED3DSIH_ENDREP) 5536 { 5537 if(priv->target_version >= NV2) 5538 { 5539 /* Nothing to do. The control frame is popped after the HW instr handler */ 5540 } 5541 else 5542 { 5543 struct list *e = list_head(&priv->control_frames); 5544 control_frame = LIST_ENTRY(e, struct control_frame, entry); 5545 list_remove(&control_frame->entry); 5546 5547 if(control_frame->outer_loop) 5548 { 5549 unsigned int iteration; 5550 int aL = 0; 5551 struct list copy; 5552 5553 /* Turn off recording before playback */ 5554 priv->recording = FALSE; 5555 5556 /* Move the recorded instructions to a separate list and get them out of the private data 5557 * structure. If there are nested loops, the shader_arb_handle_instruction below will 5558 * be recorded again, thus priv->record might be overwritten 5559 */ 5560 list_init(©); 5561 list_move_tail(©, &priv->record); 5562 list_init(&priv->record); 5563 5564 if(ins->handler_idx == WINED3DSIH_ENDLOOP) 5565 { 5566 shader_addline(buffer, "#unrolling loop: %u iterations, aL=%u, inc %d\n", 5567 control_frame->loop_control.count, control_frame->loop_control.start, 5568 control_frame->loop_control.step); 5569 aL = control_frame->loop_control.start; 5570 } 5571 else 5572 { 5573 shader_addline(buffer, "#unrolling rep: %u iterations\n", control_frame->loop_control.count); 5574 } 5575 5576 for (iteration = 0; iteration < control_frame->loop_control.count; ++iteration) 5577 { 5578 struct recorded_instruction *rec_ins; 5579 if(ins->handler_idx == WINED3DSIH_ENDLOOP) 5580 { 5581 priv->aL = aL; 5582 shader_addline(buffer, "#Iteration %u, aL=%d\n", iteration, aL); 5583 } 5584 else 5585 { 5586 shader_addline(buffer, "#Iteration %u\n", iteration); 5587 } 5588 5589 LIST_FOR_EACH_ENTRY(rec_ins, ©, struct recorded_instruction, entry) 5590 { 5591 shader_arb_handle_instruction(&rec_ins->ins); 5592 } 5593 5594 if(ins->handler_idx == WINED3DSIH_ENDLOOP) 5595 { 5596 aL += control_frame->loop_control.step; 5597 } 5598 } 5599 shader_addline(buffer, "#end loop/rep\n"); 5600 5601 free_recorded_instruction(©); 5602 HeapFree(GetProcessHeap(), 0, control_frame); 5603 return; /* Instruction is handled */ 5604 } 5605 else 5606 { 5607 /* This is a nested loop. Proceed to the normal recording function */ 5608 HeapFree(GetProcessHeap(), 0, control_frame); 5609 } 5610 } 5611 } 5612 5613 if(priv->recording) 5614 { 5615 record_instruction(&priv->record, ins); 5616 return; 5617 } 5618 5619 /* boolean if */ 5620 if(ins->handler_idx == WINED3DSIH_IF) 5621 { 5622 control_frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*control_frame)); 5623 list_add_head(&priv->control_frames, &control_frame->entry); 5624 control_frame->type = IF; 5625 5626 bool_const = get_bool_const(ins, shader, ins->src[0].reg.idx[0].offset); 5627 if (ins->src[0].modifiers == WINED3DSPSM_NOT) 5628 bool_const = !bool_const; 5629 if (!priv->muted && !bool_const) 5630 { 5631 shader_addline(buffer, "#if(FALSE){\n"); 5632 priv->muted = TRUE; 5633 control_frame->muting = TRUE; 5634 } 5635 else shader_addline(buffer, "#if(TRUE) {\n"); 5636 5637 return; /* Instruction is handled */ 5638 } 5639 else if(ins->handler_idx == WINED3DSIH_IFC) 5640 { 5641 /* IF(bool) and if_cond(a, b) use the same ELSE and ENDIF tokens */ 5642 control_frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*control_frame)); 5643 control_frame->type = IFC; 5644 control_frame->no.ifc = priv->num_ifcs++; 5645 list_add_head(&priv->control_frames, &control_frame->entry); 5646 } 5647 else if(ins->handler_idx == WINED3DSIH_ELSE) 5648 { 5649 struct list *e = list_head(&priv->control_frames); 5650 control_frame = LIST_ENTRY(e, struct control_frame, entry); 5651 5652 if(control_frame->type == IF) 5653 { 5654 shader_addline(buffer, "#} else {\n"); 5655 if(!priv->muted && !control_frame->muting) 5656 { 5657 priv->muted = TRUE; 5658 control_frame->muting = TRUE; 5659 } 5660 else if(control_frame->muting) priv->muted = FALSE; 5661 return; /* Instruction is handled. */ 5662 } 5663 /* In case of an ifc, generate a HW shader instruction */ 5664 if (control_frame->type != IFC) 5665 ERR("Control frame does not match.\n"); 5666 } 5667 else if(ins->handler_idx == WINED3DSIH_ENDIF) 5668 { 5669 struct list *e = list_head(&priv->control_frames); 5670 control_frame = LIST_ENTRY(e, struct control_frame, entry); 5671 5672 if(control_frame->type == IF) 5673 { 5674 shader_addline(buffer, "#} endif\n"); 5675 if(control_frame->muting) priv->muted = FALSE; 5676 list_remove(&control_frame->entry); 5677 HeapFree(GetProcessHeap(), 0, control_frame); 5678 return; /* Instruction is handled */ 5679 } 5680 /* In case of an ifc, generate a HW shader instruction */ 5681 if (control_frame->type != IFC) 5682 ERR("Control frame does not match.\n"); 5683 } 5684 5685 if(priv->muted) 5686 { 5687 pop_control_frame(ins); 5688 return; 5689 } 5690 5691 /* Select handler */ 5692 hw_fct = shader_arb_instruction_handler_table[ins->handler_idx]; 5693 5694 /* Unhandled opcode */ 5695 if (!hw_fct) 5696 { 5697 FIXME("Backend can't handle opcode %#x\n", ins->handler_idx); 5698 return; 5699 } 5700 hw_fct(ins); 5701 5702 pop_control_frame(ins); 5703 5704 shader_arb_add_instruction_modifiers(ins); 5705 } 5706 5707 static BOOL shader_arb_has_ffp_proj_control(void *shader_priv) 5708 { 5709 struct shader_arb_priv *priv = shader_priv; 5710 5711 return priv->ffp_proj_control; 5712 } 5713 5714 const struct wined3d_shader_backend_ops arb_program_shader_backend = 5715 { 5716 shader_arb_handle_instruction, 5717 shader_arb_select, 5718 shader_arb_disable, 5719 shader_arb_select_depth_blt, 5720 shader_arb_deselect_depth_blt, 5721 shader_arb_update_float_vertex_constants, 5722 shader_arb_update_float_pixel_constants, 5723 shader_arb_load_constants, 5724 shader_arb_destroy, 5725 shader_arb_alloc, 5726 shader_arb_free, 5727 shader_arb_allocate_context_data, 5728 shader_arb_free_context_data, 5729 shader_arb_get_caps, 5730 shader_arb_color_fixup_supported, 5731 shader_arb_has_ffp_proj_control, 5732 }; 5733 5734 /* ARB_fragment_program fixed function pipeline replacement definitions */ 5735 #define ARB_FFP_CONST_TFACTOR 0 5736 #define ARB_FFP_CONST_SPECULAR_ENABLE ((ARB_FFP_CONST_TFACTOR) + 1) 5737 #define ARB_FFP_CONST_CONSTANT(i) ((ARB_FFP_CONST_SPECULAR_ENABLE) + 1 + i) 5738 #define ARB_FFP_CONST_BUMPMAT(i) ((ARB_FFP_CONST_CONSTANT(7)) + 1 + i) 5739 #define ARB_FFP_CONST_LUMINANCE(i) ((ARB_FFP_CONST_BUMPMAT(7)) + 1 + i) 5740 5741 struct arbfp_ffp_desc 5742 { 5743 struct ffp_frag_desc parent; 5744 GLuint shader; 5745 }; 5746 5747 /* Context activation is done by the caller. */ 5748 static void arbfp_enable(const struct wined3d_gl_info *gl_info, BOOL enable) 5749 { 5750 if (enable) 5751 { 5752 gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); 5753 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)"); 5754 } 5755 else 5756 { 5757 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); 5758 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); 5759 } 5760 } 5761 5762 static void *arbfp_alloc(const struct wined3d_shader_backend_ops *shader_backend, void *shader_priv) 5763 { 5764 struct shader_arb_priv *priv; 5765 5766 /* Share private data between the shader backend and the pipeline 5767 * replacement, if both are the arb implementation. This is needed to 5768 * figure out whether ARBfp should be disabled if no pixel shader is bound 5769 * or not. */ 5770 if (shader_backend == &arb_program_shader_backend) 5771 priv = shader_priv; 5772 else if (!(priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv)))) 5773 return NULL; 5774 5775 if (wine_rb_init(&priv->fragment_shaders, &wined3d_ffp_frag_program_rb_functions) == -1) 5776 { 5777 ERR("Failed to initialize rbtree.\n"); 5778 if (priv != shader_priv) 5779 HeapFree(GetProcessHeap(), 0, priv); 5780 return NULL; 5781 } 5782 priv->use_arbfp_fixed_func = TRUE; 5783 5784 return priv; 5785 } 5786 5787 /* Context activation is done by the caller. */ 5788 static void arbfp_free_ffpshader(struct wine_rb_entry *entry, void *context) 5789 { 5790 const struct wined3d_gl_info *gl_info = context; 5791 struct arbfp_ffp_desc *entry_arb = WINE_RB_ENTRY_VALUE(entry, struct arbfp_ffp_desc, parent.entry); 5792 5793 GL_EXTCALL(glDeleteProgramsARB(1, &entry_arb->shader)); 5794 checkGLcall("glDeleteProgramsARB(1, &entry_arb->shader)"); 5795 HeapFree(GetProcessHeap(), 0, entry_arb); 5796 } 5797 5798 /* Context activation is done by the caller. */ 5799 static void arbfp_free(struct wined3d_device *device) 5800 { 5801 struct shader_arb_priv *priv = device->fragment_priv; 5802 5803 wine_rb_destroy(&priv->fragment_shaders, arbfp_free_ffpshader, &device->adapter->gl_info); 5804 priv->use_arbfp_fixed_func = FALSE; 5805 5806 if (device->shader_backend != &arb_program_shader_backend) 5807 { 5808 HeapFree(GetProcessHeap(), 0, device->fragment_priv); 5809 } 5810 } 5811 5812 static void arbfp_get_caps(const struct wined3d_gl_info *gl_info, struct fragment_caps *caps) 5813 { 5814 caps->wined3d_caps = WINED3D_FRAGMENT_CAP_PROJ_CONTROL 5815 | WINED3D_FRAGMENT_CAP_SRGB_WRITE; 5816 caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP; 5817 caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE | 5818 WINED3DTEXOPCAPS_SELECTARG1 | 5819 WINED3DTEXOPCAPS_SELECTARG2 | 5820 WINED3DTEXOPCAPS_MODULATE4X | 5821 WINED3DTEXOPCAPS_MODULATE2X | 5822 WINED3DTEXOPCAPS_MODULATE | 5823 WINED3DTEXOPCAPS_ADDSIGNED2X | 5824 WINED3DTEXOPCAPS_ADDSIGNED | 5825 WINED3DTEXOPCAPS_ADD | 5826 WINED3DTEXOPCAPS_SUBTRACT | 5827 WINED3DTEXOPCAPS_ADDSMOOTH | 5828 WINED3DTEXOPCAPS_BLENDCURRENTALPHA | 5829 WINED3DTEXOPCAPS_BLENDFACTORALPHA | 5830 WINED3DTEXOPCAPS_BLENDTEXTUREALPHA | 5831 WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA | 5832 WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM | 5833 WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | 5834 WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | 5835 WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA | 5836 WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | 5837 WINED3DTEXOPCAPS_DOTPRODUCT3 | 5838 WINED3DTEXOPCAPS_MULTIPLYADD | 5839 WINED3DTEXOPCAPS_LERP | 5840 WINED3DTEXOPCAPS_BUMPENVMAP | 5841 WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE; 5842 5843 /* TODO: Implement WINED3DTEXOPCAPS_PREMODULATE */ 5844 5845 caps->MaxTextureBlendStages = 8; 5846 caps->MaxSimultaneousTextures = min(gl_info->limits.fragment_samplers, 8); 5847 } 5848 5849 static void state_texfactor_arbfp(struct wined3d_context *context, 5850 const struct wined3d_state *state, DWORD state_id) 5851 { 5852 struct wined3d_device *device = context->swapchain->device; 5853 const struct wined3d_gl_info *gl_info = context->gl_info; 5854 float col[4]; 5855 5856 /* Don't load the parameter if we're using an arbfp pixel shader, 5857 * otherwise we'll overwrite application provided constants. */ 5858 if (device->shader_backend == &arb_program_shader_backend) 5859 { 5860 struct shader_arb_priv *priv; 5861 5862 if (use_ps(state)) return; 5863 5864 priv = device->shader_priv; 5865 priv->pshader_const_dirty[ARB_FFP_CONST_TFACTOR] = 1; 5866 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, ARB_FFP_CONST_TFACTOR + 1); 5867 } 5868 5869 D3DCOLORTOGLFLOAT4(state->render_states[WINED3D_RS_TEXTUREFACTOR], col); 5870 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_TFACTOR, col)); 5871 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_TFACTOR, col)"); 5872 } 5873 5874 static void state_arb_specularenable(struct wined3d_context *context, 5875 const struct wined3d_state *state, DWORD state_id) 5876 { 5877 struct wined3d_device *device = context->swapchain->device; 5878 const struct wined3d_gl_info *gl_info = context->gl_info; 5879 float col[4]; 5880 5881 /* Don't load the parameter if we're using an arbfp pixel shader, otherwise we'll overwrite 5882 * application provided constants 5883 */ 5884 if (device->shader_backend == &arb_program_shader_backend) 5885 { 5886 struct shader_arb_priv *priv; 5887 5888 if (use_ps(state)) return; 5889 5890 priv = device->shader_priv; 5891 priv->pshader_const_dirty[ARB_FFP_CONST_SPECULAR_ENABLE] = 1; 5892 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, ARB_FFP_CONST_SPECULAR_ENABLE + 1); 5893 } 5894 5895 if (state->render_states[WINED3D_RS_SPECULARENABLE]) 5896 { 5897 /* The specular color has no alpha */ 5898 col[0] = 1.0f; col[1] = 1.0f; 5899 col[2] = 1.0f; col[3] = 0.0f; 5900 } else { 5901 col[0] = 0.0f; col[1] = 0.0f; 5902 col[2] = 0.0f; col[3] = 0.0f; 5903 } 5904 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_SPECULAR_ENABLE, col)); 5905 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_SPECULAR_ENABLE, col)"); 5906 } 5907 5908 static void set_bumpmat_arbfp(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) 5909 { 5910 DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1); 5911 struct wined3d_device *device = context->swapchain->device; 5912 const struct wined3d_gl_info *gl_info = context->gl_info; 5913 float mat[2][2]; 5914 5915 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_BUMP_ENV; 5916 5917 if (device->shader_backend == &arb_program_shader_backend) 5918 { 5919 struct shader_arb_priv *priv = device->shader_priv; 5920 5921 /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants. */ 5922 if (use_ps(state)) 5923 return; 5924 5925 priv->pshader_const_dirty[ARB_FFP_CONST_BUMPMAT(stage)] = 1; 5926 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, ARB_FFP_CONST_BUMPMAT(stage) + 1); 5927 } 5928 5929 mat[0][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT00]); 5930 mat[0][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT01]); 5931 mat[1][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT10]); 5932 mat[1][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT11]); 5933 5934 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_BUMPMAT(stage), &mat[0][0])); 5935 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_BUMPMAT(stage), &mat[0][0])"); 5936 } 5937 5938 static void tex_bumpenvlum_arbfp(struct wined3d_context *context, 5939 const struct wined3d_state *state, DWORD state_id) 5940 { 5941 DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1); 5942 struct wined3d_device *device = context->swapchain->device; 5943 const struct wined3d_gl_info *gl_info = context->gl_info; 5944 float param[4]; 5945 5946 context->constant_update_mask |= WINED3D_SHADER_CONST_PS_BUMP_ENV; 5947 5948 if (device->shader_backend == &arb_program_shader_backend) 5949 { 5950 struct shader_arb_priv *priv = device->shader_priv; 5951 5952 /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants. */ 5953 if (use_ps(state)) 5954 return; 5955 5956 priv->pshader_const_dirty[ARB_FFP_CONST_LUMINANCE(stage)] = 1; 5957 priv->highest_dirty_ps_const = max(priv->highest_dirty_ps_const, ARB_FFP_CONST_LUMINANCE(stage) + 1); 5958 } 5959 5960 param[0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_LSCALE]); 5961 param[1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_LOFFSET]); 5962 param[2] = 0.0f; 5963 param[3] = 0.0f; 5964 5965 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_LUMINANCE(stage), param)); 5966 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARB_FFP_CONST_LUMINANCE(stage), param)"); 5967 } 5968 5969 static const char *get_argreg(struct wined3d_shader_buffer *buffer, DWORD argnum, unsigned int stage, DWORD arg) 5970 { 5971 const char *ret; 5972 5973 if(arg == ARG_UNUSED) return "unused"; /* This is the marker for unused registers */ 5974 5975 switch(arg & WINED3DTA_SELECTMASK) { 5976 case WINED3DTA_DIFFUSE: 5977 ret = "fragment.color.primary"; break; 5978 5979 case WINED3DTA_CURRENT: 5980 if (!stage) ret = "fragment.color.primary"; 5981 else ret = "ret"; 5982 break; 5983 5984 case WINED3DTA_TEXTURE: 5985 switch(stage) { 5986 case 0: ret = "tex0"; break; 5987 case 1: ret = "tex1"; break; 5988 case 2: ret = "tex2"; break; 5989 case 3: ret = "tex3"; break; 5990 case 4: ret = "tex4"; break; 5991 case 5: ret = "tex5"; break; 5992 case 6: ret = "tex6"; break; 5993 case 7: ret = "tex7"; break; 5994 default: ret = "unknown texture"; 5995 } 5996 break; 5997 5998 case WINED3DTA_TFACTOR: 5999 ret = "tfactor"; break; 6000 6001 case WINED3DTA_SPECULAR: 6002 ret = "fragment.color.secondary"; break; 6003 6004 case WINED3DTA_TEMP: 6005 ret = "tempreg"; break; 6006 6007 case WINED3DTA_CONSTANT: 6008 FIXME("Implement perstage constants\n"); 6009 switch(stage) { 6010 case 0: ret = "const0"; break; 6011 case 1: ret = "const1"; break; 6012 case 2: ret = "const2"; break; 6013 case 3: ret = "const3"; break; 6014 case 4: ret = "const4"; break; 6015 case 5: ret = "const5"; break; 6016 case 6: ret = "const6"; break; 6017 case 7: ret = "const7"; break; 6018 default: ret = "unknown constant"; 6019 } 6020 break; 6021 6022 default: 6023 return "unknown"; 6024 } 6025 6026 if(arg & WINED3DTA_COMPLEMENT) { 6027 shader_addline(buffer, "SUB arg%u, const.x, %s;\n", argnum, ret); 6028 if(argnum == 0) ret = "arg0"; 6029 if(argnum == 1) ret = "arg1"; 6030 if(argnum == 2) ret = "arg2"; 6031 } 6032 if(arg & WINED3DTA_ALPHAREPLICATE) { 6033 shader_addline(buffer, "MOV arg%u, %s.w;\n", argnum, ret); 6034 if(argnum == 0) ret = "arg0"; 6035 if(argnum == 1) ret = "arg1"; 6036 if(argnum == 2) ret = "arg2"; 6037 } 6038 return ret; 6039 } 6040 6041 static void gen_ffp_instr(struct wined3d_shader_buffer *buffer, unsigned int stage, BOOL color, 6042 BOOL alpha, DWORD dst, DWORD op, DWORD dw_arg0, DWORD dw_arg1, DWORD dw_arg2) 6043 { 6044 const char *dstmask, *dstreg, *arg0, *arg1, *arg2; 6045 unsigned int mul = 1; 6046 6047 if(color && alpha) dstmask = ""; 6048 else if(color) dstmask = ".xyz"; 6049 else dstmask = ".w"; 6050 6051 if(dst == tempreg) dstreg = "tempreg"; 6052 else dstreg = "ret"; 6053 6054 arg0 = get_argreg(buffer, 0, stage, dw_arg0); 6055 arg1 = get_argreg(buffer, 1, stage, dw_arg1); 6056 arg2 = get_argreg(buffer, 2, stage, dw_arg2); 6057 6058 switch (op) 6059 { 6060 case WINED3D_TOP_DISABLE: 6061 if (!stage) 6062 shader_addline(buffer, "MOV %s%s, fragment.color.primary;\n", dstreg, dstmask); 6063 break; 6064 6065 case WINED3D_TOP_SELECT_ARG2: 6066 arg1 = arg2; 6067 /* FALLTHROUGH */ 6068 case WINED3D_TOP_SELECT_ARG1: 6069 shader_addline(buffer, "MOV %s%s, %s;\n", dstreg, dstmask, arg1); 6070 break; 6071 6072 case WINED3D_TOP_MODULATE_4X: 6073 mul = 2; 6074 /* FALLTHROUGH */ 6075 case WINED3D_TOP_MODULATE_2X: 6076 mul *= 2; 6077 /* FALLTHROUGH */ 6078 case WINED3D_TOP_MODULATE: 6079 shader_addline(buffer, "MUL %s%s, %s, %s;\n", dstreg, dstmask, arg1, arg2); 6080 break; 6081 6082 case WINED3D_TOP_ADD_SIGNED_2X: 6083 mul = 2; 6084 /* FALLTHROUGH */ 6085 case WINED3D_TOP_ADD_SIGNED: 6086 shader_addline(buffer, "SUB arg2, %s, const.w;\n", arg2); 6087 arg2 = "arg2"; 6088 /* FALLTHROUGH */ 6089 case WINED3D_TOP_ADD: 6090 shader_addline(buffer, "ADD_SAT %s%s, %s, %s;\n", dstreg, dstmask, arg1, arg2); 6091 break; 6092 6093 case WINED3D_TOP_SUBTRACT: 6094 shader_addline(buffer, "SUB_SAT %s%s, %s, %s;\n", dstreg, dstmask, arg1, arg2); 6095 break; 6096 6097 case WINED3D_TOP_ADD_SMOOTH: 6098 shader_addline(buffer, "SUB arg1, const.x, %s;\n", arg1); 6099 shader_addline(buffer, "MAD_SAT %s%s, arg1, %s, %s;\n", dstreg, dstmask, arg2, arg1); 6100 break; 6101 6102 case WINED3D_TOP_BLEND_CURRENT_ALPHA: 6103 arg0 = get_argreg(buffer, 0, stage, WINED3DTA_CURRENT); 6104 shader_addline(buffer, "LRP %s%s, %s.w, %s, %s;\n", dstreg, dstmask, arg0, arg1, arg2); 6105 break; 6106 case WINED3D_TOP_BLEND_FACTOR_ALPHA: 6107 arg0 = get_argreg(buffer, 0, stage, WINED3DTA_TFACTOR); 6108 shader_addline(buffer, "LRP %s%s, %s.w, %s, %s;\n", dstreg, dstmask, arg0, arg1, arg2); 6109 break; 6110 case WINED3D_TOP_BLEND_TEXTURE_ALPHA: 6111 arg0 = get_argreg(buffer, 0, stage, WINED3DTA_TEXTURE); 6112 shader_addline(buffer, "LRP %s%s, %s.w, %s, %s;\n", dstreg, dstmask, arg0, arg1, arg2); 6113 break; 6114 case WINED3D_TOP_BLEND_DIFFUSE_ALPHA: 6115 arg0 = get_argreg(buffer, 0, stage, WINED3DTA_DIFFUSE); 6116 shader_addline(buffer, "LRP %s%s, %s.w, %s, %s;\n", dstreg, dstmask, arg0, arg1, arg2); 6117 break; 6118 6119 case WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM: 6120 arg0 = get_argreg(buffer, 0, stage, WINED3DTA_TEXTURE); 6121 shader_addline(buffer, "SUB arg0.w, const.x, %s.w;\n", arg0); 6122 shader_addline(buffer, "MAD_SAT %s%s, %s, arg0.w, %s;\n", dstreg, dstmask, arg2, arg1); 6123 break; 6124 6125 /* D3DTOP_PREMODULATE ???? */ 6126 6127 case WINED3D_TOP_MODULATE_INVALPHA_ADD_COLOR: 6128 shader_addline(buffer, "SUB arg0.w, const.x, %s;\n", arg1); 6129 shader_addline(buffer, "MAD_SAT %s%s, arg0.w, %s, %s;\n", dstreg, dstmask, arg2, arg1); 6130 break; 6131 case WINED3D_TOP_MODULATE_ALPHA_ADD_COLOR: 6132 shader_addline(buffer, "MAD_SAT %s%s, %s.w, %s, %s;\n", dstreg, dstmask, arg1, arg2, arg1); 6133 break; 6134 case WINED3D_TOP_MODULATE_INVCOLOR_ADD_ALPHA: 6135 shader_addline(buffer, "SUB arg0, const.x, %s;\n", arg1); 6136 shader_addline(buffer, "MAD_SAT %s%s, arg0, %s, %s.w;\n", dstreg, dstmask, arg2, arg1); 6137 break; 6138 case WINED3D_TOP_MODULATE_COLOR_ADD_ALPHA: 6139 shader_addline(buffer, "MAD_SAT %s%s, %s, %s, %s.w;\n", dstreg, dstmask, arg1, arg2, arg1); 6140 break; 6141 6142 case WINED3D_TOP_DOTPRODUCT3: 6143 mul = 4; 6144 shader_addline(buffer, "SUB arg1, %s, const.w;\n", arg1); 6145 shader_addline(buffer, "SUB arg2, %s, const.w;\n", arg2); 6146 shader_addline(buffer, "DP3_SAT %s%s, arg1, arg2;\n", dstreg, dstmask); 6147 break; 6148 6149 case WINED3D_TOP_MULTIPLY_ADD: 6150 shader_addline(buffer, "MAD_SAT %s%s, %s, %s, %s;\n", dstreg, dstmask, arg1, arg2, arg0); 6151 break; 6152 6153 case WINED3D_TOP_LERP: 6154 /* The msdn is not quite right here */ 6155 shader_addline(buffer, "LRP %s%s, %s, %s, %s;\n", dstreg, dstmask, arg0, arg1, arg2); 6156 break; 6157 6158 case WINED3D_TOP_BUMPENVMAP: 6159 case WINED3D_TOP_BUMPENVMAP_LUMINANCE: 6160 /* Those are handled in the first pass of the shader(generation pass 1 and 2) already */ 6161 break; 6162 6163 default: 6164 FIXME("Unhandled texture op %08x\n", op); 6165 } 6166 6167 if (mul == 2) 6168 shader_addline(buffer, "MUL_SAT %s%s, %s, const.y;\n", dstreg, dstmask, dstreg); 6169 else if (mul == 4) 6170 shader_addline(buffer, "MUL_SAT %s%s, %s, const.z;\n", dstreg, dstmask, dstreg); 6171 } 6172 6173 static GLuint gen_arbfp_ffp_shader(const struct ffp_frag_settings *settings, const struct wined3d_gl_info *gl_info) 6174 { 6175 unsigned int stage; 6176 struct wined3d_shader_buffer buffer; 6177 BOOL tex_read[MAX_TEXTURES] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; 6178 BOOL bump_used[MAX_TEXTURES] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; 6179 BOOL luminance_used[MAX_TEXTURES] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; 6180 UINT lowest_disabled_stage; 6181 const char *textype; 6182 const char *instr; 6183 char colorcor_dst[8]; 6184 GLuint ret; 6185 DWORD arg0, arg1, arg2; 6186 BOOL tempreg_used = FALSE, tfactor_used = FALSE; 6187 BOOL op_equal; 6188 const char *final_combiner_src = "ret"; 6189 GLint pos; 6190 BOOL custom_linear_fog = FALSE; 6191 6192 /* Find out which textures are read */ 6193 for (stage = 0; stage < MAX_TEXTURES; ++stage) 6194 { 6195 if (settings->op[stage].cop == WINED3D_TOP_DISABLE) 6196 break; 6197 arg0 = settings->op[stage].carg0 & WINED3DTA_SELECTMASK; 6198 arg1 = settings->op[stage].carg1 & WINED3DTA_SELECTMASK; 6199 arg2 = settings->op[stage].carg2 & WINED3DTA_SELECTMASK; 6200 if(arg0 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6201 if(arg1 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6202 if(arg2 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6203 6204 if (settings->op[stage].cop == WINED3D_TOP_BLEND_TEXTURE_ALPHA) 6205 tex_read[stage] = TRUE; 6206 if (settings->op[stage].cop == WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM) 6207 tex_read[stage] = TRUE; 6208 if (settings->op[stage].cop == WINED3D_TOP_BUMPENVMAP) 6209 { 6210 bump_used[stage] = TRUE; 6211 tex_read[stage] = TRUE; 6212 } 6213 if (settings->op[stage].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE) 6214 { 6215 bump_used[stage] = TRUE; 6216 tex_read[stage] = TRUE; 6217 luminance_used[stage] = TRUE; 6218 } 6219 else if (settings->op[stage].cop == WINED3D_TOP_BLEND_FACTOR_ALPHA) 6220 { 6221 tfactor_used = TRUE; 6222 } 6223 6224 if(arg0 == WINED3DTA_TFACTOR || arg1 == WINED3DTA_TFACTOR || arg2 == WINED3DTA_TFACTOR) { 6225 tfactor_used = TRUE; 6226 } 6227 6228 if(settings->op[stage].dst == tempreg) tempreg_used = TRUE; 6229 if(arg0 == WINED3DTA_TEMP || arg1 == WINED3DTA_TEMP || arg2 == WINED3DTA_TEMP) { 6230 tempreg_used = TRUE; 6231 } 6232 6233 if (settings->op[stage].aop == WINED3D_TOP_DISABLE) 6234 continue; 6235 arg0 = settings->op[stage].aarg0 & WINED3DTA_SELECTMASK; 6236 arg1 = settings->op[stage].aarg1 & WINED3DTA_SELECTMASK; 6237 arg2 = settings->op[stage].aarg2 & WINED3DTA_SELECTMASK; 6238 if(arg0 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6239 if(arg1 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6240 if(arg2 == WINED3DTA_TEXTURE) tex_read[stage] = TRUE; 6241 6242 if(arg0 == WINED3DTA_TEMP || arg1 == WINED3DTA_TEMP || arg2 == WINED3DTA_TEMP) { 6243 tempreg_used = TRUE; 6244 } 6245 if(arg0 == WINED3DTA_TFACTOR || arg1 == WINED3DTA_TFACTOR || arg2 == WINED3DTA_TFACTOR) { 6246 tfactor_used = TRUE; 6247 } 6248 } 6249 lowest_disabled_stage = stage; 6250 6251 /* Shader header */ 6252 if (!shader_buffer_init(&buffer)) 6253 { 6254 ERR("Failed to initialize shader buffer.\n"); 6255 return 0; 6256 } 6257 6258 shader_addline(&buffer, "!!ARBfp1.0\n"); 6259 6260 switch (settings->fog) 6261 { 6262 case WINED3D_FFP_PS_FOG_OFF: break; 6263 case WINED3D_FFP_PS_FOG_LINEAR: 6264 if (gl_info->quirks & WINED3D_QUIRK_BROKEN_ARB_FOG) 6265 { 6266 custom_linear_fog = TRUE; 6267 break; 6268 } 6269 shader_addline(&buffer, "OPTION ARB_fog_linear;\n"); 6270 break; 6271 6272 case WINED3D_FFP_PS_FOG_EXP: shader_addline(&buffer, "OPTION ARB_fog_exp;\n"); break; 6273 case WINED3D_FFP_PS_FOG_EXP2: shader_addline(&buffer, "OPTION ARB_fog_exp2;\n"); break; 6274 default: FIXME("Unexpected fog setting %d\n", settings->fog); 6275 } 6276 6277 shader_addline(&buffer, "PARAM const = {1, 2, 4, 0.5};\n"); 6278 shader_addline(&buffer, "TEMP TMP;\n"); 6279 shader_addline(&buffer, "TEMP ret;\n"); 6280 if(tempreg_used || settings->sRGB_write) shader_addline(&buffer, "TEMP tempreg;\n"); 6281 shader_addline(&buffer, "TEMP arg0;\n"); 6282 shader_addline(&buffer, "TEMP arg1;\n"); 6283 shader_addline(&buffer, "TEMP arg2;\n"); 6284 for(stage = 0; stage < MAX_TEXTURES; stage++) { 6285 if(!tex_read[stage]) continue; 6286 shader_addline(&buffer, "TEMP tex%u;\n", stage); 6287 if(!bump_used[stage]) continue; 6288 shader_addline(&buffer, "PARAM bumpmat%u = program.env[%u];\n", stage, ARB_FFP_CONST_BUMPMAT(stage)); 6289 if(!luminance_used[stage]) continue; 6290 shader_addline(&buffer, "PARAM luminance%u = program.env[%u];\n", stage, ARB_FFP_CONST_LUMINANCE(stage)); 6291 } 6292 if(tfactor_used) { 6293 shader_addline(&buffer, "PARAM tfactor = program.env[%u];\n", ARB_FFP_CONST_TFACTOR); 6294 } 6295 shader_addline(&buffer, "PARAM specular_enable = program.env[%u];\n", ARB_FFP_CONST_SPECULAR_ENABLE); 6296 6297 if (settings->sRGB_write) 6298 { 6299 shader_addline(&buffer, "PARAM srgb_consts0 = "); 6300 shader_arb_append_imm_vec4(&buffer, wined3d_srgb_const0); 6301 shader_addline(&buffer, ";\n"); 6302 shader_addline(&buffer, "PARAM srgb_consts1 = "); 6303 shader_arb_append_imm_vec4(&buffer, wined3d_srgb_const1); 6304 shader_addline(&buffer, ";\n"); 6305 } 6306 6307 if (lowest_disabled_stage < 7 && settings->emul_clipplanes) 6308 shader_addline(&buffer, "KIL fragment.texcoord[7];\n"); 6309 6310 /* Generate texture sampling instructions) */ 6311 for (stage = 0; stage < MAX_TEXTURES && settings->op[stage].cop != WINED3D_TOP_DISABLE; ++stage) 6312 { 6313 if (!tex_read[stage]) 6314 continue; 6315 6316 switch(settings->op[stage].tex_type) { 6317 case tex_1d: textype = "1D"; break; 6318 case tex_2d: textype = "2D"; break; 6319 case tex_3d: textype = "3D"; break; 6320 case tex_cube: textype = "CUBE"; break; 6321 case tex_rect: textype = "RECT"; break; 6322 default: textype = "unexpected_textype"; break; 6323 } 6324 6325 if(settings->op[stage].projected == proj_none) { 6326 instr = "TEX"; 6327 } else if(settings->op[stage].projected == proj_count4 || 6328 settings->op[stage].projected == proj_count3) { 6329 instr = "TXP"; 6330 } else { 6331 FIXME("Unexpected projection mode %d\n", settings->op[stage].projected); 6332 instr = "TXP"; 6333 } 6334 6335 if (stage > 0 6336 && (settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP 6337 || settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE)) 6338 { 6339 shader_addline(&buffer, "SWZ arg1, bumpmat%u, x, z, 0, 0;\n", stage - 1); 6340 shader_addline(&buffer, "DP3 ret.x, arg1, tex%u;\n", stage - 1); 6341 shader_addline(&buffer, "SWZ arg1, bumpmat%u, y, w, 0, 0;\n", stage - 1); 6342 shader_addline(&buffer, "DP3 ret.y, arg1, tex%u;\n", stage - 1); 6343 6344 /* with projective textures, texbem only divides the static texture coord, not the displacement, 6345 * so multiply the displacement with the dividing parameter before passing it to TXP 6346 */ 6347 if (settings->op[stage].projected != proj_none) { 6348 if(settings->op[stage].projected == proj_count4) { 6349 shader_addline(&buffer, "MOV ret.w, fragment.texcoord[%u].w;\n", stage); 6350 shader_addline(&buffer, "MUL ret.xyz, ret, fragment.texcoord[%u].w, fragment.texcoord[%u];\n", stage, stage); 6351 } else { 6352 shader_addline(&buffer, "MOV ret.w, fragment.texcoord[%u].z;\n", stage); 6353 shader_addline(&buffer, "MAD ret.xyz, ret, fragment.texcoord[%u].z, fragment.texcoord[%u];\n", stage, stage); 6354 } 6355 } else { 6356 shader_addline(&buffer, "ADD ret, ret, fragment.texcoord[%u];\n", stage); 6357 } 6358 6359 shader_addline(&buffer, "%s tex%u, ret, texture[%u], %s;\n", 6360 instr, stage, stage, textype); 6361 if (settings->op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE) 6362 { 6363 shader_addline(&buffer, "MAD_SAT ret.x, tex%u.z, luminance%u.x, luminance%u.y;\n", 6364 stage - 1, stage - 1, stage - 1); 6365 shader_addline(&buffer, "MUL tex%u, tex%u, ret.x;\n", stage, stage); 6366 } 6367 } else if(settings->op[stage].projected == proj_count3) { 6368 shader_addline(&buffer, "MOV ret, fragment.texcoord[%u];\n", stage); 6369 shader_addline(&buffer, "MOV ret.w, ret.z;\n"); 6370 shader_addline(&buffer, "%s tex%u, ret, texture[%u], %s;\n", 6371 instr, stage, stage, textype); 6372 } else { 6373 shader_addline(&buffer, "%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n", 6374 instr, stage, stage, stage, textype); 6375 } 6376 6377 sprintf(colorcor_dst, "tex%u", stage); 6378 gen_color_correction(&buffer, colorcor_dst, WINED3DSP_WRITEMASK_ALL, "const.x", "const.y", 6379 settings->op[stage].color_fixup); 6380 } 6381 6382 /* Generate the main shader */ 6383 for (stage = 0; stage < MAX_TEXTURES; ++stage) 6384 { 6385 if (settings->op[stage].cop == WINED3D_TOP_DISABLE) 6386 { 6387 if (!stage) 6388 final_combiner_src = "fragment.color.primary"; 6389 break; 6390 } 6391 6392 if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG1 6393 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG1) 6394 op_equal = settings->op[stage].carg1 == settings->op[stage].aarg1; 6395 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG1 6396 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG2) 6397 op_equal = settings->op[stage].carg1 == settings->op[stage].aarg2; 6398 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG2 6399 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG1) 6400 op_equal = settings->op[stage].carg2 == settings->op[stage].aarg1; 6401 else if (settings->op[stage].cop == WINED3D_TOP_SELECT_ARG2 6402 && settings->op[stage].aop == WINED3D_TOP_SELECT_ARG2) 6403 op_equal = settings->op[stage].carg2 == settings->op[stage].aarg2; 6404 else 6405 op_equal = settings->op[stage].aop == settings->op[stage].cop 6406 && settings->op[stage].carg0 == settings->op[stage].aarg0 6407 && settings->op[stage].carg1 == settings->op[stage].aarg1 6408 && settings->op[stage].carg2 == settings->op[stage].aarg2; 6409 6410 if (settings->op[stage].aop == WINED3D_TOP_DISABLE) 6411 { 6412 gen_ffp_instr(&buffer, stage, TRUE, FALSE, settings->op[stage].dst, 6413 settings->op[stage].cop, settings->op[stage].carg0, 6414 settings->op[stage].carg1, settings->op[stage].carg2); 6415 if (!stage) 6416 shader_addline(&buffer, "MOV ret.w, fragment.color.primary.w;\n"); 6417 } 6418 else if (op_equal) 6419 { 6420 gen_ffp_instr(&buffer, stage, TRUE, TRUE, settings->op[stage].dst, 6421 settings->op[stage].cop, settings->op[stage].carg0, 6422 settings->op[stage].carg1, settings->op[stage].carg2); 6423 } else { 6424 gen_ffp_instr(&buffer, stage, TRUE, FALSE, settings->op[stage].dst, 6425 settings->op[stage].cop, settings->op[stage].carg0, 6426 settings->op[stage].carg1, settings->op[stage].carg2); 6427 gen_ffp_instr(&buffer, stage, FALSE, TRUE, settings->op[stage].dst, 6428 settings->op[stage].aop, settings->op[stage].aarg0, 6429 settings->op[stage].aarg1, settings->op[stage].aarg2); 6430 } 6431 } 6432 6433 if (settings->sRGB_write || custom_linear_fog) 6434 { 6435 shader_addline(&buffer, "MAD ret, fragment.color.secondary, specular_enable, %s;\n", final_combiner_src); 6436 if (settings->sRGB_write) 6437 arbfp_add_sRGB_correction(&buffer, "ret", "arg0", "arg1", "arg2", "tempreg", FALSE); 6438 if (custom_linear_fog) 6439 arbfp_add_linear_fog(&buffer, "ret", "arg0"); 6440 shader_addline(&buffer, "MOV result.color, ret;\n"); 6441 } 6442 else 6443 { 6444 shader_addline(&buffer, "MAD result.color, fragment.color.secondary, specular_enable, %s;\n", 6445 final_combiner_src); 6446 } 6447 6448 /* Footer */ 6449 shader_addline(&buffer, "END\n"); 6450 6451 /* Generate the shader */ 6452 GL_EXTCALL(glGenProgramsARB(1, &ret)); 6453 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret)); 6454 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 6455 strlen(buffer.buffer), buffer.buffer)); 6456 checkGLcall("glProgramStringARB()"); 6457 6458 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); 6459 if (pos != -1) 6460 { 6461 FIXME("Fragment program error at position %d: %s\n\n", pos, 6462 debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 6463 shader_arb_dump_program_source(buffer.buffer); 6464 } 6465 else 6466 { 6467 GLint native; 6468 6469 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 6470 checkGLcall("glGetProgramivARB()"); 6471 if (!native) WARN("Program exceeds native resource limits.\n"); 6472 } 6473 6474 shader_buffer_free(&buffer); 6475 return ret; 6476 } 6477 6478 static void fragment_prog_arbfp(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) 6479 { 6480 const struct wined3d_device *device = context->swapchain->device; 6481 const struct wined3d_gl_info *gl_info = context->gl_info; 6482 struct shader_arb_priv *priv = device->fragment_priv; 6483 BOOL use_pshader = use_ps(state); 6484 struct ffp_frag_settings settings; 6485 const struct arbfp_ffp_desc *desc; 6486 unsigned int i; 6487 6488 TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); 6489 6490 if (isStateDirty(context, STATE_RENDER(WINED3D_RS_FOGENABLE))) 6491 { 6492 if (!use_pshader && device->shader_backend == &arb_program_shader_backend && context->last_was_pshader) 6493 { 6494 /* Reload fixed function constants since they collide with the 6495 * pixel shader constants. */ 6496 for (i = 0; i < MAX_TEXTURES; ++i) 6497 { 6498 set_bumpmat_arbfp(context, state, STATE_TEXTURESTAGE(i, WINED3D_TSS_BUMPENV_MAT00)); 6499 } 6500 state_texfactor_arbfp(context, state, STATE_RENDER(WINED3D_RS_TEXTUREFACTOR)); 6501 state_arb_specularenable(context, state, STATE_RENDER(WINED3D_RS_SPECULARENABLE)); 6502 } 6503 else if (use_pshader) 6504 { 6505 context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; 6506 } 6507 return; 6508 } 6509 6510 if (!use_pshader) 6511 { 6512 /* Find or create a shader implementing the fixed function pipeline 6513 * settings, then activate it. */ 6514 gen_ffp_frag_op(context, state, &settings, FALSE); 6515 desc = (const struct arbfp_ffp_desc *)find_ffp_frag_shader(&priv->fragment_shaders, &settings); 6516 if(!desc) { 6517 struct arbfp_ffp_desc *new_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_desc)); 6518 if (!new_desc) 6519 { 6520 ERR("Out of memory\n"); 6521 return; 6522 } 6523 6524 new_desc->parent.settings = settings; 6525 new_desc->shader = gen_arbfp_ffp_shader(&settings, gl_info); 6526 add_ffp_frag_shader(&priv->fragment_shaders, &new_desc->parent); 6527 TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc); 6528 desc = new_desc; 6529 } 6530 6531 /* Now activate the replacement program. GL_FRAGMENT_PROGRAM_ARB is already active (however, note the 6532 * comment above the shader_select call below). If e.g. GLSL is active, the shader_select call will 6533 * deactivate it. 6534 */ 6535 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, desc->shader)); 6536 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, desc->shader)"); 6537 priv->current_fprogram_id = desc->shader; 6538 6539 if (device->shader_backend == &arb_program_shader_backend && context->last_was_pshader) 6540 { 6541 /* Reload fixed function constants since they collide with the 6542 * pixel shader constants. */ 6543 for (i = 0; i < MAX_TEXTURES; ++i) 6544 { 6545 set_bumpmat_arbfp(context, state, STATE_TEXTURESTAGE(i, WINED3D_TSS_BUMPENV_MAT00)); 6546 } 6547 state_texfactor_arbfp(context, state, STATE_RENDER(WINED3D_RS_TEXTUREFACTOR)); 6548 state_arb_specularenable(context, state, STATE_RENDER(WINED3D_RS_SPECULARENABLE)); 6549 } 6550 context->last_was_pshader = FALSE; 6551 } else { 6552 context->last_was_pshader = TRUE; 6553 } 6554 6555 context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; 6556 } 6557 6558 /* We can't link the fog states to the fragment state directly since the 6559 * vertex pipeline links them to FOGENABLE. A different linking in different 6560 * pipeline parts can't be expressed in the combined state table, so we need 6561 * to handle that with a forwarding function. The other invisible side effect 6562 * is that changing the fog start and fog end (which links to FOGENABLE in 6563 * vertex) results in the fragment_prog_arbfp function being called because 6564 * FOGENABLE is dirty, which calls this function here. */ 6565 static void state_arbfp_fog(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) 6566 { 6567 enum fogsource new_source; 6568 DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; 6569 DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; 6570 6571 TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); 6572 6573 if (!isStateDirty(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL))) 6574 fragment_prog_arbfp(context, state, state_id); 6575 6576 if (!state->render_states[WINED3D_RS_FOGENABLE]) 6577 return; 6578 6579 if (state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE) 6580 { 6581 if (use_vs(state)) 6582 { 6583 new_source = FOGSOURCE_VS; 6584 } 6585 else 6586 { 6587 if (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE || context->last_was_rhw) 6588 new_source = FOGSOURCE_COORD; 6589 else 6590 new_source = FOGSOURCE_FFP; 6591 } 6592 } 6593 else 6594 { 6595 new_source = FOGSOURCE_FFP; 6596 } 6597 6598 if (new_source != context->fog_source || fogstart == fogend) 6599 { 6600 context->fog_source = new_source; 6601 state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART)); 6602 } 6603 } 6604 6605 static void textransform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) 6606 { 6607 if (!isStateDirty(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL))) 6608 fragment_prog_arbfp(context, state, state_id); 6609 } 6610 6611 static const struct StateEntryTemplate arbfp_fragmentstate_template[] = 6612 { 6613 {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), { STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), state_texfactor_arbfp }, WINED3D_GL_EXT_NONE }, 6614 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6615 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6616 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6617 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6618 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6619 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6620 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6621 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6622 {STATE_TEXTURESTAGE(0, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6623 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6624 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6625 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6626 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6627 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6628 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6629 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6630 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6631 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6632 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6633 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6634 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6635 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6636 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6637 {STATE_TEXTURESTAGE(1, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6638 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6639 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6640 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6641 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6642 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6643 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6644 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6645 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6646 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6647 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6648 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6649 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6650 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6651 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6652 {STATE_TEXTURESTAGE(2, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6653 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6654 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6655 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6656 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6657 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6658 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6659 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6660 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6661 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6662 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6663 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6664 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6665 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6666 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6667 {STATE_TEXTURESTAGE(3, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6668 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6669 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6670 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6671 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6672 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6673 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6674 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6675 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6676 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6677 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6678 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6679 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6680 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6681 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6682 {STATE_TEXTURESTAGE(4, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6683 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6684 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6685 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6686 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6687 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6688 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6689 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6690 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6691 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6692 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6693 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6694 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6695 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6696 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6697 {STATE_TEXTURESTAGE(5, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6698 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6699 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6700 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6701 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6702 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6703 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6704 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6705 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6706 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6707 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6708 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6709 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6710 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6711 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6712 {STATE_TEXTURESTAGE(6, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6713 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6714 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6715 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6716 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6717 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6718 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6719 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6720 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6721 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6722 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6723 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_OP), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6724 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG1), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6725 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG2), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6726 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG0), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6727 {STATE_TEXTURESTAGE(7, WINED3D_TSS_RESULT_ARG), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6728 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat_arbfp }, WINED3D_GL_EXT_NONE }, 6729 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6730 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6731 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE }, 6732 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE), tex_bumpenvlum_arbfp }, WINED3D_GL_EXT_NONE }, 6733 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE), NULL }, WINED3D_GL_EXT_NONE }, 6734 {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), fragment_prog_arbfp }, WINED3D_GL_EXT_NONE }, 6735 {STATE_RENDER(WINED3D_RS_FOGENABLE), { STATE_RENDER(WINED3D_RS_FOGENABLE), state_arbfp_fog }, WINED3D_GL_EXT_NONE }, 6736 {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), { STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, 6737 {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), { STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, 6738 {STATE_RENDER(WINED3D_RS_FOGSTART), { STATE_RENDER(WINED3D_RS_FOGSTART), state_fogstartend }, WINED3D_GL_EXT_NONE }, 6739 {STATE_RENDER(WINED3D_RS_FOGEND), { STATE_RENDER(WINED3D_RS_FOGSTART), NULL }, WINED3D_GL_EXT_NONE }, 6740 {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), { STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), state_srgbwrite }, ARB_FRAMEBUFFER_SRGB }, 6741 {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), { STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, 6742 {STATE_RENDER(WINED3D_RS_FOGCOLOR), { STATE_RENDER(WINED3D_RS_FOGCOLOR), state_fogcolor }, WINED3D_GL_EXT_NONE }, 6743 {STATE_RENDER(WINED3D_RS_FOGDENSITY), { STATE_RENDER(WINED3D_RS_FOGDENSITY), state_fogdensity }, WINED3D_GL_EXT_NONE }, 6744 {STATE_TEXTURESTAGE(0,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6745 {STATE_TEXTURESTAGE(1,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6746 {STATE_TEXTURESTAGE(2,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6747 {STATE_TEXTURESTAGE(3,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6748 {STATE_TEXTURESTAGE(4,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6749 {STATE_TEXTURESTAGE(5,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6750 {STATE_TEXTURESTAGE(6,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6751 {STATE_TEXTURESTAGE(7,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE }, 6752 {STATE_RENDER(WINED3D_RS_SPECULARENABLE), { STATE_RENDER(WINED3D_RS_SPECULARENABLE), state_arb_specularenable}, WINED3D_GL_EXT_NONE }, 6753 {0 /* Terminate */, { 0, 0 }, WINED3D_GL_EXT_NONE }, 6754 }; 6755 6756 const struct fragment_pipeline arbfp_fragment_pipeline = { 6757 arbfp_enable, 6758 arbfp_get_caps, 6759 arbfp_alloc, 6760 arbfp_free, 6761 shader_arb_color_fixup_supported, 6762 arbfp_fragmentstate_template, 6763 }; 6764 6765 struct arbfp_blit_priv { 6766 GLenum yuy2_rect_shader, yuy2_2d_shader; 6767 GLenum uyvy_rect_shader, uyvy_2d_shader; 6768 GLenum yv12_rect_shader, yv12_2d_shader; 6769 GLenum p8_rect_shader, p8_2d_shader; 6770 GLuint palette_texture; 6771 }; 6772 6773 static HRESULT arbfp_blit_alloc(struct wined3d_device *device) 6774 { 6775 device->blit_priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct arbfp_blit_priv)); 6776 if(!device->blit_priv) { 6777 ERR("Out of memory\n"); 6778 return E_OUTOFMEMORY; 6779 } 6780 return WINED3D_OK; 6781 } 6782 6783 /* Context activation is done by the caller. */ 6784 static void arbfp_blit_free(struct wined3d_device *device) 6785 { 6786 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 6787 struct arbfp_blit_priv *priv = device->blit_priv; 6788 6789 GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_rect_shader)); 6790 GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_2d_shader)); 6791 GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_rect_shader)); 6792 GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_2d_shader)); 6793 GL_EXTCALL(glDeleteProgramsARB(1, &priv->yv12_rect_shader)); 6794 GL_EXTCALL(glDeleteProgramsARB(1, &priv->yv12_2d_shader)); 6795 GL_EXTCALL(glDeleteProgramsARB(1, &priv->p8_rect_shader)); 6796 GL_EXTCALL(glDeleteProgramsARB(1, &priv->p8_2d_shader)); 6797 checkGLcall("Delete yuv and p8 programs"); 6798 6799 if (priv->palette_texture) 6800 gl_info->gl_ops.gl.p_glDeleteTextures(1, &priv->palette_texture); 6801 6802 HeapFree(GetProcessHeap(), 0, device->blit_priv); 6803 device->blit_priv = NULL; 6804 } 6805 6806 static BOOL gen_planar_yuv_read(struct wined3d_shader_buffer *buffer, enum complex_fixup fixup, 6807 GLenum textype, char *luminance) 6808 { 6809 char chroma; 6810 const char *tex, *texinstr; 6811 6812 if (fixup == COMPLEX_FIXUP_UYVY) { 6813 chroma = 'x'; 6814 *luminance = 'w'; 6815 } else { 6816 chroma = 'w'; 6817 *luminance = 'x'; 6818 } 6819 switch(textype) { 6820 case GL_TEXTURE_2D: tex = "2D"; texinstr = "TXP"; break; 6821 case GL_TEXTURE_RECTANGLE_ARB: tex = "RECT"; texinstr = "TEX"; break; 6822 default: 6823 /* This is more tricky than just replacing the texture type - we have to navigate 6824 * properly in the texture to find the correct chroma values 6825 */ 6826 FIXME("Implement yuv correction for non-2d, non-rect textures\n"); 6827 return FALSE; 6828 } 6829 6830 /* First we have to read the chroma values. This means we need at least two pixels(no filtering), 6831 * or 4 pixels(with filtering). To get the unmodified chromas, we have to rid ourselves of the 6832 * filtering when we sample the texture. 6833 * 6834 * These are the rules for reading the chroma: 6835 * 6836 * Even pixel: Cr 6837 * Even pixel: U 6838 * Odd pixel: V 6839 * 6840 * So we have to get the sampling x position in non-normalized coordinates in integers 6841 */ 6842 if(textype != GL_TEXTURE_RECTANGLE_ARB) { 6843 shader_addline(buffer, "MUL texcrd.xy, fragment.texcoord[0], size.x;\n"); 6844 shader_addline(buffer, "MOV texcrd.w, size.x;\n"); 6845 } else { 6846 shader_addline(buffer, "MOV texcrd, fragment.texcoord[0];\n"); 6847 } 6848 /* We must not allow filtering between pixel x and x+1, this would mix U and V 6849 * Vertical filtering is ok. However, bear in mind that the pixel center is at 6850 * 0.5, so add 0.5. 6851 */ 6852 shader_addline(buffer, "FLR texcrd.x, texcrd.x;\n"); 6853 shader_addline(buffer, "ADD texcrd.x, texcrd.x, coef.y;\n"); 6854 6855 /* Divide the x coordinate by 0.5 and get the fraction. This gives 0.25 and 0.75 for the 6856 * even and odd pixels respectively 6857 */ 6858 shader_addline(buffer, "MUL texcrd2, texcrd, coef.y;\n"); 6859 shader_addline(buffer, "FRC texcrd2, texcrd2;\n"); 6860 6861 /* Sample Pixel 1 */ 6862 shader_addline(buffer, "%s luminance, texcrd, texture[0], %s;\n", texinstr, tex); 6863 6864 /* Put the value into either of the chroma values */ 6865 shader_addline(buffer, "SGE temp.x, texcrd2.x, coef.y;\n"); 6866 shader_addline(buffer, "MUL chroma.x, luminance.%c, temp.x;\n", chroma); 6867 shader_addline(buffer, "SLT temp.x, texcrd2.x, coef.y;\n"); 6868 shader_addline(buffer, "MUL chroma.y, luminance.%c, temp.x;\n", chroma); 6869 6870 /* Sample pixel 2. If we read an even pixel(SLT above returned 1), sample 6871 * the pixel right to the current one. Otherwise, sample the left pixel. 6872 * Bias and scale the SLT result to -1;1 and add it to the texcrd.x. 6873 */ 6874 shader_addline(buffer, "MAD temp.x, temp.x, coef.z, -coef.x;\n"); 6875 shader_addline(buffer, "ADD texcrd.x, texcrd, temp.x;\n"); 6876 shader_addline(buffer, "%s luminance, texcrd, texture[0], %s;\n", texinstr, tex); 6877 6878 /* Put the value into the other chroma */ 6879 shader_addline(buffer, "SGE temp.x, texcrd2.x, coef.y;\n"); 6880 shader_addline(buffer, "MAD chroma.y, luminance.%c, temp.x, chroma.y;\n", chroma); 6881 shader_addline(buffer, "SLT temp.x, texcrd2.x, coef.y;\n"); 6882 shader_addline(buffer, "MAD chroma.x, luminance.%c, temp.x, chroma.x;\n", chroma); 6883 6884 /* TODO: If filtering is enabled, sample a 2nd pair of pixels left or right of 6885 * the current one and lerp the two U and V values 6886 */ 6887 6888 /* This gives the correctly filtered luminance value */ 6889 shader_addline(buffer, "TEX luminance, fragment.texcoord[0], texture[0], %s;\n", tex); 6890 6891 return TRUE; 6892 } 6893 6894 static BOOL gen_yv12_read(struct wined3d_shader_buffer *buffer, GLenum textype, char *luminance) 6895 { 6896 const char *tex; 6897 static const float yv12_coef[] 6898 = {2.0f / 3.0f, 1.0f / 6.0f, (2.0f / 3.0f) + (1.0f / 6.0f), 1.0f / 3.0f}; 6899 6900 switch(textype) { 6901 case GL_TEXTURE_2D: tex = "2D"; break; 6902 case GL_TEXTURE_RECTANGLE_ARB: tex = "RECT"; break; 6903 default: 6904 FIXME("Implement yv12 correction for non-2d, non-rect textures\n"); 6905 return FALSE; 6906 } 6907 6908 /* YV12 surfaces contain a WxH sized luminance plane, followed by a (W/2)x(H/2) 6909 * V and a (W/2)x(H/2) U plane, each with 8 bit per pixel. So the effective 6910 * bitdepth is 12 bits per pixel. Since the U and V planes have only half the 6911 * pitch of the luminance plane, the packing into the gl texture is a bit 6912 * unfortunate. If the whole texture is interpreted as luminance data it looks 6913 * approximately like this: 6914 * 6915 * +----------------------------------+---- 6916 * | | 6917 * | | 6918 * | | 6919 * | | 6920 * | | 2 6921 * | LUMINANCE | - 6922 * | | 3 6923 * | | 6924 * | | 6925 * | | 6926 * | | 6927 * +----------------+-----------------+---- 6928 * | | | 6929 * | U even rows | U odd rows | 6930 * | | | 1 6931 * +----------------+------------------ - 6932 * | | | 3 6933 * | V even rows | V odd rows | 6934 * | | | 6935 * +----------------+-----------------+---- 6936 * | | | 6937 * | 0.5 | 0.5 | 6938 * 6939 * So it appears as if there are 4 chroma images, but in fact the odd rows 6940 * in the chroma images are in the same row as the even ones. So its is 6941 * kinda tricky to read 6942 * 6943 * When reading from rectangle textures, keep in mind that the input y coordinates 6944 * go from 0 to d3d_height, whereas the opengl texture height is 1.5 * d3d_height 6945 */ 6946 shader_addline(buffer, "PARAM yv12_coef = "); 6947 shader_arb_append_imm_vec4(buffer, yv12_coef); 6948 shader_addline(buffer, ";\n"); 6949 6950 shader_addline(buffer, "MOV texcrd, fragment.texcoord[0];\n"); 6951 /* the chroma planes have only half the width */ 6952 shader_addline(buffer, "MUL texcrd.x, texcrd.x, coef.y;\n"); 6953 6954 /* The first value is between 2/3 and 5/6th of the texture's height, so scale+bias 6955 * the coordinate. Also read the right side of the image when reading odd lines 6956 * 6957 * Don't forget to clamp the y values in into the range, otherwise we'll get filtering 6958 * bleeding 6959 */ 6960 if(textype == GL_TEXTURE_2D) { 6961 6962 shader_addline(buffer, "RCP chroma.w, size.y;\n"); 6963 6964 shader_addline(buffer, "MUL texcrd2.y, texcrd.y, size.y;\n"); 6965 6966 shader_addline(buffer, "FLR texcrd2.y, texcrd2.y;\n"); 6967 shader_addline(buffer, "MAD texcrd.y, texcrd.y, yv12_coef.y, yv12_coef.x;\n"); 6968 6969 /* Read odd lines from the right side(add size * 0.5 to the x coordinate */ 6970 shader_addline(buffer, "ADD texcrd2.x, texcrd2.y, yv12_coef.y;\n"); /* To avoid 0.5 == 0.5 comparisons */ 6971 shader_addline(buffer, "FRC texcrd2.x, texcrd2.x;\n"); 6972 shader_addline(buffer, "SGE texcrd2.x, texcrd2.x, coef.y;\n"); 6973 shader_addline(buffer, "MAD texcrd.x, texcrd2.x, coef.y, texcrd.x;\n"); 6974 6975 /* clamp, keep the half pixel origin in mind */ 6976 shader_addline(buffer, "MAD temp.y, coef.y, chroma.w, yv12_coef.x;\n"); 6977 shader_addline(buffer, "MAX texcrd.y, temp.y, texcrd.y;\n"); 6978 shader_addline(buffer, "MAD temp.y, -coef.y, chroma.w, yv12_coef.z;\n"); 6979 shader_addline(buffer, "MIN texcrd.y, temp.y, texcrd.y;\n"); 6980 } else { 6981 /* Read from [size - size+size/4] */ 6982 shader_addline(buffer, "FLR texcrd.y, texcrd.y;\n"); 6983 shader_addline(buffer, "MAD texcrd.y, texcrd.y, coef.w, size.y;\n"); 6984 6985 /* Read odd lines from the right side(add size * 0.5 to the x coordinate */ 6986 shader_addline(buffer, "ADD texcrd2.x, texcrd.y, yv12_coef.y;\n"); /* To avoid 0.5 == 0.5 comparisons */ 6987 shader_addline(buffer, "FRC texcrd2.x, texcrd2.x;\n"); 6988 shader_addline(buffer, "SGE texcrd2.x, texcrd2.x, coef.y;\n"); 6989 shader_addline(buffer, "MUL texcrd2.x, texcrd2.x, size.x;\n"); 6990 shader_addline(buffer, "MAD texcrd.x, texcrd2.x, coef.y, texcrd.x;\n"); 6991 6992 /* Make sure to read exactly from the pixel center */ 6993 shader_addline(buffer, "FLR texcrd.y, texcrd.y;\n"); 6994 shader_addline(buffer, "ADD texcrd.y, texcrd.y, coef.y;\n"); 6995 6996 /* Clamp */ 6997 shader_addline(buffer, "MAD temp.y, size.y, coef.w, size.y;\n"); 6998 shader_addline(buffer, "ADD temp.y, temp.y, -coef.y;\n"); 6999 shader_addline(buffer, "MIN texcrd.y, temp.y, texcrd.y;\n"); 7000 shader_addline(buffer, "ADD temp.y, size.y, -coef.y;\n"); 7001 shader_addline(buffer, "MAX texcrd.y, temp.y, texcrd.y;\n"); 7002 } 7003 /* Read the texture, put the result into the output register */ 7004 shader_addline(buffer, "TEX temp, texcrd, texture[0], %s;\n", tex); 7005 shader_addline(buffer, "MOV chroma.x, temp.w;\n"); 7006 7007 /* The other chroma value is 1/6th of the texture lower, from 5/6th to 6/6th 7008 * No need to clamp because we're just reusing the already clamped value from above 7009 */ 7010 if(textype == GL_TEXTURE_2D) { 7011 shader_addline(buffer, "ADD texcrd.y, texcrd.y, yv12_coef.y;\n"); 7012 } else { 7013 shader_addline(buffer, "MAD texcrd.y, size.y, coef.w, texcrd.y;\n"); 7014 } 7015 shader_addline(buffer, "TEX temp, texcrd, texture[0], %s;\n", tex); 7016 shader_addline(buffer, "MOV chroma.y, temp.w;\n"); 7017 7018 /* Sample the luminance value. It is in the top 2/3rd of the texture, so scale the y coordinate. 7019 * Clamp the y coordinate to prevent the chroma values from bleeding into the sampled luminance 7020 * values due to filtering 7021 */ 7022 shader_addline(buffer, "MOV texcrd, fragment.texcoord[0];\n"); 7023 if(textype == GL_TEXTURE_2D) { 7024 /* Multiply the y coordinate by 2/3 and clamp it */ 7025 shader_addline(buffer, "MUL texcrd.y, texcrd.y, yv12_coef.x;\n"); 7026 shader_addline(buffer, "MAD temp.y, -coef.y, chroma.w, yv12_coef.x;\n"); 7027 shader_addline(buffer, "MIN texcrd.y, temp.y, texcrd.y;\n"); 7028 shader_addline(buffer, "TEX luminance, texcrd, texture[0], %s;\n", tex); 7029 } else { 7030 /* Reading from texture_rectangles is pretty straightforward, just use the unmodified 7031 * texture coordinate. It is still a good idea to clamp it though, since the opengl texture 7032 * is bigger 7033 */ 7034 shader_addline(buffer, "ADD temp.x, size.y, -coef.y;\n"); 7035 shader_addline(buffer, "MIN texcrd.y, texcrd.y, size.x;\n"); 7036 shader_addline(buffer, "TEX luminance, texcrd, texture[0], %s;\n", tex); 7037 } 7038 *luminance = 'a'; 7039 7040 return TRUE; 7041 } 7042 7043 static GLuint gen_p8_shader(struct arbfp_blit_priv *priv, 7044 const struct wined3d_gl_info *gl_info, GLenum textype) 7045 { 7046 GLenum shader; 7047 struct wined3d_shader_buffer buffer; 7048 GLint pos; 7049 7050 /* Shader header */ 7051 if (!shader_buffer_init(&buffer)) 7052 { 7053 ERR("Failed to initialize shader buffer.\n"); 7054 return 0; 7055 } 7056 7057 GL_EXTCALL(glGenProgramsARB(1, &shader)); 7058 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)); 7059 if (!shader) 7060 { 7061 shader_buffer_free(&buffer); 7062 return 0; 7063 } 7064 7065 shader_addline(&buffer, "!!ARBfp1.0\n"); 7066 shader_addline(&buffer, "TEMP index;\n"); 7067 7068 /* { 255/256, 0.5/255*255/256, 0, 0 } */ 7069 shader_addline(&buffer, "PARAM constants = { 0.996, 0.00195, 0, 0 };\n"); 7070 7071 /* The alpha-component contains the palette index */ 7072 if(textype == GL_TEXTURE_RECTANGLE_ARB) 7073 shader_addline(&buffer, "TXP index, fragment.texcoord[0], texture[0], RECT;\n"); 7074 else 7075 shader_addline(&buffer, "TEX index, fragment.texcoord[0], texture[0], 2D;\n"); 7076 7077 /* Scale the index by 255/256 and add a bias of '0.5' in order to sample in the middle */ 7078 shader_addline(&buffer, "MAD index.a, index.a, constants.x, constants.y;\n"); 7079 7080 /* Use the alpha-component as an index in the palette to get the final color */ 7081 shader_addline(&buffer, "TEX result.color, index.a, texture[1], 1D;\n"); 7082 shader_addline(&buffer, "END\n"); 7083 7084 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 7085 strlen(buffer.buffer), buffer.buffer)); 7086 checkGLcall("glProgramStringARB()"); 7087 7088 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); 7089 if (pos != -1) 7090 { 7091 FIXME("Fragment program error at position %d: %s\n\n", pos, 7092 debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 7093 shader_arb_dump_program_source(buffer.buffer); 7094 } 7095 7096 if (textype == GL_TEXTURE_RECTANGLE_ARB) 7097 priv->p8_rect_shader = shader; 7098 else 7099 priv->p8_2d_shader = shader; 7100 7101 shader_buffer_free(&buffer); 7102 7103 return shader; 7104 } 7105 7106 /* Context activation is done by the caller. */ 7107 static void upload_palette(const struct wined3d_surface *surface, struct wined3d_context *context) 7108 { 7109 BYTE table[256][4]; 7110 struct wined3d_device *device = surface->resource.device; 7111 const struct wined3d_gl_info *gl_info = context->gl_info; 7112 struct arbfp_blit_priv *priv = device->blit_priv; 7113 BOOL colorkey = !!(surface->container->color_key_flags & WINEDDSD_CKSRCBLT); 7114 7115 d3dfmt_p8_init_palette(surface, table, colorkey); 7116 7117 if (!priv->palette_texture) 7118 gl_info->gl_ops.gl.p_glGenTextures(1, &priv->palette_texture); 7119 7120 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1)); 7121 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, priv->palette_texture); 7122 7123 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 7124 7125 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 7126 /* Make sure we have discrete color levels. */ 7127 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 7128 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 7129 /* Upload the palette */ 7130 /* TODO: avoid unneeded uploads in the future by adding some SFLAG_PALETTE_DIRTY mechanism */ 7131 gl_info->gl_ops.gl.p_glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, table); 7132 7133 /* Switch back to unit 0 in which the 2D texture will be stored. */ 7134 context_active_texture(context, gl_info, 0); 7135 } 7136 7137 /* Context activation is done by the caller. */ 7138 static GLuint gen_yuv_shader(struct arbfp_blit_priv *priv, const struct wined3d_gl_info *gl_info, 7139 enum complex_fixup yuv_fixup, GLenum textype) 7140 { 7141 GLenum shader; 7142 struct wined3d_shader_buffer buffer; 7143 char luminance_component; 7144 GLint pos; 7145 7146 /* Shader header */ 7147 if (!shader_buffer_init(&buffer)) 7148 { 7149 ERR("Failed to initialize shader buffer.\n"); 7150 return 0; 7151 } 7152 7153 GL_EXTCALL(glGenProgramsARB(1, &shader)); 7154 checkGLcall("GL_EXTCALL(glGenProgramsARB(1, &shader))"); 7155 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)); 7156 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)"); 7157 if (!shader) 7158 { 7159 shader_buffer_free(&buffer); 7160 return 0; 7161 } 7162 7163 /* The YUY2 and UYVY formats contain two pixels packed into a 32 bit macropixel, 7164 * giving effectively 16 bit per pixel. The color consists of a luminance(Y) and 7165 * two chroma(U and V) values. Each macropixel has two luminance values, one for 7166 * each single pixel it contains, and one U and one V value shared between both 7167 * pixels. 7168 * 7169 * The data is loaded into an A8L8 texture. With YUY2, the luminance component 7170 * contains the luminance and alpha the chroma. With UYVY it is vice versa. Thus 7171 * take the format into account when generating the read swizzles 7172 * 7173 * Reading the Y value is straightforward - just sample the texture. The hardware 7174 * takes care of filtering in the horizontal and vertical direction. 7175 * 7176 * Reading the U and V values is harder. We have to avoid filtering horizontally, 7177 * because that would mix the U and V values of one pixel or two adjacent pixels. 7178 * Thus floor the texture coordinate and add 0.5 to get an unfiltered read, 7179 * regardless of the filtering setting. Vertical filtering works automatically 7180 * though - the U and V values of two rows are mixed nicely. 7181 * 7182 * Apart of avoiding filtering issues, the code has to know which value it just 7183 * read, and where it can find the other one. To determine this, it checks if 7184 * it sampled an even or odd pixel, and shifts the 2nd read accordingly. 7185 * 7186 * Handling horizontal filtering of U and V values requires reading a 2nd pair 7187 * of pixels, extracting U and V and mixing them. This is not implemented yet. 7188 * 7189 * An alternative implementation idea is to load the texture as A8R8G8B8 texture, 7190 * with width / 2. This way one read gives all 3 values, finding U and V is easy 7191 * in an unfiltered situation. Finding the luminance on the other hand requires 7192 * finding out if it is an odd or even pixel. The real drawback of this approach 7193 * is filtering. This would have to be emulated completely in the shader, reading 7194 * up two 2 packed pixels in up to 2 rows and interpolating both horizontally and 7195 * vertically. Beyond that it would require adjustments to the texture handling 7196 * code to deal with the width scaling 7197 */ 7198 shader_addline(&buffer, "!!ARBfp1.0\n"); 7199 shader_addline(&buffer, "TEMP luminance;\n"); 7200 shader_addline(&buffer, "TEMP temp;\n"); 7201 shader_addline(&buffer, "TEMP chroma;\n"); 7202 shader_addline(&buffer, "TEMP texcrd;\n"); 7203 shader_addline(&buffer, "TEMP texcrd2;\n"); 7204 shader_addline(&buffer, "PARAM coef = {1.0, 0.5, 2.0, 0.25};\n"); 7205 shader_addline(&buffer, "PARAM yuv_coef = {1.403, 0.344, 0.714, 1.770};\n"); 7206 shader_addline(&buffer, "PARAM size = program.local[0];\n"); 7207 7208 switch (yuv_fixup) 7209 { 7210 case COMPLEX_FIXUP_UYVY: 7211 case COMPLEX_FIXUP_YUY2: 7212 if (!gen_planar_yuv_read(&buffer, yuv_fixup, textype, &luminance_component)) 7213 { 7214 shader_buffer_free(&buffer); 7215 return 0; 7216 } 7217 break; 7218 7219 case COMPLEX_FIXUP_YV12: 7220 if (!gen_yv12_read(&buffer, textype, &luminance_component)) 7221 { 7222 shader_buffer_free(&buffer); 7223 return 0; 7224 } 7225 break; 7226 7227 default: 7228 FIXME("Unsupported YUV fixup %#x\n", yuv_fixup); 7229 shader_buffer_free(&buffer); 7230 return 0; 7231 } 7232 7233 /* Calculate the final result. Formula is taken from 7234 * http://www.fourcc.org/fccyvrgb.php. Note that the chroma 7235 * ranges from -0.5 to 0.5 7236 */ 7237 shader_addline(&buffer, "SUB chroma.xy, chroma, coef.y;\n"); 7238 7239 shader_addline(&buffer, "MAD result.color.x, chroma.x, yuv_coef.x, luminance.%c;\n", luminance_component); 7240 shader_addline(&buffer, "MAD temp.x, -chroma.y, yuv_coef.y, luminance.%c;\n", luminance_component); 7241 shader_addline(&buffer, "MAD result.color.y, -chroma.x, yuv_coef.z, temp.x;\n"); 7242 shader_addline(&buffer, "MAD result.color.z, chroma.y, yuv_coef.w, luminance.%c;\n", luminance_component); 7243 shader_addline(&buffer, "END\n"); 7244 7245 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 7246 strlen(buffer.buffer), buffer.buffer)); 7247 checkGLcall("glProgramStringARB()"); 7248 7249 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); 7250 if (pos != -1) 7251 { 7252 FIXME("Fragment program error at position %d: %s\n\n", pos, 7253 debugstr_a((const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB))); 7254 shader_arb_dump_program_source(buffer.buffer); 7255 } 7256 else 7257 { 7258 GLint native; 7259 7260 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native)); 7261 checkGLcall("glGetProgramivARB()"); 7262 if (!native) WARN("Program exceeds native resource limits.\n"); 7263 } 7264 7265 shader_buffer_free(&buffer); 7266 7267 switch (yuv_fixup) 7268 { 7269 case COMPLEX_FIXUP_YUY2: 7270 if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yuy2_rect_shader = shader; 7271 else priv->yuy2_2d_shader = shader; 7272 break; 7273 7274 case COMPLEX_FIXUP_UYVY: 7275 if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->uyvy_rect_shader = shader; 7276 else priv->uyvy_2d_shader = shader; 7277 break; 7278 7279 case COMPLEX_FIXUP_YV12: 7280 if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yv12_rect_shader = shader; 7281 else priv->yv12_2d_shader = shader; 7282 break; 7283 default: 7284 ERR("Unsupported complex fixup: %d\n", yuv_fixup); 7285 } 7286 7287 return shader; 7288 } 7289 7290 /* Context activation is done by the caller. */ 7291 static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface) 7292 { 7293 GLenum shader; 7294 float size[4] = {(float) surface->pow2Width, (float) surface->pow2Height, 1.0f, 1.0f}; 7295 struct arbfp_blit_priv *priv = blit_priv; 7296 enum complex_fixup fixup; 7297 const struct wined3d_gl_info *gl_info = context->gl_info; 7298 GLenum textype = surface->container->target; 7299 7300 if (surface->flags & SFLAG_CONVERTED) 7301 { 7302 gl_info->gl_ops.gl.p_glEnable(textype); 7303 checkGLcall("glEnable(textype)"); 7304 return WINED3D_OK; 7305 } 7306 7307 if (!is_complex_fixup(surface->resource.format->color_fixup)) 7308 { 7309 TRACE("Fixup:\n"); 7310 dump_color_fixup_desc(surface->resource.format->color_fixup); 7311 /* Don't bother setting up a shader for unconverted formats */ 7312 gl_info->gl_ops.gl.p_glEnable(textype); 7313 checkGLcall("glEnable(textype)"); 7314 return WINED3D_OK; 7315 } 7316 7317 fixup = get_complex_fixup(surface->resource.format->color_fixup); 7318 7319 switch(fixup) 7320 { 7321 case COMPLEX_FIXUP_YUY2: 7322 shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yuy2_rect_shader : priv->yuy2_2d_shader; 7323 break; 7324 7325 case COMPLEX_FIXUP_UYVY: 7326 shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->uyvy_rect_shader : priv->uyvy_2d_shader; 7327 break; 7328 7329 case COMPLEX_FIXUP_YV12: 7330 shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yv12_rect_shader : priv->yv12_2d_shader; 7331 break; 7332 7333 case COMPLEX_FIXUP_P8: 7334 shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->p8_rect_shader : priv->p8_2d_shader; 7335 if (!shader) shader = gen_p8_shader(priv, gl_info, textype); 7336 7337 upload_palette(surface, context); 7338 break; 7339 7340 default: 7341 FIXME("Unsupported complex fixup %#x, not setting a shader\n", fixup); 7342 gl_info->gl_ops.gl.p_glEnable(textype); 7343 checkGLcall("glEnable(textype)"); 7344 return E_NOTIMPL; 7345 } 7346 7347 if (!shader) shader = gen_yuv_shader(priv, gl_info, fixup, textype); 7348 7349 gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); 7350 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)"); 7351 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)); 7352 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)"); 7353 GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, size)); 7354 checkGLcall("glProgramLocalParameter4fvARB"); 7355 7356 return WINED3D_OK; 7357 } 7358 7359 /* Context activation is done by the caller. */ 7360 static void arbfp_blit_unset(const struct wined3d_gl_info *gl_info) 7361 { 7362 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); 7363 checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); 7364 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D); 7365 checkGLcall("glDisable(GL_TEXTURE_2D)"); 7366 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) 7367 { 7368 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB); 7369 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); 7370 } 7371 if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) 7372 { 7373 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB); 7374 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); 7375 } 7376 } 7377 7378 static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op, 7379 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format, 7380 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format) 7381 { 7382 enum complex_fixup src_fixup; 7383 7384 if (!gl_info->supported[ARB_FRAGMENT_PROGRAM]) 7385 return FALSE; 7386 7387 if (blit_op != WINED3D_BLIT_OP_COLOR_BLIT) 7388 { 7389 TRACE("Unsupported blit_op=%d\n", blit_op); 7390 return FALSE; 7391 } 7392 7393 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM) 7394 return FALSE; 7395 7396 src_fixup = get_complex_fixup(src_format->color_fixup); 7397 if (TRACE_ON(d3d_shader) && TRACE_ON(d3d)) 7398 { 7399 TRACE("Checking support for fixup:\n"); 7400 dump_color_fixup_desc(src_format->color_fixup); 7401 } 7402 7403 if (!is_identity_fixup(dst_format->color_fixup)) 7404 { 7405 TRACE("Destination fixups are not supported\n"); 7406 return FALSE; 7407 } 7408 7409 if (is_identity_fixup(src_format->color_fixup)) 7410 { 7411 TRACE("[OK]\n"); 7412 return TRUE; 7413 } 7414 7415 /* We only support YUV conversions. */ 7416 if (!is_complex_fixup(src_format->color_fixup)) 7417 { 7418 TRACE("[FAILED]\n"); 7419 return FALSE; 7420 } 7421 7422 switch(src_fixup) 7423 { 7424 case COMPLEX_FIXUP_YUY2: 7425 case COMPLEX_FIXUP_UYVY: 7426 case COMPLEX_FIXUP_YV12: 7427 case COMPLEX_FIXUP_P8: 7428 TRACE("[OK]\n"); 7429 return TRUE; 7430 7431 default: 7432 FIXME("Unsupported YUV fixup %#x\n", src_fixup); 7433 TRACE("[FAILED]\n"); 7434 return FALSE; 7435 } 7436 } 7437 7438 HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter, 7439 struct wined3d_surface *src_surface, const RECT *src_rect_in, 7440 struct wined3d_surface *dst_surface, const RECT *dst_rect_in) 7441 { 7442 struct wined3d_context *context; 7443 RECT src_rect = *src_rect_in; 7444 RECT dst_rect = *dst_rect_in; 7445 7446 /* Activate the destination context, set it up for blitting */ 7447 context = context_acquire(device, dst_surface); 7448 7449 /* Now load the surface */ 7450 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO 7451 && (src_surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_DRAWABLE)) 7452 == WINED3D_LOCATION_DRAWABLE 7453 && !surface_is_offscreen(src_surface)) 7454 { 7455 /* Without FBO blits transferring from the drawable to the texture is 7456 * expensive, because we have to flip the data in sysmem. Since we can 7457 * flip in the blitter, we don't actually need that flip anyway. So we 7458 * use the surface's texture as scratch texture, and flip the source 7459 * rectangle instead. */ 7460 surface_load_fb_texture(src_surface, FALSE); 7461 7462 src_rect.top = src_surface->resource.height - src_rect.top; 7463 src_rect.bottom = src_surface->resource.height - src_rect.bottom; 7464 } 7465 else 7466 wined3d_texture_load(src_surface->container, context, FALSE); 7467 7468 context_apply_blit_state(context, device); 7469 7470 if (!surface_is_offscreen(dst_surface)) 7471 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect); 7472 7473 arbfp_blit_set(device->blit_priv, context, src_surface); 7474 7475 /* Draw a textured quad */ 7476 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter); 7477 7478 /* Leave the opengl state valid for blitting */ 7479 arbfp_blit_unset(context->gl_info); 7480 7481 if (wined3d_settings.strict_draw_ordering 7482 || (dst_surface->swapchain && (dst_surface->swapchain->front_buffer == dst_surface))) 7483 context->gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */ 7484 7485 context_release(context); 7486 7487 surface_validate_location(dst_surface, dst_surface->draw_binding); 7488 surface_invalidate_location(dst_surface, ~dst_surface->draw_binding); 7489 7490 return WINED3D_OK; 7491 } 7492 7493 static HRESULT arbfp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface, 7494 const RECT *dst_rect, const struct wined3d_color *color) 7495 { 7496 FIXME("Color filling not implemented by arbfp_blit\n"); 7497 return WINED3DERR_INVALIDCALL; 7498 } 7499 7500 static HRESULT arbfp_blit_depth_fill(struct wined3d_device *device, 7501 struct wined3d_surface *surface, const RECT *rect, float depth) 7502 { 7503 FIXME("Depth filling not implemented by arbfp_blit.\n"); 7504 return WINED3DERR_INVALIDCALL; 7505 } 7506 7507 const struct blit_shader arbfp_blit = { 7508 arbfp_blit_alloc, 7509 arbfp_blit_free, 7510 arbfp_blit_set, 7511 arbfp_blit_unset, 7512 arbfp_blit_supported, 7513 arbfp_blit_color_fill, 7514 arbfp_blit_depth_fill, 7515 }; 7516