shader.c 70.6 KB
Newer Older
1 2
/*
 * Copyright 2008 Luis Busquets
3
 * Copyright 2009 Matteo Bruni
4
 * Copyright 2011 Travis Athougies
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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
 */

#include "config.h"
#include "wine/port.h"
23

24
#include "d3dx9_private.h"
25
#include "d3dcommon.h"
26
#include "d3dcompiler.h"
27 28 29

WINE_DEFAULT_DEBUG_CHANNEL(d3dx);

Henri Verbeet's avatar
Henri Verbeet committed
30 31 32 33
/* This function is not declared in the SDK headers yet. */
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);
34

35 36 37 38 39
static inline BOOL is_valid_bytecode(DWORD token)
{
    return (token & 0xfffe0000) == 0xfffe0000;
}

40
const char * WINAPI D3DXGetPixelShaderProfile(struct IDirect3DDevice9 *device)
41 42 43
{
    D3DCAPS9 caps;

44
    TRACE("device %p\n", device);
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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

    if (!device) return NULL;

    IDirect3DDevice9_GetDeviceCaps(device,&caps);

    switch (caps.PixelShaderVersion)
    {
    case D3DPS_VERSION(1, 1):
        return "ps_1_1";

    case D3DPS_VERSION(1, 2):
        return "ps_1_2";

    case D3DPS_VERSION(1, 3):
        return "ps_1_3";

    case D3DPS_VERSION(1, 4):
        return "ps_1_4";

    case D3DPS_VERSION(2, 0):
        if ((caps.PS20Caps.NumTemps>=22)                          &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
        {
            return "ps_2_a";
        }
        if ((caps.PS20Caps.NumTemps>=32)                          &&
            (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
        {
            return "ps_2_b";
        }
        return "ps_2_0";

    case D3DPS_VERSION(3, 0):
        return "ps_3_0";
    }

    return NULL;
}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
{
    const DWORD *ptr = byte_code;

    TRACE("byte_code %p\n", byte_code);

    if (!ptr) return 0;

    /* Look for the END token, skipping the VERSION token */
    while (*++ptr != D3DSIO_END)
    {
        /* Skip comments */
        if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
        {
            ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
        }
    }
    ++ptr;

    /* Return the shader size in bytes */
    return (ptr - byte_code) * sizeof(*ptr);
}
110 111 112 113 114 115 116

DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
{
    TRACE("byte_code %p\n", byte_code);

    return byte_code ? *byte_code : 0;
}
117

118
const char * WINAPI D3DXGetVertexShaderProfile(struct IDirect3DDevice9 *device)
119 120 121
{
    D3DCAPS9 caps;

122
    TRACE("device %p\n", device);
123 124 125 126 127 128 129 130 131 132 133

    if (!device) return NULL;

    IDirect3DDevice9_GetDeviceCaps(device,&caps);

    switch (caps.VertexShaderVersion)
    {
    case D3DVS_VERSION(1, 1):
        return "vs_1_1";
    case D3DVS_VERSION(2, 0):
        if ((caps.VS20Caps.NumTemps>=13) &&
134
            (caps.VS20Caps.DynamicFlowControlDepth==24) &&
135 136 137 138 139 140 141 142 143 144 145
            (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
        {
            return "vs_2_a";
        }
        return "vs_2_0";
    case D3DVS_VERSION(3, 0):
        return "vs_3_0";
    }

    return NULL;
}
146

147
HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const void **data, UINT *size)
148
{
149
    const DWORD *ptr = byte_code;
150
    DWORD version;
151

152
    TRACE("byte_code %p, fourcc %x, data %p, size %p\n", byte_code, fourcc, data, size);
153

154 155 156
    if (data) *data = NULL;
    if (size) *size = 0;

157
    if (!byte_code) return D3DERR_INVALIDCALL;
158 159 160 161 162 163 164 165 166 167 168 169

    version = *ptr >> 16;
    if (version != 0x4658         /* FX */
            && version != 0x5458  /* TX */
            && version != 0x7ffe
            && version != 0x7fff
            && version != 0xfffe  /* VS */
            && version != 0xffff) /* PS */
    {
        WARN("Invalid data supplied\n");
        return D3DXERR_INVALIDDATA;
    }
170 171 172 173 174 175 176 177 178 179 180

    while (*++ptr != D3DSIO_END)
    {
        /* Check if it is a comment */
        if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
        {
            DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;

            /* Check if this is the comment we are looking for */
            if (*(ptr + 1) == fourcc)
            {
181
                UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
Henri Verbeet's avatar
Henri Verbeet committed
182
                const void *ctab_data = ptr + 2;
183
                if (size)
184
                    *size = ctab_size;
185
                if (data)
186 187
                    *data = ctab_data;
                TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
188 189 190 191 192 193 194 195 196
                return D3D_OK;
            }
            ptr += comment_size;
        }
    }

    return S_FALSE;
}

197 198
HRESULT WINAPI D3DXAssembleShader(const char *data, UINT data_len, const D3DXMACRO *defines,
        ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
199
{
200 201 202 203 204
    HRESULT hr;

    TRACE("data %p, data_len %u, defines %p, include %p, flags %#x, shader %p, error_messages %p\n",
          data, data_len, defines, include, flags, shader, error_messages);

205 206
    /* Forward to d3dcompiler: the parameter types aren't really different,
       the actual data types are equivalent */
207 208 209
    hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
                     (ID3DInclude *)include, flags, (ID3DBlob **)shader,
                     (ID3DBlob **)error_messages);
210

211
    if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
212
    return hr;
213 214
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228
static const void *main_file_data;

static CRITICAL_SECTION from_file_mutex;
static CRITICAL_SECTION_DEBUG from_file_mutex_debug =
{
    0, 0, &from_file_mutex,
    {
        &from_file_mutex_debug.ProcessLocksList,
        &from_file_mutex_debug.ProcessLocksList
    },
    0, 0, {(DWORD_PTR)(__FILE__ ": from_file_mutex")}
};
static CRITICAL_SECTION from_file_mutex = {&from_file_mutex_debug, -1, 0, 0, 0, 0};

229
/* D3DXInclude private implementation, used to implement
Henri Verbeet's avatar
Henri Verbeet committed
230 231 232 233 234 235 236
 * D3DXAssembleShaderFromFile() from D3DXAssembleShader(). */
/* To be able to correctly resolve include search paths we have to store the
 * pathname of each include file. We store the pathname pointer right before
 * the file data. */
static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
        const char *filename, const void *parent_data, const void **data, UINT *bytes)
{
237
    const char *p, *parent_name = "";
238
    char *pathname = NULL, *ptr;
239 240 241 242
    char **buffer = NULL;
    HANDLE file;
    UINT size;

243 244
    if (parent_data)
    {
245
        parent_name = *((const char **)parent_data - 1);
246 247 248 249 250 251
    }
    else
    {
        if (main_file_data)
            parent_name = *((const char **)main_file_data - 1);
    }
252 253 254

    TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));

255 256 257 258
    if ((p = strrchr(parent_name, '\\')))
        ++p;
    else
        p = parent_name;
259 260 261 262 263 264
    pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
    if(!pathname)
        return HRESULT_FROM_WIN32(GetLastError());

    memcpy(pathname, parent_name, p - parent_name);
    strcpy(pathname + (p - parent_name), filename);
265 266 267 268 269 270 271
    ptr = pathname + (p - parent_name);
    while (*ptr)
    {
        if (*ptr == '/')
            *ptr = '\\';
        ++ptr;
    }
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

    file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    if(file == INVALID_HANDLE_VALUE)
        goto error;

    TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));

    size = GetFileSize(file, NULL);
    if(size == INVALID_FILE_SIZE)
        goto error;

    buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
    if(!buffer)
        goto error;
    *buffer = pathname;
    if(!ReadFile(file, buffer + 1, size, bytes, NULL))
        goto error;

    *data = buffer + 1;
291 292
    if (!main_file_data)
        main_file_data = *data;
293 294 295 296 297 298 299 300 301 302 303

    CloseHandle(file);
    return S_OK;

error:
    CloseHandle(file);
    HeapFree(GetProcessHeap(), 0, pathname);
    HeapFree(GetProcessHeap(), 0, buffer);
    return HRESULT_FROM_WIN32(GetLastError());
}

