compiler.c 25.5 KB
Newer Older
1
/*
2
 * Copyright 2009 Matteo Bruni
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * Copyright 2010 Matteo Bruni for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

20
#define COBJMACROS
21 22 23 24 25 26
#include "config.h"
#include "wine/port.h"
#include "wine/debug.h"
#include "wine/unicode.h"

#include "d3dcompiler_private.h"
27
#include "wine/wpp.h"
28 29 30

WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler);

31 32 33 34 35 36 37 38 39 40 41
#define D3DXERR_INVALIDDATA                      0x88760b59

#define BUFFER_INITIAL_CAPACITY 256

struct mem_file_desc
{
    const char *buffer;
    unsigned int size;
    unsigned int pos;
};

42 43
static struct mem_file_desc current_shader;
static ID3DInclude *current_include;
44
static const char *initial_filename;
45 46 47 48 49 50 51 52 53

#define INCLUDES_INITIAL_CAPACITY 4

struct loaded_include
{
    const char *name;
    const char *data;
};

54 55 56
static struct loaded_include *includes;
static int includes_capacity, includes_size;
static const char *parent_include;
57

58 59
static char *wpp_output;
static int wpp_output_capacity, wpp_output_size;
60

61 62
static char *wpp_messages;
static int wpp_messages_capacity, wpp_messages_size;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

/* Mutex used to guarantee a single invocation
   of the D3DXAssembleShader function (or its variants) at a time.
   This is needed as wpp isn't thread-safe */
static CRITICAL_SECTION wpp_mutex;
static CRITICAL_SECTION_DEBUG wpp_mutex_debug =
{
    0, 0, &wpp_mutex,
    { &wpp_mutex_debug.ProcessLocksList,
      &wpp_mutex_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": wpp_mutex") }
};
static CRITICAL_SECTION wpp_mutex = { &wpp_mutex_debug, -1, 0, 0, 0, 0 };

/* Preprocessor error reporting functions */
static void wpp_write_message(const char *fmt, va_list args)
{
    char* newbuffer;
    int rc, newsize;

    if(wpp_messages_capacity == 0)
    {
        wpp_messages = HeapAlloc(GetProcessHeap(), 0, MESSAGEBUFFER_INITIAL_SIZE);
        if(wpp_messages == NULL)
            return;
88

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        wpp_messages_capacity = MESSAGEBUFFER_INITIAL_SIZE;
    }

    while(1)
    {
        rc = vsnprintf(wpp_messages + wpp_messages_size,
                       wpp_messages_capacity - wpp_messages_size, fmt, args);

        if (rc < 0 ||                                           /* C89 */
            rc >= wpp_messages_capacity - wpp_messages_size) {  /* C99 */
            /* Resize the buffer */
            newsize = wpp_messages_capacity * 2;
            newbuffer = HeapReAlloc(GetProcessHeap(), 0, wpp_messages, newsize);
            if(newbuffer == NULL)
            {
                ERR("Error reallocating memory for parser messages\n");
                return;
            }
            wpp_messages = newbuffer;
            wpp_messages_capacity = newsize;
        }
        else
        {
            wpp_messages_size += rc;
            return;
        }
    }
}

static void PRINTF_ATTR(1,2) wpp_write_message_var(const char *fmt, ...)
{
    va_list args;

    va_start(args, fmt);
    wpp_write_message(fmt, args);
    va_end(args);
}

static void wpp_error(const char *file, int line, int col, const char *near,
                      const char *msg, va_list ap)
{
    wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
                          line, col, "Error");
    wpp_write_message(msg, ap);
    wpp_write_message_var("\n");
}

static void wpp_warning(const char *file, int line, int col, const char *near,
                        const char *msg, va_list ap)
{
    wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
                          line, col, "Warning");
    wpp_write_message(msg, ap);
    wpp_write_message_var("\n");
}

145
static char *wpp_lookup_mem(const char *filename, int type, const char *parent_name,
146 147
                            char **include_path, int include_path_count)
{
148 149
    /* We don't check for file existence here. We will potentially fail on
     * the following wpp_open_mem(). */
150 151 152
    char *path;
    int i;

153
    TRACE("Looking for include %s, parent %s.\n", debugstr_a(filename), debugstr_a(parent_name));
154

155
    parent_include = NULL;
156
    if (strcmp(parent_name, initial_filename))
157 158 159 160 161 162 163 164 165 166 167
    {
        for(i = 0; i < includes_size; i++)
        {
            if(!strcmp(parent_name, includes[i].name))
            {
                parent_include = includes[i].data;
                break;
            }
        }
        if(parent_include == NULL)
        {
168
            ERR("Parent include %s missing.\n", debugstr_a(parent_name));
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
            return NULL;
        }
    }

    path = malloc(strlen(filename) + 1);
    if(path)
        memcpy(path, filename, strlen(filename) + 1);
    return path;
}

static void *wpp_open_mem(const char *filename, int type)
{
    struct mem_file_desc *desc;
    HRESULT hr;

184 185
    TRACE("Opening include %s.\n", debugstr_a(filename));

186
    if(!strcmp(filename, initial_filename))
187 188 189 190 191 192 193 194 195
    {
        current_shader.pos = 0;
        return &current_shader;
    }

    if(current_include == NULL) return NULL;
    desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));
    if(!desc)
        return NULL;
196

197 198
    if (FAILED(hr = ID3DInclude_Open(current_include, type ? D3D_INCLUDE_LOCAL : D3D_INCLUDE_SYSTEM,
            filename, parent_include, (const void **)&desc->buffer, &desc->size)))
199 200 201 202 203 204 205 206 207
    {
        HeapFree(GetProcessHeap(), 0, desc);
        return NULL;
    }

    if(includes_capacity == includes_size)
    {
        if(includes_capacity == 0)
        {
208
            includes = HeapAlloc(GetProcessHeap(), 0, INCLUDES_INITIAL_CAPACITY * sizeof(*includes));
209 210 211 212 213
            if(includes == NULL)
            {
                ERR("Error allocating memory for the loaded includes structure\n");
                goto error;
            }
214
            includes_capacity = INCLUDES_INITIAL_CAPACITY * sizeof(*includes);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        }
        else
        {
            int newcapacity = includes_capacity * 2;
            struct loaded_include *newincludes =
                HeapReAlloc(GetProcessHeap(), 0, includes, newcapacity);
            if(newincludes == NULL)
            {
                ERR("Error reallocating memory for the loaded includes structure\n");
                goto error;
            }
            includes = newincludes;
            includes_capacity = newcapacity;
        }
    }
    includes[includes_size].name = filename;
    includes[includes_size++].data = desc->buffer;

    desc->pos = 0;
    return desc;

error:
    ID3DInclude_Close(current_include, desc->buffer);
    HeapFree(GetProcessHeap(), 0, desc);
    return NULL;
}

static void wpp_close_mem(void *file)
{
    struct mem_file_desc *desc = file;

    if(desc != &current_shader)
    {
        if(current_include)
            ID3DInclude_Close(current_include, desc->buffer);
        else
            ERR("current_include == NULL, desc == %p, buffer = %s\n",
                desc, desc->buffer);

        HeapFree(GetProcessHeap(), 0, desc);
    }
}

static int wpp_read_mem(void *file, char *buffer, unsigned int len)
{
    struct mem_file_desc *desc = file;

    len = min(len, desc->size - desc->pos);
    memcpy(buffer, desc->buffer + desc->pos, len);
    desc->pos += len;
    return len;
}

static void wpp_write_mem(const char *buffer, unsigned int len)
{
    char *new_wpp_output;

    if(wpp_output_capacity == 0)
    {
        wpp_output = HeapAlloc(GetProcessHeap(), 0, BUFFER_INITIAL_CAPACITY);
        if(!wpp_output)
            return;
277

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        wpp_output_capacity = BUFFER_INITIAL_CAPACITY;
    }
    if(len > wpp_output_capacity - wpp_output_size)
    {
        while(len > wpp_output_capacity - wpp_output_size)
        {
            wpp_output_capacity *= 2;
        }
        new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
                                     wpp_output_capacity);
        if(!new_wpp_output)
        {
            ERR("Error allocating memory\n");
            return;
        }
        wpp_output = new_wpp_output;
    }
    memcpy(wpp_output + wpp_output_size, buffer, len);
    wpp_output_size += len;
}

