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 HRESULT
preprocess_shader(const void *data
, SIZE_T data_size
, const char *filename
,
177 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, ID3DBlob
**shader_blob
,
178 ID3DBlob
**messages_blob
)
180 struct d3dcompiler_include_from_file include_from_file
;
181 struct vkd3d_shader_preprocess_info preprocess_info
;
182 struct vkd3d_shader_compile_info compile_info
;
183 const D3D_SHADER_MACRO
*def
= defines
;
184 struct vkd3d_shader_code byte_code
;
189 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
191 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
192 include_from_file
.initial_filename
= filename
? filename
: "";
193 include
= &include_from_file
.ID3DInclude_iface
;
196 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
197 compile_info
.next
= &preprocess_info
;
198 compile_info
.source
.code
= data
;
199 compile_info
.source
.size
= data_size
;
200 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
201 compile_info
.target_type
= VKD3D_SHADER_TARGET_NONE
;
202 compile_info
.options
= NULL
;
203 compile_info
.option_count
= 0;
204 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
205 compile_info
.source_name
= filename
;
207 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
208 preprocess_info
.next
= NULL
;
209 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)defines
;
210 preprocess_info
.macro_count
= 0;
213 for (def
= defines
; def
->Name
; ++def
)
214 ++preprocess_info
.macro_count
;
216 preprocess_info
.pfn_open_include
= open_include
;
217 preprocess_info
.pfn_close_include
= close_include
;
218 preprocess_info
.include_context
= include
;
220 ret
= vkd3d_shader_preprocess(&compile_info
, &byte_code
, &messages
);
225 size_t size
= strlen(messages
);
226 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
228 vkd3d_shader_free_messages(messages
);
229 vkd3d_shader_free_shader_code(&byte_code
);
232 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
236 vkd3d_shader_free_messages(messages
);
242 if (FAILED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
244 vkd3d_shader_free_shader_code(&byte_code
);
247 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
250 return hresult_from_vkd3d_result(ret
);
253 static HRESULT
assemble_shader(const char *preproc_shader
, ID3DBlob
**shader_blob
, ID3DBlob
**error_messages
)
255 struct bwriter_shader
*shader
;
256 char *messages
= NULL
;
262 shader
= SlAssembleShader(preproc_shader
, &messages
);
266 TRACE("Assembler messages:\n");
267 TRACE("%s\n", debugstr_a(messages
));
269 TRACE("Shader source:\n");
270 TRACE("%s\n", debugstr_a(preproc_shader
));
274 const char *preproc_messages
= *error_messages
? ID3D10Blob_GetBufferPointer(*error_messages
) : NULL
;
276 size
= strlen(messages
) + (preproc_messages
? strlen(preproc_messages
) : 0) + 1;
277 hr
= D3DCreateBlob(size
, &buffer
);
280 HeapFree(GetProcessHeap(), 0, messages
);
281 if (shader
) SlDeleteShader(shader
);
284 pos
= ID3D10Blob_GetBufferPointer(buffer
);
285 if (preproc_messages
)
287 CopyMemory(pos
, preproc_messages
, strlen(preproc_messages
) + 1);
288 pos
+= strlen(preproc_messages
);
290 CopyMemory(pos
, messages
, strlen(messages
) + 1);
292 if (*error_messages
) ID3D10Blob_Release(*error_messages
);
293 *error_messages
= buffer
;
295 HeapFree(GetProcessHeap(), 0, messages
);
300 ERR("Asm reading failed\n");
301 return D3DXERR_INVALIDDATA
;
304 hr
= shader_write_bytecode(shader
, &res
, &size
);
305 SlDeleteShader(shader
);
308 ERR("Failed to write bytecode, hr %#lx.\n", hr
);
309 return D3DXERR_INVALIDDATA
;
314 hr
= D3DCreateBlob(size
, &buffer
);
317 HeapFree(GetProcessHeap(), 0, res
);
320 CopyMemory(ID3D10Blob_GetBufferPointer(buffer
), res
, size
);
321 *shader_blob
= buffer
;
324 HeapFree(GetProcessHeap(), 0, res
);
329 HRESULT WINAPI
D3DAssemble(const void *data
, SIZE_T datasize
, const char *filename
,
330 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, UINT flags
,
331 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
333 unsigned int preproc_size
;
334 ID3DBlob
*preproc_shader
;
335 char *preproc_terminated
;
338 TRACE("data %p, datasize %Iu, filename %s, defines %p, include %p, sflags %#x, "
339 "shader %p, error_messages %p.\n",
340 data
, datasize
, debugstr_a(filename
), defines
, include
, flags
, shader
, error_messages
);
342 EnterCriticalSection(&wpp_mutex
);
345 if (flags
) FIXME("flags %x\n", flags
);
347 if (shader
) *shader
= NULL
;
348 if (error_messages
) *error_messages
= NULL
;
350 hr
= preprocess_shader(data
, datasize
, filename
, defines
, include
, &preproc_shader
, error_messages
);
353 preproc_size
= ID3D10Blob_GetBufferSize(preproc_shader
);
354 if ((preproc_terminated
= malloc(preproc_size
+ 1)))
356 memcpy(preproc_terminated
, ID3D10Blob_GetBufferPointer(preproc_shader
), preproc_size
);
357 ID3D10Blob_Release(preproc_shader
);
358 preproc_terminated
[preproc_size
] = 0;
360 hr
= assemble_shader(preproc_terminated
, shader
, error_messages
);
361 free(preproc_terminated
);
364 LeaveCriticalSection(&wpp_mutex
);
368 HRESULT WINAPI
D3DCompile2(const void *data
, SIZE_T data_size
, const char *filename
,
369 const D3D_SHADER_MACRO
*macros
, ID3DInclude
*include
, const char *entry_point
,
370 const char *profile
, UINT flags
, UINT effect_flags
, UINT secondary_flags
,
371 const void *secondary_data
, SIZE_T secondary_data_size
, ID3DBlob
**shader_blob
,
372 ID3DBlob
**messages_blob
)
374 struct d3dcompiler_include_from_file include_from_file
;
375 struct vkd3d_shader_preprocess_info preprocess_info
;
376 struct vkd3d_shader_hlsl_source_info hlsl_info
;
377 struct vkd3d_shader_compile_option options
[2];
378 struct vkd3d_shader_compile_info compile_info
;
379 struct vkd3d_shader_compile_option
*option
;
380 struct vkd3d_shader_code byte_code
;
381 const D3D_SHADER_MACRO
*macro
;
382 size_t profile_len
, i
;
387 static const char * const d3dbc_profiles
[] =
410 TRACE("data %p, data_size %Iu, filename %s, macros %p, include %p, entry_point %s, "
411 "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, "
412 "secondary_data_size %Iu, shader_blob %p, messages_blob %p.\n",
413 data
, data_size
, debugstr_a(filename
), macros
, include
, debugstr_a(entry_point
),
414 debugstr_a(profile
), flags
, effect_flags
, secondary_flags
, secondary_data
,
415 secondary_data_size
, shader_blob
, messages_blob
);
417 if (include
== D3D_COMPILE_STANDARD_FILE_INCLUDE
)
419 include_from_file
.ID3DInclude_iface
.lpVtbl
= &d3dcompiler_include_from_file_vtbl
;
420 include_from_file
.initial_filename
= filename
? filename
: "";
421 include
= &include_from_file
.ID3DInclude_iface
;
424 if (flags
& ~D3DCOMPILE_DEBUG
)
425 FIXME("Ignoring flags %#x.\n", flags
);
427 FIXME("Ignoring effect flags %#x.\n", effect_flags
);
429 FIXME("Ignoring secondary flags %#x.\n", secondary_flags
);
432 *messages_blob
= NULL
;
434 option
= &options
[0];
435 option
->name
= VKD3D_SHADER_COMPILE_OPTION_API_VERSION
;
436 option
->value
= VKD3D_SHADER_API_VERSION_1_3
;
438 compile_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO
;
439 compile_info
.next
= &preprocess_info
;
440 compile_info
.source
.code
= data
;
441 compile_info
.source
.size
= data_size
;
442 compile_info
.source_type
= VKD3D_SHADER_SOURCE_HLSL
;
443 compile_info
.target_type
= VKD3D_SHADER_TARGET_DXBC_TPF
;
444 compile_info
.options
= options
;
445 compile_info
.option_count
= 1;
446 compile_info
.log_level
= VKD3D_SHADER_LOG_INFO
;
447 compile_info
.source_name
= filename
;
449 profile_len
= strlen(profile
);
450 for (i
= 0; i
< ARRAY_SIZE(d3dbc_profiles
); ++i
)
452 size_t len
= strlen(d3dbc_profiles
[i
]);
454 if (len
<= profile_len
&& !memcmp(profile
, d3dbc_profiles
[i
], len
))
456 compile_info
.target_type
= VKD3D_SHADER_TARGET_D3D_BYTECODE
;
461 preprocess_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO
;
462 preprocess_info
.next
= &hlsl_info
;
463 preprocess_info
.macros
= (const struct vkd3d_shader_macro
*)macros
;
464 preprocess_info
.macro_count
= 0;
467 for (macro
= macros
; macro
->Name
; ++macro
)
468 ++preprocess_info
.macro_count
;
470 preprocess_info
.pfn_open_include
= open_include
;
471 preprocess_info
.pfn_close_include
= close_include
;
472 preprocess_info
.include_context
= include
;
474 hlsl_info
.type
= VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO
;
475 hlsl_info
.next
= NULL
;
476 hlsl_info
.profile
= profile
;
477 hlsl_info
.entry_point
= entry_point
;
478 hlsl_info
.secondary_code
.code
= secondary_data
;
479 hlsl_info
.secondary_code
.size
= secondary_data_size
;
481 if (!(flags
& D3DCOMPILE_DEBUG
))
483 option
= &options
[compile_info
.option_count
++];
484 option
->name
= VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG
;
485 option
->value
= true;
488 ret
= vkd3d_shader_compile(&compile_info
, &byte_code
, &messages
);
493 size_t size
= strlen(messages
);
494 if (FAILED(hr
= D3DCreateBlob(size
, messages_blob
)))
496 vkd3d_shader_free_messages(messages
);
497 vkd3d_shader_free_shader_code(&byte_code
);
500 memcpy(ID3D10Blob_GetBufferPointer(*messages_blob
), messages
, size
);
503 vkd3d_shader_free_messages(messages
);
508 if (FAILED(hr
= D3DCreateBlob(byte_code
.size
, shader_blob
)))
510 vkd3d_shader_free_shader_code(&byte_code
);
513 memcpy(ID3D10Blob_GetBufferPointer(*shader_blob
), byte_code
.code
, byte_code
.size
);
516 return hresult_from_vkd3d_result(ret
);
519 HRESULT WINAPI
D3DCompile(const void *data
, SIZE_T data_size
, const char *filename
,
520 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
, const char *entrypoint
,
521 const char *target
, UINT sflags
, UINT eflags
, ID3DBlob
**shader
, ID3DBlob
**error_messages
)
523 TRACE("data %p, data_size %Iu, filename %s, defines %p, include %p, entrypoint %s, "
524 "target %s, sflags %#x, eflags %#x, shader %p, error_messages %p.\n",
525 data
, data_size
, debugstr_a(filename
), defines
, include
, debugstr_a(entrypoint
),
526 debugstr_a(target
), sflags
, eflags
, shader
, error_messages
);
528 return D3DCompile2(data
, data_size
, filename
, defines
, include
, entrypoint
, target
, sflags
,
529 eflags
, 0, NULL
, 0, shader
, error_messages
);
532 HRESULT WINAPI
D3DPreprocess(const void *data
, SIZE_T size
, const char *filename
,
533 const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
534 ID3DBlob
**shader
, ID3DBlob
**error_messages
)
536 TRACE("data %p, size %Iu, filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
537 data
, size
, debugstr_a(filename
), defines
, include
, shader
, error_messages
);
542 if (shader
) *shader
= NULL
;
543 if (error_messages
) *error_messages
= NULL
;
545 return preprocess_shader(data
, size
, filename
, defines
, include
, shader
, error_messages
);
548 HRESULT WINAPI
D3DDisassemble(const void *data
, SIZE_T size
, UINT flags
, const char *comments
, ID3DBlob
**disassembly
)
550 FIXME("data %p, size %Iu, flags %#x, comments %p, disassembly %p stub!\n",
551 data
, size
, flags
, comments
, disassembly
);
555 HRESULT WINAPI
D3DCompileFromFile(const WCHAR
*filename
, const D3D_SHADER_MACRO
*defines
, ID3DInclude
*include
,
556 const char *entrypoint
, const char *target
, UINT flags1
, UINT flags2
, ID3DBlob
**code
, ID3DBlob
**errors
)
558 char filename_a
[MAX_PATH
], *source
= NULL
;
559 DWORD source_size
, read_size
;
563 TRACE("filename %s, defines %p, include %p, entrypoint %s, target %s, flags1 %#x, flags2 %#x, "
564 "code %p, errors %p.\n", debugstr_w(filename
), defines
, include
, debugstr_a(entrypoint
),
565 debugstr_a(target
), flags1
, flags2
, code
, errors
);
567 file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
568 if (file
== INVALID_HANDLE_VALUE
)
569 return HRESULT_FROM_WIN32(GetLastError());
571 source_size
= GetFileSize(file
, NULL
);
572 if (source_size
== INVALID_FILE_SIZE
)
574 hr
= HRESULT_FROM_WIN32(GetLastError());
578 if (!(source
= heap_alloc(source_size
)))
584 if (!ReadFile(file
, source
, source_size
, &read_size
, NULL
) || read_size
!= source_size
)
586 WARN("Failed to read file contents.\n");
591 WideCharToMultiByte(CP_ACP
, 0, filename
, -1, filename_a
, sizeof(filename_a
), NULL
, NULL
);
593 hr
= D3DCompile(source
, source_size
, filename_a
, defines
, include
, entrypoint
, target
,
594 flags1
, flags2
, code
, errors
);
602 HRESULT WINAPI
D3DLoadModule(const void *data
, SIZE_T size
, ID3D11Module
**module
)
604 FIXME("data %p, size %Iu, module %p stub!\n", data
, size
, module
);