Henri Verbeet's avatar
Henri Verbeet committed
304 305
static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, const void *data)
{
306 307
    HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
    HeapFree(GetProcessHeap(), 0, (char **)data - 1);
308 309
    if (main_file_data == data)
        main_file_data = NULL;
310 311 312 313 314 315 316 317 318
    return S_OK;
}

static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
    d3dincludefromfile_open,
    d3dincludefromfile_close
};

struct D3DXIncludeImpl {
319
    ID3DXInclude ID3DXInclude_iface;
320 321
};

322 323
HRESULT WINAPI D3DXAssembleShaderFromFileA(const char *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
324
{
Henri Verbeet's avatar
Henri Verbeet committed
325
    WCHAR *filename_w;
326 327 328
    DWORD len;
    HRESULT ret;

Henri Verbeet's avatar
Henri Verbeet committed
329 330 331
    TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
            debugstr_a(filename), defines, include, flags, shader, error_messages);

332 333 334 335 336 337 338 339 340 341 342 343 344
    if (!filename) return D3DXERR_INVALIDDATA;

    len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
    filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    if (!filename_w) return E_OUTOFMEMORY;
    MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);

    ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);

    HeapFree(GetProcessHeap(), 0, filename_w);
    return ret;
}

345 346
HRESULT WINAPI D3DXAssembleShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
347
{
348
    const void *buffer;
349 350 351
    DWORD len;
    HRESULT hr;
    struct D3DXIncludeImpl includefromfile;
352
    char *filename_a;
353

354 355 356
    TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
            debugstr_w(filename), defines, include, flags, shader, error_messages);

357 358
    if(!include)
    {
359 360
        includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
        include = &includefromfile.ID3DXInclude_iface;
361 362
    }

363 364 365 366 367
    len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
    filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
    if (!filename_a)
        return E_OUTOFMEMORY;
    WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);
368

369
    EnterCriticalSection(&from_file_mutex);
370
    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
371 372
    if (FAILED(hr))
    {
373
        LeaveCriticalSection(&from_file_mutex);
374 375 376 377 378 379 380
        HeapFree(GetProcessHeap(), 0, filename_a);
        return D3DXERR_INVALIDDATA;
    }

    hr = D3DXAssembleShader(buffer, len, defines, include, flags, shader, error_messages);

    ID3DXInclude_Close(include, buffer);
381
    LeaveCriticalSection(&from_file_mutex);
382
    HeapFree(GetProcessHeap(), 0, filename_a);
383
    return hr;
384
}
385

386 387
HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
388
{
389
    void *buffer;
390 391 392
    HRSRC res;
    DWORD len;

393 394 395
    TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
            module, debugstr_a(resource), defines, include, flags, shader, error_messages);

Henri Verbeet's avatar
Henri Verbeet committed
396
    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
397
        return D3DXERR_INVALIDDATA;
398
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
399 400 401 402 403
        return D3DXERR_INVALIDDATA;
    return D3DXAssembleShader(buffer, len, defines, include, flags,
                              shader, error_messages);
}

404 405
HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
406
{
407
    void *buffer;
408 409 410
    HRSRC res;
    DWORD len;

Henri Verbeet's avatar
Henri Verbeet committed
411 412 413 414
    TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
            module, debugstr_w(resource), defines, include, flags, shader, error_messages);

    if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
415
        return D3DXERR_INVALIDDATA;
416
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
417 418 419 420
        return D3DXERR_INVALIDDATA;
    return D3DXAssembleShader(buffer, len, defines, include, flags,
                              shader, error_messages);
}
421

422 423 424
HRESULT WINAPI D3DXCompileShader(const char *data, UINT length, const D3DXMACRO *defines,
        ID3DXInclude *include, const char *function, const char *profile, DWORD flags,
        ID3DXBuffer **shader, ID3DXBuffer **error_msgs, ID3DXConstantTable **constant_table)
425
{
426 427
    HRESULT hr;

428 429 430 431
    TRACE("data %s, length %u, defines %p, include %p, function %s, profile %s, "
            "flags %#x, shader %p, error_msgs %p, constant_table %p.\n",
            debugstr_a(data), length, defines, include, debugstr_a(function), debugstr_a(profile),
            flags, shader, error_msgs, constant_table);
432 433 434 435 436

    hr = D3DCompile(data, length, NULL, (D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
                    function, profile, flags, 0, (ID3DBlob **)shader, (ID3DBlob **)error_msgs);

    if (SUCCEEDED(hr) && constant_table)
437
    {
438
        hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader), constant_table);
439 440 441 442 443 444
        if (FAILED(hr))
        {
            ID3DXBuffer_Release(*shader);
            *shader = NULL;
        }
    }
445

446
    return hr;
447
}
448

449 450 451
HRESULT WINAPI D3DXCompileShaderFromFileA(const char *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
        ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
452
{
Henri Verbeet's avatar
Henri Verbeet committed
453
    WCHAR *filename_w;
454 455 456
    DWORD len;
    HRESULT ret;

Henri Verbeet's avatar
Henri Verbeet committed
457 458 459 460 461
    TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
            debugstr_a(filename), defines, include, debugstr_a(entrypoint),
            debugstr_a(profile), flags, shader, error_messages, constant_table);

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    if (!filename) return D3DXERR_INVALIDDATA;

    len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
    filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    if (!filename_w) return E_OUTOFMEMORY;
    MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);

    ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
                                     entrypoint, profile, flags,
                                     shader, error_messages, constant_table);

    HeapFree(GetProcessHeap(), 0, filename_w);
    return ret;
}

477 478 479
HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
        ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
480
{
481
    const void *buffer;
482
    DWORD len, filename_len;
483 484 485 486
    HRESULT hr;
    struct D3DXIncludeImpl includefromfile;
    char *filename_a;

487 488 489 490 491
    TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
            debugstr_w(filename), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
            flags, shader, error_messages, constant_table);

492 493
    if (!include)
    {
494 495
        includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
        include = &includefromfile.ID3DXInclude_iface;
496 497
    }

498 499
    filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
    filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
500 501
    if (!filename_a)
        return E_OUTOFMEMORY;
502
    WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
503

504
    EnterCriticalSection(&from_file_mutex);
505
    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
506 507
    if (FAILED(hr))
    {
508
        LeaveCriticalSection(&from_file_mutex);
509 510 511 512
        HeapFree(GetProcessHeap(), 0, filename_a);
        return D3DXERR_INVALIDDATA;
    }

513
    hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
514 515 516 517 518 519 520
                    (ID3DInclude *)include, entrypoint, profile, flags, 0,
                    (ID3DBlob **)shader, (ID3DBlob **)error_messages);

    if (SUCCEEDED(hr) && constant_table)
        hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
                                        constant_table);

521
    ID3DXInclude_Close(include, buffer);
522
    LeaveCriticalSection(&from_file_mutex);
523 524 525 526
    HeapFree(GetProcessHeap(), 0, filename_a);
    return hr;
}

527 528 529
HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
        ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
530
{
531
    void *buffer;
532 533 534
    HRSRC res;
    DWORD len;

535 536 537 538 539
    TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
            module, debugstr_a(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
            flags, shader, error_messages, constant_table);

Henri Verbeet's avatar
Henri Verbeet committed
540
    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
541
        return D3DXERR_INVALIDDATA;
542
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
543 544 545 546 547
        return D3DXERR_INVALIDDATA;
    return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
                             flags, shader, error_messages, constant_table);
}

548 549 550
HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
        ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
551
{
552
    void *buffer;
553 554 555
    HRSRC res;
    DWORD len;

Henri Verbeet's avatar
Henri Verbeet committed
556 557 558 559 560 561
    TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
            module, debugstr_w(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
            flags, shader, error_messages, constant_table);

    if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
562
        return D3DXERR_INVALIDDATA;
563
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
564 565 566 567 568
        return D3DXERR_INVALIDDATA;
    return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
                             flags, shader, error_messages, constant_table);
}