static int wpp_close_output(void)
{
    char *new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
                                       wpp_output_size + 1);
    if(!new_wpp_output) return 0;
    wpp_output = new_wpp_output;
    wpp_output[wpp_output_size]='\0';
306
    wpp_output_size++;
307 308 309
    return 1;
}

310
static HRESULT preprocess_shader(const void *data, SIZE_T data_size, const char *filename,
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
        const D3D_SHADER_MACRO *defines, ID3DInclude *include, ID3DBlob **error_messages)
{
    int ret;
    HRESULT hr = S_OK;
    const D3D_SHADER_MACRO *def = defines;

    static const struct wpp_callbacks wpp_callbacks =
    {
        wpp_lookup_mem,
        wpp_open_mem,
        wpp_close_mem,
        wpp_read_mem,
        wpp_write_mem,
        wpp_error,
        wpp_warning,
    };

    if (def != NULL)
    {
        while (def->Name != NULL)
        {
            wpp_add_define(def->Name, def->Definition);
            def++;
        }
    }
    current_include = include;
    includes_size = 0;

    wpp_output_size = wpp_output_capacity = 0;
    wpp_output = NULL;

    wpp_set_callbacks(&wpp_callbacks);
    wpp_messages_size = wpp_messages_capacity = 0;
    wpp_messages = NULL;
    current_shader.buffer = data;
    current_shader.size = data_size;
347
    initial_filename = filename ? filename : "";
348

349
    ret = wpp_parse(initial_filename, NULL);
350 351 352 353 354 355 356 357 358 359
    if (!wpp_close_output())
        ret = 1;
    if (ret)
    {
        TRACE("Error during shader preprocessing\n");
        if (wpp_messages)
        {
            int size;
            ID3DBlob *buffer;

360
            TRACE("Preprocessor messages:\n%s\n", debugstr_a(wpp_messages));
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

            if (error_messages)
            {
                size = strlen(wpp_messages) + 1;
                hr = D3DCreateBlob(size, &buffer);
                if (FAILED(hr))
                    goto cleanup;
                CopyMemory(ID3D10Blob_GetBufferPointer(buffer), wpp_messages, size);
                *error_messages = buffer;
            }
        }
        if (data)
            TRACE("Shader source:\n%s\n", debugstr_an(data, data_size));
        hr = E_FAIL;
    }

cleanup:
    /* Remove the previously added defines */
    if (defines != NULL)
    {
        while (defines->Name != NULL)
        {
            wpp_del_define(defines->Name);
            defines++;
        }
    }
    HeapFree(GetProcessHeap(), 0, wpp_messages);
    return hr;
}

391
static HRESULT assemble_shader(const char *preproc_shader,
392
        ID3DBlob **shader_blob, ID3DBlob **error_messages)
393 394 395 396
{
    struct bwriter_shader *shader;
    char *messages = NULL;
    HRESULT hr;
397 398
    DWORD *res, size;
    ID3DBlob *buffer;
399 400
    char *pos;

401
    shader = SlAssembleShader(preproc_shader, &messages);
402

403
    if (messages)
404
    {
405
        TRACE("Assembler messages:\n");
406
        TRACE("%s\n", debugstr_a(messages));
407 408

        TRACE("Shader source:\n");
409
        TRACE("%s\n", debugstr_a(preproc_shader));
410

411
        if (error_messages)
412
        {
413 414 415
            const char *preproc_messages = *error_messages ? ID3D10Blob_GetBufferPointer(*error_messages) : NULL;

            size = strlen(messages) + (preproc_messages ? strlen(preproc_messages) : 0) + 1;
416
            hr = D3DCreateBlob(size, &buffer);
417
            if (FAILED(hr))
418 419
            {
                HeapFree(GetProcessHeap(), 0, messages);
420
                if (shader) SlDeleteShader(shader);
421 422 423
                return hr;
            }
            pos = ID3D10Blob_GetBufferPointer(buffer);
424
            if (preproc_messages)
425
            {
426 427
                CopyMemory(pos, preproc_messages, strlen(preproc_messages) + 1);
                pos += strlen(preproc_messages);
428
            }
429
            CopyMemory(pos, messages, strlen(messages) + 1);
430

431
            if (*error_messages) ID3D10Blob_Release(*error_messages);
432
            *error_messages = buffer;
433 434 435 436
        }
        HeapFree(GetProcessHeap(), 0, messages);
    }

437
    if (shader == NULL)
438 439 440 441 442
    {
        ERR("Asm reading failed\n");
        return D3DXERR_INVALIDDATA;
    }

443
    hr = SlWriteBytecode(shader, 9, &res, &size);
444
    SlDeleteShader(shader);
445
    if (FAILED(hr))
446 447 448 449 450
    {
        ERR("SlWriteBytecode failed with 0x%08x\n", hr);
        return D3DXERR_INVALIDDATA;
    }

451
    if (shader_blob)
452 453
    {
        hr = D3DCreateBlob(size, &buffer);
454
        if (FAILED(hr))
455 456 457 458 459
        {
            HeapFree(GetProcessHeap(), 0, res);
            return hr;
        }
        CopyMemory(ID3D10Blob_GetBufferPointer(buffer), res, size);
460
        *shader_blob = buffer;
461 462 463 464 465 466 467
    }

    HeapFree(GetProcessHeap(), 0, res);

    return S_OK;
}

