[PATCH 1/3] d3dcompiler: Add D3D_COMPILE_STANDARD_FILE_INCLUDE support for D3DCompile2().

Jactry Zeng jzeng at codeweavers.com
Fri Jul 31 01:04:30 CDT 2020


This patch includes some improvements from Matteo.

Signed-off-by: Jactry Zeng <jzeng at codeweavers.com>
---
 dlls/d3dcompiler_43/compiler.c        |  82 +++++++++
 dlls/d3dcompiler_43/tests/hlsl_d3d9.c | 250 ++++++++++++++++++++++++++
 include/d3dcompiler.h                 |   2 +
 3 files changed, 334 insertions(+)

diff --git a/dlls/d3dcompiler_43/compiler.c b/dlls/d3dcompiler_43/compiler.c
index c400b83d8d..b3dd39a6f2 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 = NULL, *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 ed148ff112..cf13574c52 100644
--- a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c
+++ b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c
@@ -25,6 +25,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 +40,63 @@ struct vec4
     float x, y, z, w;
 };
 
+static WCHAR temp_dir[MAX_PATH];
+
+static BOOL create_file(const WCHAR *filename, const char *data, const 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 +1329,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 +1338,194 @@ 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 = HeapAlloc(GetProcessHeap(), 0, strlen(include1));
+        CopyMemory(buffer, include1, strlen(include1));
+        *bytes = strlen(include1);
+        ok(include_type == D3D_INCLUDE_LOCAL, "Wrong include type %d.\n", include_type);
+        ok(parent_data != NULL && !strncmp(include2, parent_data, strlen(include2)),
+                "Wrong parent_data value.\n");
+    }
+    else if (!strcmp(filename, "include\\include2.h"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, strlen(include2));
+        CopyMemory(buffer, include2, strlen(include2));
+        *bytes = strlen(include2);
+        ok(!parent_data, "Wrong parent_data value.\n");
+        ok(include_type == D3D_INCLUDE_LOCAL, "Wrong 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)
+{
+    HeapFree(GetProcessHeap(), 0, (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)
+{
+    WCHAR filename[MAX_PATH], directory[MAX_PATH];
+    ID3D10Blob *blob = NULL, *errors = NULL;
+    struct test_d3dinclude include;
+    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";
+
+    include.ID3DInclude_iface.lpVtbl = &test_d3dinclude_vtbl;
+
+    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 tests of D3D_COMPILE_STANDARD_FILE_INCLUDE for D3DCompile() from
+     * d3dcompiler_43 or eailier 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 +1558,5 @@ START_TEST(hlsl_d3d9)
 
     test_constant_table();
     test_fail();
+    test_d3dcompile();
 }
diff --git a/include/d3dcompiler.h b/include/d3dcompiler.h
index bd1b3d1d44..b892950aa7 100644
--- a/include/d3dcompiler.h
+++ b/include/d3dcompiler.h
@@ -81,6 +81,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);
-- 
2.27.0




More information about the wine-devel mailing list