569 570
HRESULT WINAPI D3DXPreprocessShader(const char *data, UINT data_len, const D3DXMACRO *defines,
        ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
571
{
572 573 574
    TRACE("data %s, data_len %u, defines %p, include %p, shader %p, error_messages %p.\n",
            debugstr_a(data), data_len, defines, include, shader, error_messages);

575 576 577 578 579
    return D3DPreprocess(data, data_len, NULL,
                         (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
                         (ID3DBlob **)shader, (ID3DBlob **)error_messages);
}

580 581
HRESULT WINAPI D3DXPreprocessShaderFromFileA(const char *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
582 583 584 585 586
{
    WCHAR *filename_w = NULL;
    DWORD len;
    HRESULT ret;

587 588 589
    TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
            debugstr_a(filename), defines, include, shader, error_messages);

590 591 592 593 594 595 596 597 598 599 600 601 602
    if (!filename) return D3DXERR_INVALIDDATA;

    len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
    filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    if (!filename_w) return E_OUTOFMEMORY;
    MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);

    ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);

    HeapFree(GetProcessHeap(), 0, filename_w);
    return ret;
}

603 604
HRESULT WINAPI D3DXPreprocessShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
        ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
605
{
606
    const void *buffer;
607
    DWORD len;
608 609
    HRESULT hr;
    struct D3DXIncludeImpl includefromfile;
610
    char *filename_a;
611

612 613 614
    TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
            debugstr_w(filename), defines, include, shader, error_messages);

615 616
    if (!include)
    {
617 618
        includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
        include = &includefromfile.ID3DXInclude_iface;
619 620
    }

621 622 623 624 625 626
    len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
    filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
    if (!filename_a)
        return E_OUTOFMEMORY;
    WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);

627
    EnterCriticalSection(&from_file_mutex);
628
    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
629 630
    if (FAILED(hr))
    {
631
        LeaveCriticalSection(&from_file_mutex);
632 633 634 635
        HeapFree(GetProcessHeap(), 0, filename_a);
        return D3DXERR_INVALIDDATA;
    }

636 637 638 639 640
    hr = D3DPreprocess(buffer, len, NULL,
                       (const D3D_SHADER_MACRO *)defines,
                       (ID3DInclude *) include,
                       (ID3DBlob **)shader, (ID3DBlob **)error_messages);

641
    ID3DXInclude_Close(include, buffer);
642
    LeaveCriticalSection(&from_file_mutex);
643
    HeapFree(GetProcessHeap(), 0, filename_a);
644 645 646
    return hr;
}

647 648
HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
649
{
650
    void *buffer;
651 652 653
    HRSRC res;
    DWORD len;

654 655 656
    TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
            module, debugstr_a(resource), defines, include, shader, error_messages);

Henri Verbeet's avatar
Henri Verbeet committed
657
    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
658
        return D3DXERR_INVALIDDATA;
659
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
660 661 662 663 664
        return D3DXERR_INVALIDDATA;
    return D3DXPreprocessShader(buffer, len, defines, include,
                                shader, error_messages);
}

665 666
HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
        ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
667
{
668
    void *buffer;
669 670 671
    HRSRC res;
    DWORD len;

672 673 674
    TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
            module, debugstr_w(resource), defines, include, shader, error_messages);

675 676
    if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
        return D3DXERR_INVALIDDATA;
677
    if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
678 679 680 681 682 683
        return D3DXERR_INVALIDDATA;
    return D3DXPreprocessShader(buffer, len, defines, include,
                                shader, error_messages);

}

684
struct ctab_constant {
685
    D3DXCONSTANT_DESC desc;
686
    struct ctab_constant *constants;
687
};
688

689
struct ID3DXConstantTableImpl {
690
    ID3DXConstantTable ID3DXConstantTable_iface;
691
    LONG ref;
692
    char *ctab;
693
    DWORD size;
694
    D3DXCONSTANTTABLE_DESC desc;
695
    struct ctab_constant *constants;
696
};
697

698 699 700 701 702 703 704 705 706 707 708 709 710 711
static void free_constant(struct ctab_constant *constant)
{
    if (constant->constants)
    {
        UINT i, count = constant->desc.Elements > 1 ? constant->desc.Elements : constant->desc.StructMembers;

        for (i = 0; i < count; ++i)
        {
            free_constant(&constant->constants[i]);
        }
        HeapFree(GetProcessHeap(), 0, constant->constants);
    }
}

712 713
static void free_constant_table(struct ID3DXConstantTableImpl *table)
{
714 715 716 717 718 719 720 721 722 723
    if (table->constants)
    {
        UINT i;

        for (i = 0; i < table->desc.Constants; ++i)
        {
            free_constant(&table->constants[i]);
        }
        HeapFree(GetProcessHeap(), 0, table->constants);
    }
724 725 726
    HeapFree(GetProcessHeap(), 0, table->ctab);
}

727
static inline struct ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
728
{
729
    return CONTAINING_RECORD(iface, struct ID3DXConstantTableImpl, ID3DXConstantTable_iface);
730 731
}

732
static inline BOOL is_vertex_shader(DWORD version)
733
{
734
    return (version & 0xffff0000) == 0xfffe0000;
735 736
}

737
static inline D3DXHANDLE handle_from_constant(struct ctab_constant *constant)
738
{
739
    return (D3DXHANDLE)constant;
740 741
}

Henri Verbeet's avatar
Henri Verbeet committed
742 743
static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
        struct ctab_constant *constant, const char *name);
744

Henri Verbeet's avatar
Henri Verbeet committed
745
static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, const char *name)
746
{
Henri Verbeet's avatar
Henri Verbeet committed
747
    const char *part;
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    UINT element;

    TRACE("constant %p, name %s\n", constant, debugstr_a(name));

    if (!name || !*name) return NULL;

    element = atoi(name);
    part = strchr(name, ']') + 1;

    if (constant->desc.Elements > element)
    {
        struct ctab_constant *c = constant->constants ? &constant->constants[element] : constant;

        switch (*part++)
        {
            case '.':
                return get_constant_by_name(NULL, c, part);

            case '[':
                return get_constant_element_by_name(c, part);

            case '\0':
                TRACE("Returning parameter %p\n", c);
                return c;

            default:
                FIXME("Unhandled case \"%c\"\n", *--part);
                break;
        }
    }

    TRACE("Constant not found\n");
    return NULL;
}

static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
Henri Verbeet's avatar
Henri Verbeet committed
784
        struct ctab_constant *constant, const char *name)
785 786 787
{
    UINT i, count, length;
    struct ctab_constant *handles;
Henri Verbeet's avatar
Henri Verbeet committed
788
    const char *part;
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804

    TRACE("table %p, constant %p, name %s\n", table, constant, debugstr_a(name));

    if (!name || !*name) return NULL;

    if (!constant)
    {
        count = table->desc.Constants;
        handles = table->constants;
    }
    else
    {
        count = constant->desc.StructMembers;
        handles = constant->constants;
    }

805
    length = strcspn(name, "[.");
806 807 808 809 810 811 812 813 814 815 816 817 818 819
    part = name + length;

    for (i = 0; i < count; i++)
    {
        if (strlen(handles[i].desc.Name) == length && !strncmp(handles[i].desc.Name, name, length))
        {
            switch (*part++)
            {
                case '.':
                    return get_constant_by_name(NULL, &handles[i], part);

                case '[':
                    return get_constant_element_by_name(&handles[i], part);

820
                default:
821 822 823 824 825 826 827 828 829 830
                    TRACE("Returning parameter %p\n", &handles[i]);
                    return &handles[i];
            }
        }
    }

    TRACE("Constant not found\n");
    return NULL;
}

