2 * Copyright 2009 Matteo Bruni
3 * Copyright 2010 Matteo Bruni for CodeWeavers
4 * Copyright 2016,2018 Józef Kucia for CodeWeavers
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.
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.
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
24 #include "wine/debug.h"
26 #include "d3dcompiler_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler
);
30 static HRESULT
hresult_from_vkd3d_result(int vkd3d_result
)
36 case VKD3D_ERROR_INVALID_SHADER
:
37 WARN("Invalid shader bytecode.\n");
41 case VKD3D_ERROR_OUT_OF_MEMORY
:
43 case VKD3D_ERROR_INVALID_ARGUMENT
:
45 case VKD3D_ERROR_NOT_IMPLEMENTED
:
48 FIXME("Unhandled vkd3d result %d.\n", vkd3d_result
);
53 #define D3DXERR_INVALIDDATA 0x88760b59
55 /* Mutex used to guarantee a single invocation of the D3DAssemble function at
56 * a time. This is needed as the assembler isn't thread-safe. */
57 static CRITICAL_SECTION wpp_mutex
;
58 static CRITICAL_SECTION_DEBUG wpp_mutex_debug
=
61 { &wpp_mutex_debug
.ProcessLocksList
,
62 &wpp_mutex_debug
.ProcessLocksList
},
63 0, 0, { (DWORD_PTR
)(__FILE__
": wpp_mutex") }
65 static CRITICAL_SECTION wpp_mutex
= { &wpp_mutex_debug
, -1, 0, 0, 0, 0 };
67 struct d3dcompiler_include_from_file
69 ID3DInclude ID3DInclude_iface
;
70 const char *initial_filename
;
73 static inline struct d3dcompiler_include_from_file
*impl_from_ID3DInclude(ID3DInclude
*iface
)
75 return CONTAINING_RECORD(iface
, struct d3dcompiler_include_from_file
, ID3DInclude_iface
);
78 static HRESULT WINAPI
d3dcompiler_include_from_file_open(ID3DInclude
*iface
, D3D_INCLUDE_TYPE include_type
,
79 const char *filename
, const void *parent_data
, const void **data
, UINT
*bytes
)
81 struct d3dcompiler_include_from_file
*include
= impl_from_ID3DInclude(iface
);
82 char *fullpath
, *buffer
= NULL
, current_dir
[MAX_PATH
+ 1];
83 const char *initial_dir
;
89 if ((initial_dir
= strrchr(include
->initial_filename
, '\\')))
91 len
= initial_dir
- include
->initial_filename
+ 1;
92 initial_dir
= include
->initial_filename
;
96 len
= GetCurrentDirectoryA(MAX_PATH
, current_dir
);
97 current_dir
[len
] = '\\';
99 initial_dir
= current_dir
;
101 fullpath
= heap_alloc(len
+ strlen(filename
) + 1);
103 return E_OUTOFMEMORY
;
104 memcpy(fullpath
, initial_dir
, len
);
105 strcpy(fullpath
+ len
, filename
);
107 file
= CreateFileA(fullpath
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, 0, 0);
108 if (file
== INVALID_HANDLE_VALUE
)
111 TRACE("Include file found at %s.\n", debugstr_a(fullpath
));
113 size
= GetFileSize(file
, NULL
);
114 if (size
== INVALID_FILE_SIZE
)
116 buffer
= heap_alloc(size
);
119 if (!ReadFile(file
, buffer
, size
, &read
, NULL
) || read
!= size
)
133 WARN("Returning E_FAIL.\n");
137 static HRESULT WINAPI
d3dcompiler_include_from_file_close(ID3DInclude
*iface
, const void *data
)
139 heap_free((void *)data
);
143 const struct ID3DIncludeVtbl d3dcompiler_include_from_file_vtbl
=
145 d3dcompiler_include_from_file_open
,
146 d3dcompiler_include_from_file_close
149 static int open_include(const char *filename
, bool local
, const char *parent_data
, void *context
,
150 struct vkd3d_shader_code
*code
)
152 ID3DInclude
*iface
= context
;
153 unsigned int size
= 0;
158 memset(code
, 0, sizeof(*code
));
159 if (FAILED(ID3DInclude_Open(iface
, local
? D3D_INCLUDE_LOCAL
: D3D_INCLUDE_SYSTEM
,
160 filename
, parent_data
, &code
->code
, &size
)))
167 static void close_include(const struct vkd3d_shader_code
*code
, void *context
)
169 ID3DInclude
*iface
= context
;
171 ID3DInclude_Close(iface
, code
->code
);
174 static const char *get_line(const char **ptr
)
179 if (!(q
= strstr(p
, "\n")))
191 static HRESULT
preprocess_shader(const void *data
, SIZE_T data_size
, const char *filename
,
192 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, ID3DBlob
**shader_blob
,
193 ID3DBlob
**messages_blob
)
195 struct d3dcompiler_include_from_file include_from_file
;
196 struct vkd3d_shader_preprocess_info preprocess_info
;
197 struct vkd3d_shader_compile_info compile_info
;
198 const D3D_SHADER_MACRO
*def
= defines
;
199 struct vkd3d_shader_code byte_code
;
204 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
206 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
207 include_from_file
.initial_filename
= filename
? filename
: "";
208 include
= &include_from_file
.ID3DInclude_iface
;
211 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
212 compile_info
.next
= &preprocess_info
;
213 compile_info
.source
.code
= data
;
214 compile_info
.source
.size
= data_size
;
215 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
216 compile_info
.target_type
= VKD3D_SHADER_TARGET_NONE
;
217 compile_info
.options
= NULL
;
218 compile_info
.option_count
= 0;
219 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
220 compile_info
.source_name
= filename
;
222 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
223 preprocess_info
.next
= NULL
;
224 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)defines
;
225 preprocess_info
.macro_count
= 0;
228 for (def
= defines
; def
->Name
; ++def
)
229 ++preprocess_info
.macro_count
;
231 preprocess_info
.pfn_open_include
= open_include
;
232 preprocess_info
.pfn_close_include
= close_include
;
233 preprocess_info
.include_context
= include
;
235 ret
= vkd3d_shader_preprocess(&compile_info
, &byte_code
, &messages
);
238 ERR("Failed to preprocess shader, vkd3d result %d.\n", ret
);
242 if (*messages
&& ERR_ON(d3dcompiler
))
244 const char *ptr
= messages
;
247 ERR("Shader log:\n");
248 while ((line
= get_line(&ptr
)))
250 ERR(" %.*s", (int)(ptr
- line
), line
);
257 size_t size
= strlen(messages
);
258 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
260 vkd3d_shader_free_messages(messages
);
261 vkd3d_shader_free_shader_code(&byte_code
);
264 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
268 vkd3d_shader_free_messages(messages
);
274 if (FAILED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
276 vkd3d_shader_free_shader_code(&byte_code
);
279 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
282 return hresult_from_vkd3d_result(ret
);
285 static HRESULT
assemble_shader(const char *preproc_shader
, ID3DBlob
**shader_blob
, ID3DBlob
**error_messages
)
287 struct bwriter_shader
*shader
;
288 char *messages
= NULL
;
294 shader
= SlAssembleShader(preproc_shader
, &messages
);
298 TRACE("Assembler messages:\n");
299 TRACE("%s\n", debugstr_a(messages
));
301 TRACE("Shader source:\n");
302 TRACE("%s\n", debugstr_a(preproc_shader
));
306 const char *preproc_messages
= *error_messages
? ID3D10Blob_GetBufferPointer(*error_messages
) : NULL
;
308 size
= strlen(messages
) + (preproc_messages
? strlen(preproc_messages
) : 0) + 1;
309 hr
= D3DCreateBlob(size
, &buffer
);
312 HeapFree(GetProcessHeap(), 0, messages
);
313 if (shader
) SlDeleteShader(shader
);
316 pos
= ID3D10Blob_GetBufferPointer(buffer
);
317 if (preproc_messages
)
319 CopyMemory(pos
, preproc_messages
, strlen(preproc_messages
) + 1);
320 pos
+= strlen(preproc_messages
);
322 CopyMemory(pos
, messages
, strlen(messages
) + 1);
324 if (*error_messages
) ID3D10Blob_Release(*error_messages
);
325 *error_messages
= buffer
;
327 HeapFree(GetProcessHeap(), 0, messages
);
332 ERR("Asm reading failed\n");
333 return D3DXERR_INVALIDDATA
;
336 hr
= shader_write_bytecode(shader
, &res
, &size
);
337 SlDeleteShader(shader
);
340 ERR("Failed to write bytecode, hr %#lx.\n", hr
);
341 return D3DXERR_INVALIDDATA
;
346 hr
= D3DCreateBlob(size
, &buffer
);
349 HeapFree(GetProcessHeap(), 0, res
);
352 CopyMemory(ID3D10Blob_GetBufferPointer(buffer
), res
, size
);
353 *shader_blob
= buffer
;
356 HeapFree(GetProcessHeap(), 0, res
);
361 HRESULT WINAPI
D3DAssemble(const void *data
, SIZE_T datasize
, const char *filename
,
362 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, UINT flags
,
363 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
365 unsigned int preproc_size
;
366 ID3DBlob
*preproc_shader
;
367 char *preproc_terminated
;
370 TRACE("data %p, datasize %Iu, filename %s, defines %p, include %p, sflags %#x, "
371 "shader %p, error_messages %p.\n",
372 data
, datasize
, debugstr_a(filename
), defines
, include
, flags
, shader
, error_messages
);
374 EnterCriticalSection(&wpp_mutex
);
377 if (flags
) FIXME("flags %x\n", flags
);
379 if (shader
) *shader
= NULL
;
380 if (error_messages
) *error_messages
= NULL
;
382 hr
= preprocess_shader(data
, datasize
, filename
, defines
, include
, &preproc_shader
, error_messages
);
385 preproc_size
= ID3D10Blob_GetBufferSize(preproc_shader
);
386 if ((preproc_terminated
= malloc(preproc_size
+ 1)))
388 memcpy(preproc_terminated
, ID3D10Blob_GetBufferPointer(preproc_shader
), preproc_size
);
389 ID3D10Blob_Release(preproc_shader
);
390 preproc_terminated
[preproc_size
] = 0;
392 hr
= assemble_shader(preproc_terminated
, shader
, error_messages
);
393 free(preproc_terminated
);
396 LeaveCriticalSection(&wpp_mutex
);
400 HRESULT WINAPI
D3DCompile2(const void *data
, SIZE_T data_size
, const char *filename
,
401 const D3D_SHADER_MACRO
*macros
, ID3DInclude
*include
, const char *entry_point
,
402 const char *profile
, UINT flags
, UINT effect_flags
, UINT secondary_flags
,
403 const void *secondary_data
, SIZE_T secondary_data_size
, ID3DBlob
**shader_blob
,
404 ID3DBlob
**messages_blob
)
406 struct d3dcompiler_include_from_file include_from_file
;
407 struct vkd3d_shader_preprocess_info preprocess_info
;
408 struct vkd3d_shader_hlsl_source_info hlsl_info
;
409 struct vkd3d_shader_compile_option options
[2];
410 struct vkd3d_shader_compile_info compile_info
;
411 struct vkd3d_shader_compile_option
*option
;
412 struct vkd3d_shader_code byte_code
;
413 const D3D_SHADER_MACRO
*macro
;
414 size_t profile_len
, i
;
419 static const char * const d3dbc_profiles
[] =
442 TRACE("data %p, data_size %Iu, filename %s, macros %p, include %p, entry_point %s, "
443 "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, "
444 "secondary_data_size %Iu, shader_blob %p, messages_blob %p.\n",
445 data
, data_size
, debugstr_a(filename
), macros
, include
, debugstr_a(entry_point
),
446 debugstr_a(profile
), flags
, effect_flags
, secondary_flags
, secondary_data
,
447 secondary_data_size
, shader_blob
, messages_blob
);
449 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
451 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
452 include_from_file
.initial_filename
= filename
? filename
: "";
453 include
= &include_from_file
.ID3DInclude_iface
;
456 if (flags
& ~D3DCOMPILE_DEBUG
)
457 FIXME("Ignoring flags %#x.\n", flags
);
459 FIXME("Ignoring effect flags %#x.\n", effect_flags
);
461 FIXME("Ignoring secondary flags %#x.\n", secondary_flags
);
466 *messages_blob
= NULL
;
468 option
= &options
[0];
469 option
->name
= VKD3D_SHADER_COMPILE_OPTION_API_VERSION
;
470 option
->value
= VKD3D_SHADER_API_VERSION_1_3
;
472 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
473 compile_info
.next
= &preprocess_info
;
474 compile_info
.source
.code
= data
;
475 compile_info
.source
.size
= data_size
;
476 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
477 compile_info
.target_type
= VKD3D_SHADER_TARGET_DXBC_TPF
;
478 compile_info
.options
= options
;
479 compile_info
.option_count
= 1;
480 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
481 compile_info
.source_name
= filename
;
483 profile_len
= strlen(profile
);
484 for (i
= 0; i
< ARRAY_SIZE(d3dbc_profiles
); ++i
)
486 size_t len
= strlen(d3dbc_profiles
[i
]);
488 if (len
<= profile_len
&& !memcmp(profile
, d3dbc_profiles
[i
], len
))
490 compile_info
.target_type
= VKD3D_SHADER_TARGET_D3D_BYTECODE
;
495 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
496 preprocess_info
.next
= &hlsl_info
;
497 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)macros
;
498 preprocess_info
.macro_count
= 0;
501 for (macro
= macros
; macro
->Name
; ++macro
)
502 ++preprocess_info
.macro_count
;
504 preprocess_info
.pfn_open_include
= open_include
;
505 preprocess_info
.pfn_close_include
= close_include
;
506 preprocess_info
.include_context
= include
;
508 hlsl_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO
;
509 hlsl_info
.next
= NULL
;
510 hlsl_info
.profile
= profile
;
511 hlsl_info
.entry_point
= entry_point
;
512 hlsl_info
.secondary_code
.code
= secondary_data
;
513 hlsl_info
.secondary_code
.size
= secondary_data_size
;
515 if (!(flags
& D3DCOMPILE_DEBUG
))
517 option
= &options
[compile_info
.option_count
++];
518 option
->name
= VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG
;
519 option
->value
= true;
522 ret
= vkd3d_shader_compile(&compile_info
, &byte_code
, &messages
);
525 ERR("Failed to compile shader, vkd3d result %d.\n", ret
);
529 if (*messages
&& ERR_ON(d3dcompiler
))
531 const char *ptr
= messages
;
534 ERR("Shader log:\n");
535 while ((line
= get_line(&ptr
)))
537 ERR(" %.*s", (int)(ptr
- line
), line
);
544 size_t size
= strlen(messages
);
545 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
547 vkd3d_shader_free_messages(messages
);
548 vkd3d_shader_free_shader_code(&byte_code
);
551 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
554 vkd3d_shader_free_messages(messages
);
558 return hresult_from_vkd3d_result(ret
);
562 vkd3d_shader_free_shader_code(&byte_code
);
566 if (SUCCEEDED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
567 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
569 vkd3d_shader_free_shader_code(&byte_code
);
574 HRESULT WINAPI
D3DCompile(const void *data
, SIZE_T data_size
, const char *filename
,
575 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, const char *entrypoint
,
576 const char *target
, UINT sflags
, UINT eflags
, ID3DBlob
**shader
, ID3DBlob
**error_messages
)
578 TRACE("data %p, data_size %Iu, filename %s, defines %p, include %p, entrypoint %s, "
579 "target %s, sflags %#x, eflags %#x, shader %p, error_messages %p.\n",
580 data
, data_size
, debugstr_a(filename
), defines
, include
, debugstr_a(entrypoint
),
581 debugstr_a(target
), sflags
, eflags
, shader
, error_messages
);
583 return D3DCompile2(data
, data_size
, filename
, defines
, include
, entrypoint
, target
, sflags
,
584 eflags
, 0, NULL
, 0, shader
, error_messages
);
587 HRESULT WINAPI
D3DPreprocess(const void *data
, SIZE_T size
, const char *filename
,
588 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
589 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
591 TRACE("data %p, size %Iu, filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
592 data
, size
, debugstr_a(filename
), defines
, include
, shader
, error_messages
);
597 if (shader
) *shader
= NULL
;
598 if (error_messages
) *error_messages
= NULL
;
600 return preprocess_shader(data
, size
, filename
, defines
, include
, shader
, error_messages
);
603 HRESULT WINAPI
D3DDisassemble(const void *data
, SIZE_T size
, UINT flags
, const char *comments
,
604 ID3DBlob
**disassembly
)
606 struct vkd3d_shader_compile_info compile_info
;
607 enum vkd3d_shader_source_type source_type
;
608 struct vkd3d_shader_code asm_code
;
609 const char *ptr
= data
;
614 TRACE("data %p, size %Iu, flags %#x, comments %p, disassembly %p.\n",
615 data
, size
, flags
, comments
, disassembly
);
618 FIXME("Ignoring flags %#x.\n", flags
);
621 FIXME("Ignoring comments %s.\n", debugstr_a(comments
));
623 #if D3D_COMPILER_VERSION >= 46
628 if (size
>= 4 && read_u32(&ptr
) == TAG_DXBC
)
629 source_type
= VKD3D_SHADER_SOURCE_DXBC_TPF
;
631 source_type
= VKD3D_SHADER_SOURCE_D3D_BYTECODE
;
633 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
634 compile_info
.next
= NULL
;
635 compile_info
.source
.code
= data
;
636 compile_info
.source
.size
= size
;
637 compile_info
.source_type
= source_type
;
638 compile_info
.target_type
= VKD3D_SHADER_TARGET_D3D_ASM
;
639 compile_info
.options
= NULL
;
640 compile_info
.option_count
= 0;
641 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
642 compile_info
.source_name
= NULL
;
644 ret
= vkd3d_shader_compile(&compile_info
, &asm_code
, &messages
);
647 ERR("Failed to disassemble shader, vkd3d result %d.\n", ret
);
651 if (*messages
&& ERR_ON(d3dcompiler
))
653 const char *ptr
= messages
;
656 ERR("Shader log:\n");
657 while ((line
= get_line(&ptr
)))
659 ERR(" %.*s", (int)(ptr
- line
), line
);
664 vkd3d_shader_free_messages(messages
);
668 return hresult_from_vkd3d_result(ret
);
670 if (SUCCEEDED(hr
= D3DCreateBlob(asm_code
.size
, disassembly
)))
671 memcpy(ID3D10Blob_GetBufferPointer(*disassembly
), asm_code
.code
, asm_code
.size
);
673 vkd3d_shader_free_shader_code(&asm_code
);
678 HRESULT WINAPI
D3DCompileFromFile(const WCHAR
*filename
, const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
679 const char *entrypoint
, const char *target
, UINT flags1
, UINT flags2
, ID3DBlob
**code
, ID3DBlob
**errors
)
681 char filename_a
[MAX_PATH
], *source
= NULL
;
682 DWORD source_size
, read_size
;
686 TRACE("filename %s, defines %p, include %p, entrypoint %s, target %s, flags1 %#x, flags2 %#x, "
687 "code %p, errors %p.\n", debugstr_w(filename
), defines
, include
, debugstr_a(entrypoint
),
688 debugstr_a(target
), flags1
, flags2
, code
, errors
);
690 file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
691 if (file
== INVALID_HANDLE_VALUE
)
692 return HRESULT_FROM_WIN32(GetLastError());
694 source_size
= GetFileSize(file
, NULL
);
695 if (source_size
== INVALID_FILE_SIZE
)
697 hr
= HRESULT_FROM_WIN32(GetLastError());
701 if (!(source
= heap_alloc(source_size
)))
707 if (!ReadFile(file
, source
, source_size
, &read_size
, NULL
) || read_size
!= source_size
)
709 WARN("Failed to read file contents.\n");
714 WideCharToMultiByte(CP_ACP
, 0, filename
, -1, filename_a
, sizeof(filename_a
), NULL
, NULL
);
716 hr
= D3DCompile(source
, source_size
, filename_a
, defines
, include
, entrypoint
, target
,
717 flags1
, flags2
, code
, errors
);
725 HRESULT WINAPI
D3DLoadModule(const void *data
, SIZE_T size
, ID3D11Module
**module
)
727 FIXME("data %p, size %Iu, module %p stub!\n", data
, size
, module
);