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 #include <vkd3d_shader.h>
30 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler
);
32 static HRESULT
hresult_from_vkd3d_result(int vkd3d_result
)
38 case VKD3D_ERROR_INVALID_SHADER
:
39 WARN("Invalid shader bytecode.\n");
43 case VKD3D_ERROR_OUT_OF_MEMORY
:
45 case VKD3D_ERROR_INVALID_ARGUMENT
:
47 case VKD3D_ERROR_NOT_IMPLEMENTED
:
50 FIXME("Unhandled vkd3d result %d.\n", vkd3d_result
);
55 #define D3DXERR_INVALIDDATA 0x88760b59
57 /* Mutex used to guarantee a single invocation of the D3DAssemble function at
58 * a time. This is needed as the assembler isn't thread-safe. */
59 static CRITICAL_SECTION wpp_mutex
;
60 static CRITICAL_SECTION_DEBUG wpp_mutex_debug
=
63 { &wpp_mutex_debug
.ProcessLocksList
,
64 &wpp_mutex_debug
.ProcessLocksList
},
65 0, 0, { (DWORD_PTR
)(__FILE__
": wpp_mutex") }
67 static CRITICAL_SECTION wpp_mutex
= { &wpp_mutex_debug
, -1, 0, 0, 0, 0 };
69 struct d3dcompiler_include_from_file
71 ID3DInclude ID3DInclude_iface
;
72 const char *initial_filename
;
75 static inline struct d3dcompiler_include_from_file
*impl_from_ID3DInclude(ID3DInclude
*iface
)
77 return CONTAINING_RECORD(iface
, struct d3dcompiler_include_from_file
, ID3DInclude_iface
);
80 static HRESULT WINAPI
d3dcompiler_include_from_file_open(ID3DInclude
*iface
, D3D_INCLUDE_TYPE include_type
,
81 const char *filename
, const void *parent_data
, const void **data
, UINT
*bytes
)
83 struct d3dcompiler_include_from_file
*include
= impl_from_ID3DInclude(iface
);
84 char *fullpath
, *buffer
= NULL
, current_dir
[MAX_PATH
+ 1];
85 const char *initial_dir
;
91 if ((initial_dir
= strrchr(include
->initial_filename
, '\\')))
93 len
= initial_dir
- include
->initial_filename
+ 1;
94 initial_dir
= include
->initial_filename
;
98 len
= GetCurrentDirectoryA(MAX_PATH
, current_dir
);
99 current_dir
[len
] = '\\';
101 initial_dir
= current_dir
;
103 fullpath
= heap_alloc(len
+ strlen(filename
) + 1);
105 return E_OUTOFMEMORY
;
106 memcpy(fullpath
, initial_dir
, len
);
107 strcpy(fullpath
+ len
, filename
);
109 file
= CreateFileA(fullpath
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, 0, 0);
110 if (file
== INVALID_HANDLE_VALUE
)
113 TRACE("Include file found at %s.\n", debugstr_a(fullpath
));
115 size
= GetFileSize(file
, NULL
);
116 if (size
== INVALID_FILE_SIZE
)
118 buffer
= heap_alloc(size
);
121 if (!ReadFile(file
, buffer
, size
, &read
, NULL
) || read
!= size
)
135 WARN("Returning E_FAIL.\n");
139 static HRESULT WINAPI
d3dcompiler_include_from_file_close(ID3DInclude
*iface
, const void *data
)
141 heap_free((void *)data
);
145 const struct ID3DIncludeVtbl d3dcompiler_include_from_file_vtbl
=
147 d3dcompiler_include_from_file_open
,
148 d3dcompiler_include_from_file_close
151 static int open_include(const char *filename
, bool local
, const char *parent_data
, void *context
,
152 struct vkd3d_shader_code
*code
)
154 ID3DInclude
*iface
= context
;
155 unsigned int size
= 0;
160 memset(code
, 0, sizeof(*code
));
161 if (FAILED(ID3DInclude_Open(iface
, local
? D3D_INCLUDE_LOCAL
: D3D_INCLUDE_SYSTEM
,
162 filename
, parent_data
, &code
->code
, &size
)))
169 static void close_include(const struct vkd3d_shader_code
*code
, void *context
)
171 ID3DInclude
*iface
= context
;
173 ID3DInclude_Close(iface
, code
->code
);
176 static const char *get_line(const char **ptr
)
181 if (!(q
= strstr(p
, "\n")))
193 static HRESULT
preprocess_shader(const void *data
, SIZE_T data_size
, const char *filename
,
194 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, ID3DBlob
**shader_blob
,
195 ID3DBlob
**messages_blob
)
197 struct d3dcompiler_include_from_file include_from_file
;
198 struct vkd3d_shader_preprocess_info preprocess_info
;
199 struct vkd3d_shader_compile_info compile_info
;
200 const D3D_SHADER_MACRO
*def
= defines
;
201 struct vkd3d_shader_code byte_code
;
206 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
208 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
209 include_from_file
.initial_filename
= filename
? filename
: "";
210 include
= &include_from_file
.ID3DInclude_iface
;
213 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
214 compile_info
.next
= &preprocess_info
;
215 compile_info
.source
.code
= data
;
216 compile_info
.source
.size
= data_size
;
217 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
218 compile_info
.target_type
= VKD3D_SHADER_TARGET_NONE
;
219 compile_info
.options
= NULL
;
220 compile_info
.option_count
= 0;
221 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
222 compile_info
.source_name
= filename
;
224 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
225 preprocess_info
.next
= NULL
;
226 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)defines
;
227 preprocess_info
.macro_count
= 0;
230 for (def
= defines
; def
->Name
; ++def
)
231 ++preprocess_info
.macro_count
;
233 preprocess_info
.pfn_open_include
= open_include
;
234 preprocess_info
.pfn_close_include
= close_include
;
235 preprocess_info
.include_context
= include
;
237 ret
= vkd3d_shader_preprocess(&compile_info
, &byte_code
, &messages
);
240 ERR("Failed to preprocess shader, vkd3d result %d.\n", ret
);
244 if (*messages
&& ERR_ON(d3dcompiler
))
246 const char *ptr
= messages
;
249 ERR("Shader log:\n");
250 while ((line
= get_line(&ptr
)))
252 ERR(" %.*s", (int)(ptr
- line
), line
);
259 size_t size
= strlen(messages
);
260 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
262 vkd3d_shader_free_messages(messages
);
263 vkd3d_shader_free_shader_code(&byte_code
);
266 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
270 vkd3d_shader_free_messages(messages
);
276 if (FAILED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
278 vkd3d_shader_free_shader_code(&byte_code
);
281 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
284 return hresult_from_vkd3d_result(ret
);
287 static HRESULT
assemble_shader(const char *preproc_shader
, ID3DBlob
**shader_blob
, ID3DBlob
**error_messages
)
289 struct bwriter_shader
*shader
;
290 char *messages
= NULL
;
296 shader
= SlAssembleShader(preproc_shader
, &messages
);
300 TRACE("Assembler messages:\n");
301 TRACE("%s\n", debugstr_a(messages
));
303 TRACE("Shader source:\n");
304 TRACE("%s\n", debugstr_a(preproc_shader
));
308 const char *preproc_messages
= *error_messages
? ID3D10Blob_GetBufferPointer(*error_messages
) : NULL
;
310 size
= strlen(messages
) + (preproc_messages
? strlen(preproc_messages
) : 0) + 1;
311 hr
= D3DCreateBlob(size
, &buffer
);
314 HeapFree(GetProcessHeap(), 0, messages
);
315 if (shader
) SlDeleteShader(shader
);
318 pos
= ID3D10Blob_GetBufferPointer(buffer
);
319 if (preproc_messages
)
321 CopyMemory(pos
, preproc_messages
, strlen(preproc_messages
) + 1);
322 pos
+= strlen(preproc_messages
);
324 CopyMemory(pos
, messages
, strlen(messages
) + 1);
326 if (*error_messages
) ID3D10Blob_Release(*error_messages
);
327 *error_messages
= buffer
;
329 HeapFree(GetProcessHeap(), 0, messages
);
334 ERR("Asm reading failed\n");
335 return D3DXERR_INVALIDDATA
;
338 hr
= shader_write_bytecode(shader
, &res
, &size
);
339 SlDeleteShader(shader
);
342 ERR("Failed to write bytecode, hr %#lx.\n", hr
);
343 return D3DXERR_INVALIDDATA
;
348 hr
= D3DCreateBlob(size
, &buffer
);
351 HeapFree(GetProcessHeap(), 0, res
);
354 CopyMemory(ID3D10Blob_GetBufferPointer(buffer
), res
, size
);
355 *shader_blob
= buffer
;
358 HeapFree(GetProcessHeap(), 0, res
);
363 HRESULT WINAPI
D3DAssemble(const void *data
, SIZE_T datasize
, const char *filename
,
364 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, UINT flags
,
365 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
367 unsigned int preproc_size
;
368 ID3DBlob
*preproc_shader
;
369 char *preproc_terminated
;
372 TRACE("data %p, datasize %Iu, filename %s, defines %p, include %p, sflags %#x, "
373 "shader %p, error_messages %p.\n",
374 data
, datasize
, debugstr_a(filename
), defines
, include
, flags
, shader
, error_messages
);
376 EnterCriticalSection(&wpp_mutex
);
379 if (flags
) FIXME("flags %x\n", flags
);
381 if (shader
) *shader
= NULL
;
382 if (error_messages
) *error_messages
= NULL
;
384 hr
= preprocess_shader(data
, datasize
, filename
, defines
, include
, &preproc_shader
, error_messages
);
387 preproc_size
= ID3D10Blob_GetBufferSize(preproc_shader
);
388 if ((preproc_terminated
= malloc(preproc_size
+ 1)))
390 memcpy(preproc_terminated
, ID3D10Blob_GetBufferPointer(preproc_shader
), preproc_size
);
391 ID3D10Blob_Release(preproc_shader
);
392 preproc_terminated
[preproc_size
] = 0;
394 hr
= assemble_shader(preproc_terminated
, shader
, error_messages
);
395 free(preproc_terminated
);
398 LeaveCriticalSection(&wpp_mutex
);
402 HRESULT WINAPI
D3DCompile2(const void *data
, SIZE_T data_size
, const char *filename
,
403 const D3D_SHADER_MACRO
*macros
, ID3DInclude
*include
, const char *entry_point
,
404 const char *profile
, UINT flags
, UINT effect_flags
, UINT secondary_flags
,
405 const void *secondary_data
, SIZE_T secondary_data_size
, ID3DBlob
**shader_blob
,
406 ID3DBlob
**messages_blob
)
408 struct d3dcompiler_include_from_file include_from_file
;
409 struct vkd3d_shader_preprocess_info preprocess_info
;
410 struct vkd3d_shader_hlsl_source_info hlsl_info
;
411 struct vkd3d_shader_compile_option options
[2];
412 struct vkd3d_shader_compile_info compile_info
;
413 struct vkd3d_shader_compile_option
*option
;
414 struct vkd3d_shader_code byte_code
;
415 const D3D_SHADER_MACRO
*macro
;
416 size_t profile_len
, i
;
421 static const char * const d3dbc_profiles
[] =
444 TRACE("data %p, data_size %Iu, filename %s, macros %p, include %p, entry_point %s, "
445 "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, "
446 "secondary_data_size %Iu, shader_blob %p, messages_blob %p.\n",
447 data
, data_size
, debugstr_a(filename
), macros
, include
, debugstr_a(entry_point
),
448 debugstr_a(profile
), flags
, effect_flags
, secondary_flags
, secondary_data
,
449 secondary_data_size
, shader_blob
, messages_blob
);
451 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
453 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
454 include_from_file
.initial_filename
= filename
? filename
: "";
455 include
= &include_from_file
.ID3DInclude_iface
;
458 if (flags
& ~D3DCOMPILE_DEBUG
)
459 FIXME("Ignoring flags %#x.\n", flags
);
461 FIXME("Ignoring effect flags %#x.\n", effect_flags
);
463 FIXME("Ignoring secondary flags %#x.\n", secondary_flags
);
468 *messages_blob
= NULL
;
470 option
= &options
[0];
471 option
->name
= VKD3D_SHADER_COMPILE_OPTION_API_VERSION
;
472 option
->value
= VKD3D_SHADER_API_VERSION_1_3
;
474 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
475 compile_info
.next
= &preprocess_info
;
476 compile_info
.source
.code
= data
;
477 compile_info
.source
.size
= data_size
;
478 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
479 compile_info
.target_type
= VKD3D_SHADER_TARGET_DXBC_TPF
;
480 compile_info
.options
= options
;
481 compile_info
.option_count
= 1;
482 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
483 compile_info
.source_name
= filename
;
485 profile_len
= strlen(profile
);
486 for (i
= 0; i
< ARRAY_SIZE(d3dbc_profiles
); ++i
)
488 size_t len
= strlen(d3dbc_profiles
[i
]);
490 if (len
<= profile_len
&& !memcmp(profile
, d3dbc_profiles
[i
], len
))
492 compile_info
.target_type
= VKD3D_SHADER_TARGET_D3D_BYTECODE
;
497 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
498 preprocess_info
.next
= &hlsl_info
;
499 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)macros
;
500 preprocess_info
.macro_count
= 0;
503 for (macro
= macros
; macro
->Name
; ++macro
)
504 ++preprocess_info
.macro_count
;
506 preprocess_info
.pfn_open_include
= open_include
;
507 preprocess_info
.pfn_close_include
= close_include
;
508 preprocess_info
.include_context
= include
;
510 hlsl_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO
;
511 hlsl_info
.next
= NULL
;
512 hlsl_info
.profile
= profile
;
513 hlsl_info
.entry_point
= entry_point
;
514 hlsl_info
.secondary_code
.code
= secondary_data
;
515 hlsl_info
.secondary_code
.size
= secondary_data_size
;
517 if (!(flags
& D3DCOMPILE_DEBUG
))
519 option
= &options
[compile_info
.option_count
++];
520 option
->name
= VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG
;
521 option
->value
= true;
524 ret
= vkd3d_shader_compile(&compile_info
, &byte_code
, &messages
);
527 ERR("Failed to compile shader, vkd3d result %d.\n", ret
);
531 if (*messages
&& ERR_ON(d3dcompiler
))
533 const char *ptr
= messages
;
536 ERR("Shader log:\n");
537 while ((line
= get_line(&ptr
)))
539 ERR(" %.*s", (int)(ptr
- line
), line
);
546 size_t size
= strlen(messages
);
547 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
549 vkd3d_shader_free_messages(messages
);
550 vkd3d_shader_free_shader_code(&byte_code
);
553 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
556 vkd3d_shader_free_messages(messages
);
560 return hresult_from_vkd3d_result(ret
);
564 vkd3d_shader_free_shader_code(&byte_code
);
568 if (SUCCEEDED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
569 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
571 vkd3d_shader_free_shader_code(&byte_code
);
576 HRESULT WINAPI
D3DCompile(const void *data
, SIZE_T data_size
, const char *filename
,
577 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, const char *entrypoint
,
578 const char *target
, UINT sflags
, UINT eflags
, ID3DBlob
**shader
, ID3DBlob
**error_messages
)
580 TRACE("data %p, data_size %Iu, filename %s, defines %p, include %p, entrypoint %s, "
581 "target %s, sflags %#x, eflags %#x, shader %p, error_messages %p.\n",
582 data
, data_size
, debugstr_a(filename
), defines
, include
, debugstr_a(entrypoint
),
583 debugstr_a(target
), sflags
, eflags
, shader
, error_messages
);
585 return D3DCompile2(data
, data_size
, filename
, defines
, include
, entrypoint
, target
, sflags
,
586 eflags
, 0, NULL
, 0, shader
, error_messages
);
589 HRESULT WINAPI
D3DPreprocess(const void *data
, SIZE_T size
, const char *filename
,
590 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
591 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
593 TRACE("data %p, size %Iu, filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
594 data
, size
, debugstr_a(filename
), defines
, include
, shader
, error_messages
);
599 if (shader
) *shader
= NULL
;
600 if (error_messages
) *error_messages
= NULL
;
602 return preprocess_shader(data
, size
, filename
, defines
, include
, shader
, error_messages
);
605 HRESULT WINAPI
D3DDisassemble(const void *data
, SIZE_T size
, UINT flags
, const char *comments
,
606 ID3DBlob
**disassembly
)
608 struct vkd3d_shader_compile_info compile_info
;
609 enum vkd3d_shader_source_type source_type
;
610 struct vkd3d_shader_code asm_code
;
611 const char *ptr
= data
;
616 TRACE("data %p, size %Iu, flags %#x, comments %p, disassembly %p.\n",
617 data
, size
, flags
, comments
, disassembly
);
620 FIXME("Ignoring flags %#x.\n", flags
);
623 FIXME("Ignoring comments %s.\n", debugstr_a(comments
));
625 #if D3D_COMPILER_VERSION >= 46
630 if (size
>= 4 && read_u32(&ptr
) == TAG_DXBC
)
631 source_type
= VKD3D_SHADER_SOURCE_DXBC_TPF
;
633 source_type
= VKD3D_SHADER_SOURCE_D3D_BYTECODE
;
635 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
636 compile_info
.next
= NULL
;
637 compile_info
.source
.code
= data
;
638 compile_info
.source
.size
= size
;
639 compile_info
.source_type
= source_type
;
640 compile_info
.target_type
= VKD3D_SHADER_TARGET_D3D_ASM
;
641 compile_info
.options
= NULL
;
642 compile_info
.option_count
= 0;
643 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
644 compile_info
.source_name
= NULL
;
646 ret
= vkd3d_shader_compile(&compile_info
, &asm_code
, &messages
);
649 ERR("Failed to disassemble shader, vkd3d result %d.\n", ret
);
653 if (*messages
&& ERR_ON(d3dcompiler
))
655 const char *ptr
= messages
;
658 ERR("Shader log:\n");
659 while ((line
= get_line(&ptr
)))
661 ERR(" %.*s", (int)(ptr
- line
), line
);
666 vkd3d_shader_free_messages(messages
);
670 return hresult_from_vkd3d_result(ret
);
672 if (SUCCEEDED(hr
= D3DCreateBlob(asm_code
.size
, disassembly
)))
673 memcpy(ID3D10Blob_GetBufferPointer(*disassembly
), asm_code
.code
, asm_code
.size
);
675 vkd3d_shader_free_shader_code(&asm_code
);
680 HRESULT WINAPI
D3DCompileFromFile(const WCHAR
*filename
, const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
681 const char *entrypoint
, const char *target
, UINT flags1
, UINT flags2
, ID3DBlob
**code
, ID3DBlob
**errors
)
683 char filename_a
[MAX_PATH
], *source
= NULL
;
684 DWORD source_size
, read_size
;
688 TRACE("filename %s, defines %p, include %p, entrypoint %s, target %s, flags1 %#x, flags2 %#x, "
689 "code %p, errors %p.\n", debugstr_w(filename
), defines
, include
, debugstr_a(entrypoint
),
690 debugstr_a(target
), flags1
, flags2
, code
, errors
);
692 file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
693 if (file
== INVALID_HANDLE_VALUE
)
694 return HRESULT_FROM_WIN32(GetLastError());
696 source_size
= GetFileSize(file
, NULL
);
697 if (source_size
== INVALID_FILE_SIZE
)
699 hr
= HRESULT_FROM_WIN32(GetLastError());
703 if (!(source
= heap_alloc(source_size
)))
709 if (!ReadFile(file
, source
, source_size
, &read_size
, NULL
) || read_size
!= source_size
)
711 WARN("Failed to read file contents.\n");
716 WideCharToMultiByte(CP_ACP
, 0, filename
, -1, filename_a
, sizeof(filename_a
), NULL
, NULL
);
718 hr
= D3DCompile(source
, source_size
, filename_a
, defines
, include
, entrypoint
, target
,
719 flags1
, flags2
, code
, errors
);
727 HRESULT WINAPI
D3DLoadModule(const void *data
, SIZE_T size
, ID3D11Module
**module
)
729 FIXME("data %p, size %Iu, module %p stub!\n", data
, size
, module
);