831
static struct ctab_constant *is_valid_sub_constant(struct ctab_constant *parent, D3DXHANDLE handle)
832
{
833
    struct ctab_constant *c;
834 835
    UINT i, count;

836
    /* all variable have at least elements = 1, but not always elements */
837 838
    if (!parent->constants) return NULL;

839
    count = parent->desc.Elements > 1 ? parent->desc.Elements : parent->desc.StructMembers;
840 841
    for (i = 0; i < count; ++i)
    {
842 843
        if (handle_from_constant(&parent->constants[i]) == handle)
            return &parent->constants[i];
844

845 846
        c = is_valid_sub_constant(&parent->constants[i], handle);
        if (c) return c;
847 848 849 850 851
    }

    return NULL;
}

852
static inline struct ctab_constant *get_valid_constant(struct ID3DXConstantTableImpl *table, D3DXHANDLE handle)
853
{
854
    struct ctab_constant *c;
855 856
    UINT i;

857
    if (!handle) return NULL;
858 859 860

    for (i = 0; i < table->desc.Constants; ++i)
    {
861 862
        if (handle_from_constant(&table->constants[i]) == handle)
            return &table->constants[i];
863

864 865
        c = is_valid_sub_constant(&table->constants[i], handle);
        if (c) return c;
866 867
    }

868
    return get_constant_by_name(table, NULL, handle);
869 870
}

871
/*** IUnknown methods ***/
872
static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable *iface, REFIID riid, void **out)
873
{
874
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
875 876

    if (IsEqualGUID(riid, &IID_IUnknown) ||
877
        IsEqualGUID(riid, &IID_ID3DXBuffer) ||
878 879 880
        IsEqualGUID(riid, &IID_ID3DXConstantTable))
    {
        ID3DXConstantTable_AddRef(iface);
881
        *out = iface;
882 883 884
        return S_OK;
    }

885
    WARN("Interface %s not found.\n", debugstr_guid(riid));
886 887 888 889

    return E_NOINTERFACE;
}

890
static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable *iface)
891
{
892
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
893 894 895 896 897 898

    TRACE("(%p)->(): AddRef from %d\n", This, This->ref);

    return InterlockedIncrement(&This->ref);
}

899
static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable *iface)
900
{
901
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
902 903 904 905 906
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p)->(): Release from %d\n", This, ref + 1);

    if (!ref)
907
    {
908
        free_constant_table(This);
909
        HeapFree(GetProcessHeap(), 0, This);
910
    }
911 912 913 914 915

    return ref;
}

/*** ID3DXBuffer methods ***/
Henri Verbeet's avatar
Henri Verbeet committed
916
static void * WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
917
{
Henri Verbeet's avatar
Henri Verbeet committed
918
    struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
919

Henri Verbeet's avatar
Henri Verbeet committed
920
    TRACE("iface %p.\n", iface);
921

Henri Verbeet's avatar
Henri Verbeet committed
922
    return table->ctab;
923 924
}

925
static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable *iface)
926
{
927
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
928

929
    TRACE("(%p)->()\n", This);
930

931
    return This->size;
932 933 934
}

/*** ID3DXConstantTable methods ***/
935
static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable *iface, D3DXCONSTANTTABLE_DESC *desc)
936
{
937
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
938

939
    TRACE("(%p)->(%p)\n", This, desc);
940

941 942 943
    if (!desc)
        return D3DERR_INVALIDCALL;

944
    *desc = This->desc;
945 946

    return D3D_OK;
947 948
}

949
static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable *iface, D3DXHANDLE constant,
950 951
                                                             D3DXCONSTANT_DESC *desc, UINT *count)
{
952
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
953
    struct ctab_constant *c = get_valid_constant(This, constant);
954

955
    TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
956

957
    if (!c)
958
    {
959 960
        WARN("Invalid argument specified\n");
        return D3DERR_INVALIDCALL;
961
    }
962

963 964
    if (desc) *desc = c->desc;
    if (count) *count = 1;
965 966

    return D3D_OK;
967 968
}

969
static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(ID3DXConstantTable *iface, D3DXHANDLE constant)
970
{
971
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
972
    struct ctab_constant *c = get_valid_constant(This, constant);
973 974 975

    TRACE("(%p)->(%p)\n", This, constant);

976 977 978
    if (!c || c->desc.RegisterSet != D3DXRS_SAMPLER)
    {
        WARN("Invalid argument specified\n");
979
        return (UINT)-1;
980
    }
981

982 983
    TRACE("Returning RegisterIndex %u\n", c->desc.RegisterIndex);
    return c->desc.RegisterIndex;
984 985
}

986
static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
987
{
988
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
989
    struct ctab_constant *c;
990

991
    TRACE("(%p)->(%p, %d)\n", This, constant, index);
992

993
    if (constant)
994
    {
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
        c = get_valid_constant(This, constant);
        if (c && index < c->desc.StructMembers)
        {
            c = &c->constants[index];
            TRACE("Returning constant %p\n", c);
            return handle_from_constant(c);
        }
    }
    else
    {
        if (index < This->desc.Constants)
        {
            c = &This->constants[index];
            TRACE("Returning constant %p\n", c);
            return handle_from_constant(c);
        }
1011
    }
1012

1013 1014
    WARN("Index out of range\n");
    return NULL;
1015 1016
}

Henri Verbeet's avatar
Henri Verbeet committed
1017 1018
static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface,
        D3DXHANDLE constant, const char *name)
1019
{
1020
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1021
    struct ctab_constant *c = get_valid_constant(This, constant);
1022

Henri Verbeet's avatar
Henri Verbeet committed
1023
    TRACE("iface %p, constant %p, name %s.\n", iface, constant, debugstr_a(name));
1024

1025 1026
    c = get_constant_by_name(This, c, name);
    TRACE("Returning constant %p\n", c);
1027

1028
    return handle_from_constant(c);
1029 1030
}

1031
static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
1032
{
1033
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1034 1035 1036
    struct ctab_constant *c = get_valid_constant(This, constant);

    TRACE("(%p)->(%p, %d)\n", This, constant, index);
1037

1038 1039
    if (c && index < c->desc.Elements)
    {
1040
        if (c->desc.Elements > 1) c = &c->constants[index];
1041 1042 1043
        TRACE("Returning constant %p\n", c);
        return handle_from_constant(c);
    }
1044

1045
    WARN("Invalid argument specified\n");
1046 1047 1048
    return NULL;
}

1049
static inline DWORD get_index(const void **indata, UINT index, BOOL is_pointer)
1050
{
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
    if (!indata)
        return 0;

    if (is_pointer)
        return ((DWORD **)indata)[index / 16][index % 16];

    return (*((DWORD **)indata))[index];
}

