[3/18] d3dx9: Add bytecode writer skeleton

Matteo Bruni matteo.mystral at gmail.com
Sun Aug 16 12:51:16 CDT 2009


-------------- next part --------------
From 1d4c7bd3b8cc2ab7d66756bbdf4f368bd47c5719 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sat, 15 Aug 2009 17:40:50 +0200
Subject: d3dx9: Add bytecode writer skeleton

---
 dlls/d3dx9_36/bytecodewriter.c |  767 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 767 insertions(+), 0 deletions(-)
 create mode 100644 dlls/d3dx9_36/bytecodewriter.c

diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
new file mode 100644
index 0000000..abdb78a
--- /dev/null
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -0,0 +1,767 @@
+/*
+ * Direct3D bytecode output functions
+ *
+ * Copyright 2008 Stefan Dösinger
+ * 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+#include "wine/debug.h"
+
+#include "d3dx9_36_private.h"
+
+/* This file needs the original d3d9 definitions. The bwriter ones
+ * aren't useable because they are wine-internal things. We're writing
+ * d3d8/9 shaders here, so we need the d3d9 definitions (which are
+ * equal to the d3d8 ones)
+ */
+#include "d3d9types.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
+
+/****************************************************************
+ * General assembler shader construction helper routines follow *
+ ****************************************************************/
+/* struct instruction *alloc_instr
+ *
+ * Allocates a new instruction structure with srcs registers
+ *
+ * Parameters:
+ *  srcs: Number of source registers to allocate
+ *
+ * Returns:
+ *  A pointer to the allocated instruction structure
+ *  NULL in case of an allocation failure
+ */
+struct instruction *alloc_instr(unsigned int srcs) {
+    struct instruction *ret = asm_alloc(sizeof(*ret));
+    if(!ret) {
+        ERR("Failed to allocate memory for an instruction structure\n");
+        return NULL;
+    }
+
+    if(srcs) {
+        ret->src = asm_alloc(srcs * sizeof(*ret->src));
+        if(!ret->src) {
+            ERR("Failed to allocate memory for instruction registers\n");
+            asm_free(ret);
+            return NULL;
+        }
+        ret->num_srcs = srcs;
+    }
+    return ret;
+}
+
+/* void add_instruction
+ *
+ * Adds a new instruction to the shader's instructions array and grows the instruction array
+ * if needed.
+ *
+ * The function does NOT copy the instruction structure. Make sure not to release the
+ * instruction or any of its substructures like registers.
+ *
+ * Parameters:
+ *  shader: Shader to add the instruction to
+ *  instr: Instruction to add to the shader
+ */
+BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr) {
+    struct instruction      **new_instructions;
+
+    if(!shader) return FALSE;
+
+    if(shader->instr_alloc_size == 0) {
+        shader->instr = asm_alloc(sizeof(*shader->instr) * INSTRARRAY_INITIAL_SIZE);
+        if(!shader->instr) {
+            ERR("Failed to allocate the shader instruction array\n");
+            return FALSE;
+        }
+        shader->instr_alloc_size = INSTRARRAY_INITIAL_SIZE;
+    } else if(shader->instr_alloc_size == shader->num_instrs) {
+        new_instructions = asm_realloc(shader->instr,
+                                       sizeof(*shader->instr) * (shader->instr_alloc_size) * 2);
+        if(!new_instructions) {
+            ERR("Failed to grow the shader instruction array\n");
+            return FALSE;
+        }
+        shader->instr = new_instructions;
+        shader->instr_alloc_size = shader->instr_alloc_size * 2;
+    } else if(shader->num_instrs > shader->instr_alloc_size) {
+        ERR("More instructions than allocated. This should not happen\n");
+        return FALSE;
+    }
+
+    shader->instr[shader->num_instrs] = instr;
+    shader->num_instrs++;
+    return TRUE;
+}
+
+BOOL add_constF(struct bwriter_shader *shader, DWORD reg, float x, float y, float z, float w) {
+    struct constant *newconst;
+
+    if(shader->num_cf) {
+        struct constant **newarray;
+        newarray = asm_realloc(shader->constF,
+                               sizeof(*shader->constF) * (shader->num_cf + 1));
+        if(!newarray) {
+            ERR("Failed to grow the constants array\n");
+            return FALSE;
+        }
+        shader->constF = newarray;
+    } else {
+        shader->constF = asm_alloc(sizeof(*shader->constF));
+        if(!shader->constF) {
+            ERR("Failed to allocate the constants array\n");
+            return FALSE;
+        }
+    }
+
+    newconst = asm_alloc(sizeof(*newconst));
+    if(!newconst) {
+        ERR("Failed to allocate a new constant\n");
+        return FALSE;
+    }
+    newconst->regnum = reg;
+    newconst->value[0].f = x;
+    newconst->value[1].f = y;
+    newconst->value[2].f = z;
+    newconst->value[3].f = w;
+    shader->constF[shader->num_cf] = newconst;
+
+    shader->num_cf++;
+    return TRUE;
+}
+
+BOOL add_constI(struct bwriter_shader *shader, DWORD reg, INT x, INT y, INT z, INT w) {
+    struct constant *newconst;
+
+    if(shader->num_ci) {
+        struct constant **newarray;
+        newarray = asm_realloc(shader->constI,
+                               sizeof(*shader->constI) * (shader->num_ci + 1));
+        if(!newarray) {
+            ERR("Failed to grow the constants array\n");
+            return FALSE;
+        }
+        shader->constI = newarray;
+    } else {
+        shader->constI = asm_alloc(sizeof(*shader->constI));
+        if(!shader->constI) {
+            ERR("Failed to allocate the constants array\n");
+            return FALSE;
+        }
+    }
+
+    newconst = asm_alloc(sizeof(*newconst));
+    if(!newconst) {
+        ERR("Failed to allocate a new constant\n");
+        return FALSE;
+    }
+    newconst->regnum = reg;
+    newconst->value[0].i = x;
+    newconst->value[1].i = y;
+    newconst->value[2].i = z;
+    newconst->value[3].i = w;
+    shader->constI[shader->num_ci] = newconst;
+
+    shader->num_ci++;
+    return TRUE;
+}
+
+BOOL add_constB(struct bwriter_shader *shader, DWORD reg, BOOL x) {
+    struct constant *newconst;
+
+    if(shader->num_cb) {
+        struct constant **newarray;
+        newarray = asm_realloc(shader->constB,
+                               sizeof(*shader->constB) * (shader->num_cb + 1));
+        if(!newarray) {
+            ERR("Failed to grow the constants array\n");
+            return FALSE;
+        }
+        shader->constB = newarray;
+    } else {
+        shader->constB = asm_alloc(sizeof(*shader->constB));
+        if(!shader->constB) {
+            ERR("Failed to allocate the constants array\n");
+            return FALSE;
+        }
+    }
+
+    newconst = asm_alloc(sizeof(*newconst));
+    if(!newconst) {
+        ERR("Failed to allocate a new constant\n");
+        return FALSE;
+    }
+    newconst->regnum = reg;
+    newconst->value[0].b = x;
+    shader->constB[shader->num_cb] = newconst;
+
+    shader->num_cb++;
+    return TRUE;
+}
+
+BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) {
+    unsigned int *num;
+    struct declaration **decl;
+    unsigned int i;
+
+    if(!shader) return FALSE;
+
+    if(output) {
+        num = &shader->num_outputs;
+        decl = &shader->outputs;
+    } else {
+        num = &shader->num_inputs;
+        decl = &shader->inputs;
+    }
+
+    if(*num == 0) {
+        *decl = asm_alloc(sizeof(**decl));
+        if(!*decl) {
+            ERR("Error allocating declarations array\n");
+            return FALSE;
+        }
+    } else {
+        struct declaration *newdecl;
+        for(i = 0; i < *num; i++) {
+            if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
+                WARN("Declaration of register %u already exists, writemask match 0x%x\n",
+                      regnum, (*decl)[i].writemask & writemask);
+            }
+        }
+
+        newdecl = asm_realloc(*decl,
+                              sizeof(**decl) * ((*num) + 1));
+        if(!newdecl) {
+            ERR("Error reallocating declarations array\n");
+            return FALSE;
+        }
+        *decl = newdecl;
+    }
+    (*decl)[*num].usage = usage;
+    (*decl)[*num].usage_idx = usage_idx;
+    (*decl)[*num].regnum = regnum;
+    (*decl)[*num].writemask = writemask;
+    (*num)++;
+
+    return TRUE;
+}
+
+BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD regnum, unsigned int line_no) {
+    unsigned int i;
+
+    if(!shader) return FALSE;
+
+    if(shader->num_samplers == 0) {
+        shader->samplers = asm_alloc(sizeof(*shader->samplers));
+        if(!shader->samplers) {
+            ERR("Error allocating samplers array\n");
+            return FALSE;
+        }
+    } else {
+        struct samplerdecl *newarray;
+
+        for(i = 0; i < shader->num_samplers; i++) {
+            if(shader->samplers[i].regnum == regnum) {
+                WARN("Line %u: Sampler %u already declared\n",
+                                  line_no, regnum);
+                WARN("Line %u: This is the place of the original declaration\n",
+                                  shader->samplers[i].line_no);
+                /* This is not an error as far as the assembler is concerned. d3dX.dll might
+                * refuse to load the compiled shader though
+                */
+            }
+        }
+
+        newarray = asm_realloc(shader->samplers,
+                               sizeof(*shader->samplers) * (shader->num_samplers + 1));
+        if(!newarray) {
+            ERR("Error reallocating samplers array\n");
+            return FALSE;
+        }
+        shader->samplers = newarray;
+    }
+
+    shader->samplers[shader->num_samplers].type = samptype;
+    shader->samplers[shader->num_samplers].regnum = regnum;
+    shader->samplers[shader->num_samplers].line_no = line_no;
+    shader->num_samplers++;
+    return TRUE;
+}
+
+
+/* shader bytecode buffer manipulation functions.
+ * allocate_buffer creates a new buffer structure, put_dword adds a new
+ * DWORD to the buffer. In the rare case of a memory allocation failure
+ * when trying to grow the buffer a flag is set in the buffer to mark it
+ * invalid. This avoids return value checking and passing in many places
+ */
+static struct bytecode_buffer *allocate_buffer() {
+    struct bytecode_buffer *ret;
+
+    ret = asm_alloc(sizeof(*ret));
+    if(!ret) return NULL;
+
+    ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
+    ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
+    if(!ret->data) {
+        asm_free(ret);
+        return NULL;
+    }
+    ret->state = S_OK;
+    return ret;
+}
+
+static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
+    if(FAILED(buffer->state)) return;
+
+    if(buffer->alloc_size == buffer->size) {
+        DWORD *newarray;
+        buffer->alloc_size *= 2;
+        newarray = asm_realloc(buffer->data,
+                               sizeof(DWORD) * buffer->alloc_size);
+        if(!newarray) {
+            ERR("Failed to grow the buffer data memory\n");
+            buffer->state = E_OUTOFMEMORY;
+            return;
+        }
+        buffer->data = newarray;
+    }
+    buffer->data[buffer->size++] = value;
+}
+
+/******************************************************
+ * Implementation of the writer functions starts here *
+ ******************************************************/
+static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
+                               const struct declaration *decls, unsigned int num, DWORD type) {
+    DWORD i;
+    DWORD instr_dcl = D3DSIO_DCL;
+    DWORD token;
+
+    if(len) {
+        instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
+    }
+
+    for(i = 0; i < num; i++) {
+        /* Write the DCL instruction */
+        put_dword(buffer, instr_dcl);
+
+        /* Write the usage and index */
+        token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
+        token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
+        token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
+        put_dword(buffer, token);
+
+        /* Write the dest register */
+        token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
+        token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL; /* no shift */
+        token |= decls[i].regnum & D3DSP_REGNUM_MASK; /* no shift */
+        put_dword(buffer, token);
+    }
+}
+
+static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
+    DWORD i;
+    DWORD instr_def = D3DSIO_DEF;
+    const DWORD reg = (1<<31) |
+                      ((D3DSPR_CONST << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
+                      D3DSP_WRITEMASK_ALL;
+
+    if(len) {
+        instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
+    }
+
+    for(i = 0; i < shader->num_cf; i++) {
+        /* Write the DEF instruction */
+        put_dword(buffer, instr_def);
+
+        put_dword(buffer, reg | (shader->constF[i]->regnum & D3DSP_REGNUM_MASK));
+        put_dword(buffer, *((DWORD *)&shader->constF[i]->value[0].f));
+        put_dword(buffer, *((DWORD *)&shader->constF[i]->value[1].f));
+        put_dword(buffer, *((DWORD *)&shader->constF[i]->value[2].f));
+        put_dword(buffer, *((DWORD *)&shader->constF[i]->value[3].f));
+    }
+}
+
+static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    put_dword(buffer, D3DSIO_END);
+}
+
+static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
+                          struct bytecode_buffer *buffer){
+    unsigned int i;
+    if(instr->has_predicate){
+        This->funcs->srcreg(This, &instr->predicate, buffer);
+    }
+    for(i = 0; i < instr->num_srcs; i++){
+        This->funcs->srcreg(This, &instr->src[i], buffer);
+    }
+}
+
+/* The length of an instruction consists of the destination register (if any),
+ * the number of source registers, the number of address registers used for
+ * indirect addressing, and optionally the predicate register
+ */
+static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
+    unsigned int i;
+    DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
+
+    if(dsts){
+        if(instr->dst.rel_reg) ret++;
+    }
+    for(i = 0; i < srcs; i++) {
+        if(instr->src[i].rel_reg) ret++;
+    }
+    return ret;
+}
+
+static void instr_handler(struct bc_writer *This,
+                          const struct instruction *instr,
+                          struct bytecode_buffer *buffer) {
+    DWORD token = d3d9_opcode(instr->opcode);
+    TRACE("token: %x\n", token);
+
+    This->funcs->opcode(This, instr, token, buffer);
+    if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+    write_srcregs(This, instr, buffer);
+}
+
+static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
+    DWORD i;
+    DWORD instr_def = D3DSIO_DEFB;
+    const DWORD reg = (1<<31) |
+            ((D3DSPR_CONSTBOOL << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
+            ((D3DSPR_CONSTBOOL << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
+            D3DSP_WRITEMASK_ALL;
+
+    if(len) {
+        instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
+    }
+
+    for(i = 0; i < shader->num_cb; i++) {
+        /* Write the DEF instruction */
+        put_dword(buffer, instr_def);
+
+        put_dword(buffer, reg | (shader->constB[i]->regnum & D3DSP_REGNUM_MASK));
+        put_dword(buffer, *((BOOL *)&shader->constB[i]->value[0].b));
+    }
+}
+
+static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
+    DWORD i;
+    DWORD instr_def = D3DSIO_DEFI;
+    const DWORD reg = (1<<31) |
+            ((D3DSPR_CONSTINT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
+            ((D3DSPR_CONSTINT << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
+            D3DSP_WRITEMASK_ALL;
+
+    if(len) {
+        instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
+    }
+
+    for(i = 0; i < shader->num_ci; i++) {
+        /* Write the DEF instruction */
+        put_dword(buffer, instr_def);
+
+        put_dword(buffer, reg | (shader->constI[i]->regnum & D3DSP_REGNUM_MASK));
+        put_dword(buffer, *((INT *)&shader->constI[i]->value[0].i));
+        put_dword(buffer, *((INT *)&shader->constI[i]->value[1].i));
+        put_dword(buffer, *((INT *)&shader->constI[i]->value[2].i));
+        put_dword(buffer, *((INT *)&shader->constI[i]->value[3].i));
+    }
+}
+
+static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    DWORD i;
+    DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
+    DWORD token;
+    const DWORD reg = (1<<31) |
+                      ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
+                      ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
+                      D3DSP_WRITEMASK_ALL;
+
+    for(i = 0; i < shader->num_samplers; i++) {
+        /* Write the DEF instruction */
+        put_dword(buffer, instr_dcl);
+        token = (1<<31);
+        /* Already shifted */
+        token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
+        put_dword(buffer, token);
+        put_dword(buffer, reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK));
+    }
+}
+
+static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
+    struct bc_writer *ret = asm_alloc(sizeof(*ret));
+
+    if(!ret) {
+        WARN("Failed to allocate a bytecode writer instance\n");
+        return NULL;
+    }
+
+    switch(version) {
+        case BWRITERVS_VERSION(1, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERVS_VERSION(1, 1):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERVS_VERSION(2, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERVS_VERSION(2, 1):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERVS_VERSION(3, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+
+        case BWRITERPS_VERSION(1, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERPS_VERSION(1, 1):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERPS_VERSION(1, 2):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERPS_VERSION(1, 3):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+        case BWRITERPS_VERSION(1, 4):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+
+        case BWRITERPS_VERSION(2, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+
+        case BWRITERPS_VERSION(2, 1):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+
+        case BWRITERPS_VERSION(3, 0):
+            if(dxversion != 9) {
+                WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
+                goto fail;
+            }
+            /* TODO: Set the appropriate writer backend */
+            break;
+
+        default:
+            WARN("Unexpected shader version requested: %08x\n", version);
+            goto fail;
+    }
+    ret->version = version;
+    return ret;
+
+fail:
+    asm_free(ret);
+    return NULL;
+}
+
+static HRESULT call_instr_handler(struct bc_writer *writer,
+                                  const struct instruction *instr,
+                                  struct bytecode_buffer *buffer) {
+    DWORD i=0;
+
+    while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
+        if(instr->opcode == writer->funcs->instructions[i].opcode) {
+            if(!writer->funcs->instructions[i].func) {
+                WARN("Opcode %u not supported by this profile\n", instr->opcode);
+                return E_INVALIDARG;
+            }
+            writer->funcs->instructions[i].func(writer, instr, buffer);
+            return S_OK;
+        }
+        i++;
+    }
+
+    FIXME("Unhandled instruction %u\n", instr->opcode);
+    return E_INVALIDARG;
+}
+
+/* SlWriteBytecode (wineshader.@)
+ *
+ * Writes shader version specific bytecode from the shader passed in.
+ * The returned bytecode can be passed to the Direct3D runtime like
+ * IDirect3DDevice9::Create*Shader.
+ *
+ * Parameters:
+ *  shader: Shader to translate into bytecode
+ *  version: Shader version to generate(d3d version token)
+ *  dxversion: DirectX version the code targets
+ *  result: the resulting shader bytecode
+ *
+ * Return values:
+ *  S_OK on success
+ */
+DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
+    struct bc_writer *writer;
+    struct bytecode_buffer *buffer = NULL;
+    HRESULT hr;
+    unsigned int i;
+
+    if(!shader){
+        ERR("NULL shader structure, aborting\n");
+        return E_FAIL;
+    }
+    writer = create_writer(shader->version, dxversion);
+    *result = NULL;
+
+    if(!writer) {
+        WARN("Could not create a bytecode writer instance. Either unsupported version\n");
+        WARN("or out of memory\n");
+        hr = E_FAIL;
+        goto error;
+    }
+
+    buffer = allocate_buffer();
+    if(!buffer) {
+        WARN("Failed to allocate a buffer for the shader bytecode\n");
+        hr = E_FAIL;
+        goto error;
+    }
+
+    writer->funcs->header(writer, shader, buffer);
+    if(FAILED(writer->state)) {
+        hr = writer->state;
+        goto error;
+    }
+
+    for(i = 0; i < shader->num_instrs; i++) {
+        hr = call_instr_handler(writer, shader->instr[i], buffer);
+        if(FAILED(hr)) {
+            goto error;
+        }
+    }
+
+    if(FAILED(writer->state)) {
+        hr = writer->state;
+        goto error;
+    }
+
+    writer->funcs->end(writer, shader, buffer);
+
+    if(FAILED(buffer->state)) {
+        hr = buffer->state;
+        goto error;
+    }
+
+    /* Cut off unneeded memory from the result buffer */
+    *result = asm_realloc(buffer->data,
+                         sizeof(DWORD) * buffer->size);
+    if(!*result) {
+        *result = buffer->data;
+    }
+    buffer->data = NULL;
+    hr = S_OK;
+
+error:
+    if(buffer) {
+        asm_free(buffer->data);
+        asm_free(buffer);
+    }
+    asm_free(writer);
+    return hr;
+}
+
+void SlDeleteShader(struct bwriter_shader *shader) {
+    unsigned int i, j;
+
+    TRACE("Deleting shader %p\n", shader);
+
+    for(i = 0; i < shader->num_cf; i++) {
+        asm_free(shader->constF[i]);
+    }
+    asm_free(shader->constF);
+    for(i = 0; i < shader->num_ci; i++) {
+        asm_free(shader->constI[i]);
+    }
+    asm_free(shader->constI);
+    for(i = 0; i < shader->num_cb; i++) {
+        asm_free(shader->constB[i]);
+    }
+    asm_free(shader->constB);
+
+    asm_free(shader->inputs);
+    asm_free(shader->outputs);
+    asm_free(shader->samplers);
+
+    for(i = 0; i < shader->num_instrs; i++) {
+        for(j = 0; j < shader->instr[i]->num_srcs; j++) {
+            asm_free(shader->instr[i]->src[j].rel_reg);
+        }
+        asm_free(shader->instr[i]->src);
+        asm_free(shader->instr[i]);
+    }
+    asm_free(shader->instr);
+
+    asm_free(shader);
+}
-- 
1.6.3.3


More information about the wine-patches mailing list