468 469 470 471
HRESULT WINAPI D3DAssemble(const void *data, SIZE_T datasize, const char *filename,
        const D3D_SHADER_MACRO *defines, ID3DInclude *include, UINT flags,
        ID3DBlob **shader, ID3DBlob **error_messages)
{
472 473
    HRESULT hr;

474 475
    TRACE("data %p, datasize %lu, filename %s, defines %p, include %p, sflags %#x, "
            "shader %p, error_messages %p.\n",
476 477
            data, datasize, debugstr_a(filename), defines, include, flags, shader, error_messages);

478 479 480
    EnterCriticalSection(&wpp_mutex);

    /* TODO: flags */
481
    if (flags) FIXME("flags %x\n", flags);
482

483 484
    if (shader) *shader = NULL;
    if (error_messages) *error_messages = NULL;
485

486
    hr = preprocess_shader(data, datasize, filename, defines, include, error_messages);
487
    if (SUCCEEDED(hr))
488
        hr = assemble_shader(wpp_output, shader, error_messages);
489 490 491 492

    HeapFree(GetProcessHeap(), 0, wpp_output);
    LeaveCriticalSection(&wpp_mutex);
    return hr;
493
}
494

495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
struct target_info {
    const char *name;
    enum shader_type type;
    DWORD sm_major;
    DWORD sm_minor;
    DWORD level_major;
    DWORD level_minor;
    BOOL sw;
    BOOL support;
};