static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, struct ctab_constant *constant,
        const void **indata, D3DXPARAMETER_TYPE intype, UINT *size, UINT incol, D3DXPARAMETER_CLASS inclass, UINT index,
        BOOL is_pointer)
{
    D3DXCONSTANT_DESC *desc = &constant->desc;
    UINT l, i, regcount = 1, regsize = 1, cin = 1, rin = 1, ret, last = 0;
    DWORD tmp;
1067

1068
    /* size too small to set anything */
1069
    if (*size < desc->Rows * desc->Columns)
1070
    {
1071 1072
        *size = 0;
        return 0;
1073 1074
    }

1075 1076 1077
    /* D3DXPC_STRUCT is somewhat special */
    if (desc->Class == D3DXPC_STRUCT)
    {
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
        /*
         * Struct array sets the last complete input to the first struct element, all other
         * elements are not set.
         * E.g.: struct {int i;} s1[2];
         *       SetValue(device, "s1", [1, 2], 8) => s1 = {2, x};
         *
         *       struct {int i; int n} s2[2];
         *       SetValue(device, "s2", [1, 2, 3, 4, 5], 20) => s1 = {{3, 4}, {x, x}};
         */
        if (desc->Elements > 1)
        {
            UINT offset = *size / (desc->Rows * desc->Columns) - 1;

            offset = min(desc->Elements - 1, offset);
            last = offset * desc->Rows * desc->Columns;

1094
            if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
            {
                set(table, device, &constant->constants[0], NULL, intype, size, incol, inclass, 0, is_pointer);
            }
            else
            {
                last += set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
                        index + last, is_pointer);
            }
        }
        else
        {
            /*
             * D3DXRS_BOOL is always set. As there are only 16 bools and there are
             * exactly 16 input values, use matrix transpose.
             */
            if (inclass == D3DXPC_MATRIX_ROWS && desc->RegisterSet == D3DXRS_BOOL)
            {
                D3DXMATRIX mat, *m, min;
                D3DXMatrixTranspose(&mat, &min);

                if (is_pointer)
                    min = *(D3DXMATRIX *)(indata[index / 16]);
                else
                    min = **(D3DXMATRIX **)indata;

                D3DXMatrixTranspose(&mat, &min);
                m = &mat;
                for (i = 0; i < desc->StructMembers; ++i)
                {
                    last += set(table, device, &constant->constants[i], (const void **)&m, intype, size, incol,
                            D3DXPC_SCALAR, index + last, is_pointer);
                }
            }
            /*
             * For pointers or for matrix rows, only the first member is set.
             * All other members are set to 0. This is not true for D3DXRS_BOOL.
             * E.g.: struct {int i; int n} s;
             *       SetValue(device, "s", [1, 2], 8) => s = {1, 0};
             */
1134
            else if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
            {
                last = set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
                        index + last, is_pointer);

                for (i = 1; i < desc->StructMembers; ++i)
                {
                    set(table, device, &constant->constants[i], NULL, intype, size, incol, inclass, 0, is_pointer);
                }
            }
            else
            {
                for (i = 0; i < desc->StructMembers; ++i)
                {
                    last += set(table, device, &constant->constants[i], indata, intype, size, incol, D3DXPC_SCALAR,
                            index + last, is_pointer);
                }
            }
        }

        return last;
1155
    }
1156

1157 1158
    /* elements */
    if (desc->Elements > 1)
1159
    {
1160 1161 1162 1163 1164 1165 1166
        for (i = 0; i < desc->Elements && *size > 0; ++i)
        {
            last += set(table, device, &constant->constants[i], indata, intype, size, incol, inclass,
                    index + last, is_pointer);

            /* adjust the vector size for matrix rows */
            if (inclass == D3DXPC_MATRIX_ROWS && desc->Class == D3DXPC_VECTOR && (i % 4) == 3)
1167
            {
1168 1169
                last += 12;
                *size = *size < 12 ? 0 : *size - 12;
1170
            }
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
        }

        return last;
    }

    switch (desc->Class)
    {
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
            regcount = min(desc->RegisterCount, desc->Rows);
            if (inclass == D3DXPC_MATRIX_ROWS) cin = incol;
            else rin = incol;
            regsize = desc->Columns;
1185
            break;
1186 1187

        case D3DXPC_MATRIX_COLUMNS:
1188
            regcount = min(desc->RegisterCount, desc->Columns);
1189 1190 1191 1192 1193
            if (inclass == D3DXPC_MATRIX_ROWS) rin = incol;
            else cin = incol;
            regsize = desc->Rows;
            break;

1194
        default:
1195 1196
            FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
            return 0;
1197 1198
    }

1199 1200 1201 1202 1203 1204 1205
    /* specific stuff for different in types */
    switch (inclass)
    {
        case D3DXPC_SCALAR:
            ret = desc->Columns * desc->Rows;
            *size -= desc->Columns * desc->Rows;
            break;
1206

1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
        case D3DXPC_VECTOR:
            switch (desc->Class)
            {
                case D3DXPC_MATRIX_ROWS:
                    if (*size < regcount * 4)
                    {
                        *size = 0;
                        return 0;
                    }
                    ret = 4 * regcount;
                    *size -= 4 * regcount;
                    break;
1219

1220 1221 1222 1223
                case D3DXPC_MATRIX_COLUMNS:
                    ret = 4 * regsize;
                    *size -= 4 * regcount;
                    break;
1224

1225 1226 1227 1228
                case D3DXPC_SCALAR:
                    ret = 1;
                    *size -= ret;
                    break;
1229

1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
                case D3DXPC_VECTOR:
                    ret = 4;
                    *size -= ret;
                    break;

                default:
                    FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
                    return 0;
            }
            break;

        case D3DXPC_MATRIX_ROWS:
            switch (desc->Class)
1243
            {
1244 1245 1246 1247 1248 1249 1250 1251 1252
                case D3DXPC_MATRIX_ROWS:
                case D3DXPC_MATRIX_COLUMNS:
                    if (*size < 16)
                    {
                        *size = 0;
                        return 0;
                    }
                    ret = 16;
                    break;
1253

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
                case D3DXPC_SCALAR:
                    ret = 4;
                    break;

                case D3DXPC_VECTOR:
                    ret = 1;
                    break;

                default:
                    FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
                    return 0;
1265
            }
1266
            *size -= ret;
1267
            break;
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296

        case D3DXPC_MATRIX_COLUMNS:
            switch (desc->Class)
            {
                case D3DXPC_MATRIX_ROWS:
                case D3DXPC_MATRIX_COLUMNS:
                    if (*size < 16)
                    {
                        *size = 0;
                        return 0;
                    }
                    ret = 16;
                    break;

                case D3DXPC_SCALAR:
                    ret = 1;
                    break;

                case D3DXPC_VECTOR:
                    ret = 4;
                    break;

                default:
                    FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
                    return 0;
            }
            *size -= ret;
            break;

1297
        default:
1298 1299
            FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(inclass));
            return 0;
1300 1301
    }

1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
    /* set the registers */
    switch (desc->RegisterSet)
    {
        case D3DXRS_BOOL:
            regcount = min(desc->RegisterCount, desc->Columns * desc->Rows);
            l = 0;
            for (i = 0; i < regcount; ++i)
            {
                BOOL out;
                DWORD t = get_index(indata, index + i / regsize * rin + l * cin, is_pointer);
1312

1313 1314 1315 1316 1317 1318
                set_number(&tmp, desc->Type, &t, intype);
                set_number(&out, D3DXPT_BOOL, &tmp, desc->Type);
                if (is_vertex_shader(table->desc.Version))
                    IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
                else
                    IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
1319

1320 1321 1322 1323 1324 1325
                if (++l >= regsize) l = 0;
            }
            return ret;

        case D3DXRS_INT4:
            for (i = 0; i < regcount; ++i)
1326
            {
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
                INT vec[4] = {0, 0, 1, 0};

                for (l = 0; l < regsize; ++l)
                {
                    DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);

                    set_number(&tmp, desc->Type, &t, intype);
                    set_number(&vec[l], D3DXPT_INT, &tmp, desc->Type);
                }
                if (is_vertex_shader(table->desc.Version))
                    IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
                else
                    IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
1340
            }
1341 1342 1343 1344
            return ret;

        case D3DXRS_FLOAT4:
            for (i = 0; i < regcount; ++i)
1345
            {
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
                FLOAT vec[4] = {0};

                for (l = 0; l < regsize; ++l)
                {
                    DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);

                    set_number(&tmp, desc->Type, &t, intype);
                    set_number(&vec[l], D3DXPT_FLOAT, &tmp, desc->Type);
                }
                if (is_vertex_shader(table->desc.Version))
                    IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
                else
                    IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
1359
            }
1360 1361
            return ret;

1362
        default:
1363 1364
            FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
            return 0;
1365 1366 1367
    }
}

1368 1369
static HRESULT set_scalar(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
        const void *indata, D3DXPARAMETER_TYPE intype)
1370
{
1371 1372
    struct ctab_constant *c = get_valid_constant(table, constant);
    UINT count = 1;
1373

1374
    if (!c)
1375
    {
1376
        WARN("Invalid argument specified\n");
1377 1378 1379
        return D3DERR_INVALIDCALL;
    }

1380
    switch (c->desc.Class)
1381
    {
1382 1383 1384
        case D3DXPC_SCALAR:
            set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
            return D3D_OK;
1385

1386 1387 1388 1389 1390
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
        case D3DXPC_STRUCT:
            return D3D_OK;
1391

1392 1393 1394
        default:
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
1395
    }
1396 1397 1398 1399 1400 1401 1402 1403
}

