diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 1275dd55ad82bd821ce4fa6fc1b086315ef95807..b3823c2ec5292d33407e0ac180032994137c10b0 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -277,7 +277,14 @@ HRESULT shader_get_registers_used(
                    D3DSIO_REP == curOpcode->opcode) {
             reg_maps->loop = 1;
             pToken += curOpcode->num_params;
-        
+   
+        /* For subroutine prototypes */
+        } else if (D3DSIO_LABEL == curOpcode->opcode) {
+
+            DWORD snum = *pToken & D3DSP_REGNUM_MASK; 
+            reg_maps->labels[snum] = 1;
+            pToken += curOpcode->num_params;
+ 
         /* Set texture, address, temporary registers */
         } else {
             int i, limit;
@@ -683,7 +690,8 @@ void shader_generate_main(
                        D3DSIO_NOP == curOpcode->opcode ||
                        D3DSIO_DEF == curOpcode->opcode ||
                        D3DSIO_DEFI == curOpcode->opcode ||
-                       D3DSIO_DEFB == curOpcode->opcode) {
+                       D3DSIO_DEFB == curOpcode->opcode ||
+                       D3DSIO_RET == curOpcode->opcode) {
 
                 pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token);
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index bd91f10547562284288fd90914e45f181d6fb6d9..223a8e01376280de0c1b2615c77156f99b46e7ad 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -331,6 +331,12 @@ void shader_generate_glsl_declarations(
     char pshader = shader_is_pshader_version(This->baseShader.hex_version);
     char prefix = pshader ? 'P' : 'V';
 
+    /* Prototype the subroutines */
+    for (i = 0; i < This->baseShader.limits.label; i++) {
+        if (reg_maps->labels[i])
+            shader_addline(buffer, "void subroutine%lu();\n", i);
+    }
+
     /* Declare the constants (aka uniforms) */
     if (This->baseShader.limits.constant_float > 0)
         shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, This->baseShader.limits.constant_float);
@@ -495,6 +501,9 @@ static void shader_glsl_gen_modifier (
     case D3DSPSM_NEG:
         sprintf(out_str, "-%s%s", in_reg, in_regswizzle);
         break;
+    case D3DSPSM_NOT:
+        sprintf(out_str, "!%s%s", in_reg, in_regswizzle);
+        break;
     case D3DSPSM_BIAS:
         sprintf(out_str, "(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle);
         break;
@@ -1238,6 +1247,29 @@ void shader_glsl_breakc(SHADER_OPCODE_ARG* arg) {
         src0_str, shader_get_comp_op(arg->opcode_token), src1_str);
 }
 
+void shader_glsl_label(SHADER_OPCODE_ARG* arg) {
+
+    DWORD snum = (arg->src[0]) & D3DSP_REGNUM_MASK;
+    shader_addline(arg->buffer, "}\n");
+    shader_addline(arg->buffer, "void subroutine%lu () {\n",  snum);
+}
+
+void shader_glsl_call(SHADER_OPCODE_ARG* arg) {
+    DWORD snum = (arg->src[0]) & D3DSP_REGNUM_MASK;
+    shader_addline(arg->buffer, "subroutine%lu();\n", snum);
+}
+
+void shader_glsl_callnz(SHADER_OPCODE_ARG* arg) {
+
+    char src1_str[100];
+    char src1_reg[50];
+    char src1_mask[6];
+   
+    DWORD snum = (arg->src[0]) & D3DSP_REGNUM_MASK;
+    shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str);
+    shader_addline(arg->buffer, "if (%s) subroutine%lu();\n", src1_str, snum);
+}
+
 /*********************************************
  * Pixel Shader Specific Code begins here
  ********************************************/
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 977cb4e7e2818d896536a1539815d671b20188d0..498380bf6921d26a6047d62697f6273f4ef64da8 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -685,12 +685,12 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = {
     {D3DSIO_BREAK,    "break",    NULL, 0, 0, pshader_break,   NULL, shader_glsl_break,  D3DPS_VERSION(2,1), -1},
     {D3DSIO_BREAKC,   "breakc",   NULL, 0, 2, pshader_breakc,  NULL, shader_glsl_breakc, D3DPS_VERSION(2,1), -1},
     {D3DSIO_BREAKP,   "breakp",   GLNAME_REQUIRE_GLSL, 0, 1, pshader_breakp,  NULL, NULL, 0, 0},
-    {D3DSIO_CALL,     "call",     GLNAME_REQUIRE_GLSL, 0, 1, pshader_call,    NULL, NULL, 0, 0},
-    {D3DSIO_CALLNZ,   "callnz",   GLNAME_REQUIRE_GLSL, 0, 2, pshader_callnz,  NULL, NULL, 0, 0},
+    {D3DSIO_CALL,     "call",     NULL, 0, 1, pshader_call,    NULL, shader_glsl_call, D3DPS_VERSION(2,1), -1},
+    {D3DSIO_CALLNZ,   "callnz",   NULL, 0, 2, pshader_callnz,  NULL, shader_glsl_callnz, D3DPS_VERSION(2,1), -1},
     {D3DSIO_LOOP,     "loop",     NULL, 0, 2, pshader_loop,    NULL, shader_glsl_loop,   D3DPS_VERSION(3,0), -1},
-    {D3DSIO_RET,      "ret",      GLNAME_REQUIRE_GLSL, 0, 0, pshader_ret,     NULL, NULL, 0, 0},
+    {D3DSIO_RET,      "ret",      NULL, 0, 0, pshader_ret,     NULL, NULL,               D3DPS_VERSION(2,1), -1},
     {D3DSIO_ENDLOOP,  "endloop",  NULL, 0, 0, pshader_endloop, NULL, shader_glsl_end,    D3DPS_VERSION(3,0), -1},
-    {D3DSIO_LABEL,    "label",    GLNAME_REQUIRE_GLSL, 0, 1, pshader_label,   NULL, NULL, 0, 0},
+    {D3DSIO_LABEL,    "label",    NULL, 0, 1, pshader_label,   NULL, shader_glsl_label,  D3DPS_VERSION(2,1), -1},
 
     /* Constant definitions */
     {D3DSIO_DEF,      "def",      "undefined",         1, 5, pshader_def,     NULL, NULL, 0, 0},
@@ -751,6 +751,7 @@ static void pshader_set_limits(
                    This->baseShader.limits.texcoord = 4;
                    This->baseShader.limits.sampler = 4;
                    This->baseShader.limits.packed_input = 0;
+                   This->baseShader.limits.label = 0;
                    break;
 
           case D3DPS_VERSION(1,4):
@@ -761,10 +762,20 @@ static void pshader_set_limits(
                    This->baseShader.limits.texcoord = 6;
                    This->baseShader.limits.sampler = 6;
                    This->baseShader.limits.packed_input = 0;
+                   This->baseShader.limits.label = 0;
                    break;
                
           /* FIXME: temporaries must match D3DPSHADERCAPS2_0.NumTemps */ 
           case D3DPS_VERSION(2,0):
+                   This->baseShader.limits.temporary = 32;
+                   This->baseShader.limits.constant_float = 32;
+                   This->baseShader.limits.constant_int = 16;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.texcoord = 8;
+                   This->baseShader.limits.sampler = 16;
+                   This->baseShader.limits.packed_input = 0;
+                   break;
+
           case D3DPS_VERSION(2,1):
                    This->baseShader.limits.temporary = 32;
                    This->baseShader.limits.constant_float = 32;
@@ -773,6 +784,7 @@ static void pshader_set_limits(
                    This->baseShader.limits.texcoord = 8;
                    This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 0;
+                   This->baseShader.limits.label = 16;
                    break;
 
           case D3DPS_VERSION(3,0):
@@ -783,6 +795,7 @@ static void pshader_set_limits(
                    This->baseShader.limits.texcoord = 0;
                    This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 12;
+                   This->baseShader.limits.label = 16; /* FIXME: 2048 */
                    break;
 
           default: This->baseShader.limits.temporary = 32;
@@ -792,6 +805,7 @@ static void pshader_set_limits(
                    This->baseShader.limits.texcoord = 8;
                    This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 0;
+                   This->baseShader.limits.label = 0;
                    FIXME("Unrecognized pixel shader version %#lx\n", 
                        This->baseShader.hex_version);
       }
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 20d1d4097eab6bad6c4298f781efb8a82199d666..026207997de7d969971e1562ebcbde3269be0d56 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -545,12 +545,12 @@ CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
     {D3DSIO_BREAK,    "break",    NULL, 0, 0, vshader_break,   NULL, shader_glsl_break,  D3DVS_VERSION(2,1), -1},
     {D3DSIO_BREAKC,   "breakc",   NULL, 0, 2, vshader_breakc,  NULL, shader_glsl_breakc, D3DVS_VERSION(2,1), -1},
     {D3DSIO_BREAKP,   "breakp",   GLNAME_REQUIRE_GLSL, 0, 1, vshader_breakp,  NULL, NULL, 0, 0},
-    {D3DSIO_CALL,     "call",     GLNAME_REQUIRE_GLSL, 0, 1, vshader_call,    NULL, NULL, 0, 0},
-    {D3DSIO_CALLNZ,   "callnz",   GLNAME_REQUIRE_GLSL, 0, 2, vshader_callnz,  NULL, NULL, 0, 0},
+    {D3DSIO_CALL,     "call",     NULL, 0, 1, vshader_call,    NULL, shader_glsl_call,   D3DVS_VERSION(2,0), -1},
+    {D3DSIO_CALLNZ,   "callnz",   NULL, 0, 2, vshader_callnz,  NULL, shader_glsl_callnz, D3DVS_VERSION(2,0), -1},
     {D3DSIO_LOOP,     "loop",     NULL, 0, 2, vshader_loop,    NULL, shader_glsl_loop,   D3DVS_VERSION(2,0), -1},
-    {D3DSIO_RET,      "ret",      GLNAME_REQUIRE_GLSL, 0, 0, vshader_ret,     NULL, NULL, 0, 0},
+    {D3DSIO_RET,      "ret",      NULL, 0, 0, vshader_ret,     NULL, NULL,               D3DVS_VERSION(2,0), -1},
     {D3DSIO_ENDLOOP,  "endloop",  NULL, 0, 0, vshader_endloop, NULL, shader_glsl_end,    D3DVS_VERSION(2,0), -1},
-    {D3DSIO_LABEL,    "label",    GLNAME_REQUIRE_GLSL, 0, 1, vshader_label,   NULL, NULL, 0, 0},
+    {D3DSIO_LABEL,    "label",    NULL, 0, 1, vshader_label,   NULL, shader_glsl_label,  D3DVS_VERSION(2,0), -1},
 
     {D3DSIO_MOVA,     "mova",     GLNAME_REQUIRE_GLSL, 1, 2, vshader_mova,    NULL, shader_glsl_mov, 0, 0},
     {D3DSIO_SETP,     "setp",     GLNAME_REQUIRE_GLSL, 1, 3, vshader_setp,    NULL, NULL, 0, 0},
@@ -577,6 +577,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
                    This->baseShader.limits.sampler = 0;
+                   This->baseShader.limits.label = 0;
                    break;
       
           case D3DVS_VERSION(2,0):
@@ -587,6 +588,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
                    This->baseShader.limits.sampler = 0;
+                   This->baseShader.limits.label = 16;
                    break;
 
           case D3DVS_VERSION(3,0):
@@ -596,6 +598,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 12;
                    This->baseShader.limits.sampler = 4;
+                   This->baseShader.limits.label = 16; /* FIXME: 2048 */
                    break;
 
           default: This->baseShader.limits.temporary = 12;
@@ -604,6 +607,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
                    This->baseShader.limits.sampler = 0;
+                   This->baseShader.limits.label = 16;
                    FIXME("Unrecognized vertex shader version %#lx\n",
                        This->baseShader.hex_version);
       }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 5102e7caa2aeb5b4eecc8f6ddc49cea0669b1d46..c1ce7634bb5d2a0c84b59af82741a796998f114a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1282,6 +1282,10 @@ struct glsl_shader_prog_link {
 #define MAX_CONST_I 16
 #define MAX_CONST_B 16
 
+/* FIXME: This needs to go up to 2048 for
+ * Shader model 3 according to msdn (and for software shaders) */
+#define MAX_LABELS 16
+
 typedef struct semantic {
     DWORD usage;
     DWORD reg;
@@ -1301,6 +1305,7 @@ typedef struct shader_reg_maps {
     char packed_input[MAX_REG_INPUT];       /* pshader >= 3.0 */
     char packed_output[MAX_REG_OUTPUT];     /* vertex >= 3.0 */
     char attributes[MAX_ATTRIBS];           /* vertex */
+    char labels[MAX_LABELS];                /* pixel, vertex */
 
     /* Sampler usage tokens 
      * Use 0 as default (bit 31 is always 1 on a valid token) */
@@ -1368,6 +1373,7 @@ typedef struct SHADER_LIMITS {
     unsigned int packed_output;
     unsigned int packed_input;
     unsigned int attributes;
+    unsigned int label;
 } SHADER_LIMITS;
 
 /** Keeps track of details for TEX_M#x# shader opcodes which need to 
@@ -1463,6 +1469,9 @@ extern void shader_glsl_else(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_break(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_breakc(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_rep(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_call(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_callnz(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_label(SHADER_OPCODE_ARG* arg);
 
 /** GLSL Pixel Shader Prototypes */
 extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg);