Merge branch 'arb_sampler_objects'
[mesa.git] / src / mesa / drivers / dri / i965 / brw_program.c
index a18dee85e80e40b4cd152484fb9299dff3dc2790..b5ec55b2ae3c13c4ec0f3a49dd54116cf38fac8c 100644 (file)
   
 #include "main/imports.h"
 #include "main/enums.h"
-#include "shader/prog_parameter.h"
-#include "shader/program.h"
-#include "shader/programopt.h"
+#include "main/shaderobj.h"
+#include "program/prog_parameter.h"
+#include "program/program.h"
+#include "program/programopt.h"
 #include "tnl/tnl.h"
+#include "../glsl/ralloc.h"
 
 #include "brw_context.h"
-#include "brw_util.h"
+#include "brw_wm.h"
 
-static void brwBindProgram( GLcontext *ctx,
+static void brwBindProgram( struct gl_context *ctx,
                            GLenum target, 
                            struct gl_program *prog )
 {
@@ -55,7 +57,7 @@ static void brwBindProgram( GLcontext *ctx,
    }
 }
 
-static struct gl_program *brwNewProgram( GLcontext *ctx,
+static struct gl_program *brwNewProgram( struct gl_context *ctx,
                                      GLenum target, 
                                      GLuint id )
 {
@@ -91,48 +93,142 @@ static struct gl_program *brwNewProgram( GLcontext *ctx,
    }
 }
 
-static void brwDeleteProgram( GLcontext *ctx,
+static void brwDeleteProgram( struct gl_context *ctx,
                              struct gl_program *prog )
 {
-   
    _mesa_delete_program( ctx, prog );
 }
 
 
-static GLboolean brwIsProgramNative( GLcontext *ctx,
+static GLboolean brwIsProgramNative( struct gl_context *ctx,
                                     GLenum target, 
                                     struct gl_program *prog )
 {
    return GL_TRUE;
 }
 
-static void brwProgramStringNotify( GLcontext *ctx,
-                                   GLenum target,
-                                   struct gl_program *prog )
+static void
+shader_error(struct gl_context *ctx, struct gl_program *prog, const char *msg)
 {
+   struct gl_shader_program *shader;
+
+   shader = _mesa_lookup_shader_program(ctx, prog->Id);
+
+   if (shader) {
+      ralloc_strcat(&shader->InfoLog, msg);
+      shader->LinkStatus = GL_FALSE;
+   }
+}
+
+static GLboolean brwProgramStringNotify( struct gl_context *ctx,
+                                         GLenum target,
+                                         struct gl_program *prog )
+{
+   struct brw_context *brw = brw_context(ctx);
+   int i;
+
    if (target == GL_FRAGMENT_PROGRAM_ARB) {
-      struct brw_context *brw = brw_context(ctx);
-      struct brw_fragment_program *p = (struct brw_fragment_program *)prog;
-      struct brw_fragment_program *fp = (struct brw_fragment_program *)brw->fragment_program;
-      if (p == fp)
+      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
+      struct brw_fragment_program *newFP = brw_fragment_program(fprog);
+      const struct brw_fragment_program *curFP =
+         brw_fragment_program_const(brw->fragment_program);
+      struct gl_shader_program *shader_program;
+
+      if (fprog->FogOption) {
+         _mesa_append_fog_code(ctx, fprog, GL_TRUE);
+         fprog->FogOption = GL_NONE;
+      }
+
+      if (newFP == curFP)
         brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
-      p->id = brw->program_id++;      
+      newFP->id = brw->program_id++;      
+
+      /* Don't reject fragment shaders for their Mesa IR state when we're
+       * using the new FS backend.
+       */
+      shader_program = _mesa_lookup_shader_program(ctx, prog->Id);
+      if (shader_program
+         && shader_program->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
+        return GL_TRUE;
+      }
    }
    else if (target == GL_VERTEX_PROGRAM_ARB) {
-      struct brw_context *brw = brw_context(ctx);
-      struct brw_vertex_program *p = (struct brw_vertex_program *)prog;
-      struct brw_vertex_program *vp = (struct brw_vertex_program *)brw->vertex_program;
-      if (p == vp)
+      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
+      struct brw_vertex_program *newVP = brw_vertex_program(vprog);
+      const struct brw_vertex_program *curVP =
+         brw_vertex_program_const(brw->vertex_program);
+
+      if (newVP == curVP)
         brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
-      if (p->program.IsPositionInvariant) {
-        _mesa_insert_mvp_code(ctx, &p->program);
+      if (newVP->program.IsPositionInvariant) {
+        _mesa_insert_mvp_code(ctx, &newVP->program);
       }
-      p->id = brw->program_id++;      
+      newVP->id = brw->program_id++;      
 
       /* Also tell tnl about it:
        */
       _tnl_program_string(ctx, target, prog);
    }
+
+   /* Reject programs with subroutines, which are totally broken at the moment
+    * (all program flows return when any program flow returns, and
+    * the VS also hangs if a function call calls a function.
+    *
+    * See piglit glsl-{vs,fs}-functions-[23] tests.
+    */
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      int r;
+
+      if (prog->Instructions[i].Opcode == OPCODE_CAL) {
+        shader_error(ctx, prog,
+                     "i965 driver doesn't yet support uninlined function "
+                     "calls.  Move to using a single return statement at "
+                     "the end of the function to work around it.\n");
+        return GL_FALSE;
+      }
+
+      if (prog->Instructions[i].Opcode == OPCODE_RET) {
+        shader_error(ctx, prog,
+                     "i965 driver doesn't yet support \"return\" "
+                     "from main().\n");
+        return GL_FALSE;
+      }
+
+      for (r = 0; r < _mesa_num_inst_src_regs(inst->Opcode); r++) {
+        if (prog->Instructions[i].SrcReg[r].RelAddr &&
+            prog->Instructions[i].SrcReg[r].File == PROGRAM_INPUT) {
+           shader_error(ctx, prog,
+                        "Variable indexing of shader inputs unsupported\n");
+           return GL_FALSE;
+        }
+      }
+
+      if (target == GL_FRAGMENT_PROGRAM_ARB &&
+         prog->Instructions[i].DstReg.RelAddr &&
+         prog->Instructions[i].DstReg.File == PROGRAM_OUTPUT) {
+        shader_error(ctx, prog,
+                     "Variable indexing of FS outputs unsupported\n");
+        return GL_FALSE;
+      }
+      if (target == GL_FRAGMENT_PROGRAM_ARB) {
+        if ((prog->Instructions[i].DstReg.RelAddr &&
+             prog->Instructions[i].DstReg.File == PROGRAM_TEMPORARY) ||
+            (prog->Instructions[i].SrcReg[0].RelAddr &&
+             prog->Instructions[i].SrcReg[0].File == PROGRAM_TEMPORARY) ||
+            (prog->Instructions[i].SrcReg[1].RelAddr &&
+             prog->Instructions[i].SrcReg[1].File == PROGRAM_TEMPORARY) ||
+            (prog->Instructions[i].SrcReg[2].RelAddr &&
+             prog->Instructions[i].SrcReg[2].File == PROGRAM_TEMPORARY)) {
+           shader_error(ctx, prog,
+                        "Variable indexing of variable arrays in the FS "
+                        "unsupported\n");
+           return GL_FALSE;
+        }
+      }
+   }
+
+   return GL_TRUE;
 }
 
 void brwInitFragProgFuncs( struct dd_function_table *functions )
@@ -144,5 +240,9 @@ void brwInitFragProgFuncs( struct dd_function_table *functions )
    functions->DeleteProgram = brwDeleteProgram;
    functions->IsProgramNative = brwIsProgramNative;
    functions->ProgramStringNotify = brwProgramStringNotify;
+
+   functions->NewShader = brw_new_shader;
+   functions->NewShaderProgram = brw_new_shader_program;
+   functions->LinkShader = brw_link_shader;
 }