static HRESULT set_scalar_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
        const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
{
    struct ctab_constant *c = get_valid_constant(table, constant);

    if (!c)
1404
    {
1405 1406
        WARN("Invalid argument specified\n");
        return D3DERR_INVALIDCALL;
1407 1408
    }

1409
    switch (c->desc.Class)
1410
    {
1411 1412 1413 1414 1415 1416 1417
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
        case D3DXPC_STRUCT:
            set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
            return D3D_OK;
1418

1419
        default:
1420 1421
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
1422 1423 1424
    }
}

1425 1426
static HRESULT set_vector(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
        const void *indata, D3DXPARAMETER_TYPE intype)
1427
{
1428 1429 1430 1431
    struct ctab_constant *c = get_valid_constant(table, constant);
    UINT count = 4;

    if (!c)
1432
    {
1433
        WARN("Invalid argument specified\n");
1434 1435 1436
        return D3DERR_INVALIDCALL;
    }

1437
    switch (c->desc.Class)
1438
    {
1439 1440 1441 1442 1443
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_STRUCT:
            set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
            return D3D_OK;
1444

1445 1446 1447
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
            return D3D_OK;
1448

1449 1450 1451
        default:
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
1452
    }
1453 1454 1455 1456 1457 1458 1459 1460
}

static HRESULT set_vector_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
        const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
{
    struct ctab_constant *c = get_valid_constant(table, constant);

    if (!c)
1461
    {
1462 1463
        WARN("Invalid argument specified\n");
        return D3DERR_INVALIDCALL;
1464
    }
1465 1466

    switch (c->desc.Class)
1467
    {
1468 1469 1470 1471 1472 1473 1474 1475
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
        case D3DXPC_STRUCT:
            count *= 4;
            set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
            return D3D_OK;
1476

1477 1478 1479
        default:
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
1480
    }
1481 1482 1483 1484 1485 1486 1487 1488
}

static HRESULT set_matrix_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
        const void *indata, UINT count, BOOL transpose)
{
    struct ctab_constant *c = get_valid_constant(table, constant);

    if (!c)
1489
    {
1490 1491
        WARN("Invalid argument specified\n");
        return D3DERR_INVALIDCALL;
1492 1493
    }

1494
    switch (c->desc.Class)
1495
    {
1496 1497 1498 1499 1500 1501 1502 1503 1504
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
        case D3DXPC_STRUCT:
            count *= 16;
            set(table, device, c, &indata, D3DXPT_FLOAT, &count, 4,
                    transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, FALSE);
            return D3D_OK;
1505

1506 1507 1508 1509 1510
        default:
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
    }
}
1511

1512 1513 1514 1515
static HRESULT set_matrix_pointer_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
        D3DXHANDLE constant, const void **indata, UINT count, BOOL transpose)
{
    struct ctab_constant *c = get_valid_constant(table, constant);
1516

1517 1518 1519 1520
    if (!c)
    {
        WARN("Invalid argument specified\n");
        return D3DERR_INVALIDCALL;
1521 1522
    }

1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
    switch (c->desc.Class)
    {
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
        case D3DXPC_STRUCT:
            count *= 16;
            set(table, device, c, indata, D3DXPT_FLOAT, &count, 4,
                    transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, TRUE);
            return D3D_OK;

        default:
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
            return D3DERR_INVALIDCALL;
    }
1539 1540
}

1541 1542
static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device)
1543
{
1544
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1545 1546
    UINT i;

1547
    TRACE("iface %p, device %p\n", iface, device);
1548 1549

    if (!device)
1550 1551
    {
        WARN("Invalid argument specified\n");
1552
        return D3DERR_INVALIDCALL;
1553
    }
1554 1555 1556 1557

    for (i = 0; i < This->desc.Constants; i++)
    {
        D3DXCONSTANT_DESC *desc = &This->constants[i].desc;
1558
        HRESULT hr;
1559

1560 1561
        if (!desc->DefaultValue)
            continue;
1562

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
        switch (desc->RegisterSet)
        {
            case D3DXRS_BOOL:
                if (is_vertex_shader(This->desc.Version))
                    hr = IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
                            desc->RegisterCount);
                else
                    hr = IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
                            desc->RegisterCount);
                break;

            case D3DXRS_INT4:
                if (is_vertex_shader(This->desc.Version))
                    hr = IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
                            desc->RegisterCount);
                else
                    hr = IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
                        desc->RegisterCount);
                break;

            case D3DXRS_FLOAT4:
                if (is_vertex_shader(This->desc.Version))
                    hr = IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
                            desc->RegisterCount);
                else
                    hr = IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
                        desc->RegisterCount);
                break;

            default:
                FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
                hr = E_NOTIMPL;
                break;
        }

        if (hr != D3D_OK)
            return hr;
1600 1601 1602
    }

    return D3D_OK;
1603 1604
}

1605
static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(struct ID3DXConstantTable *iface,
1606
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data, unsigned int bytes)
1607
{
1608 1609 1610
    struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
    struct ctab_constant *c = get_valid_constant(table, constant);
    D3DXCONSTANT_DESC *desc;
1611

1612
    TRACE("iface %p, device %p, constant %p, data %p, bytes %u\n", iface, device, constant, data, bytes);
1613

1614 1615 1616
    if (!device || !c || !data)
    {
        WARN("Invalid argument specified\n");
1617
        return D3DERR_INVALIDCALL;
1618
    }
1619

1620
    desc = &c->desc;
1621

1622
    switch (desc->Class)
1623 1624 1625 1626 1627
    {
        case D3DXPC_SCALAR:
        case D3DXPC_VECTOR:
        case D3DXPC_MATRIX_ROWS:
        case D3DXPC_MATRIX_COLUMNS:
1628 1629 1630 1631 1632
        case D3DXPC_STRUCT:
            bytes /= 4;
            set(table, device, c, &data, desc->Type, &bytes, desc->Columns, D3DXPC_SCALAR, 0, FALSE);
            return D3D_OK;

1633
        default:
1634
            FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(desc->Class));
1635 1636
            return D3DERR_INVALIDCALL;
    }
1637 1638
}

1639 1640
static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, BOOL b)
1641
{
1642
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1643

1644
    TRACE("iface %p, device %p, constant %p, b %d\n", iface, device, constant, b);
1645

1646
    return set_scalar(This, device, constant, &b, D3DXPT_BOOL);
1647 1648
}

1649 1650
static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const BOOL *b, UINT count)
1651
{
1652
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1653

1654
    TRACE("iface %p, device %p, constant %p, b %p, count %d\n", iface, device, constant, b, count);
1655

1656
    return set_scalar_array(This, device, constant, b, count, D3DXPT_BOOL);
1657 1658
}

1659 1660
static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, INT n)
1661
{
1662
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1663

1664
    TRACE("iface %p, device %p, constant %p, n %d\n", iface, device, constant, n);
1665

1666
    return set_scalar(This, device, constant, &n, D3DXPT_INT);
1667 1668
}

1669 1670
static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const INT *n, UINT count)
1671
{
1672
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1673

1674
    TRACE("iface %p, device %p, constant %p, n %p, count %d\n", iface, device, constant, n, count);
1675

1676
    return set_scalar_array(This, device, constant, n, count, D3DXPT_INT);
1677 1678
}

1679 1680
static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, float f)
1681
{
1682
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1683

1684
    TRACE("iface %p, device %p, constant %p, f %f\n", iface, device, constant, f);
1685

1686
    return set_scalar(This, device, constant, &f, D3DXPT_FLOAT);
1687 1688
}

1689 1690
static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const float *f, UINT count)
1691
{
1692
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1693

1694
    TRACE("iface %p, device %p, constant %p, f %p, count %d\n", iface, device, constant, f, count);
1695

1696
    return set_scalar_array(This, device, constant, f, count, D3DXPT_FLOAT);
1697 1698
}