/* Must be kept sorted for binary search */
static const struct target_info targets_info[] = {
    { "cs_4_0",            ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE },
    { "cs_4_1",            ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE },
    { "cs_5_0",            ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE },
    { "ds_5_0",            ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE },
    { "fx_2_0",            ST_UNKNOWN, 2, 0, 0, 0, FALSE, FALSE },
    { "fx_4_0",            ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE },
    { "fx_4_1",            ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE },
    { "fx_5_0",            ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE },
    { "gs_4_0",            ST_UNKNOWN, 4, 0, 0, 0, FALSE, FALSE },
    { "gs_4_1",            ST_UNKNOWN, 4, 1, 0, 0, FALSE, FALSE },
    { "gs_5_0",            ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE },
    { "hs_5_0",            ST_UNKNOWN, 5, 0, 0, 0, FALSE, FALSE },
    { "ps.1.0",            ST_PIXEL,   1, 0, 0, 0, FALSE, TRUE  },
    { "ps.1.1",            ST_PIXEL,   1, 1, 0, 0, FALSE, FALSE },
    { "ps.1.2",            ST_PIXEL,   1, 2, 0, 0, FALSE, FALSE },
    { "ps.1.3",            ST_PIXEL,   1, 3, 0, 0, FALSE, FALSE },
    { "ps.1.4",            ST_PIXEL,   1, 4, 0, 0, FALSE, FALSE },
    { "ps.2.0",            ST_PIXEL,   2, 0, 0, 0, FALSE, TRUE  },
    { "ps.2.a",            ST_PIXEL,   2, 1, 0, 0, FALSE, FALSE },
    { "ps.2.b",            ST_PIXEL,   2, 2, 0, 0, FALSE, FALSE },
    { "ps.2.sw",           ST_PIXEL,   2, 0, 0, 0, TRUE,  FALSE },
    { "ps.3.0",            ST_PIXEL,   3, 0, 0, 0, FALSE, TRUE  },
    { "ps_1_0",            ST_PIXEL,   1, 0, 0, 0, FALSE, TRUE  },
    { "ps_1_1",            ST_PIXEL,   1, 1, 0, 0, FALSE, FALSE },
    { "ps_1_2",            ST_PIXEL,   1, 2, 0, 0, FALSE, FALSE },
    { "ps_1_3",            ST_PIXEL,   1, 3, 0, 0, FALSE, FALSE },
    { "ps_1_4",            ST_PIXEL,   1, 4, 0, 0, FALSE, FALSE },
    { "ps_2_0",            ST_PIXEL,   2, 0, 0, 0, FALSE, TRUE  },
    { "ps_2_a",            ST_PIXEL,   2, 1, 0, 0, FALSE, FALSE },
    { "ps_2_b",            ST_PIXEL,   2, 2, 0, 0, FALSE, FALSE },
    { "ps_2_sw",           ST_PIXEL,   2, 0, 0, 0, TRUE,  FALSE },
    { "ps_3_0",            ST_PIXEL,   3, 0, 0, 0, FALSE, TRUE  },
    { "ps_3_sw",           ST_PIXEL,   3, 0, 0, 0, TRUE,  FALSE },
    { "ps_4_0",            ST_PIXEL,   4, 0, 0, 0, FALSE, TRUE  },
    { "ps_4_0_level_9_0",  ST_PIXEL,   4, 0, 9, 0, FALSE, FALSE },
    { "ps_4_0_level_9_1",  ST_PIXEL,   4, 0, 9, 1, FALSE, FALSE },
    { "ps_4_0_level_9_3",  ST_PIXEL,   4, 0, 9, 3, FALSE, FALSE },
    { "ps_4_1",            ST_PIXEL,   4, 1, 0, 0, FALSE, TRUE  },
    { "ps_5_0",            ST_PIXEL,   5, 0, 0, 0, FALSE, TRUE  },
    { "tx_1_0",            ST_UNKNOWN, 1, 0, 0, 0, FALSE, FALSE },
    { "vs.1.0",            ST_VERTEX,  1, 0, 0, 0, FALSE, TRUE  },
    { "vs.1.1",            ST_VERTEX,  1, 1, 0, 0, FALSE, TRUE  },
    { "vs.2.0",            ST_VERTEX,  2, 0, 0, 0, FALSE, TRUE  },
    { "vs.2.a",            ST_VERTEX,  2, 1, 0, 0, FALSE, FALSE },
    { "vs.2.sw",           ST_VERTEX,  2, 0, 0, 0, TRUE,  FALSE },
    { "vs.3.0",            ST_VERTEX,  3, 0, 0, 0, FALSE, TRUE  },
    { "vs.3.sw",           ST_VERTEX,  3, 0, 0, 0, TRUE,  FALSE },
    { "vs_1_0",            ST_VERTEX,  1, 0, 0, 0, FALSE, TRUE  },
    { "vs_1_1",            ST_VERTEX,  1, 1, 0, 0, FALSE, TRUE  },
    { "vs_2_0",            ST_VERTEX,  2, 0, 0, 0, FALSE, TRUE  },
    { "vs_2_a",            ST_VERTEX,  2, 1, 0, 0, FALSE, FALSE },
    { "vs_2_sw",           ST_VERTEX,  2, 0, 0, 0, TRUE,  FALSE },
    { "vs_3_0",            ST_VERTEX,  3, 0, 0, 0, FALSE, TRUE  },
    { "vs_3_sw",           ST_VERTEX,  3, 0, 0, 0, TRUE,  FALSE },
    { "vs_4_0",            ST_VERTEX,  4, 0, 0, 0, FALSE, TRUE  },
    { "vs_4_0_level_9_0",  ST_VERTEX,  4, 0, 9, 0, FALSE, FALSE },
    { "vs_4_0_level_9_1",  ST_VERTEX,  4, 0, 9, 1, FALSE, FALSE },
    { "vs_4_0_level_9_3",  ST_VERTEX,  4, 0, 9, 3, FALSE, FALSE },
    { "vs_4_1",            ST_VERTEX,  4, 1, 0, 0, FALSE, TRUE  },
    { "vs_5_0",            ST_VERTEX,  5, 0, 0, 0, FALSE, TRUE  },
};

