[1/3] d3dx9: Partial implementation of D3DXAssembleShader function. [try 2]

Matteo Bruni matteo.mystral at gmail.com
Thu Feb 4 12:26:43 CST 2010


With many thanks to Henri for his continuing reviews.
-------------- next part --------------
From 3a9b4ae6059eac1d2944731082202627a69d7f2d Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Thu, 4 Feb 2010 18:58:39 +0100
Subject: d3dx9: Partial implementation of D3DXAssembleShader function.

This only executes the preprocessing pass. No parsing of the shader yet.
---
 dlls/d3dx9_36/Makefile.in        |    1 +
 dlls/d3dx9_36/d3dx9_36_private.h |    5 +
 dlls/d3dx9_36/shader.c           |  318 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 323 insertions(+), 1 deletions(-)

diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in
index 88ac1d7..a2ad690 100644
--- a/dlls/d3dx9_36/Makefile.in
+++ b/dlls/d3dx9_36/Makefile.in
@@ -5,6 +5,7 @@ VPATH     = @srcdir@
 MODULE    = d3dx9_36.dll
 IMPORTLIB = d3dx9
 IMPORTS   = d3d9 gdi32 user32 kernel32
+EXTRALIBS = $(LIBWPP) $(LIBPORT)
 
 C_SRCS = \
 	core.c \
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index cca4403..a5e9357 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -128,5 +128,10 @@ typedef struct ID3DXSpriteImpl
     int allocated_sprites; /* number of (pre-)allocated sprites */
 } ID3DXSpriteImpl;
 
+#ifdef __GNUC__
+#define PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
+#else
+#define PRINTF_ATTR(fmt,args)
+#endif
 
 #endif /* __WINE_D3DX9_36_PRIVATE_H */
diff --git a/dlls/d3dx9_36/shader.c b/dlls/d3dx9_36/shader.c
index c05f7b7..0a5ecf5 100644
--- a/dlls/d3dx9_36/shader.c
+++ b/dlls/d3dx9_36/shader.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008 Luis Busquets
+ * Copyright 2009 Matteo Bruni
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +24,7 @@
 #include "windef.h"
 #include "wingdi.h"
 #include "d3dx9.h"
+#include "wine/wpp.h"
 #include "d3dx9_36_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -134,6 +136,227 @@ LPCSTR WINAPI D3DXGetVertexShaderProfile(LPDIRECT3DDEVICE9 device)
     return NULL;
 }
 