1699 1700
static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector)
1701
{
1702
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1703

1704
    TRACE("iface %p, device %p, constant %p, vector %p\n", iface, device, constant, vector);
1705

1706
    return set_vector(This, device, constant, vector, D3DXPT_FLOAT);
1707 1708
}

1709 1710
static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector, UINT count)
1711
{
1712
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1713

1714
    TRACE("iface %p, device %p, constant %p, vector %p, count %u\n", iface, device, constant, vector, count);
1715

1716
    return set_vector_array(This, device, constant, vector, count, D3DXPT_FLOAT);
1717 1718
}

1719 1720
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1721
{
1722
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1723

1724
    TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1725

1726
    return set_matrix_array(This, device, constant, matrix, 1, FALSE);
1727 1728
}

1729 1730
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1731
{
1732
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1733

1734
    TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1735

1736
    return set_matrix_array(This, device, constant, matrix, count, FALSE);
1737 1738
}

1739 1740
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1741
{
1742
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1743

1744
    TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1745

1746
    return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, FALSE);
1747 1748
}

1749 1750
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1751
{
1752
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1753

1754
    TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1755

1756
    return set_matrix_array(This, device, constant, matrix, 1, TRUE);
1757 1758
}

1759 1760
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1761
{
1762
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1763

1764
    TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1765

1766
    return set_matrix_array(This, device, constant, matrix, count, TRUE);
1767 1768
}

1769 1770
static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(struct ID3DXConstantTable *iface,
        struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1771
{
1772
    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1773

1774
    TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1775

1776
    return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, TRUE);
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
}

static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
{
    /*** IUnknown methods ***/
    ID3DXConstantTableImpl_QueryInterface,
    ID3DXConstantTableImpl_AddRef,
    ID3DXConstantTableImpl_Release,
    /*** ID3DXBuffer methods ***/
    ID3DXConstantTableImpl_GetBufferPointer,
    ID3DXConstantTableImpl_GetBufferSize,
    /*** ID3DXConstantTable methods ***/
    ID3DXConstantTableImpl_GetDesc,
    ID3DXConstantTableImpl_GetConstantDesc,
1791
    ID3DXConstantTableImpl_GetSamplerIndex,
1792 1793
    ID3DXConstantTableImpl_GetConstant,
    ID3DXConstantTableImpl_GetConstantByName,
1794
    ID3DXConstantTableImpl_GetConstantElement,
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
    ID3DXConstantTableImpl_SetDefaults,
    ID3DXConstantTableImpl_SetValue,
    ID3DXConstantTableImpl_SetBool,
    ID3DXConstantTableImpl_SetBoolArray,
    ID3DXConstantTableImpl_SetInt,
    ID3DXConstantTableImpl_SetIntArray,
    ID3DXConstantTableImpl_SetFloat,
    ID3DXConstantTableImpl_SetFloatArray,
    ID3DXConstantTableImpl_SetVector,
    ID3DXConstantTableImpl_SetVectorArray,
    ID3DXConstantTableImpl_SetMatrix,
    ID3DXConstantTableImpl_SetMatrixArray,
    ID3DXConstantTableImpl_SetMatrixPointerArray,
    ID3DXConstantTableImpl_SetMatrixTranspose,
    ID3DXConstantTableImpl_SetMatrixTransposeArray,
    ID3DXConstantTableImpl_SetMatrixTransposePointerArray
};

1813
static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, struct ctab_constant *constant,
1814
        BOOL is_element, WORD index, WORD max_index, DWORD *offset, DWORD nameoffset, UINT regset)
1815
{
1816 1817 1818 1819 1820 1821 1822
    const D3DXSHADER_TYPEINFO *type = (LPD3DXSHADER_TYPEINFO)(ctab + typeoffset);
    const D3DXSHADER_STRUCTMEMBERINFO *memberinfo = NULL;
    HRESULT hr = D3D_OK;
    UINT i, count = 0;
    WORD size = 0;

    constant->desc.DefaultValue = offset ? ctab + *offset : NULL;
1823 1824 1825 1826
    constant->desc.Class = type->Class;
    constant->desc.Type = type->Type;
    constant->desc.Rows = type->Rows;
    constant->desc.Columns = type->Columns;
1827
    constant->desc.Elements = is_element ? 1 : type->Elements;
1828
    constant->desc.StructMembers = type->StructMembers;
1829 1830 1831
    constant->desc.Name = ctab + nameoffset;
    constant->desc.RegisterSet = regset;
    constant->desc.RegisterIndex = index;
1832

1833 1834 1835
    TRACE("name %s, elements %u, index %u, defaultvalue %p, regset %s\n", constant->desc.Name,
            constant->desc.Elements, index, constant->desc.DefaultValue,
            debug_d3dxparameter_registerset(regset));
1836 1837 1838
    TRACE("class %s, type %s, rows %d, columns %d, elements %d, struct_members %d\n",
            debug_d3dxparameter_class(type->Class), debug_d3dxparameter_type(type->Type),
            type->Rows, type->Columns, type->Elements, type->StructMembers);
1839

1840 1841 1842 1843 1844
    if (type->Elements > 1 && !is_element)
    {
        count = type->Elements;
    }
    else if ((type->Class == D3DXPC_STRUCT) && type->StructMembers)
1845
    {
1846 1847
        memberinfo = (D3DXSHADER_STRUCTMEMBERINFO*)(ctab + type->StructMemberInfo);
        count = type->StructMembers;
1848 1849
    }

1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
    if (count)
    {
        constant->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*constant->constants) * count);
        if (!constant->constants)
        {
             ERR("Out of memory\n");
             hr = E_OUTOFMEMORY;
             goto error;
        }

        for (i = 0; i < count; ++i)
        {
            hr = parse_ctab_constant_type(ctab, memberinfo ? memberinfo[i].TypeInfo : typeoffset,
1863
                    &constant->constants[i], memberinfo == NULL, index + size, max_index, offset,
1864 1865 1866 1867
                    memberinfo ? memberinfo[i].Name : nameoffset, regset);
            if (hr != D3D_OK)
                goto error;

1868
            size += constant->constants[i].desc.RegisterCount;
1869 1870 1871 1872
        }
    }
    else
    {
1873 1874
        WORD offsetdiff = type->Columns * type->Rows;
        BOOL fail = FALSE;
1875

1876 1877 1878
        size = type->Columns * type->Rows;

        switch (regset)
1879
        {
1880 1881 1882
            case D3DXRS_BOOL:
                fail = type->Class != D3DXPC_SCALAR && type->Class != D3DXPC_VECTOR
                        && type->Class != D3DXPC_MATRIX_ROWS && type->Class != D3DXPC_MATRIX_COLUMNS;
1883 1884
                break;

1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897
            case D3DXRS_FLOAT4:
            case D3DXRS_INT4:
                switch (type->Class)
                {
                    case D3DXPC_VECTOR:
                        size = 1;
                        /* fall through */
                    case D3DXPC_SCALAR:
                        offsetdiff = type->Rows * 4;
                        break;

                    case D3DXPC_MATRIX_ROWS:
                        offsetdiff = type->Rows * 4;
1898
                        size = type->Rows;
1899
                        break;
1900

1901 1902 1903 1904 1905 1906 1907 1908 1909
                    case D3DXPC_MATRIX_COLUMNS:
                        offsetdiff = type->Columns * 4;
                        size = type->Columns;
                        break;

                    default:
                        fail = TRUE;
                        break;
                }
1910 1911
                break;

1912
            case D3DXRS_SAMPLER:
1913
                size = 1;
1914
                fail = type->Class != D3DXPC_OBJECT;
1915 1916 1917
                break;

            default:
1918
                fail = TRUE;
1919 1920 1921
                break;
        }

1922
        if (fail)
1923
        {
1924 1925
            FIXME("Unhandled register set %s, type class %s\n", debug_d3dxparameter_registerset(regset),
                    debug_d3dxparameter_class(type->Class));
1926
        }
1927 1928 1929

        /* offset in bytes => offsetdiff * sizeof(DWORD) */
        if (offset) *offset += offsetdiff * 4;
1930 1931
    }

1932
    constant->desc.RegisterCount = max(0, min(max_index - index, size));