static const struct target_info * get_target_info(const char *target)
{
    LONG min = 0;
    LONG max = sizeof(targets_info) / sizeof(targets_info[0]) - 1;
    LONG cur;
    int res;

    while (min <= max)
    {
        cur = (min + max) / 2;
        res = strcmp(target, targets_info[cur].name);
        if (res < 0)
            max = cur - 1;
        else if (res > 0)
            min = cur + 1;
        else
            return &targets_info[cur];
    }

    return NULL;
}

592 593 594 595 596 597
static HRESULT compile_shader(const char *preproc_shader, const char *target, const char *entrypoint,
        ID3DBlob **shader_blob, ID3DBlob **error_messages)
{
    struct bwriter_shader *shader;
    char *messages = NULL;
    HRESULT hr;
598
    DWORD *res, size, major, minor;
599 600
    ID3DBlob *buffer;
    char *pos;
601
    enum shader_type shader_type;
602
    const struct target_info *info;
603

604 605
    TRACE("Preprocessed shader source: %s\n", debugstr_a(preproc_shader));

606 607 608
    TRACE("Checking compilation target %s\n", debugstr_a(target));
    info = get_target_info(target);
    if (!info)
609
    {
610
        FIXME("Unknown compilation target %s\n", debugstr_a(target));
611 612 613 614
        return D3DERR_INVALIDCALL;
    }
    else
    {
615 616 617 618 619 620 621 622 623 624 625
        if (!info->support)
        {
            FIXME("Compilation target %s not yet supported\n", debugstr_a(target));
            return D3DERR_INVALIDCALL;
        }
        else
        {
            shader_type = info->type;
            major = info->sm_major;
            minor = info->sm_minor;
        }
626 627 628
    }

    shader = parse_hlsl_shader(preproc_shader, shader_type, major, minor, entrypoint, &messages);
629 630 631 632

    if (messages)
    {
        TRACE("Compiler messages:\n");
633
        TRACE("%s\n", debugstr_a(messages));
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

        TRACE("Shader source:\n");
        TRACE("%s\n", debugstr_a(preproc_shader));

        if (error_messages)
        {
            const char *preproc_messages = *error_messages ? ID3D10Blob_GetBufferPointer(*error_messages) : NULL;

            size = strlen(messages) + (preproc_messages ? strlen(preproc_messages) : 0) + 1;
            hr = D3DCreateBlob(size, &buffer);
            if (FAILED(hr))
            {
                HeapFree(GetProcessHeap(), 0, messages);
                if (shader) SlDeleteShader(shader);
                return hr;
            }
            pos = ID3D10Blob_GetBufferPointer(buffer);
            if (preproc_messages)
            {
                memcpy(pos, preproc_messages, strlen(preproc_messages) + 1);
                pos += strlen(preproc_messages);
            }
            memcpy(pos, messages, strlen(messages) + 1);

            if (*error_messages) ID3D10Blob_Release(*error_messages);
            *error_messages = buffer;
        }
        HeapFree(GetProcessHeap(), 0, messages);
    }

    if (!shader)
    {
        ERR("HLSL shader parsing failed.\n");
        return D3DXERR_INVALIDDATA;
    }

    hr = SlWriteBytecode(shader, 9, &res, &size);
    SlDeleteShader(shader);
    if (FAILED(hr))
    {
        ERR("SlWriteBytecode failed with error 0x%08x.\n", hr);
        return D3DXERR_INVALIDDATA;
    }

    if (shader_blob)
    {
        hr = D3DCreateBlob(size, &buffer);
        if (FAILED(hr))
        {
            HeapFree(GetProcessHeap(), 0, res);
            return hr;
        }
        memcpy(ID3D10Blob_GetBufferPointer(buffer), res, size);
        *shader_blob = buffer;
    }

    HeapFree(GetProcessHeap(), 0, res);

    return S_OK;
}

695
HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename,
696
        const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
697 698 699
        const char *target, UINT sflags, UINT eflags, UINT secondary_flags,
        const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader,
        ID3DBlob **error_messages)