+#define MESSAGEBUFFER_INITIAL_SIZE 256
+#define BUFFER_INITIAL_CAPACITY 256
+
+struct mem_file_desc
+{
+    char *buffer;
+    unsigned int size;
+    unsigned int pos;
+};
+
+struct mem_file_desc current_shader;
+LPD3DXINCLUDE current_include;
+char *wpp_output;
+int wpp_output_capacity, wpp_output_size;
+
+char *wpp_messages;
+int wpp_messages_capacity, wpp_messages_size;
+
+/* Mutex used to guarantee a single invocation
+   of the D3DXAssembleShader function (or its variants) at a time.
+   This is needed as wpp isn't thread-safe */
+static CRITICAL_SECTION wpp_mutex;
+static CRITICAL_SECTION_DEBUG wpp_mutex_debug =
+{
+    0, 0, &wpp_mutex,
+    { &wpp_mutex_debug.ProcessLocksList,
+      &wpp_mutex_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": wpp_mutex") }
+};
+static CRITICAL_SECTION wpp_mutex = { &wpp_mutex_debug, -1, 0, 0, 0, 0 };
+
+/* Preprocessor error reporting functions */
+void wpp_write_message(const char *fmt, va_list args)
+{
+    char* newbuffer;
+    int rc, newsize;
+
+    if(wpp_messages_capacity == 0)
+    {
+        wpp_messages = HeapAlloc(GetProcessHeap(), 0, MESSAGEBUFFER_INITIAL_SIZE);
+        if(wpp_messages == NULL)
+        {
+            ERR("Error allocating memory for parser messages\n");
+            return;
+        }
+        wpp_messages_capacity = MESSAGEBUFFER_INITIAL_SIZE;
+    }
+
+    while(1)
+    {
+        rc = vsnprintf(wpp_messages + wpp_messages_size,
+                       wpp_messages_capacity - wpp_messages_size, fmt, args);
+
+        if (rc < 0 ||                                           /* C89 */
+            rc >= wpp_messages_capacity - wpp_messages_size) {    /* C99 */
+            /* Resize the buffer */
+            newsize = wpp_messages_capacity * 2;
+            newbuffer = HeapReAlloc(GetProcessHeap(), 0, wpp_messages, newsize);
+            if(newbuffer == NULL)
+            {
+                ERR("Error reallocating memory for parser messages\n");
+                return;
+            }
+            wpp_messages = newbuffer;
+            wpp_messages_capacity = newsize;
+        }
+        else
+        {
+            wpp_messages_size += rc;
+            return;
+        }
+    }
+}
+
+void wpp_write_message_var(const char *fmt, ...) PRINTF_ATTR(1,2);
+void wpp_write_message_var(const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    wpp_write_message(fmt, args);
+    va_end(args);
+}
+
+void wpp_error(const char *file, int line, int col, const char *near,
+               const char *msg, va_list ap)
+{
+    wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
+                          line, col, "Error");
+    wpp_write_message(msg, ap);
+    wpp_write_message_var("\n");
+}
+
+void wpp_warning(const char *file, int line, int col, const char *near,
+                 const char *msg, va_list ap)
+{
+    wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
+                          line, col, "Warning");
+    wpp_write_message(msg, ap);
+    wpp_write_message_var("\n");
+}
+
+char *wpp_lookup_mem(const char *filename, const char *parent_name,
+                     char **include_path, int include_path_count)
+{
+    /* Here we return always ok. We will maybe fail on the next wpp_open_mem */
+    char *path;
+
+    path = malloc(strlen(filename) + 1);
+    if(!path) return NULL;
+    memcpy(path, filename, strlen(filename) + 1);
+    return path;
+}
+
+void *wpp_open_mem(const char *filename, int type)
+{
+    struct mem_file_desc *desc;
+
+    if(filename[0] == '\0') /* "" means to load the initial shader */
+    {
+        current_shader.pos = 0;
+        return &current_shader;
+    }
+    else
+    {
+        HRESULT hr;
+
+        if(current_include == NULL) return NULL;
+        desc = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mem_file_desc));
+        if(!desc)
+        {
+            ERR("Error allocating memory\n");
+            return NULL;
+        }
+        hr = ID3DXInclude_Open(current_include,
+                               type ? D3DXINC_SYSTEM : D3DXINC_LOCAL,
+                               filename, NULL, (LPCVOID *)&desc->buffer,
+                               &desc->size);
+        if(FAILED(hr))
+        {
+            HeapFree(GetProcessHeap(), 0, desc);
+            return NULL;
+        }
+    }
+    desc->pos = 0;
+    return desc;
+}
+
+void wpp_close_mem(void *file)
+{
+    struct mem_file_desc *desc = file;
+
+    if(desc != &current_shader)
+    {
+        if(current_include)
+            ID3DXInclude_Close(current_include, desc->buffer);
+        else
+            ERR("current_include == NULL, desc == %p, buffer = %s\n",
+                desc, desc->buffer);
+
+        HeapFree(GetProcessHeap(), 0, desc);
+        return;
+    }
+    /* This is the main file */
+    HeapFree(GetProcessHeap(), 0, desc->buffer);
+    desc->buffer = NULL;
+}
+
+int wpp_read_mem(void *file, char *buffer, unsigned int len)
+{
+    struct mem_file_desc *desc = file;
+
+    if(desc->pos + len > desc->size) len = desc->size - desc->pos;
+    memcpy(buffer, &desc->buffer[desc->pos], len);
+    desc->pos += len;
+    return len;
+}
+
+void wpp_write_mem(const char *buffer, unsigned int len)
+{
+    char *new_wpp_output;
+
+    if(wpp_output_capacity == 0)
+    {
+        wpp_output = HeapAlloc(GetProcessHeap(), 0, BUFFER_INITIAL_CAPACITY);
+        if(!wpp_output)
+        {
+            ERR("Error allocating memory\n");
+            return;
+        }
+        wpp_output_capacity = BUFFER_INITIAL_CAPACITY;
+    }
+    if(wpp_output_size + len > wpp_output_capacity)
+    {
+        while(wpp_output_size + len > wpp_output_capacity)
+        {
+            wpp_output_capacity *= 2;
+        }
+        new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
+                                     wpp_output_capacity);
+        if(!new_wpp_output)
+        {
+            ERR("Error allocating memory\n");
+            return;
+        }
+        wpp_output = new_wpp_output;
+    }
+    memcpy(wpp_output+wpp_output_size, buffer, len);
+    wpp_output_size += len;
+}
+
+int wpp_close_output(void)
+{
+    /* trim buffer to the effective size */
+    char *new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
+                                       wpp_output_size + 1);
+    if(!new_wpp_output) return 0;
+    wpp_output[wpp_output_size]='\0';
+    return 1;
+}
+
 HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
                                   UINT data_len,
                                   CONST D3DXMACRO* defines,