1933
    constant->desc.Bytes = 4 * constant->desc.Elements * type->Rows * type->Columns;
1934

1935
    return D3D_OK;
1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948

error:
    if (constant->constants)
    {
        for (i = 0; i < count; ++i)
        {
            free_constant(&constant->constants[i]);
        }
        HeapFree(GetProcessHeap(), 0, constant->constants);
        constant->constants = NULL;
    }

    return hr;
1949 1950
}

1951
HRESULT WINAPI D3DXGetShaderConstantTableEx(const DWORD *byte_code, DWORD flags, ID3DXConstantTable **constant_table)
1952
{
1953
    struct ID3DXConstantTableImpl *object = NULL;
Henri Verbeet's avatar
Henri Verbeet committed
1954
    const void *data;
1955 1956
    HRESULT hr;
    UINT size;
1957
    const D3DXSHADER_CONSTANTTABLE *ctab_header;
1958
    const D3DXSHADER_CONSTANTINFO *constant_info;
1959
    DWORD i;
1960

1961 1962 1963
    TRACE("byte_code %p, flags %x, constant_table %p\n", byte_code, flags, constant_table);

    if (constant_table) *constant_table = NULL;
1964

1965
    if (!byte_code || !constant_table)
1966 1967
    {
        WARN("Invalid argument specified.\n");
1968
        return D3DERR_INVALIDCALL;
1969
    }
1970

1971 1972 1973 1974 1975 1976
    if (!is_valid_bytecode(*byte_code))
    {
        WARN("Invalid byte_code specified.\n");
        return D3D_OK;
    }

1977 1978
    if (flags) FIXME("Flags (%#x) are not handled, yet!\n", flags);

1979
    hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1980
    if (hr != D3D_OK)
1981 1982
    {
        WARN("CTAB not found.\n");
1983
        return D3DXERR_INVALIDDATA;
1984 1985
    }

1986
    if (size < sizeof(*ctab_header))
1987 1988 1989 1990 1991 1992
    {
        WARN("Invalid CTAB size.\n");
        return D3DXERR_INVALIDDATA;
    }

    ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
1993
    if (ctab_header->Size != sizeof(*ctab_header))
1994 1995 1996 1997
    {
        WARN("Invalid D3DXSHADER_CONSTANTTABLE size.\n");
        return D3DXERR_INVALIDDATA;
    }
1998

1999
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2000 2001 2002
    if (!object)
        return E_OUTOFMEMORY;

2003
    object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
2004 2005
    object->ref = 1;

2006
    object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
2007 2008 2009
    if (!object->ctab)
    {
        ERR("Out of memory\n");
2010 2011
        HeapFree(GetProcessHeap(), 0, object);
        return E_OUTOFMEMORY;
2012 2013 2014 2015
    }
    object->size = size;
    memcpy(object->ctab, data, object->size);

2016
    object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
2017 2018
    object->desc.Version = ctab_header->Version;
    object->desc.Constants = ctab_header->Constants;
2019 2020 2021
    TRACE("Creator %s, Version %x, Constants %u, Target %s\n",
            debugstr_a(object->desc.Creator), object->desc.Version, object->desc.Constants,
            debugstr_a(ctab_header->Target ? object->ctab + ctab_header->Target : NULL));
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031

    object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                  sizeof(*object->constants) * object->desc.Constants);
    if (!object->constants)
    {
         ERR("Out of memory\n");
         hr = E_OUTOFMEMORY;
         goto error;
    }

2032
    constant_info = (const D3DXSHADER_CONSTANTINFO *)(object->ctab + ctab_header->ConstantInfo);
2033 2034
    for (i = 0; i < ctab_header->Constants; i++)
    {
2035 2036 2037 2038 2039 2040
        DWORD offset = constant_info[i].DefaultValue;

        hr = parse_ctab_constant_type(object->ctab, constant_info[i].TypeInfo,
                &object->constants[i], FALSE, constant_info[i].RegisterIndex,
                constant_info[i].RegisterIndex + constant_info[i].RegisterCount,
                offset ? &offset : NULL, constant_info[i].Name, constant_info[i].RegisterSet);
2041 2042
        if (hr != D3D_OK)
            goto error;
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054

        /*
         * Set the register count, it may differ for D3DXRS_INT4, because somehow
         * it makes the assumption that the register size is 1 instead of 4, so the
         * count is 4 times bigger. This holds true only for toplevel shader
         * constants. The count of elements and members is always based on a
         * register size of 4.
         */
        if (object->constants[i].desc.RegisterSet == D3DXRS_INT4)
        {
            object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
        }
2055
    }
2056

2057
    *constant_table = &object->ID3DXConstantTable_iface;
2058 2059

    return D3D_OK;
2060 2061

error:
2062
    free_constant_table(object);
2063
    HeapFree(GetProcessHeap(), 0, object);
2064

2065
    return hr;
2066 2067
}

2068
HRESULT WINAPI D3DXGetShaderConstantTable(const DWORD *byte_code, ID3DXConstantTable **constant_table)
2069
{
2070
    TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
2071

2072
    return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
2073
}
2074

2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
HRESULT WINAPI D3DXCreateFragmentLinker(IDirect3DDevice9 *device, UINT size, ID3DXFragmentLinker **linker)
{
    FIXME("device %p, size %u, linker %p: stub.\n", device, size, linker);

    if (linker)
        *linker = NULL;


    return E_NOTIMPL;
}

HRESULT WINAPI D3DXCreateFragmentLinkerEx(IDirect3DDevice9 *device, UINT size, DWORD flags, ID3DXFragmentLinker **linker)
{
    FIXME("device %p, size %u, flags %#x, linker %p: stub.\n", device, size, flags, linker);

    if (linker)
        *linker = NULL;

    return E_NOTIMPL;
}

2096
HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **samplers, UINT *count)
2097 2098
{
    UINT i, sampler_count = 0;
2099
    UINT size;
2100
    const char *data;
2101 2102
    const D3DXSHADER_CONSTANTTABLE *ctab_header;
    const D3DXSHADER_CONSTANTINFO *constant_info;
2103 2104 2105 2106 2107

    TRACE("byte_code %p, samplers %p, count %p\n", byte_code, samplers, count);

    if (count) *count = 0;

2108 2109
    if (D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), (const void **)&data, &size) != D3D_OK)
        return D3D_OK;
2110

2111
    if (size < sizeof(*ctab_header)) return D3D_OK;
2112

2113 2114
    ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
    if (ctab_header->Size != sizeof(*ctab_header)) return D3D_OK;
2115

2116
    constant_info = (const D3DXSHADER_CONSTANTINFO *)(data + ctab_header->ConstantInfo);
2117
    for (i = 0; i < ctab_header->Constants; i++)
2118
    {
2119
        const D3DXSHADER_TYPEINFO *type;
2120

2121 2122
        TRACE("name = %s\n", data + constant_info[i].Name);

2123
        type = (const D3DXSHADER_TYPEINFO *)(data + constant_info[i].TypeInfo);
2124

2125 2126 2127 2128 2129
        if (type->Type == D3DXPT_SAMPLER
                || type->Type == D3DXPT_SAMPLER1D
                || type->Type == D3DXPT_SAMPLER2D
                || type->Type == D3DXPT_SAMPLER3D
                || type->Type == D3DXPT_SAMPLERCUBE)
2130
        {
2131
            if (samplers) samplers[sampler_count] = data + constant_info[i].Name;
2132 2133 2134 2135 2136 2137 2138 2139 2140

            ++sampler_count;
        }
    }

    TRACE("Found %u samplers\n", sampler_count);

    if (count) *count = sampler_count;

2141
    return D3D_OK;
2142
}
2143 2144 2145 2146 2147 2148

HRESULT WINAPI D3DXDisassembleShader(const DWORD *shader, BOOL colorcode, const char *comments, ID3DXBuffer **disassembly)
{
   FIXME("%p %d %s %p: stub\n", shader, colorcode, debugstr_a(comments), disassembly);
   return E_OUTOFMEMORY;
}