From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Fix up style a bit.
dlls/d3dcompiler_43/compiler.c | 82 +++++++++ dlls/d3dcompiler_43/tests/hlsl_d3d9.c | 249 ++++++++++++++++++++++++++ include/d3dcompiler.h | 2 + 3 files changed, 333 insertions(+)
diff --git a/dlls/d3dcompiler_43/compiler.c b/dlls/d3dcompiler_43/compiler.c index c400b83d8d1a..02e74198e93a 100644 --- a/dlls/d3dcompiler_43/compiler.c +++ b/dlls/d3dcompiler_43/compiler.c @@ -829,12 +829,88 @@ static HRESULT compile_shader(const char *preproc_shader, const char *target, co return hr; }
+static HRESULT WINAPI d3dcompiler_include_from_file_open(ID3DInclude *iface, D3D_INCLUDE_TYPE include_type, + const char *filename, const void *parent_data, const void **data, UINT *bytes) +{ + char *fullpath, *buffer = NULL, current_dir[MAX_PATH + 1]; + const char *initial_dir; + SIZE_T size; + HANDLE file; + ULONG read; + DWORD len; + + if ((initial_dir = strrchr(initial_filename, '\'))) + { + len = initial_dir - initial_filename + 1; + initial_dir = initial_filename; + } + else + { + len = GetCurrentDirectoryA(MAX_PATH, current_dir); + current_dir[len] = '\'; + len++; + initial_dir = current_dir; + } + fullpath = heap_alloc(len + strlen(filename) + 1); + if (!fullpath) + return E_OUTOFMEMORY; + memcpy(fullpath, initial_dir, len); + strcpy(fullpath + len, filename); + + file = CreateFileA(fullpath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (file == INVALID_HANDLE_VALUE) + goto error; + + TRACE("Include file found at %s.\n", debugstr_a(fullpath)); + + size = GetFileSize(file, NULL); + if (size == INVALID_FILE_SIZE) + goto error; + buffer = heap_alloc(size); + if (!buffer) + goto error; + if (!ReadFile(file, buffer, size, &read, NULL) || read != size) + goto error; + + *bytes = size; + *data = buffer; + + heap_free(fullpath); + CloseHandle(file); + return S_OK; + +error: + heap_free(fullpath); + heap_free(buffer); + CloseHandle(file); + WARN("Returning E_FAIL.\n"); + return E_FAIL; +} + +static HRESULT WINAPI d3dcompiler_include_from_file_close(ID3DInclude *iface, const void *data) +{ + heap_free((void *)data); + return S_OK; +} + +const struct ID3DIncludeVtbl d3dcompiler_include_from_file_vtbl = +{ + d3dcompiler_include_from_file_open, + d3dcompiler_include_from_file_close +}; + +struct d3dcompiler_include_from_file +{ + ID3DInclude ID3DInclude_iface; +}; + HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, const char *target, UINT sflags, UINT eflags, UINT secondary_flags, const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, ID3DBlob **error_messages) { + struct d3dcompiler_include_from_file include_from_file; HRESULT hr;
TRACE("data %p, data_size %lu, filename %s, defines %p, include %p, entrypoint %s, " @@ -850,6 +926,12 @@ HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filen if (shader) *shader = NULL; if (error_messages) *error_messages = NULL;
+ if (include == D3D_COMPILE_STANDARD_FILE_INCLUDE) + { + include_from_file.ID3DInclude_iface.lpVtbl = &d3dcompiler_include_from_file_vtbl; + include = &include_from_file.ID3DInclude_iface; + } + EnterCriticalSection(&wpp_mutex);
hr = preprocess_shader(data, data_size, filename, defines, include, error_messages); diff --git a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c index ed148ff112a1..f6b389ccdf30 100644 --- a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c +++ b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c @@ -18,6 +18,7 @@ */ #define COBJMACROS #include "wine/test.h" +#include "wine/heap.h" #include "d3dx9.h" #include "d3dcompiler.h"
@@ -25,6 +26,9 @@
static pD3DCompile ppD3DCompile;
+static HRESULT (WINAPI *pD3DCompile2)(const void *data, SIZE_T data_size, const char *filename, const D3D_SHADER_MACRO *defines, + ID3DInclude *include, const char *entrypoint, const char *target, UINT sflags, UINT eflags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, ID3DBlob **error_messages); static HRESULT (WINAPI *pD3DXGetShaderConstantTable)(const DWORD *byte_code, ID3DXConstantTable **constant_table);
struct vec2 @@ -37,6 +41,63 @@ struct vec4 float x, y, z, w; };
+static WCHAR temp_dir[MAX_PATH]; + +static BOOL create_file(const WCHAR *filename, const char *data, unsigned int size, WCHAR *out_path) +{ + WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + + if (!temp_dir[0]) + GetTempPathW(ARRAY_SIZE(temp_dir), temp_dir); + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + + file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + if (WriteFile(file, data, size, &written, NULL)) + { + CloseHandle(file); + + if (out_path) + lstrcpyW(out_path, path); + return TRUE; + } + + CloseHandle(file); + return FALSE; +} + +static void delete_file(const WCHAR *filename) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + DeleteFileW(path); +} + +static BOOL create_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + return CreateDirectoryW(path, NULL); +} + +static void delete_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + RemoveDirectoryW(path); +} + #define compile_shader(a, b) compile_shader_(__LINE__, a, b) static ID3D10Blob *compile_shader_(unsigned int line, const char *source, const char *target) { @@ -1269,6 +1330,7 @@ static BOOL load_d3dcompiler(void)
#if D3D_COMPILER_VERSION == 47 if (!(module = LoadLibraryA("d3dcompiler_47.dll"))) return FALSE; + pD3DCompile2 = (void*)GetProcAddress(module, "D3DCompile2"); #else if (!(module = LoadLibraryA("d3dcompiler_43.dll"))) return FALSE; #endif @@ -1277,6 +1339,192 @@ static BOOL load_d3dcompiler(void) return TRUE; }
+static HRESULT WINAPI test_d3dinclude_open(ID3DInclude *iface, D3D_INCLUDE_TYPE include_type, + const char *filename, const void *parent_data, const void **data, UINT *bytes) +{ + static const char include1[] = + "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; + static const char include2[] = + "#include "include1.h"\n" + "float4 light_color = LIGHT;\n"; + char *buffer; + + trace("filename %s.\n", filename); + trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)"); + + if (!strcmp(filename, "include1.h")) + { + buffer = heap_alloc(strlen(include1)); + CopyMemory(buffer, include1, strlen(include1)); + *bytes = strlen(include1); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + ok(!strncmp(include2, parent_data, strlen(include2)), + "Unexpected parent_data value.\n"); + } + else if (!strcmp(filename, "include\include2.h")) + { + buffer = heap_alloc(strlen(include2)); + CopyMemory(buffer, include2, strlen(include2)); + *bytes = strlen(include2); + ok(!parent_data, "Unexpected parent_data value.\n"); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + } + else + { + ok(0, "Unexpected #include for file %s.\n", filename); + return D3DERR_INVALIDCALL; + } + + *data = buffer; + return S_OK; +} + +static HRESULT WINAPI test_d3dinclude_close(ID3DInclude *iface, const void *data) +{ + heap_free((void *)data); + return S_OK; +} + +static const struct ID3DIncludeVtbl test_d3dinclude_vtbl = +{ + test_d3dinclude_open, + test_d3dinclude_close +}; + +struct test_d3dinclude +{ + ID3DInclude ID3DInclude_iface; +}; + +static void test_d3dcompile(void) +{ + struct test_d3dinclude include = {{&test_d3dinclude_vtbl}}; + WCHAR filename[MAX_PATH], directory[MAX_PATH]; + ID3D10Blob *blob = NULL, *errors = NULL; + CHAR filename_a[MAX_PATH]; + HRESULT hr; + DWORD len; + static const char ps_code[] = + "#include "include\include2.h"\n" + "\n" + "float4 main() : COLOR\n" + "{\n" + " return light_color;\n" + "}"; + static const char include1[] = + "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; + static const char include1_wrong[] = + "#define LIGHT nope\n"; + static const char include2[] = + "#include "include1.h"\n" + "float4 light_color = LIGHT;\n"; + + create_file(L"source.ps", ps_code, strlen(ps_code), filename); + create_directory(L"include"); + create_file(L"include\include1.h", include1_wrong, strlen(include1_wrong), NULL); + create_file(L"include1.h", include1, strlen(include1), NULL); + create_file(L"include\include2.h", include2, strlen(include2), NULL); + + len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL); + + hr = ppD3DCompile(ps_code, sizeof(ps_code), filename_a, NULL, &include.ID3DInclude_iface, "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + /* Also skip D3DCompile() D3D_COMPILE_STANDARD_FILE_INCLUDE tests from + * d3dcompiler_43 or earlier since they crash on Windows. */ + if (!pD3DCompile2) + { + skip("D3DCompile2() isn't supported.\n"); + goto cleanup; + } + + hr = ppD3DCompile(ps_code, sizeof(ps_code), NULL, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", "ps_2_0", 0, 0, &blob, &errors); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + ok(!blob, "Got unexpected blob.\n"); + ok(!!errors, "Got unexpected errors.\n"); + ID3D10Blob_Release(errors); + errors = NULL; + + /* Windows always seems to resolve includes from the initial file location + * instead of using the immediate parent, as it would be the case for + * standard C preprocessor includes. */ + hr = ppD3DCompile(ps_code, sizeof(ps_code), filename_a, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + hr = pD3DCompile2(ps_code, sizeof(ps_code), filename_a, NULL, &include.ID3DInclude_iface, + "main", "ps_2_0", 0, 0, 0, NULL, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + hr = pD3DCompile2(ps_code, sizeof(ps_code), filename_a, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", "ps_2_0", 0, 0, 0, NULL, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + GetCurrentDirectoryW(MAX_PATH, directory); + SetCurrentDirectoryW(temp_dir); + + hr = ppD3DCompile(ps_code, sizeof(ps_code), "source.ps", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + hr = pD3DCompile2(ps_code, sizeof(ps_code), "source.ps", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", "ps_2_0", 0, 0, 0, NULL, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + SetCurrentDirectoryW(directory); + +cleanup: + delete_file(L"source.ps"); + delete_file(L"include\include1.h"); + delete_file(L"include1.h"); + delete_file(L"include\include2.h"); + delete_directory(L"include"); +} + START_TEST(hlsl_d3d9) { HMODULE mod; @@ -1309,4 +1557,5 @@ START_TEST(hlsl_d3d9)
test_constant_table(); test_fail(); + test_d3dcompile(); } diff --git a/include/d3dcompiler.h b/include/d3dcompiler.h index f11251e9dbf0..f897a7859923 100644 --- a/include/d3dcompiler.h +++ b/include/d3dcompiler.h @@ -82,6 +82,8 @@ static const WCHAR D3DCOMPILER_DLL_W[] = {'d','3','d','c','o','m','p','i','l','e #define D3D_DISASM_INSTRUCTION_ONLY 0x00000040 #define D3D_DISASM_PRINT_HEX_LITERALS 0x00000080
+#define D3D_COMPILE_STANDARD_FILE_INCLUDE ((ID3DInclude *)(UINT_PTR)1) + HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages);
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Fix up style, fix broken WideCharToMultiByte() use.
dlls/d3dcompiler_43/compiler.c | 46 +++++++++++++++++++++--- dlls/d3dcompiler_43/tests/hlsl_d3d9.c | 50 +++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/dlls/d3dcompiler_43/compiler.c b/dlls/d3dcompiler_43/compiler.c index 02e74198e93a..f60585a36d15 100644 --- a/dlls/d3dcompiler_43/compiler.c +++ b/dlls/d3dcompiler_43/compiler.c @@ -1003,13 +1003,51 @@ HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T size, UINT flags, const c return E_NOTIMPL; }
-HRESULT WINAPI D3DCompileFromFile(const WCHAR *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *includes, +HRESULT WINAPI D3DCompileFromFile(const WCHAR *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, const char *target, UINT flags1, UINT flags2, ID3DBlob **code, ID3DBlob **errors) { - FIXME("filename %s, defines %p, includes %p, entrypoint %s, target %s, flags1 %x, flags2 %x, code %p, errors %p\n", - debugstr_w(filename), defines, includes, debugstr_a(entrypoint), debugstr_a(target), flags1, flags2, code, errors); + char filename_a[MAX_PATH], *source = NULL; + DWORD source_size, read_size; + HANDLE file; + HRESULT hr;
- return E_NOTIMPL; + TRACE("filename %s, defines %p, include %p, entrypoint %s, target %s, flags1 %#x, flags2 %#x, " + "code %p, errors %p.\n", debugstr_w(filename), defines, include, debugstr_a(entrypoint), + debugstr_a(target), flags1, flags2, code, errors); + + file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + source_size = GetFileSize(file, NULL); + if (source_size == INVALID_FILE_SIZE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto end; + } + + if (!(source = heap_alloc(source_size))) + { + hr = E_OUTOFMEMORY; + goto end; + } + + if (!ReadFile(file, source, source_size, &read_size, NULL) || read_size != source_size) + { + WARN("Failed to read file contents.\n"); + hr = E_FAIL; + goto end; + } + + WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, sizeof(filename_a), NULL, NULL); + + hr = D3DCompile(source, source_size, filename_a, defines, include, entrypoint, target, + flags1, flags2, code, errors); + +end: + heap_free(source); + CloseHandle(file); + return hr; }
HRESULT WINAPI D3DLoadModule(const void *data, SIZE_T size, ID3D11Module **module) diff --git a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c index f6b389ccdf30..8443406402ed 100644 --- a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c +++ b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c @@ -29,6 +29,9 @@ static pD3DCompile ppD3DCompile; static HRESULT (WINAPI *pD3DCompile2)(const void *data, SIZE_T data_size, const char *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, const char *target, UINT sflags, UINT eflags, UINT secondary_flags, const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, ID3DBlob **error_messages); +static HRESULT (WINAPI *pD3DCompileFromFile)(const WCHAR *filename, const D3D_SHADER_MACRO *defines, + ID3DInclude *include, const char *entrypoint, const char *target, UINT flags1, UINT flags2, + ID3DBlob **code, ID3DBlob **errors); static HRESULT (WINAPI *pD3DXGetShaderConstantTable)(const DWORD *byte_code, ID3DXConstantTable **constant_table);
struct vec2 @@ -1331,6 +1334,7 @@ static BOOL load_d3dcompiler(void) #if D3D_COMPILER_VERSION == 47 if (!(module = LoadLibraryA("d3dcompiler_47.dll"))) return FALSE; pD3DCompile2 = (void*)GetProcAddress(module, "D3DCompile2"); + pD3DCompileFromFile = (void*)GetProcAddress(module, "D3DCompileFromFile"); #else if (!(module = LoadLibraryA("d3dcompiler_43.dll"))) return FALSE; #endif @@ -1490,6 +1494,42 @@ static void test_d3dcompile(void) blob = NULL; }
+ hr = pD3DCompileFromFile(L"nonexistent", NULL, NULL, "main", "vs_2_0", 0, 0, &blob, &errors); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Got hr %#x.\n", hr); + ok(!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + + hr = pD3DCompileFromFile(filename, NULL, NULL, "main", "ps_2_0", 0, 0, &blob, &errors); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + ok(!blob, "Got unexpected blob.\n"); + ok(!!errors, "Got unexpected errors.\n"); + trace("%s.\n", (char *)ID3D10Blob_GetBufferPointer(errors)); + ID3D10Blob_Release(errors); + errors = NULL; + + hr = pD3DCompileFromFile(filename, NULL, &include.ID3DInclude_iface, "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + /* Windows always seems to resolve includes from the initial file location + * instead of using the immediate parent, as it would be the case for + * standard C preprocessor includes. */ + hr = pD3DCompileFromFile(filename, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + GetCurrentDirectoryW(MAX_PATH, directory); SetCurrentDirectoryW(temp_dir);
@@ -1515,6 +1555,16 @@ static void test_d3dcompile(void) blob = NULL; }
+ hr = pD3DCompileFromFile(L"source.ps", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "ps_2_0", 0, 0, &blob, &errors); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + SetCurrentDirectoryW(directory);
cleanup:
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Fix up style, fix broken MultiByteToWideChar() use.
dlls/d3dx11_43/async.c | 29 ++++- dlls/d3dx11_43/tests/d3dx11.c | 202 ++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 6 deletions(-)
diff --git a/dlls/d3dx11_43/async.c b/dlls/d3dx11_43/async.c index cde87cec6054..ee20602310a7 100644 --- a/dlls/d3dx11_43/async.c +++ b/dlls/d3dx11_43/async.c @@ -236,24 +236,41 @@ HRESULT WINAPI D3DX11CompileFromFileA(const char *filename, const D3D10_SHADER_M ID3D10Include *include, const char *entry_point, const char *target, UINT sflags, UINT eflags, ID3DX11ThreadPump *pump, ID3D10Blob **shader, ID3D10Blob **error_messages, HRESULT *hresult) { - FIXME("filename %s, defines %p, include %p, entry_point %s, target %s, sflags %#x, " - "eflags %#x, pump %p, shader %p, error_messages %p, hresult %p stub.\n", + WCHAR filename_w[MAX_PATH]; + + TRACE("filename %s, defines %p, include %p, entry_point %s, target %s, sflags %#x, " + "eflags %#x, pump %p, shader %p, error_messages %p, hresult %p.\n", debugstr_a(filename), defines, include, debugstr_a(entry_point), debugstr_a(target), sflags, eflags, pump, shader, error_messages, hresult);
- return E_NOTIMPL; + MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, ARRAY_SIZE(filename_w)); + + return D3DX11CompileFromFileW(filename_w, defines, include, entry_point, target, + sflags, eflags, pump, shader, error_messages, hresult); }
HRESULT WINAPI D3DX11CompileFromFileW(const WCHAR *filename, const D3D10_SHADER_MACRO *defines, ID3D10Include *include, const char *entry_point, const char *target, UINT sflags, UINT eflags, ID3DX11ThreadPump *pump, ID3D10Blob **shader, ID3D10Blob **error_messages, HRESULT *hresult) { - FIXME("filename %s, defines %p, include %p, entry_point %s, target %s, sflags %#x, " - "eflags %#x, pump %p, shader %p, error_messages %p, hresult %p stub.\n", + HRESULT hr; + + TRACE("filename %s, defines %p, include %p, entry_point %s, target %s, sflags %#x, " + "eflags %#x, pump %p, shader %p, error_messages %p, hresult %p.\n", debugstr_w(filename), defines, include, debugstr_a(entry_point), debugstr_a(target), sflags, eflags, pump, shader, error_messages, hresult);
- return E_NOTIMPL; + if (pump) + FIXME("Unimplemented ID3DX11ThreadPump handling.\n"); + + if (!include) + include = D3D_COMPILE_STANDARD_FILE_INCLUDE; + + hr = D3DCompileFromFile(filename, defines, include, entry_point, target, sflags, eflags, shader, error_messages); + if (hresult) + *hresult = hr; + + return hr; }
HRESULT WINAPI D3DX11CreateAsyncMemoryLoader(const void *data, SIZE_T data_size, ID3DX11DataLoader **loader) diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index f7ced893b047..db06c9714402 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -21,6 +21,64 @@ #include "d3d11.h" #include "d3dx11.h" #include "wine/test.h" +#include "wine/heap.h" + +static WCHAR temp_dir[MAX_PATH]; + +static BOOL create_file(const WCHAR *filename, const char *data, unsigned int size, WCHAR *out_path) +{ + WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + + if (!temp_dir[0]) + GetTempPathW(ARRAY_SIZE(temp_dir), temp_dir); + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + + file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + if (WriteFile(file, data, size, &written, NULL)) + { + CloseHandle(file); + + if (out_path) + lstrcpyW(out_path, path); + return TRUE; + } + + CloseHandle(file); + return FALSE; +} + +static void delete_file(const WCHAR *filename) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + DeleteFileW(path); +} + +static BOOL create_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + return CreateDirectoryW(path, NULL); +} + +static void delete_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + RemoveDirectoryW(path); +}
static void test_D3DX11CreateAsyncMemoryLoader(void) { @@ -205,9 +263,153 @@ static void test_D3DX11CreateAsyncResourceLoader(void) ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#x.\n", hr); }
+static HRESULT WINAPI test_d3dinclude_open(ID3DInclude *iface, D3D_INCLUDE_TYPE include_type, + const char *filename, const void *parent_data, const void **data, UINT *bytes) +{ + static const char include1[] = + "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; + static const char include2[] = + "#include "include1.h"\n" + "float4 light_color = LIGHT;\n"; + char *buffer; + + trace("filename %s.\n", filename); + trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)"); + + if (!strcmp(filename, "include1.h")) + { + buffer = heap_alloc(strlen(include1)); + CopyMemory(buffer, include1, strlen(include1)); + *bytes = strlen(include1); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + ok(!strncmp(include2, parent_data, strlen(include2)), + "Unexpected parent_data value.\n"); + } + else if (!strcmp(filename, "include\include2.h")) + { + buffer = heap_alloc(strlen(include2)); + CopyMemory(buffer, include2, strlen(include2)); + *bytes = strlen(include2); + ok(!parent_data, "Unexpected parent_data value.\n"); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + } + else + { + ok(0, "Unexpected #include for file %s.\n", filename); + return E_INVALIDARG; + } + + *data = buffer; + return S_OK; +} + +static HRESULT WINAPI test_d3dinclude_close(ID3DInclude *iface, const void *data) +{ + heap_free((void *)data); + return S_OK; +} + +static const struct ID3DIncludeVtbl test_d3dinclude_vtbl = +{ + test_d3dinclude_open, + test_d3dinclude_close +}; + +struct test_d3dinclude +{ + ID3DInclude ID3DInclude_iface; +}; + +static void test_D3DX11CompileFromFile(void) +{ + struct test_d3dinclude include = {{&test_d3dinclude_vtbl}}; + WCHAR filename[MAX_PATH], directory[MAX_PATH]; + ID3D10Blob *blob = NULL, *errors = NULL; + CHAR filename_a[MAX_PATH]; + HRESULT hr, result; + DWORD len; + static const char ps_code[] = + "#include "include\include2.h"\n" + "\n" + "float4 main() : COLOR\n" + "{\n" + " return light_color;\n" + "}"; + static const char include1[] = + "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; + static const char include1_wrong[] = + "#define LIGHT nope\n"; + static const char include2[] = + "#include "include1.h"\n" + "float4 light_color = LIGHT;\n"; + + create_file(L"source.ps", ps_code, strlen(ps_code), filename); + create_directory(L"include"); + create_file(L"include\include1.h", include1_wrong, strlen(include1_wrong), NULL); + create_file(L"include1.h", include1, strlen(include1), NULL); + create_file(L"include\include2.h", include2, strlen(include2), NULL); + + hr = D3DX11CompileFromFileW(filename, NULL, &include.ID3DInclude_iface, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + todo_wine ok(hr == S_OK && hr == result, "Got hr %#x, result %#x.\n", hr, result); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + /* Windows always seems to resolve includes from the initial file location + * instead of using the immediate parent, as it would be the case for + * standard C preprocessor includes. */ + hr = D3DX11CompileFromFileW(filename, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + todo_wine ok(hr == S_OK && hr == result, "Got hr %#x, result %#x.\n", hr, result); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL); + hr = D3DX11CompileFromFileA(filename_a, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + todo_wine ok(hr == S_OK && hr == result, "Got hr %#x, result %#x.\n", hr, result); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + GetCurrentDirectoryW(MAX_PATH, directory); + SetCurrentDirectoryW(temp_dir); + + hr = D3DX11CompileFromFileW(L"source.ps", NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + todo_wine ok(hr == S_OK && hr == result, "Got hr %#x, result %#x.\n", hr, result); + todo_wine ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + if (blob) + { + ID3D10Blob_Release(blob); + blob = NULL; + } + + SetCurrentDirectoryW(directory); + + delete_file(L"source.ps"); + delete_file(L"include\include1.h"); + delete_file(L"include1.h"); + delete_file(L"include\include2.h"); + delete_directory(L"include"); +} + START_TEST(d3dx11) { test_D3DX11CreateAsyncMemoryLoader(); test_D3DX11CreateAsyncFileLoader(); test_D3DX11CreateAsyncResourceLoader(); + test_D3DX11CompileFromFile(); }