1 /* 2 * Copyright 2009 Matteo Bruni 3 * Copyright 2010 Matteo Bruni for CodeWeavers 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #define COBJMACROS 21 #include <stdarg.h> 22 #include <time.h> 23 #include "wine/debug.h" 24 25 #include "d3dcompiler_private.h" 26 #include "wpp_private.h" 27 28 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler); 29 30 #define D3DXERR_INVALIDDATA 0x88760b59 31 32 #define BUFFER_INITIAL_CAPACITY 256 33 34 struct mem_file_desc 35 { 36 const char *buffer; 37 unsigned int size; 38 unsigned int pos; 39 }; 40 41 static struct mem_file_desc current_shader; 42 static ID3DInclude *current_include; 43 static const char *initial_filename; 44 45 #define INCLUDES_INITIAL_CAPACITY 4 46 47 struct loaded_include 48 { 49 const char *name; 50 const char *data; 51 }; 52 53 static struct loaded_include *includes; 54 static int includes_capacity, includes_size; 55 static const char *parent_include; 56 57 static char *wpp_output; 58 static int wpp_output_capacity, wpp_output_size; 59 60 static char *wpp_messages; 61 static int wpp_messages_capacity, wpp_messages_size; 62 63 struct define 64 { 65 struct define *next; 66 char *name; 67 char *value; 68 }; 69 70 static struct define *cmdline_defines; 71 72 /* Mutex used to guarantee a single invocation 73 of the D3DXAssembleShader function (or its variants) at a time. 74 This is needed as wpp isn't thread-safe */ 75 static CRITICAL_SECTION wpp_mutex; 76 static CRITICAL_SECTION_DEBUG wpp_mutex_debug = 77 { 78 0, 0, &wpp_mutex, 79 { &wpp_mutex_debug.ProcessLocksList, 80 &wpp_mutex_debug.ProcessLocksList }, 81 0, 0, { (DWORD_PTR)(__FILE__ ": wpp_mutex") } 82 }; 83 static CRITICAL_SECTION wpp_mutex = { &wpp_mutex_debug, -1, 0, 0, 0, 0 }; 84 85 /* Preprocessor error reporting functions */ 86 static void wpp_write_message(const char *fmt, __ms_va_list args) 87 { 88 char* newbuffer; 89 int rc, newsize; 90 91 if(wpp_messages_capacity == 0) 92 { 93 wpp_messages = HeapAlloc(GetProcessHeap(), 0, MESSAGEBUFFER_INITIAL_SIZE); 94 if(wpp_messages == NULL) 95 return; 96 97 wpp_messages_capacity = MESSAGEBUFFER_INITIAL_SIZE; 98 } 99 100 while(1) 101 { 102 rc = vsnprintf(wpp_messages + wpp_messages_size, 103 wpp_messages_capacity - wpp_messages_size, fmt, args); 104 105 if (rc < 0 || /* C89 */ 106 rc >= wpp_messages_capacity - wpp_messages_size) { /* C99 */ 107 /* Resize the buffer */ 108 newsize = wpp_messages_capacity * 2; 109 newbuffer = HeapReAlloc(GetProcessHeap(), 0, wpp_messages, newsize); 110 if(newbuffer == NULL) 111 { 112 ERR("Error reallocating memory for parser messages\n"); 113 return; 114 } 115 wpp_messages = newbuffer; 116 wpp_messages_capacity = newsize; 117 } 118 else 119 { 120 wpp_messages_size += rc; 121 return; 122 } 123 } 124 } 125 126 static void WINAPIV PRINTF_ATTR(1,2) wpp_write_message_var(const char *fmt, ...) 127 { 128 __ms_va_list args; 129 130 __ms_va_start(args, fmt); 131 wpp_write_message(fmt, args); 132 __ms_va_end(args); 133 } 134 135 int WINAPIV ppy_error(const char *msg, ...) 136 { 137 __ms_va_list ap; 138 __ms_va_start(ap, msg); 139 wpp_write_message_var("%s:%d:%d: %s: ", 140 pp_status.input ? pp_status.input : "'main file'", 141 pp_status.line_number, pp_status.char_number, "Error"); 142 wpp_write_message(msg, ap); 143 wpp_write_message_var("\n"); 144 __ms_va_end(ap); 145 pp_status.state = 1; 146 return 1; 147 } 148 149 int WINAPIV ppy_warning(const char *msg, ...) 150 { 151 __ms_va_list ap; 152 __ms_va_start(ap, msg); 153 wpp_write_message_var("%s:%d:%d: %s: ", 154 pp_status.input ? pp_status.input : "'main file'", 155 pp_status.line_number, pp_status.char_number, "Warning"); 156 wpp_write_message(msg, ap); 157 wpp_write_message_var("\n"); 158 __ms_va_end(ap); 159 return 0; 160 } 161 162 char *wpp_lookup(const char *filename, int type, const char *parent_name) 163 { 164 /* We don't check for file existence here. We will potentially fail on 165 * the following wpp_open_mem(). */ 166 char *path; 167 int i; 168 169 TRACE("Looking for include %s, parent %s.\n", debugstr_a(filename), debugstr_a(parent_name)); 170 171 parent_include = NULL; 172 if (strcmp(parent_name, initial_filename)) 173 { 174 for(i = 0; i < includes_size; i++) 175 { 176 if(!strcmp(parent_name, includes[i].name)) 177 { 178 parent_include = includes[i].data; 179 break; 180 } 181 } 182 if(parent_include == NULL) 183 { 184 ERR("Parent include %s missing.\n", debugstr_a(parent_name)); 185 return NULL; 186 } 187 } 188 189 path = malloc(strlen(filename) + 1); 190 if(path) 191 memcpy(path, filename, strlen(filename) + 1); 192 return path; 193 } 194 195 void *wpp_open(const char *filename, int type) 196 { 197 struct mem_file_desc *desc; 198 HRESULT hr; 199 200 TRACE("Opening include %s.\n", debugstr_a(filename)); 201 202 if(!strcmp(filename, initial_filename)) 203 { 204 current_shader.pos = 0; 205 return ¤t_shader; 206 } 207 208 if(current_include == NULL) return NULL; 209 desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc)); 210 if(!desc) 211 return NULL; 212 213 if (FAILED(hr = ID3DInclude_Open(current_include, type ? D3D_INCLUDE_LOCAL : D3D_INCLUDE_SYSTEM, 214 filename, parent_include, (const void **)&desc->buffer, &desc->size))) 215 { 216 HeapFree(GetProcessHeap(), 0, desc); 217 return NULL; 218 } 219 220 if(includes_capacity == includes_size) 221 { 222 if(includes_capacity == 0) 223 { 224 includes = HeapAlloc(GetProcessHeap(), 0, INCLUDES_INITIAL_CAPACITY * sizeof(*includes)); 225 if(includes == NULL) 226 { 227 ERR("Error allocating memory for the loaded includes structure\n"); 228 goto error; 229 } 230 includes_capacity = INCLUDES_INITIAL_CAPACITY * sizeof(*includes); 231 } 232 else 233 { 234 int newcapacity = includes_capacity * 2; 235 struct loaded_include *newincludes = 236 HeapReAlloc(GetProcessHeap(), 0, includes, newcapacity); 237 if(newincludes == NULL) 238 { 239 ERR("Error reallocating memory for the loaded includes structure\n"); 240 goto error; 241 } 242 includes = newincludes; 243 includes_capacity = newcapacity; 244 } 245 } 246 includes[includes_size].name = filename; 247 includes[includes_size++].data = desc->buffer; 248 249 desc->pos = 0; 250 return desc; 251 252 error: 253 ID3DInclude_Close(current_include, desc->buffer); 254 HeapFree(GetProcessHeap(), 0, desc); 255 return NULL; 256 } 257 258 void wpp_close(void *file) 259 { 260 struct mem_file_desc *desc = file; 261 262 if(desc != ¤t_shader) 263 { 264 if(current_include) 265 ID3DInclude_Close(current_include, desc->buffer); 266 else 267 ERR("current_include == NULL, desc == %p, buffer = %s\n", 268 desc, desc->buffer); 269 270 HeapFree(GetProcessHeap(), 0, desc); 271 } 272 } 273 274 int wpp_read(void *file, char *buffer, unsigned int len) 275 { 276 struct mem_file_desc *desc = file; 277 278 len = min(len, desc->size - desc->pos); 279 memcpy(buffer, desc->buffer + desc->pos, len); 280 desc->pos += len; 281 return len; 282 } 283 284 void wpp_write(const char *buffer, unsigned int len) 285 { 286 char *new_wpp_output; 287 288 if(wpp_output_capacity == 0) 289 { 290 wpp_output = HeapAlloc(GetProcessHeap(), 0, BUFFER_INITIAL_CAPACITY); 291 if(!wpp_output) 292 return; 293 294 wpp_output_capacity = BUFFER_INITIAL_CAPACITY; 295 } 296 if(len > wpp_output_capacity - wpp_output_size) 297 { 298 while(len > wpp_output_capacity - wpp_output_size) 299 { 300 wpp_output_capacity *= 2; 301 } 302 new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output, 303 wpp_output_capacity); 304 if(!new_wpp_output) 305 { 306 ERR("Error allocating memory\n"); 307 return; 308 } 309 wpp_output = new_wpp_output; 310 } 311 memcpy(wpp_output + wpp_output_size, buffer, len); 312 wpp_output_size += len; 313 } 314 315 static int wpp_close_output(void) 316 { 317 char *new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output, 318 wpp_output_size + 1); 319 if(!new_wpp_output) return 0; 320 wpp_output = new_wpp_output; 321 wpp_output[wpp_output_size]='\0'; 322 wpp_output_size++; 323 return 1; 324 } 325 326 static void add_cmdline_defines(void) 327 { 328 struct define *def; 329 330 for (def = cmdline_defines; def; def = def->next) 331 { 332 if (def->value) pp_add_define( def->name, def->value ); 333 } 334 } 335 336 static void del_cmdline_defines(void) 337 { 338 struct define *def; 339 340 for (def = cmdline_defines; def; def = def->next) 341 { 342 if (def->value) pp_del_define( def->name ); 343 } 344 } 345 346 static void add_special_defines(void) 347 { 348 time_t now = time(NULL); 349 pp_entry_t *ppp; 350 char buf[32]; 351 352 strftime(buf, sizeof(buf), "\"%b %d %Y\"", localtime(&now)); 353 pp_add_define( "__DATE__", buf ); 354 355 strftime(buf, sizeof(buf), "\"%H:%M:%S\"", localtime(&now)); 356 pp_add_define( "__TIME__", buf ); 357 358 ppp = pp_add_define( "__FILE__", "" ); 359 if(ppp) 360 ppp->type = def_special; 361 362 ppp = pp_add_define( "__LINE__", "" ); 363 if(ppp) 364 ppp->type = def_special; 365 } 366 367 static void del_special_defines(void) 368 { 369 pp_del_define( "__DATE__" ); 370 pp_del_define( "__TIME__" ); 371 pp_del_define( "__FILE__" ); 372 pp_del_define( "__LINE__" ); 373 } 374 375 376 /* add a define to the preprocessor list */ 377 int wpp_add_define( const char *name, const char *value ) 378 { 379 struct define *def; 380 381 if (!value) value = ""; 382 383 for (def = cmdline_defines; def; def = def->next) 384 { 385 if (!strcmp( def->name, name )) 386 { 387 char *new_value = pp_xstrdup(value); 388 if(!new_value) 389 return 1; 390 free( def->value ); 391 def->value = new_value; 392 393 return 0; 394 } 395 } 396 397 def = pp_xmalloc( sizeof(*def) ); 398 if(!def) 399 return 1; 400 def->next = cmdline_defines; 401 def->name = pp_xstrdup(name); 402 if(!def->name) 403 { 404 free(def); 405 return 1; 406 } 407 def->value = pp_xstrdup(value); 408 if(!def->value) 409 { 410 free(def->name); 411 free(def); 412 return 1; 413 } 414 cmdline_defines = def; 415 return 0; 416 } 417 418 419 /* undefine a previously added definition */ 420 void wpp_del_define( const char *name ) 421 { 422 struct define *def; 423 424 for (def = cmdline_defines; def; def = def->next) 425 { 426 if (!strcmp( def->name, name )) 427 { 428 free( def->value ); 429 def->value = NULL; 430 return; 431 } 432 } 433 } 434 435 436 /* the main preprocessor parsing loop */ 437 int wpp_parse( const char *input, FILE *output ) 438 { 439 int ret; 440 441 pp_status.input = NULL; 442 pp_status.line_number = 1; 443 pp_status.char_number = 1; 444 pp_status.state = 0; 445 446 ret = pp_push_define_state(); 447 if(ret) 448 return ret; 449 add_cmdline_defines(); 450 add_special_defines(); 451 452 if (!input) pp_status.file = stdin; 453 else if (!(pp_status.file = wpp_open(input, 1))) 454 { 455 ppy_error("Could not open %s\n", input); 456 del_special_defines(); 457 del_cmdline_defines(); 458 pp_pop_define_state(); 459 return 2; 460 } 461 462 pp_status.input = input ? pp_xstrdup(input) : NULL; 463 464 ppy_out = output; 465 pp_writestring("# 1 \"%s\" 1\n", input ? input : ""); 466 467 ret = ppy_parse(); 468 /* If there were errors during processing, return an error code */ 469 if (!ret && pp_status.state) ret = pp_status.state; 470 471 if (input) 472 { 473 wpp_close(pp_status.file); 474 free(pp_status.input); 475 } 476 /* Clean if_stack, it could remain dirty on errors */ 477 while (pp_get_if_depth()) pp_pop_if(); 478 del_special_defines(); 479 del_cmdline_defines(); 480 pp_pop_define_state(); 481 return ret; 482 } 483 484 static HRESULT preprocess_shader(const void *data, SIZE_T data_size, const char *filename, 485 const D3D_SHADER_MACRO *defines, ID3DInclude *include, ID3DBlob **error_messages) 486 { 487 int ret; 488 HRESULT hr = S_OK; 489 const D3D_SHADER_MACRO *def = defines; 490 491 if (def != NULL) 492 { 493 while (def->Name != NULL) 494 { 495 wpp_add_define(def->Name, def->Definition); 496 def++; 497 } 498 } 499 current_include = include; 500 includes_size = 0; 501 502 wpp_output_size = wpp_output_capacity = 0; 503 wpp_output = NULL; 504 505 wpp_messages_size = wpp_messages_capacity = 0; 506 wpp_messages = NULL; 507 current_shader.buffer = data; 508 current_shader.size = data_size; 509 initial_filename = filename ? filename : ""; 510 511 ret = wpp_parse(initial_filename, NULL); 512 if (!wpp_close_output()) 513 ret = 1; 514 if (ret) 515 { 516 TRACE("Error during shader preprocessing\n"); 517 if (wpp_messages) 518 { 519 int size; 520 ID3DBlob *buffer; 521 522 TRACE("Preprocessor messages:\n%s\n", debugstr_a(wpp_messages)); 523 524 if (error_messages) 525 { 526 size = strlen(wpp_messages) + 1; 527 hr = D3DCreateBlob(size, &buffer); 528 if (FAILED(hr)) 529 goto cleanup; 530 CopyMemory(ID3D10Blob_GetBufferPointer(buffer), wpp_messages, size); 531 *error_messages = buffer; 532 } 533 } 534 if (data) 535 TRACE("Shader source:\n%s\n", debugstr_an(data, data_size)); 536 hr = E_FAIL; 537 } 538 539 cleanup: 540 /* Remove the previously added defines */ 541 if (defines != NULL) 542 { 543 while (defines->Name != NULL) 544 { 545 wpp_del_define(defines->Name); 546 defines++; 547 } 548 } 549 HeapFree(GetProcessHeap(), 0, wpp_messages); 550 return hr; 551 } 552 553 static HRESULT assemble_shader(const char *preproc_shader, 554 ID3DBlob **shader_blob, ID3DBlob **error_messages) 555 { 556 struct bwriter_shader *shader; 557 char *messages = NULL; 558 HRESULT hr; 559 DWORD *res, size; 560 ID3DBlob *buffer; 561 char *pos; 562 563 shader = SlAssembleShader(preproc_shader, &messages); 564 565 if (messages) 566 { 567 TRACE("Assembler messages:\n"); 568 TRACE("%s\n", debugstr_a(messages)); 569 570 TRACE("Shader source:\n"); 571 TRACE("%s\n", debugstr_a(preproc_shader)); 572 573 if (error_messages) 574 { 575 const char *preproc_messages = *error_messages ? ID3D10Blob_GetBufferPointer(*error_messages) : NULL; 576 577 size = strlen(messages) + (preproc_messages ? strlen(preproc_messages) : 0) + 1; 578 hr = D3DCreateBlob(size, &buffer); 579 if (FAILED(hr)) 580 { 581 HeapFree(GetProcessHeap(), 0, messages); 582 if (shader) SlDeleteShader(shader); 583 return hr; 584 } 585 pos = ID3D10Blob_GetBufferPointer(buffer); 586 if (preproc_messages) 587 { 588 CopyMemory(pos, preproc_messages, strlen(preproc_messages) + 1); 589 pos += strlen(preproc_messages); 590 } 591 CopyMemory(pos, messages, strlen(messages) + 1); 592 593 if (*error_messages) ID3D10Blob_Release(*error_messages); 594 *error_messages = buffer; 595 } 596 HeapFree(GetProcessHeap(), 0, messages); 597 } 598 599 if (shader == NULL) 600 { 601 ERR("Asm reading failed\n"); 602 return D3DXERR_INVALIDDATA; 603 } 604 605 hr = SlWriteBytecode(shader, 9, &res, &size); 606 SlDeleteShader(shader); 607 if (FAILED(hr)) 608 { 609 ERR("SlWriteBytecode failed with 0x%08x\n", hr); 610 return D3DXERR_INVALIDDATA; 611 } 612 613 if (shader_blob) 614 { 615 hr = D3DCreateBlob(size, &buffer); 616 if (FAILED(hr)) 617 { 618 HeapFree(GetProcessHeap(), 0, res); 619 return hr; 620 } 621 CopyMemory(ID3D10Blob_GetBufferPointer(buffer), res, size); 622 *shader_blob = buffer; 623 } 624 625 HeapFree(GetProcessHeap(), 0, res); 626 627 return S_OK; 628 } 629 630 HRESULT WINAPI D3DAssemble(const void *data, SIZE_T datasize, const char *filename, 631 const D3D_SHADER_MACRO *defines, ID3DInclude *include, UINT flags, 632 ID3DBlob **shader, ID3DBlob **error_messages) 633 { 634 HRESULT hr; 635 636 TRACE("data %p, datasize %lu, filename %s, defines %p, include %p, sflags %#x, " 637 "shader %p, error_messages %p.\n", 638 data, datasize, debugstr_a(filename), defines, include, flags, shader, error_messages); 639 640 EnterCriticalSection(&wpp_mutex); 641 642 /* TODO: flags */ 643 if (flags) FIXME("flags %x\n", flags); 644 645 if (shader) *shader = NULL; 646 if (error_messages) *error_messages = NULL; 647 648 hr = preprocess_shader(data, datasize, filename, defines, include, error_messages); 649 if (SUCCEEDED(hr)) 650 hr = assemble_shader(wpp_output, shader, error_messages); 651 652 HeapFree(GetProcessHeap(), 0, wpp_output); 653 LeaveCriticalSection(&wpp_mutex); 654 return hr; 655 } 656 657 struct target_info { 658 const char *name; 659 enum shader_type type; 660 DWORD sm_major; 661 DWORD sm_minor; 662 DWORD level_major; 663 DWORD level_minor; 664 BOOL sw; 665 BOOL support; 666 }; 667 668 /* Must be kept sorted for binary search */ 669 static const struct target_info targets_info[] = { 670 { "cs_4_0", ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE }, 671 { "cs_4_1", ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE }, 672 { "cs_5_0", ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE }, 673 { "ds_5_0", ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE }, 674 { "fx_2_0", ST_UNKNOWN, 2, 0, 0, 0, FALSE, FALSE }, 675 { "fx_4_0", ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE }, 676 { "fx_4_1", ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE }, 677 { "fx_5_0", ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE }, 678 { "gs_4_0", ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE }, 679 { "gs_4_1", ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE }, 680 { "gs_5_0", ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE }, 681 { "hs_5_0", ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE }, 682 { "ps.1.0", ST_PIXEL, 1, 0, 0, 0, FALSE, TRUE }, 683 { "ps.1.1", ST_PIXEL, 1, 1, 0, 0, FALSE, FALSE }, 684 { "ps.1.2", ST_PIXEL, 1, 2, 0, 0, FALSE, FALSE }, 685 { "ps.1.3", ST_PIXEL, 1, 3, 0, 0, FALSE, FALSE }, 686 { "ps.1.4", ST_PIXEL, 1, 4, 0, 0, FALSE, FALSE }, 687 { "ps.2.0", ST_PIXEL, 2, 0, 0, 0, FALSE, TRUE }, 688 { "ps.2.a", ST_PIXEL, 2, 1, 0, 0, FALSE, FALSE }, 689 { "ps.2.b", ST_PIXEL, 2, 2, 0, 0, FALSE, FALSE }, 690 { "ps.2.sw", ST_PIXEL, 2, 0, 0, 0, TRUE, FALSE }, 691 { "ps.3.0", ST_PIXEL, 3, 0, 0, 0, FALSE, TRUE }, 692 { "ps_1_0", ST_PIXEL, 1, 0, 0, 0, FALSE, TRUE }, 693 { "ps_1_1", ST_PIXEL, 1, 1, 0, 0, FALSE, FALSE }, 694 { "ps_1_2", ST_PIXEL, 1, 2, 0, 0, FALSE, FALSE }, 695 { "ps_1_3", ST_PIXEL, 1, 3, 0, 0, FALSE, FALSE }, 696 { "ps_1_4", ST_PIXEL, 1, 4, 0, 0, FALSE, FALSE }, 697 { "ps_2_0", ST_PIXEL, 2, 0, 0, 0, FALSE, TRUE }, 698 { "ps_2_a", ST_PIXEL, 2, 1, 0, 0, FALSE, FALSE }, 699 { "ps_2_b", ST_PIXEL, 2, 2, 0, 0, FALSE, FALSE }, 700 { "ps_2_sw", ST_PIXEL, 2, 0, 0, 0, TRUE, FALSE }, 701 { "ps_3_0", ST_PIXEL, 3, 0, 0, 0, FALSE, TRUE }, 702 { "ps_3_sw", ST_PIXEL, 3, 0, 0, 0, TRUE, FALSE }, 703 { "ps_4_0", ST_PIXEL, 4, 0, 0, 0, FALSE, TRUE }, 704 { "ps_4_0_level_9_0", ST_PIXEL, 4, 0, 9, 0, FALSE, FALSE }, 705 { "ps_4_0_level_9_1", ST_PIXEL, 4, 0, 9, 1, FALSE, FALSE }, 706 { "ps_4_0_level_9_3", ST_PIXEL, 4, 0, 9, 3, FALSE, FALSE }, 707 { "ps_4_1", ST_PIXEL, 4, 1, 0, 0, FALSE, TRUE }, 708 { "ps_5_0", ST_PIXEL, 5, 0, 0, 0, FALSE, TRUE }, 709 { "tx_1_0", ST_UNKNOWN, 1, 0, 0, 0, FALSE, FALSE }, 710 { "vs.1.0", ST_VERTEX, 1, 0, 0, 0, FALSE, TRUE }, 711 { "vs.1.1", ST_VERTEX, 1, 1, 0, 0, FALSE, TRUE }, 712 { "vs.2.0", ST_VERTEX, 2, 0, 0, 0, FALSE, TRUE }, 713 { "vs.2.a", ST_VERTEX, 2, 1, 0, 0, FALSE, FALSE }, 714 { "vs.2.sw", ST_VERTEX, 2, 0, 0, 0, TRUE, FALSE }, 715 { "vs.3.0", ST_VERTEX, 3, 0, 0, 0, FALSE, TRUE }, 716 { "vs.3.sw", ST_VERTEX, 3, 0, 0, 0, TRUE, FALSE }, 717 { "vs_1_0", ST_VERTEX, 1, 0, 0, 0, FALSE, TRUE }, 718 { "vs_1_1", ST_VERTEX, 1, 1, 0, 0, FALSE, TRUE }, 719 { "vs_2_0", ST_VERTEX, 2, 0, 0, 0, FALSE, TRUE }, 720 { "vs_2_a", ST_VERTEX, 2, 1, 0, 0, FALSE, FALSE }, 721 { "vs_2_sw", ST_VERTEX, 2, 0, 0, 0, TRUE, FALSE }, 722 { "vs_3_0", ST_VERTEX, 3, 0, 0, 0, FALSE, TRUE }, 723 { "vs_3_sw", ST_VERTEX, 3, 0, 0, 0, TRUE, FALSE }, 724 { "vs_4_0", ST_VERTEX, 4, 0, 0, 0, FALSE, TRUE }, 725 { "vs_4_0_level_9_0", ST_VERTEX, 4, 0, 9, 0, FALSE, FALSE }, 726 { "vs_4_0_level_9_1", ST_VERTEX, 4, 0, 9, 1, FALSE, FALSE }, 727 { "vs_4_0_level_9_3", ST_VERTEX, 4, 0, 9, 3, FALSE, FALSE }, 728 { "vs_4_1", ST_VERTEX, 4, 1, 0, 0, FALSE, TRUE }, 729 { "vs_5_0", ST_VERTEX, 5, 0, 0, 0, FALSE, TRUE }, 730 }; 731 732 static const struct target_info * get_target_info(const char *target) 733 { 734 LONG min = 0; 735 LONG max = ARRAY_SIZE(targets_info) - 1; 736 LONG cur; 737 int res; 738 739 while (min <= max) 740 { 741 cur = (min + max) / 2; 742 res = strcmp(target, targets_info[cur].name); 743 if (res < 0) 744 max = cur - 1; 745 else if (res > 0) 746 min = cur + 1; 747 else 748 return &targets_info[cur]; 749 } 750 751 return NULL; 752 } 753 754 static HRESULT compile_shader(const char *preproc_shader, const char *target, const char *entrypoint, 755 ID3DBlob **shader_blob, ID3DBlob **error_messages) 756 { 757 struct bwriter_shader *shader; 758 char *messages = NULL; 759 HRESULT hr; 760 DWORD *res, size, major, minor; 761 ID3DBlob *buffer; 762 char *pos; 763 enum shader_type shader_type; 764 const struct target_info *info; 765 766 TRACE("Preprocessed shader source: %s\n", debugstr_a(preproc_shader)); 767 768 TRACE("Checking compilation target %s\n", debugstr_a(target)); 769 info = get_target_info(target); 770 if (!info) 771 { 772 FIXME("Unknown compilation target %s\n", debugstr_a(target)); 773 return D3DERR_INVALIDCALL; 774 } 775 else 776 { 777 if (!info->support) 778 { 779 FIXME("Compilation target %s not yet supported\n", debugstr_a(target)); 780 return D3DERR_INVALIDCALL; 781 } 782 else 783 { 784 shader_type = info->type; 785 major = info->sm_major; 786 minor = info->sm_minor; 787 } 788 } 789 790 shader = parse_hlsl_shader(preproc_shader, shader_type, major, minor, entrypoint, &messages); 791 792 if (messages) 793 { 794 TRACE("Compiler messages:\n"); 795 TRACE("%s\n", debugstr_a(messages)); 796 797 TRACE("Shader source:\n"); 798 TRACE("%s\n", debugstr_a(preproc_shader)); 799 800 if (error_messages) 801 { 802 const char *preproc_messages = *error_messages ? ID3D10Blob_GetBufferPointer(*error_messages) : NULL; 803 804 size = strlen(messages) + (preproc_messages ? strlen(preproc_messages) : 0) + 1; 805 hr = D3DCreateBlob(size, &buffer); 806 if (FAILED(hr)) 807 { 808 HeapFree(GetProcessHeap(), 0, messages); 809 if (shader) SlDeleteShader(shader); 810 return hr; 811 } 812 pos = ID3D10Blob_GetBufferPointer(buffer); 813 if (preproc_messages) 814 { 815 memcpy(pos, preproc_messages, strlen(preproc_messages) + 1); 816 pos += strlen(preproc_messages); 817 } 818 memcpy(pos, messages, strlen(messages) + 1); 819 820 if (*error_messages) ID3D10Blob_Release(*error_messages); 821 *error_messages = buffer; 822 } 823 HeapFree(GetProcessHeap(), 0, messages); 824 } 825 826 if (!shader) 827 { 828 ERR("HLSL shader parsing failed.\n"); 829 return D3DXERR_INVALIDDATA; 830 } 831 832 hr = SlWriteBytecode(shader, 9, &res, &size); 833 SlDeleteShader(shader); 834 if (FAILED(hr)) 835 { 836 ERR("SlWriteBytecode failed with error 0x%08x.\n", hr); 837 return D3DXERR_INVALIDDATA; 838 } 839 840 if (shader_blob) 841 { 842 hr = D3DCreateBlob(size, &buffer); 843 if (FAILED(hr)) 844 { 845 HeapFree(GetProcessHeap(), 0, res); 846 return hr; 847 } 848 memcpy(ID3D10Blob_GetBufferPointer(buffer), res, size); 849 *shader_blob = buffer; 850 } 851 852 HeapFree(GetProcessHeap(), 0, res); 853 854 return S_OK; 855 } 856 857 HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, 858 const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, 859 const char *target, UINT sflags, UINT eflags, UINT secondary_flags, 860 const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, 861 ID3DBlob **error_messages) 862 { 863 HRESULT hr; 864 865 TRACE("data %p, data_size %lu, filename %s, defines %p, include %p, entrypoint %s, " 866 "target %s, sflags %#x, eflags %#x, secondary_flags %#x, secondary_data %p, " 867 "secondary_data_size %lu, shader %p, error_messages %p.\n", 868 data, data_size, debugstr_a(filename), defines, include, debugstr_a(entrypoint), 869 debugstr_a(target), sflags, eflags, secondary_flags, secondary_data, 870 secondary_data_size, shader, error_messages); 871 872 if (secondary_data) 873 FIXME("secondary data not implemented yet\n"); 874 875 if (shader) *shader = NULL; 876 if (error_messages) *error_messages = NULL; 877 878 EnterCriticalSection(&wpp_mutex); 879 880 hr = preprocess_shader(data, data_size, filename, defines, include, error_messages); 881 if (SUCCEEDED(hr)) 882 hr = compile_shader(wpp_output, target, entrypoint, shader, error_messages); 883 884 HeapFree(GetProcessHeap(), 0, wpp_output); 885 LeaveCriticalSection(&wpp_mutex); 886 return hr; 887 } 888 889 HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, 890 const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, 891 const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages) 892 { 893 TRACE("data %p, data_size %lu, filename %s, defines %p, include %p, entrypoint %s, " 894 "target %s, sflags %#x, eflags %#x, shader %p, error_messages %p.\n", 895 data, data_size, debugstr_a(filename), defines, include, debugstr_a(entrypoint), 896 debugstr_a(target), sflags, eflags, shader, error_messages); 897 898 return D3DCompile2(data, data_size, filename, defines, include, entrypoint, target, sflags, 899 eflags, 0, NULL, 0, shader, error_messages); 900 } 901 902 HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename, 903 const D3D_SHADER_MACRO *defines, ID3DInclude *include, 904 ID3DBlob **shader, ID3DBlob **error_messages) 905 { 906 HRESULT hr; 907 ID3DBlob *buffer; 908 909 TRACE("data %p, size %lu, filename %s, defines %p, include %p, shader %p, error_messages %p\n", 910 data, size, debugstr_a(filename), defines, include, shader, error_messages); 911 912 if (!data) 913 return E_INVALIDARG; 914 915 EnterCriticalSection(&wpp_mutex); 916 917 if (shader) *shader = NULL; 918 if (error_messages) *error_messages = NULL; 919 920 hr = preprocess_shader(data, size, filename, defines, include, error_messages); 921 922 if (SUCCEEDED(hr)) 923 { 924 if (shader) 925 { 926 hr = D3DCreateBlob(wpp_output_size, &buffer); 927 if (FAILED(hr)) 928 goto cleanup; 929 CopyMemory(ID3D10Blob_GetBufferPointer(buffer), wpp_output, wpp_output_size); 930 *shader = buffer; 931 } 932 else 933 hr = E_INVALIDARG; 934 } 935 936 cleanup: 937 HeapFree(GetProcessHeap(), 0, wpp_output); 938 LeaveCriticalSection(&wpp_mutex); 939 return hr; 940 } 941 942 HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T size, UINT flags, const char *comments, ID3DBlob **disassembly) 943 { 944 FIXME("data %p, size %lu, flags %#x, comments %p, disassembly %p stub!\n", 945 data, size, flags, comments, disassembly); 946 return E_NOTIMPL; 947 } 948 949 HRESULT WINAPI D3DCompileFromFile(const WCHAR *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *includes, 950 const char *entrypoint, const char *target, UINT flags1, UINT flags2, ID3DBlob **code, ID3DBlob **errors) 951 { 952 FIXME("filename %s, defines %p, includes %p, entrypoint %s, target %s, flags1 %x, flags2 %x, code %p, errors %p\n", 953 debugstr_w(filename), defines, includes, debugstr_a(entrypoint), debugstr_a(target), flags1, flags2, code, errors); 954 955 return E_NOTIMPL; 956 } 957 958 #ifndef __REACTOS__ 959 HRESULT WINAPI D3DLoadModule(const void *data, SIZE_T size, ID3D11Module **module) 960 { 961 FIXME("data %p, size %lu, module %p stub!\n", data, size, module); 962 return E_NOTIMPL; 963 } 964 #endif 965