700
{
701 702
    HRESULT hr;

703 704 705
    TRACE("data %p, data_size %lu, filename %s, defines %p, include %p, entrypoint %s, "
            "target %s, sflags %#x, eflags %#x, secondary_flags %#x, secondary_data %p, "
            "secondary_data_size %lu, shader %p, error_messages %p.\n",
706
            data, data_size, debugstr_a(filename), defines, include, debugstr_a(entrypoint),
707 708 709 710 711
            debugstr_a(target), sflags, eflags, secondary_flags, secondary_data,
            secondary_data_size, shader, error_messages);

    if (secondary_data)
        FIXME("secondary data not implemented yet\n");
712

713 714 715 716
    if (shader) *shader = NULL;
    if (error_messages) *error_messages = NULL;

    EnterCriticalSection(&wpp_mutex);
717

718
    hr = preprocess_shader(data, data_size, filename, defines, include, error_messages);
719 720
    if (SUCCEEDED(hr))
        hr = compile_shader(wpp_output, target, entrypoint, shader, error_messages);
721

722 723 724
    HeapFree(GetProcessHeap(), 0, wpp_output);
    LeaveCriticalSection(&wpp_mutex);
    return hr;
725
}
726

727 728 729 730
HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename,
        const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
        const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages)
{
731 732
    TRACE("data %p, data_size %lu, filename %s, defines %p, include %p, entrypoint %s, "
            "target %s, sflags %#x, eflags %#x, shader %p, error_messages %p.\n",
733 734 735 736 737 738 739
            data, data_size, debugstr_a(filename), defines, include, debugstr_a(entrypoint),
            debugstr_a(target), sflags, eflags, shader, error_messages);

    return D3DCompile2(data, data_size, filename, defines, include, entrypoint, target, sflags,
            eflags, 0, NULL, 0, shader, error_messages);
}

740 741 742 743 744 745 746
HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename,
        const D3D_SHADER_MACRO *defines, ID3DInclude *include,
        ID3DBlob **shader, ID3DBlob **error_messages)
{
    HRESULT hr;
    ID3DBlob *buffer;

747 748 749
    TRACE("data %p, size %lu, filename %s, defines %p, include %p, shader %p, error_messages %p\n",
          data, size, debugstr_a(filename), defines, include, shader, error_messages);

750 751 752 753 754 755 756 757
    if (!data)
        return E_INVALIDARG;

    EnterCriticalSection(&wpp_mutex);

    if (shader) *shader = NULL;
    if (error_messages) *error_messages = NULL;

758
    hr = preprocess_shader(data, size, filename, defines, include, error_messages);
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778

    if (SUCCEEDED(hr))
    {
        if (shader)
        {
            hr = D3DCreateBlob(wpp_output_size, &buffer);
            if (FAILED(hr))
                goto cleanup;
            CopyMemory(ID3D10Blob_GetBufferPointer(buffer), wpp_output, wpp_output_size);
            *shader = buffer;
        }
        else
            hr = E_INVALIDARG;
    }

cleanup:
    HeapFree(GetProcessHeap(), 0, wpp_output);
    LeaveCriticalSection(&wpp_mutex);
    return hr;
}
779 780 781 782 783 784 785

HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T size, UINT flags, const char *comments, ID3DBlob **disassembly)
{
    FIXME("data %p, size %lu, flags %#x, comments %p, disassembly %p stub!\n",
            data, size, flags, comments, disassembly);
    return E_NOTIMPL;
}
786 787 788 789 790 791 792 793 794

HRESULT WINAPI D3DCompileFromFile(const WCHAR *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *includes,
        const char *entrypoint, const char *target, UINT flags1, UINT flags2, ID3DBlob **code, ID3DBlob **errors)
{
    FIXME("filename %s, defines %p, includes %p, entrypoint %s, target %s, flags1 %x, flags2 %x, code %p, errors %p\n",
            debugstr_w(filename), defines, includes, debugstr_a(entrypoint), debugstr_a(target), flags1, flags2, code, errors);

    return E_NOTIMPL;
}
795 796 797 798 799 800

HRESULT WINAPI D3DLoadModule(const void *data, SIZE_T size, ID3D11Module **module)
{
    FIXME("data %p, size %lu, module %p stub!\n", data, size, module);
    return E_NOTIMPL;
}