@@ -142,8 +365,101 @@ HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
                                   LPD3DXBUFFER* shader,
                                   LPD3DXBUFFER* error_messages)
 {
+    int ret;
+    HRESULT hr;
+    CONST D3DXMACRO* def = defines;
+
+    static const struct wpp_callbacks wpp_callbacks = {
+        wpp_lookup_mem,
+        wpp_open_mem,
+        wpp_close_mem,
+        wpp_read_mem,
+        wpp_write_mem,
+        wpp_error,
+        wpp_warning,
+    };
+
+    EnterCriticalSection(&wpp_mutex);
+
+    /* TODO: flags */
+    if(flags) FIXME("flags: %x\n", flags);
+
+    if(def != NULL)
+    {
+        while(def->Name != NULL)
+        {
+            wpp_add_define(def->Name, def->Definition);
+            def++;
+        }
+    }
+    current_include = include;
+
+    *shader = *error_messages = NULL;
+    wpp_output_size = wpp_output_capacity = 0;
+    wpp_output = NULL;
+
+    /* Preprocess shader */
+    wpp_set_callbacks(&wpp_callbacks);
+    wpp_messages_size = wpp_messages_capacity = 0;
+    wpp_messages = NULL;
+    current_shader.buffer = HeapAlloc(GetProcessHeap(), 0, data_len + 1);
+    if(!current_shader.buffer)
+    {
+        ERR("Not enough free memory\n");
+        hr = E_OUTOFMEMORY;
+        goto cleanup;
+    }
+    memcpy(current_shader.buffer, data, data_len);
+    current_shader.buffer[data_len] = '\0';
+    current_shader.size = data_len;
+
+    ret = wpp_parse("", NULL);
+    if(!wpp_close_output())
+        ret = 1;
+    if(ret)
+    {
+        TRACE("Error during shader preprocessing\n");
+        HeapFree(GetProcessHeap(), 0, current_shader.buffer);
+        if(wpp_messages)
+        {
+            int size;
+            LPD3DXBUFFER buffer;
+
+            TRACE("Preprocessor messages:\n");
+            TRACE("%s", wpp_messages);
+
+            size = strlen(wpp_messages) + 1;
+            hr = D3DXCreateBuffer(size, &buffer);
+            if(FAILED(hr)) goto cleanup;
+            CopyMemory(ID3DXBuffer_GetBufferPointer(buffer), wpp_messages, size);
+            *error_messages = buffer;
+        }
+        if(data)
+        {
+            TRACE("Shader source:\n");
+            TRACE("%s\n", debugstr_an(data, data_len));
+        }
+        hr = D3DXERR_INVALIDDATA;
+        goto cleanup;
+    }
+
     FIXME("stub\n");
-    return D3DERR_INVALIDCALL;
+    hr = D3DERR_INVALIDCALL;
+
+cleanup:
+    /* Remove the previously added defines */
+    if(defines != NULL)
+    {
+        while(defines->Name != NULL)
+        {
+            wpp_del_define(defines->Name);
+            defines++;
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, wpp_messages);
+    HeapFree(GetProcessHeap(), 0, wpp_output);
+    LeaveCriticalSection(&wpp_mutex);
+    return hr;
 }
 
 HRESULT WINAPI D3DXAssembleShaderFromFileA(LPCSTR filename,
-- 
1.6.4.4


More information about the wine-patches mailing list