Sync with trunk r62529.
[reactos.git] / dll / directx / wine / d3dx9_36 / shader.c
1 /*
2 * Copyright 2008 Luis Busquets
3 * Copyright 2009 Matteo Bruni
4 * Copyright 2011 Travis Athougies
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "d3dx9_36_private.h"
22 #include "d3dcompiler.h"
23
24 /* This function is not declared in the SDK headers yet */
25 HRESULT WINAPI D3DAssemble(LPCVOID data, SIZE_T datasize, LPCSTR filename,
26 const D3D_SHADER_MACRO *defines, ID3DInclude *include,
27 UINT flags,
28 ID3DBlob **shader, ID3DBlob **error_messages);
29
30 static inline BOOL is_valid_bytecode(DWORD token)
31 {
32 return (token & 0xfffe0000) == 0xfffe0000;
33 }
34
35 const char * WINAPI D3DXGetPixelShaderProfile(struct IDirect3DDevice9 *device)
36 {
37 D3DCAPS9 caps;
38
39 TRACE("device %p\n", device);
40
41 if (!device) return NULL;
42
43 IDirect3DDevice9_GetDeviceCaps(device,&caps);
44
45 switch (caps.PixelShaderVersion)
46 {
47 case D3DPS_VERSION(1, 1):
48 return "ps_1_1";
49
50 case D3DPS_VERSION(1, 2):
51 return "ps_1_2";
52
53 case D3DPS_VERSION(1, 3):
54 return "ps_1_3";
55
56 case D3DPS_VERSION(1, 4):
57 return "ps_1_4";
58
59 case D3DPS_VERSION(2, 0):
60 if ((caps.PS20Caps.NumTemps>=22) &&
61 (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE) &&
62 (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
63 (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION) &&
64 (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
65 (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
66 {
67 return "ps_2_a";
68 }
69 if ((caps.PS20Caps.NumTemps>=32) &&
70 (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
71 {
72 return "ps_2_b";
73 }
74 return "ps_2_0";
75
76 case D3DPS_VERSION(3, 0):
77 return "ps_3_0";
78 }
79
80 return NULL;
81 }
82
83 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
84 {
85 const DWORD *ptr = byte_code;
86
87 TRACE("byte_code %p\n", byte_code);
88
89 if (!ptr) return 0;
90
91 /* Look for the END token, skipping the VERSION token */
92 while (*++ptr != D3DSIO_END)
93 {
94 /* Skip comments */
95 if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
96 {
97 ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
98 }
99 }
100 ++ptr;
101
102 /* Return the shader size in bytes */
103 return (ptr - byte_code) * sizeof(*ptr);
104 }
105
106 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
107 {
108 TRACE("byte_code %p\n", byte_code);
109
110 return byte_code ? *byte_code : 0;
111 }
112
113 const char * WINAPI D3DXGetVertexShaderProfile(struct IDirect3DDevice9 *device)
114 {
115 D3DCAPS9 caps;
116
117 TRACE("device %p\n", device);
118
119 if (!device) return NULL;
120
121 IDirect3DDevice9_GetDeviceCaps(device,&caps);
122
123 switch (caps.VertexShaderVersion)
124 {
125 case D3DVS_VERSION(1, 1):
126 return "vs_1_1";
127 case D3DVS_VERSION(2, 0):
128 if ((caps.VS20Caps.NumTemps>=13) &&
129 (caps.VS20Caps.DynamicFlowControlDepth==24) &&
130 (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
131 {
132 return "vs_2_a";
133 }
134 return "vs_2_0";
135 case D3DVS_VERSION(3, 0):
136 return "vs_3_0";
137 }
138
139 return NULL;
140 }
141
142 HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const void **data, UINT *size)
143 {
144 const DWORD *ptr = byte_code;
145
146 TRACE("byte_code %p, fourcc %x, data %p, size %p\n", byte_code, fourcc, data, size);
147
148 if (data) *data = NULL;
149 if (size) *size = 0;
150
151 if (!byte_code) return D3DERR_INVALIDCALL;
152 if (!is_valid_bytecode(*byte_code)) return D3DXERR_INVALIDDATA;
153
154 while (*++ptr != D3DSIO_END)
155 {
156 /* Check if it is a comment */
157 if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
158 {
159 DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
160
161 /* Check if this is the comment we are looking for */
162 if (*(ptr + 1) == fourcc)
163 {
164 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
165 LPCVOID ctab_data = ptr + 2;
166 if (size)
167 *size = ctab_size;
168 if (data)
169 *data = ctab_data;
170 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
171 return D3D_OK;
172 }
173 ptr += comment_size;
174 }
175 }
176
177 return S_FALSE;
178 }
179
180 HRESULT WINAPI D3DXAssembleShader(const char *data, UINT data_len, const D3DXMACRO *defines,
181 ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
182 {
183 HRESULT hr;
184
185 TRACE("data %p, data_len %u, defines %p, include %p, flags %#x, shader %p, error_messages %p\n",
186 data, data_len, defines, include, flags, shader, error_messages);
187
188 /* Forward to d3dcompiler: the parameter types aren't really different,
189 the actual data types are equivalent */
190 hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
191 (ID3DInclude *)include, flags, (ID3DBlob **)shader,
192 (ID3DBlob **)error_messages);
193
194 if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
195 return hr;
196 }
197
198 /* D3DXInclude private implementation, used to implement
199 D3DXAssembleShaderFromFile from D3DXAssembleShader */
200 /* To be able to correctly resolve include search paths we have to store
201 the pathname of each include file. We store the pathname pointer right
202 before the file data. */
203 static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
204 D3DXINCLUDE_TYPE include_type,
205 LPCSTR filename, LPCVOID parent_data,
206 LPCVOID *data, UINT *bytes) {
207 const char *p, *parent_name = "";
208 char *pathname = NULL;
209 char **buffer = NULL;
210 HANDLE file;
211 UINT size;
212
213 if(parent_data != NULL)
214 parent_name = *((const char **)parent_data - 1);
215
216 TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
217
218 if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
219 else p = parent_name;
220 pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
221 if(!pathname)
222 return HRESULT_FROM_WIN32(GetLastError());
223
224 memcpy(pathname, parent_name, p - parent_name);
225 strcpy(pathname + (p - parent_name), filename);
226
227 file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
228 if(file == INVALID_HANDLE_VALUE)
229 goto error;
230
231 TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
232
233 size = GetFileSize(file, NULL);
234 if(size == INVALID_FILE_SIZE)
235 goto error;
236
237 buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
238 if(!buffer)
239 goto error;
240 *buffer = pathname;
241 if(!ReadFile(file, buffer + 1, size, bytes, NULL))
242 goto error;
243
244 *data = buffer + 1;
245
246 CloseHandle(file);
247 return S_OK;
248
249 error:
250 CloseHandle(file);
251 HeapFree(GetProcessHeap(), 0, pathname);
252 HeapFree(GetProcessHeap(), 0, buffer);
253 return HRESULT_FROM_WIN32(GetLastError());
254 }
255
256 static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
257 HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
258 HeapFree(GetProcessHeap(), 0, (char **)data - 1);
259 return S_OK;
260 }
261
262 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
263 d3dincludefromfile_open,
264 d3dincludefromfile_close
265 };
266
267 struct D3DXIncludeImpl {
268 ID3DXInclude ID3DXInclude_iface;
269 };
270
271 HRESULT WINAPI D3DXAssembleShaderFromFileA(const char *filename, const D3DXMACRO *defines,
272 ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
273 {
274 LPWSTR filename_w = NULL;
275 DWORD len;
276 HRESULT ret;
277
278 if (!filename) return D3DXERR_INVALIDDATA;
279
280 len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
281 filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
282 if (!filename_w) return E_OUTOFMEMORY;
283 MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
284
285 ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
286
287 HeapFree(GetProcessHeap(), 0, filename_w);
288 return ret;
289 }
290
291 HRESULT WINAPI D3DXAssembleShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
292 ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
293 {
294 void *buffer;
295 DWORD len;
296 HRESULT hr;
297 struct D3DXIncludeImpl includefromfile;
298
299 if(FAILED(map_view_of_file(filename, &buffer, &len)))
300 return D3DXERR_INVALIDDATA;
301
302 if(!include)
303 {
304 includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
305 include = &includefromfile.ID3DXInclude_iface;
306 }
307
308 hr = D3DXAssembleShader(buffer, len, defines, include, flags,
309 shader, error_messages);
310
311 UnmapViewOfFile(buffer);
312 return hr;
313 }
314
315 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
316 ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
317 {
318 void *buffer;
319 HRSRC res;
320 DWORD len;
321
322 if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
323 return D3DXERR_INVALIDDATA;
324 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
325 return D3DXERR_INVALIDDATA;
326 return D3DXAssembleShader(buffer, len, defines, include, flags,
327 shader, error_messages);
328 }
329
330 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
331 ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
332 {
333 void *buffer;
334 HRSRC res;
335 DWORD len;
336
337 TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
338 module, debugstr_w(resource), defines, include, flags, shader, error_messages);
339
340 if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
341 return D3DXERR_INVALIDDATA;
342 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
343 return D3DXERR_INVALIDDATA;
344 return D3DXAssembleShader(buffer, len, defines, include, flags,
345 shader, error_messages);
346 }
347
348 HRESULT WINAPI D3DXCompileShader(const char *data, UINT length, const D3DXMACRO *defines,
349 ID3DXInclude *include, const char *function, const char *profile, DWORD flags,
350 ID3DXBuffer **shader, ID3DXBuffer **error_msgs, ID3DXConstantTable **constant_table)
351 {
352 HRESULT hr;
353
354 TRACE("data %p, length %u, defines %p, include %p, function %s, profile %s, flags %#x, shader %p, error_msgs %p, constant_table %p\n",
355 data, length, defines, include, function, profile, flags, shader, error_msgs, constant_table);
356
357 hr = D3DCompile(data, length, NULL, (D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
358 function, profile, flags, 0, (ID3DBlob **)shader, (ID3DBlob **)error_msgs);
359
360 if (SUCCEEDED(hr) && constant_table)
361 {
362 hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader), constant_table);
363 if (FAILED(hr))
364 {
365 ID3DXBuffer_Release(*shader);
366 *shader = NULL;
367 }
368 }
369
370 return hr;
371 }
372
373 HRESULT WINAPI D3DXCompileShaderFromFileA(const char *filename, const D3DXMACRO *defines,
374 ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
375 ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
376 {
377 LPWSTR filename_w = NULL;
378 DWORD len;
379 HRESULT ret;
380
381 if (!filename) return D3DXERR_INVALIDDATA;
382
383 len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
384 filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
385 if (!filename_w) return E_OUTOFMEMORY;
386 MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
387
388 ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
389 entrypoint, profile, flags,
390 shader, error_messages, constant_table);
391
392 HeapFree(GetProcessHeap(), 0, filename_w);
393 return ret;
394 }
395
396 HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
397 ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
398 ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
399 {
400 void *buffer;
401 DWORD len, filename_len;
402 HRESULT hr;
403 struct D3DXIncludeImpl includefromfile;
404 char *filename_a;
405
406 if (FAILED(map_view_of_file(filename, &buffer, &len)))
407 return D3DXERR_INVALIDDATA;
408
409 if (!include)
410 {
411 includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
412 include = &includefromfile.ID3DXInclude_iface;
413 }
414
415 filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
416 filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
417 if (!filename_a)
418 {
419 UnmapViewOfFile(buffer);
420 return E_OUTOFMEMORY;
421 }
422 WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
423
424 hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
425 (ID3DInclude *)include, entrypoint, profile, flags, 0,
426 (ID3DBlob **)shader, (ID3DBlob **)error_messages);
427
428 if (SUCCEEDED(hr) && constant_table)
429 hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
430 constant_table);
431
432 HeapFree(GetProcessHeap(), 0, filename_a);
433 UnmapViewOfFile(buffer);
434 return hr;
435 }
436
437 HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
438 ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
439 ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
440 {
441 void *buffer;
442 HRSRC res;
443 DWORD len;
444
445 if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
446 return D3DXERR_INVALIDDATA;
447 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
448 return D3DXERR_INVALIDDATA;
449 return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
450 flags, shader, error_messages, constant_table);
451 }
452
453 HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
454 ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
455 ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
456 {
457 void *buffer;
458 HRSRC res;
459 DWORD len;
460
461 TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
462 "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
463 module, debugstr_w(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
464 flags, shader, error_messages, constant_table);
465
466 if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
467 return D3DXERR_INVALIDDATA;
468 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
469 return D3DXERR_INVALIDDATA;
470 return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
471 flags, shader, error_messages, constant_table);
472 }
473
474 HRESULT WINAPI D3DXPreprocessShader(const char *data, UINT data_len, const D3DXMACRO *defines,
475 ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
476 {
477 TRACE("Forward to D3DPreprocess\n");
478 return D3DPreprocess(data, data_len, NULL,
479 (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
480 (ID3DBlob **)shader, (ID3DBlob **)error_messages);
481 }
482
483 HRESULT WINAPI D3DXPreprocessShaderFromFileA(const char *filename, const D3DXMACRO *defines,
484 ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
485 {
486 WCHAR *filename_w = NULL;
487 DWORD len;
488 HRESULT ret;
489
490 if (!filename) return D3DXERR_INVALIDDATA;
491
492 len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
493 filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
494 if (!filename_w) return E_OUTOFMEMORY;
495 MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
496
497 ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);
498
499 HeapFree(GetProcessHeap(), 0, filename_w);
500 return ret;
501 }
502
503 HRESULT WINAPI D3DXPreprocessShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
504 ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
505 {
506 void *buffer;
507 DWORD len;
508 HRESULT hr;
509 struct D3DXIncludeImpl includefromfile;
510
511 if (FAILED(map_view_of_file(filename, &buffer, &len)))
512 return D3DXERR_INVALIDDATA;
513
514 if (!include)
515 {
516 includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
517 include = &includefromfile.ID3DXInclude_iface;
518 }
519
520 hr = D3DPreprocess(buffer, len, NULL,
521 (const D3D_SHADER_MACRO *)defines,
522 (ID3DInclude *) include,
523 (ID3DBlob **)shader, (ID3DBlob **)error_messages);
524
525 UnmapViewOfFile(buffer);
526 return hr;
527 }
528
529 HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
530 ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
531 {
532 void *buffer;
533 HRSRC res;
534 DWORD len;
535
536 if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
537 return D3DXERR_INVALIDDATA;
538 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
539 return D3DXERR_INVALIDDATA;
540 return D3DXPreprocessShader(buffer, len, defines, include,
541 shader, error_messages);
542 }
543
544 HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
545 ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
546 {
547 void *buffer;
548 HRSRC res;
549 DWORD len;
550
551 if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
552 return D3DXERR_INVALIDDATA;
553 if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
554 return D3DXERR_INVALIDDATA;
555 return D3DXPreprocessShader(buffer, len, defines, include,
556 shader, error_messages);
557
558 }
559
560 struct ctab_constant {
561 D3DXCONSTANT_DESC desc;
562 struct ctab_constant *constants;
563 };
564
565 struct ID3DXConstantTableImpl {
566 ID3DXConstantTable ID3DXConstantTable_iface;
567 LONG ref;
568 char *ctab;
569 DWORD size;
570 D3DXCONSTANTTABLE_DESC desc;
571 struct ctab_constant *constants;
572 };
573
574 static void free_constant(struct ctab_constant *constant)
575 {
576 if (constant->constants)
577 {
578 UINT i, count = constant->desc.Elements > 1 ? constant->desc.Elements : constant->desc.StructMembers;
579
580 for (i = 0; i < count; ++i)
581 {
582 free_constant(&constant->constants[i]);
583 }
584 HeapFree(GetProcessHeap(), 0, constant->constants);
585 }
586 }
587
588 static void free_constant_table(struct ID3DXConstantTableImpl *table)
589 {
590 if (table->constants)
591 {
592 UINT i;
593
594 for (i = 0; i < table->desc.Constants; ++i)
595 {
596 free_constant(&table->constants[i]);
597 }
598 HeapFree(GetProcessHeap(), 0, table->constants);
599 }
600 HeapFree(GetProcessHeap(), 0, table->ctab);
601 }
602
603 static inline struct ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
604 {
605 return CONTAINING_RECORD(iface, struct ID3DXConstantTableImpl, ID3DXConstantTable_iface);
606 }
607
608 static inline BOOL is_vertex_shader(DWORD version)
609 {
610 return (version & 0xffff0000) == 0xfffe0000;
611 }
612
613 static inline D3DXHANDLE handle_from_constant(struct ctab_constant *constant)
614 {
615 return (D3DXHANDLE)constant;
616 }
617
618 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *, struct ctab_constant *, LPCSTR);
619
620 static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, LPCSTR name)
621 {
622 UINT element;
623 LPCSTR part;
624
625 TRACE("constant %p, name %s\n", constant, debugstr_a(name));
626
627 if (!name || !*name) return NULL;
628
629 element = atoi(name);
630 part = strchr(name, ']') + 1;
631
632 if (constant->desc.Elements > element)
633 {
634 struct ctab_constant *c = constant->constants ? &constant->constants[element] : constant;
635
636 switch (*part++)
637 {
638 case '.':
639 return get_constant_by_name(NULL, c, part);
640
641 case '[':
642 return get_constant_element_by_name(c, part);
643
644 case '\0':
645 TRACE("Returning parameter %p\n", c);
646 return c;
647
648 default:
649 FIXME("Unhandled case \"%c\"\n", *--part);
650 break;
651 }
652 }
653
654 TRACE("Constant not found\n");
655 return NULL;
656 }
657
658 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
659 struct ctab_constant *constant, LPCSTR name)
660 {
661 UINT i, count, length;
662 struct ctab_constant *handles;
663 LPCSTR part;
664
665 TRACE("table %p, constant %p, name %s\n", table, constant, debugstr_a(name));
666
667 if (!name || !*name) return NULL;
668
669 if (!constant)
670 {
671 count = table->desc.Constants;
672 handles = table->constants;
673 }
674 else
675 {
676 count = constant->desc.StructMembers;
677 handles = constant->constants;
678 }
679
680 length = strcspn(name, "[.");
681 part = name + length;
682
683 for (i = 0; i < count; i++)
684 {
685 if (strlen(handles[i].desc.Name) == length && !strncmp(handles[i].desc.Name, name, length))
686 {
687 switch (*part++)
688 {
689 case '.':
690 return get_constant_by_name(NULL, &handles[i], part);
691
692 case '[':
693 return get_constant_element_by_name(&handles[i], part);
694
695 default:
696 TRACE("Returning parameter %p\n", &handles[i]);
697 return &handles[i];
698 }
699 }
700 }
701
702 TRACE("Constant not found\n");
703 return NULL;
704 }
705
706 static struct ctab_constant *is_valid_sub_constant(struct ctab_constant *parent, D3DXHANDLE handle)
707 {
708 struct ctab_constant *c;
709 UINT i, count;
710
711 /* all variable have at least elements = 1, but not always elements */
712 if (!parent->constants) return NULL;
713
714 count = parent->desc.Elements > 1 ? parent->desc.Elements : parent->desc.StructMembers;
715 for (i = 0; i < count; ++i)
716 {
717 if (handle_from_constant(&parent->constants[i]) == handle)
718 return &parent->constants[i];
719
720 c = is_valid_sub_constant(&parent->constants[i], handle);
721 if (c) return c;
722 }
723
724 return NULL;
725 }
726
727 static inline struct ctab_constant *get_valid_constant(struct ID3DXConstantTableImpl *table, D3DXHANDLE handle)
728 {
729 struct ctab_constant *c;
730 UINT i;
731
732 if (!handle) return NULL;
733
734 for (i = 0; i < table->desc.Constants; ++i)
735 {
736 if (handle_from_constant(&table->constants[i]) == handle)
737 return &table->constants[i];
738
739 c = is_valid_sub_constant(&table->constants[i], handle);
740 if (c) return c;
741 }
742
743 return get_constant_by_name(table, NULL, handle);
744 }
745
746 /*** IUnknown methods ***/
747 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable *iface, REFIID riid, void **out)
748 {
749 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
750
751 if (IsEqualGUID(riid, &IID_IUnknown) ||
752 IsEqualGUID(riid, &IID_ID3DXBuffer) ||
753 IsEqualGUID(riid, &IID_ID3DXConstantTable))
754 {
755 ID3DXConstantTable_AddRef(iface);
756 *out = iface;
757 return S_OK;
758 }
759
760 WARN("Interface %s not found.\n", debugstr_guid(riid));
761
762 return E_NOINTERFACE;
763 }
764
765 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable *iface)
766 {
767 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
768
769 TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
770
771 return InterlockedIncrement(&This->ref);
772 }
773
774 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable *iface)
775 {
776 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
777 ULONG ref = InterlockedDecrement(&This->ref);
778
779 TRACE("(%p)->(): Release from %d\n", This, ref + 1);
780
781 if (!ref)
782 {
783 free_constant_table(This);
784 HeapFree(GetProcessHeap(), 0, This);
785 }
786
787 return ref;
788 }
789
790 /*** ID3DXBuffer methods ***/
791 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
792 {
793 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
794
795 TRACE("(%p)->()\n", This);
796
797 return This->ctab;
798 }
799
800 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable *iface)
801 {
802 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
803
804 TRACE("(%p)->()\n", This);
805
806 return This->size;
807 }
808
809 /*** ID3DXConstantTable methods ***/
810 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable *iface, D3DXCONSTANTTABLE_DESC *desc)
811 {
812 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
813
814 TRACE("(%p)->(%p)\n", This, desc);
815
816 if (!desc)
817 return D3DERR_INVALIDCALL;
818
819 *desc = This->desc;
820
821 return D3D_OK;
822 }
823
824 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable *iface, D3DXHANDLE constant,
825 D3DXCONSTANT_DESC *desc, UINT *count)
826 {
827 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
828 struct ctab_constant *c = get_valid_constant(This, constant);
829
830 TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
831
832 if (!c)
833 {
834 WARN("Invalid argument specified\n");
835 return D3DERR_INVALIDCALL;
836 }
837
838 if (desc) *desc = c->desc;
839 if (count) *count = 1;
840
841 return D3D_OK;
842 }
843
844 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(ID3DXConstantTable *iface, D3DXHANDLE constant)
845 {
846 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
847 struct ctab_constant *c = get_valid_constant(This, constant);
848
849 TRACE("(%p)->(%p)\n", This, constant);
850
851 if (!c || c->desc.RegisterSet != D3DXRS_SAMPLER)
852 {
853 WARN("Invalid argument specified\n");
854 return (UINT)-1;
855 }
856
857 TRACE("Returning RegisterIndex %u\n", c->desc.RegisterIndex);
858 return c->desc.RegisterIndex;
859 }
860
861 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
862 {
863 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
864 struct ctab_constant *c;
865
866 TRACE("(%p)->(%p, %d)\n", This, constant, index);
867
868 if (constant)
869 {
870 c = get_valid_constant(This, constant);
871 if (c && index < c->desc.StructMembers)
872 {
873 c = &c->constants[index];
874 TRACE("Returning constant %p\n", c);
875 return handle_from_constant(c);
876 }
877 }
878 else
879 {
880 if (index < This->desc.Constants)
881 {
882 c = &This->constants[index];
883 TRACE("Returning constant %p\n", c);
884 return handle_from_constant(c);
885 }
886 }
887
888 WARN("Index out of range\n");
889 return NULL;
890 }
891
892 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface, D3DXHANDLE constant, LPCSTR name)
893 {
894 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
895 struct ctab_constant *c = get_valid_constant(This, constant);
896
897 TRACE("(%p)->(%p, %s)\n", This, constant, name);
898
899 c = get_constant_by_name(This, c, name);
900 TRACE("Returning constant %p\n", c);
901
902 return handle_from_constant(c);
903 }
904
905 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
906 {
907 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
908 struct ctab_constant *c = get_valid_constant(This, constant);
909
910 TRACE("(%p)->(%p, %d)\n", This, constant, index);
911
912 if (c && index < c->desc.Elements)
913 {
914 if (c->desc.Elements > 1) c = &c->constants[index];
915 TRACE("Returning constant %p\n", c);
916 return handle_from_constant(c);
917 }
918
919 WARN("Invalid argument specified\n");
920 return NULL;
921 }
922
923 static inline DWORD get_index(const void **indata, UINT index, BOOL is_pointer)
924 {
925 if (!indata)
926 return 0;
927
928 if (is_pointer)
929 return ((DWORD **)indata)[index / 16][index % 16];
930
931 return (*((DWORD **)indata))[index];
932 }
933
934 static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, struct ctab_constant *constant,
935 const void **indata, D3DXPARAMETER_TYPE intype, UINT *size, UINT incol, D3DXPARAMETER_CLASS inclass, UINT index,
936 BOOL is_pointer)
937 {
938 D3DXCONSTANT_DESC *desc = &constant->desc;
939 UINT l, i, regcount = 1, regsize = 1, cin = 1, rin = 1, ret, last = 0;
940 DWORD tmp;
941
942 /* size to small to set anything */
943 if (*size < desc->Rows * desc->Columns)
944 {
945 *size = 0;
946 return 0;
947 }
948
949 /* D3DXPC_STRUCT is somewhat special */
950 if (desc->Class == D3DXPC_STRUCT)
951 {
952 /*
953 * Struct array sets the last complete input to the first struct element, all other
954 * elements are not set.
955 * E.g.: struct {int i;} s1[2];
956 * SetValue(device, "s1", [1, 2], 8) => s1 = {2, x};
957 *
958 * struct {int i; int n} s2[2];
959 * SetValue(device, "s2", [1, 2, 3, 4, 5], 20) => s1 = {{3, 4}, {x, x}};
960 */
961 if (desc->Elements > 1)
962 {
963 UINT offset = *size / (desc->Rows * desc->Columns) - 1;
964
965 offset = min(desc->Elements - 1, offset);
966 last = offset * desc->Rows * desc->Columns;
967
968 if ((is_pointer || (!is_pointer && inclass == D3DXPC_MATRIX_ROWS)) && desc->RegisterSet != D3DXRS_BOOL)
969 {
970 set(table, device, &constant->constants[0], NULL, intype, size, incol, inclass, 0, is_pointer);
971 }
972 else
973 {
974 last += set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
975 index + last, is_pointer);
976 }
977 }
978 else
979 {
980 /*
981 * D3DXRS_BOOL is always set. As there are only 16 bools and there are
982 * exactly 16 input values, use matrix transpose.
983 */
984 if (inclass == D3DXPC_MATRIX_ROWS && desc->RegisterSet == D3DXRS_BOOL)
985 {
986 D3DXMATRIX mat, *m, min;
987 D3DXMatrixTranspose(&mat, &min);
988
989 if (is_pointer)
990 min = *(D3DXMATRIX *)(indata[index / 16]);
991 else
992 min = **(D3DXMATRIX **)indata;
993
994 D3DXMatrixTranspose(&mat, &min);
995 m = &mat;
996 for (i = 0; i < desc->StructMembers; ++i)
997 {
998 last += set(table, device, &constant->constants[i], (const void **)&m, intype, size, incol,
999 D3DXPC_SCALAR, index + last, is_pointer);
1000 }
1001 }
1002 /*
1003 * For pointers or for matrix rows, only the first member is set.
1004 * All other members are set to 0. This is not true for D3DXRS_BOOL.
1005 * E.g.: struct {int i; int n} s;
1006 * SetValue(device, "s", [1, 2], 8) => s = {1, 0};
1007 */
1008 else if ((is_pointer || (!is_pointer && inclass == D3DXPC_MATRIX_ROWS)) && desc->RegisterSet != D3DXRS_BOOL)
1009 {
1010 last = set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
1011 index + last, is_pointer);
1012
1013 for (i = 1; i < desc->StructMembers; ++i)
1014 {
1015 set(table, device, &constant->constants[i], NULL, intype, size, incol, inclass, 0, is_pointer);
1016 }
1017 }
1018 else
1019 {
1020 for (i = 0; i < desc->StructMembers; ++i)
1021 {
1022 last += set(table, device, &constant->constants[i], indata, intype, size, incol, D3DXPC_SCALAR,
1023 index + last, is_pointer);
1024 }
1025 }
1026 }
1027
1028 return last;
1029 }
1030
1031 /* elements */
1032 if (desc->Elements > 1)
1033 {
1034 for (i = 0; i < desc->Elements && *size > 0; ++i)
1035 {
1036 last += set(table, device, &constant->constants[i], indata, intype, size, incol, inclass,
1037 index + last, is_pointer);
1038
1039 /* adjust the vector size for matrix rows */
1040 if (inclass == D3DXPC_MATRIX_ROWS && desc->Class == D3DXPC_VECTOR && (i % 4) == 3)
1041 {
1042 last += 12;
1043 *size = *size < 12 ? 0 : *size - 12;
1044 }
1045 }
1046
1047 return last;
1048 }
1049
1050 switch (desc->Class)
1051 {
1052 case D3DXPC_SCALAR:
1053 case D3DXPC_VECTOR:
1054 case D3DXPC_MATRIX_ROWS:
1055 regcount = min(desc->RegisterCount, desc->Rows);
1056 if (inclass == D3DXPC_MATRIX_ROWS) cin = incol;
1057 else rin = incol;
1058 regsize = desc->Columns;
1059 break;
1060
1061 case D3DXPC_MATRIX_COLUMNS:
1062 regcount = desc->Columns;
1063 if (inclass == D3DXPC_MATRIX_ROWS) rin = incol;
1064 else cin = incol;
1065 regsize = desc->Rows;
1066 break;
1067
1068 default:
1069 FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1070 return 0;
1071 }
1072
1073 /* specific stuff for different in types */
1074 switch (inclass)
1075 {
1076 case D3DXPC_SCALAR:
1077 ret = desc->Columns * desc->Rows;
1078 *size -= desc->Columns * desc->Rows;
1079 break;
1080
1081 case D3DXPC_VECTOR:
1082 switch (desc->Class)
1083 {
1084 case D3DXPC_MATRIX_ROWS:
1085 if (*size < regcount * 4)
1086 {
1087 *size = 0;
1088 return 0;
1089 }
1090 ret = 4 * regcount;
1091 *size -= 4 * regcount;
1092 break;
1093
1094 case D3DXPC_MATRIX_COLUMNS:
1095 ret = 4 * regsize;
1096 *size -= 4 * regcount;
1097 break;
1098
1099 case D3DXPC_SCALAR:
1100 ret = 1;
1101 *size -= ret;
1102 break;
1103
1104 case D3DXPC_VECTOR:
1105 ret = 4;
1106 *size -= ret;
1107 break;
1108
1109 default:
1110 FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1111 return 0;
1112 }
1113 break;
1114
1115 case D3DXPC_MATRIX_ROWS:
1116 switch (desc->Class)
1117 {
1118 case D3DXPC_MATRIX_ROWS:
1119 case D3DXPC_MATRIX_COLUMNS:
1120 if (*size < 16)
1121 {
1122 *size = 0;
1123 return 0;
1124 }
1125 ret = 16;
1126 break;
1127
1128 case D3DXPC_SCALAR:
1129 ret = 4;
1130 break;
1131
1132 case D3DXPC_VECTOR:
1133 ret = 1;
1134 break;
1135
1136 default:
1137 FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1138 return 0;
1139 }
1140 *size -= ret;
1141 break;
1142
1143 case D3DXPC_MATRIX_COLUMNS:
1144 switch (desc->Class)
1145 {
1146 case D3DXPC_MATRIX_ROWS:
1147 case D3DXPC_MATRIX_COLUMNS:
1148 if (*size < 16)
1149 {
1150 *size = 0;
1151 return 0;
1152 }
1153 ret = 16;
1154 break;
1155
1156 case D3DXPC_SCALAR:
1157 ret = 1;
1158 break;
1159
1160 case D3DXPC_VECTOR:
1161 ret = 4;
1162 break;
1163
1164 default:
1165 FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1166 return 0;
1167 }
1168 *size -= ret;
1169 break;
1170
1171 default:
1172 FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(inclass));
1173 return 0;
1174 }
1175
1176 /* set the registers */
1177 switch (desc->RegisterSet)
1178 {
1179 case D3DXRS_BOOL:
1180 regcount = min(desc->RegisterCount, desc->Columns * desc->Rows);
1181 l = 0;
1182 for (i = 0; i < regcount; ++i)
1183 {
1184 BOOL out;
1185 DWORD t = get_index(indata, index + i / regsize * rin + l * cin, is_pointer);
1186
1187 set_number(&tmp, desc->Type, &t, intype);
1188 set_number(&out, D3DXPT_BOOL, &tmp, desc->Type);
1189 if (is_vertex_shader(table->desc.Version))
1190 IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
1191 else
1192 IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
1193
1194 if (++l >= regsize) l = 0;
1195 }
1196 return ret;
1197
1198 case D3DXRS_INT4:
1199 for (i = 0; i < regcount; ++i)
1200 {
1201 INT vec[4] = {0, 0, 1, 0};
1202
1203 for (l = 0; l < regsize; ++l)
1204 {
1205 DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);
1206
1207 set_number(&tmp, desc->Type, &t, intype);
1208 set_number(&vec[l], D3DXPT_INT, &tmp, desc->Type);
1209 }
1210 if (is_vertex_shader(table->desc.Version))
1211 IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
1212 else
1213 IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
1214 }
1215 return ret;
1216
1217 case D3DXRS_FLOAT4:
1218 for (i = 0; i < regcount; ++i)
1219 {
1220 FLOAT vec[4] = {0};
1221
1222 for (l = 0; l < regsize; ++l)
1223 {
1224 DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);
1225
1226 set_number(&tmp, desc->Type, &t, intype);
1227 set_number(&vec[l], D3DXPT_FLOAT, &tmp, desc->Type);
1228 }
1229 if (is_vertex_shader(table->desc.Version))
1230 IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
1231 else
1232 IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
1233 }
1234 return ret;
1235
1236 default:
1237 FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
1238 return 0;
1239 }
1240 }
1241
1242 static HRESULT set_scalar(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1243 const void *indata, D3DXPARAMETER_TYPE intype)
1244 {
1245 struct ctab_constant *c = get_valid_constant(table, constant);
1246 UINT count = 1;
1247
1248 if (!c)
1249 {
1250 WARN("Invalid argument specified\n");
1251 return D3DERR_INVALIDCALL;
1252 }
1253
1254 switch (c->desc.Class)
1255 {
1256 case D3DXPC_SCALAR:
1257 set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
1258 return D3D_OK;
1259
1260 case D3DXPC_VECTOR:
1261 case D3DXPC_MATRIX_ROWS:
1262 case D3DXPC_MATRIX_COLUMNS:
1263 case D3DXPC_STRUCT:
1264 return D3D_OK;
1265
1266 default:
1267 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1268 return D3DERR_INVALIDCALL;
1269 }
1270 }
1271
1272 static HRESULT set_scalar_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1273 const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
1274 {
1275 struct ctab_constant *c = get_valid_constant(table, constant);
1276
1277 if (!c)
1278 {
1279 WARN("Invalid argument specified\n");
1280 return D3DERR_INVALIDCALL;
1281 }
1282
1283 switch (c->desc.Class)
1284 {
1285 case D3DXPC_SCALAR:
1286 case D3DXPC_VECTOR:
1287 case D3DXPC_MATRIX_ROWS:
1288 case D3DXPC_MATRIX_COLUMNS:
1289 case D3DXPC_STRUCT:
1290 set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
1291 return D3D_OK;
1292
1293 default:
1294 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1295 return D3DERR_INVALIDCALL;
1296 }
1297 }
1298
1299 static HRESULT set_vector(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1300 const void *indata, D3DXPARAMETER_TYPE intype)
1301 {
1302 struct ctab_constant *c = get_valid_constant(table, constant);
1303 UINT count = 4;
1304
1305 if (!c)
1306 {
1307 WARN("Invalid argument specified\n");
1308 return D3DERR_INVALIDCALL;
1309 }
1310
1311 switch (c->desc.Class)
1312 {
1313 case D3DXPC_SCALAR:
1314 case D3DXPC_VECTOR:
1315 case D3DXPC_STRUCT:
1316 set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
1317 return D3D_OK;
1318
1319 case D3DXPC_MATRIX_ROWS:
1320 case D3DXPC_MATRIX_COLUMNS:
1321 return D3D_OK;
1322
1323 default:
1324 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1325 return D3DERR_INVALIDCALL;
1326 }
1327 }
1328
1329 static HRESULT set_vector_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1330 const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
1331 {
1332 struct ctab_constant *c = get_valid_constant(table, constant);
1333
1334 if (!c)
1335 {
1336 WARN("Invalid argument specified\n");
1337 return D3DERR_INVALIDCALL;
1338 }
1339
1340 switch (c->desc.Class)
1341 {
1342 case D3DXPC_SCALAR:
1343 case D3DXPC_VECTOR:
1344 case D3DXPC_MATRIX_ROWS:
1345 case D3DXPC_MATRIX_COLUMNS:
1346 case D3DXPC_STRUCT:
1347 count *= 4;
1348 set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
1349 return D3D_OK;
1350
1351 default:
1352 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1353 return D3DERR_INVALIDCALL;
1354 }
1355 }
1356
1357 static HRESULT set_matrix_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1358 const void *indata, UINT count, BOOL transpose)
1359 {
1360 struct ctab_constant *c = get_valid_constant(table, constant);
1361
1362 if (!c)
1363 {
1364 WARN("Invalid argument specified\n");
1365 return D3DERR_INVALIDCALL;
1366 }
1367
1368 switch (c->desc.Class)
1369 {
1370 case D3DXPC_SCALAR:
1371 case D3DXPC_VECTOR:
1372 case D3DXPC_MATRIX_ROWS:
1373 case D3DXPC_MATRIX_COLUMNS:
1374 case D3DXPC_STRUCT:
1375 count *= 16;
1376 set(table, device, c, &indata, D3DXPT_FLOAT, &count, 4,
1377 transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, FALSE);
1378 return D3D_OK;
1379
1380 default:
1381 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1382 return D3DERR_INVALIDCALL;
1383 }
1384 }
1385
1386 static HRESULT set_matrix_pointer_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
1387 D3DXHANDLE constant, const void **indata, UINT count, BOOL transpose)
1388 {
1389 struct ctab_constant *c = get_valid_constant(table, constant);
1390
1391 if (!c)
1392 {
1393 WARN("Invalid argument specified\n");
1394 return D3DERR_INVALIDCALL;
1395 }
1396
1397 switch (c->desc.Class)
1398 {
1399 case D3DXPC_SCALAR:
1400 case D3DXPC_VECTOR:
1401 case D3DXPC_MATRIX_ROWS:
1402 case D3DXPC_MATRIX_COLUMNS:
1403 case D3DXPC_STRUCT:
1404 count *= 16;
1405 set(table, device, c, indata, D3DXPT_FLOAT, &count, 4,
1406 transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, TRUE);
1407 return D3D_OK;
1408
1409 default:
1410 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1411 return D3DERR_INVALIDCALL;
1412 }
1413 }
1414
1415 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(struct ID3DXConstantTable *iface,
1416 struct IDirect3DDevice9 *device)
1417 {
1418 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1419 UINT i;
1420
1421 TRACE("iface %p, device %p\n", iface, device);
1422
1423 if (!device)
1424 {
1425 WARN("Invalid argument specified\n");
1426 return D3DERR_INVALIDCALL;
1427 }
1428
1429 for (i = 0; i < This->desc.Constants; i++)
1430 {
1431 D3DXCONSTANT_DESC *desc = &This->constants[i].desc;
1432 HRESULT hr;
1433
1434 if (!desc->DefaultValue)
1435 continue;
1436
1437 switch (desc->RegisterSet)
1438 {
1439 case D3DXRS_BOOL:
1440 if (is_vertex_shader(This->desc.Version))
1441 hr = IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
1442 desc->RegisterCount);
1443 else
1444 hr = IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
1445 desc->RegisterCount);
1446 break;
1447
1448 case D3DXRS_INT4:
1449 if (is_vertex_shader(This->desc.Version))
1450 hr = IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
1451 desc->RegisterCount);
1452 else
1453 hr = IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
1454 desc->RegisterCount);
1455 break;
1456
1457 case D3DXRS_FLOAT4:
1458 if (is_vertex_shader(This->desc.Version))
1459 hr = IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
1460 desc->RegisterCount);
1461 else
1462 hr = IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
1463 desc->RegisterCount);
1464 break;
1465
1466 default:
1467 FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
1468 hr = E_NOTIMPL;
1469 break;
1470 }
1471
1472 if (hr != D3D_OK)
1473 return hr;
1474 }
1475
1476 return D3D_OK;
1477 }
1478
1479 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(struct ID3DXConstantTable *iface,
1480 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data, unsigned int bytes)
1481 {
1482 struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
1483 struct ctab_constant *c = get_valid_constant(table, constant);
1484 D3DXCONSTANT_DESC *desc;
1485
1486 TRACE("iface %p, device %p, constant %p, data %p, bytes %u\n", iface, device, constant, data, bytes);
1487
1488 if (!device || !c || !data)
1489 {
1490 WARN("Invalid argument specified\n");
1491 return D3DERR_INVALIDCALL;
1492 }
1493
1494 desc = &c->desc;
1495
1496 switch (desc->Class)
1497 {
1498 case D3DXPC_SCALAR:
1499 case D3DXPC_VECTOR:
1500 case D3DXPC_MATRIX_ROWS:
1501 case D3DXPC_MATRIX_COLUMNS:
1502 case D3DXPC_STRUCT:
1503 bytes /= 4;
1504 set(table, device, c, &data, desc->Type, &bytes, desc->Columns, D3DXPC_SCALAR, 0, FALSE);
1505 return D3D_OK;
1506
1507 default:
1508 FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(desc->Class));
1509 return D3DERR_INVALIDCALL;
1510 }
1511 }
1512
1513 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(struct ID3DXConstantTable *iface,
1514 struct IDirect3DDevice9 *device, D3DXHANDLE constant, BOOL b)
1515 {
1516 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1517
1518 TRACE("iface %p, device %p, constant %p, b %d\n", iface, device, constant, b);
1519
1520 return set_scalar(This, device, constant, &b, D3DXPT_BOOL);
1521 }
1522
1523 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(struct ID3DXConstantTable *iface,
1524 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const BOOL *b, UINT count)
1525 {
1526 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1527
1528 TRACE("iface %p, device %p, constant %p, b %p, count %d\n", iface, device, constant, b, count);
1529
1530 return set_scalar_array(This, device, constant, b, count, D3DXPT_BOOL);
1531 }
1532
1533 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(struct ID3DXConstantTable *iface,
1534 struct IDirect3DDevice9 *device, D3DXHANDLE constant, INT n)
1535 {
1536 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1537
1538 TRACE("iface %p, device %p, constant %p, n %d\n", iface, device, constant, n);
1539
1540 return set_scalar(This, device, constant, &n, D3DXPT_INT);
1541 }
1542
1543 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(struct ID3DXConstantTable *iface,
1544 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const INT *n, UINT count)
1545 {
1546 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1547
1548 TRACE("iface %p, device %p, constant %p, n %p, count %d\n", iface, device, constant, n, count);
1549
1550 return set_scalar_array(This, device, constant, n, count, D3DXPT_INT);
1551 }
1552
1553 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(struct ID3DXConstantTable *iface,
1554 struct IDirect3DDevice9 *device, D3DXHANDLE constant, float f)
1555 {
1556 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1557
1558 TRACE("iface %p, device %p, constant %p, f %f\n", iface, device, constant, f);
1559
1560 return set_scalar(This, device, constant, &f, D3DXPT_FLOAT);
1561 }
1562
1563 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(struct ID3DXConstantTable *iface,
1564 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const float *f, UINT count)
1565 {
1566 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1567
1568 TRACE("iface %p, device %p, constant %p, f %p, count %d\n", iface, device, constant, f, count);
1569
1570 return set_scalar_array(This, device, constant, f, count, D3DXPT_FLOAT);
1571 }
1572
1573 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(struct ID3DXConstantTable *iface,
1574 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector)
1575 {
1576 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1577
1578 TRACE("iface %p, device %p, constant %p, vector %p\n", iface, device, constant, vector);
1579
1580 return set_vector(This, device, constant, vector, D3DXPT_FLOAT);
1581 }
1582
1583 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(struct ID3DXConstantTable *iface,
1584 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector, UINT count)
1585 {
1586 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1587
1588 TRACE("iface %p, device %p, constant %p, vector %p, count %u\n", iface, device, constant, vector, count);
1589
1590 return set_vector_array(This, device, constant, vector, count, D3DXPT_FLOAT);
1591 }
1592
1593 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(struct ID3DXConstantTable *iface,
1594 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1595 {
1596 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1597
1598 TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1599
1600 return set_matrix_array(This, device, constant, matrix, 1, FALSE);
1601 }
1602
1603 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(struct ID3DXConstantTable *iface,
1604 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1605 {
1606 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1607
1608 TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1609
1610 return set_matrix_array(This, device, constant, matrix, count, FALSE);
1611 }
1612
1613 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(struct ID3DXConstantTable *iface,
1614 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1615 {
1616 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1617
1618 TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1619
1620 return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, FALSE);
1621 }
1622
1623 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(struct ID3DXConstantTable *iface,
1624 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1625 {
1626 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1627
1628 TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1629
1630 return set_matrix_array(This, device, constant, matrix, 1, TRUE);
1631 }
1632
1633 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(struct ID3DXConstantTable *iface,
1634 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1635 {
1636 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1637
1638 TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1639
1640 return set_matrix_array(This, device, constant, matrix, count, TRUE);
1641 }
1642
1643 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(struct ID3DXConstantTable *iface,
1644 struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1645 {
1646 struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1647
1648 TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1649
1650 return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, TRUE);
1651 }
1652
1653 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
1654 {
1655 /*** IUnknown methods ***/
1656 ID3DXConstantTableImpl_QueryInterface,
1657 ID3DXConstantTableImpl_AddRef,
1658 ID3DXConstantTableImpl_Release,
1659 /*** ID3DXBuffer methods ***/
1660 ID3DXConstantTableImpl_GetBufferPointer,
1661 ID3DXConstantTableImpl_GetBufferSize,
1662 /*** ID3DXConstantTable methods ***/
1663 ID3DXConstantTableImpl_GetDesc,
1664 ID3DXConstantTableImpl_GetConstantDesc,
1665 ID3DXConstantTableImpl_GetSamplerIndex,
1666 ID3DXConstantTableImpl_GetConstant,
1667 ID3DXConstantTableImpl_GetConstantByName,
1668 ID3DXConstantTableImpl_GetConstantElement,
1669 ID3DXConstantTableImpl_SetDefaults,
1670 ID3DXConstantTableImpl_SetValue,
1671 ID3DXConstantTableImpl_SetBool,
1672 ID3DXConstantTableImpl_SetBoolArray,
1673 ID3DXConstantTableImpl_SetInt,
1674 ID3DXConstantTableImpl_SetIntArray,
1675 ID3DXConstantTableImpl_SetFloat,
1676 ID3DXConstantTableImpl_SetFloatArray,
1677 ID3DXConstantTableImpl_SetVector,
1678 ID3DXConstantTableImpl_SetVectorArray,
1679 ID3DXConstantTableImpl_SetMatrix,
1680 ID3DXConstantTableImpl_SetMatrixArray,
1681 ID3DXConstantTableImpl_SetMatrixPointerArray,
1682 ID3DXConstantTableImpl_SetMatrixTranspose,
1683 ID3DXConstantTableImpl_SetMatrixTransposeArray,
1684 ID3DXConstantTableImpl_SetMatrixTransposePointerArray
1685 };
1686
1687 static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, struct ctab_constant *constant,
1688 BOOL is_element, WORD index, WORD max, DWORD *offset, DWORD nameoffset, UINT regset)
1689 {
1690 const D3DXSHADER_TYPEINFO *type = (LPD3DXSHADER_TYPEINFO)(ctab + typeoffset);
1691 const D3DXSHADER_STRUCTMEMBERINFO *memberinfo = NULL;
1692 HRESULT hr = D3D_OK;
1693 UINT i, count = 0;
1694 WORD size = 0;
1695
1696 constant->desc.DefaultValue = offset ? ctab + *offset : NULL;
1697 constant->desc.Class = type->Class;
1698 constant->desc.Type = type->Type;
1699 constant->desc.Rows = type->Rows;
1700 constant->desc.Columns = type->Columns;
1701 constant->desc.Elements = is_element ? 1 : type->Elements;
1702 constant->desc.StructMembers = type->StructMembers;
1703 constant->desc.Name = ctab + nameoffset;
1704 constant->desc.RegisterSet = regset;
1705 constant->desc.RegisterIndex = index;
1706
1707 TRACE("name %s, elements %u, index %u, defaultvalue %p, regset %s\n", constant->desc.Name,
1708 constant->desc.Elements, index, constant->desc.DefaultValue,
1709 debug_d3dxparameter_registerset(regset));
1710 TRACE("class %s, type %s, rows %d, columns %d, elements %d, struct_members %d\n",
1711 debug_d3dxparameter_class(type->Class), debug_d3dxparameter_type(type->Type),
1712 type->Rows, type->Columns, type->Elements, type->StructMembers);
1713
1714 if (type->Elements > 1 && !is_element)
1715 {
1716 count = type->Elements;
1717 }
1718 else if ((type->Class == D3DXPC_STRUCT) && type->StructMembers)
1719 {
1720 memberinfo = (D3DXSHADER_STRUCTMEMBERINFO*)(ctab + type->StructMemberInfo);
1721 count = type->StructMembers;
1722 }
1723
1724 if (count)
1725 {
1726 constant->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*constant->constants) * count);
1727 if (!constant->constants)
1728 {
1729 ERR("Out of memory\n");
1730 hr = E_OUTOFMEMORY;
1731 goto error;
1732 }
1733
1734 for (i = 0; i < count; ++i)
1735 {
1736 hr = parse_ctab_constant_type(ctab, memberinfo ? memberinfo[i].TypeInfo : typeoffset,
1737 &constant->constants[i], memberinfo == NULL, index + size, max, offset,
1738 memberinfo ? memberinfo[i].Name : nameoffset, regset);
1739 if (hr != D3D_OK)
1740 goto error;
1741
1742 size += constant->constants[i].desc.RegisterCount;
1743 }
1744 }
1745 else
1746 {
1747 WORD offsetdiff = type->Columns * type->Rows;
1748 BOOL fail = FALSE;
1749
1750 size = type->Columns * type->Rows;
1751
1752 switch (regset)
1753 {
1754 case D3DXRS_BOOL:
1755 fail = type->Class != D3DXPC_SCALAR && type->Class != D3DXPC_VECTOR
1756 && type->Class != D3DXPC_MATRIX_ROWS && type->Class != D3DXPC_MATRIX_COLUMNS;
1757 break;
1758
1759 case D3DXRS_FLOAT4:
1760 case D3DXRS_INT4:
1761 switch (type->Class)
1762 {
1763 case D3DXPC_VECTOR:
1764 size = 1;
1765 /* fall through */
1766 case D3DXPC_SCALAR:
1767 offsetdiff = type->Rows * 4;
1768 break;
1769
1770 case D3DXPC_MATRIX_ROWS:
1771 offsetdiff = type->Rows * 4;
1772 size = is_element ? type->Rows : max(type->Rows, type->Columns);
1773 break;
1774
1775 case D3DXPC_MATRIX_COLUMNS:
1776 offsetdiff = type->Columns * 4;
1777 size = type->Columns;
1778 break;
1779
1780 default:
1781 fail = TRUE;
1782 break;
1783 }
1784 break;
1785
1786 case D3DXRS_SAMPLER:
1787 size = 1;
1788 fail = type->Class != D3DXPC_OBJECT;
1789 break;
1790
1791 default:
1792 fail = TRUE;
1793 break;
1794 }
1795
1796 if (fail)
1797 {
1798 FIXME("Unhandled register set %s, type class %s\n", debug_d3dxparameter_registerset(regset),
1799 debug_d3dxparameter_class(type->Class));
1800 }
1801
1802 /* offset in bytes => offsetdiff * sizeof(DWORD) */
1803 if (offset) *offset += offsetdiff * 4;
1804 }
1805
1806 constant->desc.RegisterCount = max(0, min(max - index, size));
1807 constant->desc.Bytes = 4 * constant->desc.Elements * type->Rows * type->Columns;
1808
1809 return D3D_OK;
1810
1811 error:
1812 if (constant->constants)
1813 {
1814 for (i = 0; i < count; ++i)
1815 {
1816 free_constant(&constant->constants[i]);
1817 }
1818 HeapFree(GetProcessHeap(), 0, constant->constants);
1819 constant->constants = NULL;
1820 }
1821
1822 return hr;
1823 }
1824
1825 HRESULT WINAPI D3DXGetShaderConstantTableEx(const DWORD *byte_code, DWORD flags, ID3DXConstantTable **constant_table)
1826 {
1827 struct ID3DXConstantTableImpl *object = NULL;
1828 HRESULT hr;
1829 LPCVOID data;
1830 UINT size;
1831 const D3DXSHADER_CONSTANTTABLE *ctab_header;
1832 const D3DXSHADER_CONSTANTINFO *constant_info;
1833 DWORD i;
1834
1835 TRACE("byte_code %p, flags %x, constant_table %p\n", byte_code, flags, constant_table);
1836
1837 if (constant_table) *constant_table = NULL;
1838
1839 if (!byte_code || !constant_table)
1840 {
1841 WARN("Invalid argument specified.\n");
1842 return D3DERR_INVALIDCALL;
1843 }
1844
1845 if (!is_valid_bytecode(*byte_code))
1846 {
1847 WARN("Invalid byte_code specified.\n");
1848 return D3D_OK;
1849 }
1850
1851 if (flags) FIXME("Flags (%#x) are not handled, yet!\n", flags);
1852
1853 hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1854 if (hr != D3D_OK)
1855 {
1856 WARN("CTAB not found.\n");
1857 return D3DXERR_INVALIDDATA;
1858 }
1859
1860 if (size < sizeof(*ctab_header))
1861 {
1862 WARN("Invalid CTAB size.\n");
1863 return D3DXERR_INVALIDDATA;
1864 }
1865
1866 ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
1867 if (ctab_header->Size != sizeof(*ctab_header))
1868 {
1869 WARN("Invalid D3DXSHADER_CONSTANTTABLE size.\n");
1870 return D3DXERR_INVALIDDATA;
1871 }
1872
1873 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1874 if (!object)
1875 return E_OUTOFMEMORY;
1876
1877 object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
1878 object->ref = 1;
1879
1880 object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1881 if (!object->ctab)
1882 {
1883 ERR("Out of memory\n");
1884 HeapFree(GetProcessHeap(), 0, object);
1885 return E_OUTOFMEMORY;
1886 }
1887 object->size = size;
1888 memcpy(object->ctab, data, object->size);
1889
1890 object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
1891 object->desc.Version = ctab_header->Version;
1892 object->desc.Constants = ctab_header->Constants;
1893 TRACE("Creator %s, Version %x, Constants %u, Target %s\n",
1894 debugstr_a(object->desc.Creator), object->desc.Version, object->desc.Constants,
1895 debugstr_a(ctab_header->Target ? object->ctab + ctab_header->Target : NULL));
1896
1897 object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1898 sizeof(*object->constants) * object->desc.Constants);
1899 if (!object->constants)
1900 {
1901 ERR("Out of memory\n");
1902 hr = E_OUTOFMEMORY;
1903 goto error;
1904 }
1905
1906 constant_info = (const D3DXSHADER_CONSTANTINFO *)(object->ctab + ctab_header->ConstantInfo);
1907 for (i = 0; i < ctab_header->Constants; i++)
1908 {
1909 DWORD offset = constant_info[i].DefaultValue;
1910
1911 hr = parse_ctab_constant_type(object->ctab, constant_info[i].TypeInfo,
1912 &object->constants[i], FALSE, constant_info[i].RegisterIndex,
1913 constant_info[i].RegisterIndex + constant_info[i].RegisterCount,
1914 offset ? &offset : NULL, constant_info[i].Name, constant_info[i].RegisterSet);
1915 if (hr != D3D_OK)
1916 goto error;
1917
1918 /*
1919 * Set the register count, it may differ for D3DXRS_INT4, because somehow
1920 * it makes the assumption that the register size is 1 instead of 4, so the
1921 * count is 4 times bigger. This holds true only for toplevel shader
1922 * constants. The count of elements and members is always based on a
1923 * register size of 4.
1924 */
1925 if (object->constants[i].desc.RegisterSet == D3DXRS_INT4)
1926 {
1927 object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
1928 }
1929 }
1930
1931 *constant_table = &object->ID3DXConstantTable_iface;
1932
1933 return D3D_OK;
1934
1935 error:
1936 free_constant_table(object);
1937 HeapFree(GetProcessHeap(), 0, object);
1938
1939 return hr;
1940 }
1941
1942 HRESULT WINAPI D3DXGetShaderConstantTable(const DWORD *byte_code, ID3DXConstantTable **constant_table)
1943 {
1944 TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1945
1946 return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1947 }
1948
1949 HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **samplers, UINT *count)
1950 {
1951 UINT i, sampler_count = 0;
1952 UINT size;
1953 const char *data;
1954 const D3DXSHADER_CONSTANTTABLE *ctab_header;
1955 const D3DXSHADER_CONSTANTINFO *constant_info;
1956
1957 TRACE("byte_code %p, samplers %p, count %p\n", byte_code, samplers, count);
1958
1959 if (count) *count = 0;
1960
1961 if (D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), (const void **)&data, &size) != D3D_OK)
1962 return D3D_OK;
1963
1964 if (size < sizeof(*ctab_header)) return D3D_OK;
1965
1966 ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
1967 if (ctab_header->Size != sizeof(*ctab_header)) return D3D_OK;
1968
1969 constant_info = (const D3DXSHADER_CONSTANTINFO *)(data + ctab_header->ConstantInfo);
1970 for (i = 0; i < ctab_header->Constants; i++)
1971 {
1972 const D3DXSHADER_TYPEINFO *type;
1973
1974 TRACE("name = %s\n", data + constant_info[i].Name);
1975
1976 type = (const D3DXSHADER_TYPEINFO *)(data + constant_info[i].TypeInfo);
1977
1978 if (type->Type == D3DXPT_SAMPLER
1979 || type->Type == D3DXPT_SAMPLER1D
1980 || type->Type == D3DXPT_SAMPLER2D
1981 || type->Type == D3DXPT_SAMPLER3D
1982 || type->Type == D3DXPT_SAMPLERCUBE)
1983 {
1984 if (samplers) samplers[sampler_count] = data + constant_info[i].Name;
1985
1986 ++sampler_count;
1987 }
1988 }
1989
1990 TRACE("Found %u samplers\n", sampler_count);
1991
1992 if (count) *count = sampler_count;
1993
1994 return D3D_OK;
1995 }