Mesa (master): i965/fs: Do a FS compile up front at link time to produce link errors.

Eric Anholt anholt at kemper.freedesktop.org
Fri May 27 16:50:05 UTC 2011


Module: Mesa
Branch: master
Commit: 8752764076e5b3f052a57e0134424a37bf2e9164
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=8752764076e5b3f052a57e0134424a37bf2e9164

Author: Eric Anholt <eric at anholt.net>
Date:   Mon May 16 15:10:26 2011 -0700

i965/fs: Do a FS compile up front at link time to produce link errors.

At glLinkShaders time, a fail() call in FS compile in 8-wide (the one
that's required to succeed, though we may relax that at some point for
pre-Ironlake performance) will now report out as a link error.

---

 src/mesa/drivers/dri/i965/brw_fs.cpp     |  110 +++++++++++++++++++++++++-----
 src/mesa/drivers/dri/i965/brw_fs.h       |    9 ++-
 src/mesa/drivers/dri/i965/brw_shader.cpp |   17 +++++
 src/mesa/drivers/dri/i965/brw_wm.c       |   26 +++++--
 src/mesa/drivers/dri/i965/brw_wm.h       |    7 ++-
 5 files changed, 142 insertions(+), 27 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index bec43b4..36040c3 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -84,17 +84,23 @@ fs_visitor::type_size(const struct glsl_type *type)
 void
 fs_visitor::fail(const char *format, ...)
 {
-   if (!failed) {
-      failed = true;
+   va_list va;
+   char *msg;
 
-      if (INTEL_DEBUG & DEBUG_WM) {
-	 fprintf(stderr, "FS compile failed: ");
+   if (failed)
+      return;
 
-	 va_list va;
-	 va_start(va, format);
-	 vfprintf(stderr, format, va);
-	 va_end(va);
-      }
+   failed = true;
+
+   va_start(va, format);
+   msg = ralloc_vasprintf(mem_ctx, format, va);
+   va_end(va);
+   msg = ralloc_asprintf(mem_ctx, "FS compile failed: %s\n", msg);
+
+   this->fail_msg = msg;
+
+   if (INTEL_DEBUG & DEBUG_WM) {
+      fprintf(stderr, msg);
    }
 }
 
@@ -643,7 +649,7 @@ fs_visitor::calculate_urb_setup()
    /* Figure out where each of the incoming setup attributes lands. */
    if (intel->gen >= 6) {
       for (unsigned int i = 0; i < FRAG_ATTRIB_MAX; i++) {
-	 if (brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(i)) {
+	 if (fp->Base.InputsRead & BITFIELD64_BIT(i)) {
 	    urb_setup[i] = urb_next++;
 	 }
       }
@@ -1587,11 +1593,10 @@ fs_visitor::run()
 }
 
 bool
-brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c)
+brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c,
+	       struct gl_shader_program *prog)
 {
    struct intel_context *intel = &brw->intel;
-   struct gl_context *ctx = &intel->ctx;
-   struct gl_shader_program *prog = ctx->Shader.CurrentFragmentProgram;
 
    if (!prog)
       return false;
@@ -1611,16 +1616,17 @@ brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c)
     */
    c->dispatch_width = 8;
 
-   fs_visitor v(c, shader);
+   fs_visitor v(c, prog, shader);
    if (!v.run()) {
-      /* FINISHME: Cleanly fail, test at link time, etc. */
-      assert(!"not reached");
+      prog->LinkStatus = GL_FALSE;
+      prog->InfoLog = ralloc_strdup(prog, v.fail_msg);
+
       return false;
    }
 
    if (intel->gen >= 5 && c->prog_data.nr_pull_params == 0) {
       c->dispatch_width = 16;
-      fs_visitor v2(c, shader);
+      fs_visitor v2(c, prog, shader);
       v2.import_uniforms(v.variable_ht);
       v2.run();
    }
@@ -1629,3 +1635,73 @@ brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c)
 
    return true;
 }
+
+bool
+brw_fs_precompile(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct brw_wm_prog_key key;
+   struct gl_fragment_program *fp = prog->FragmentProgram;
+   struct brw_fragment_program *bfp = brw_fragment_program(fp);
+
+   if (!fp)
+      return true;
+
+   memset(&key, 0, sizeof(key));
+
+   if (fp->UsesKill)
+      key.iz_lookup |= IZ_PS_KILL_ALPHATEST_BIT;
+
+   if (fp->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
+      key.iz_lookup |= IZ_PS_COMPUTES_DEPTH_BIT;
+
+   /* Just assume depth testing. */
+   key.iz_lookup |= IZ_DEPTH_TEST_ENABLE_BIT;
+   key.iz_lookup |= IZ_DEPTH_WRITE_ENABLE_BIT;
+
+   key.vp_outputs_written |= BITFIELD64_BIT(FRAG_ATTRIB_WPOS);
+   for (int i = 0; i < FRAG_ATTRIB_MAX; i++) {
+      int vp_index = -1;
+
+      if (!(fp->Base.InputsRead & BITFIELD64_BIT(i)))
+	 continue;
+
+      key.proj_attrib_mask |= 1 << i;
+
+      if (i <= FRAG_ATTRIB_TEX7)
+	 vp_index = i;
+      else if (i >= FRAG_ATTRIB_VAR0)
+	 vp_index = i - FRAG_ATTRIB_VAR0 + VERT_RESULT_VAR0;
+
+      if (vp_index >= 0)
+	 key.vp_outputs_written |= BITFIELD64_BIT(vp_index);
+   }
+
+   key.clamp_fragment_color = true;
+
+   for (int i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+      /* FINISHME: depth compares might use (0,0,0,W) for example */
+      key.tex_swizzles[i] = SWIZZLE_XYZW;
+   }
+
+   if (fp->Base.InputsRead & FRAG_BIT_WPOS) {
+      key.drawable_height = ctx->DrawBuffer->Height;
+      key.render_to_fbo = ctx->DrawBuffer->Name != 0;
+   }
+
+   key.nr_color_regions = 1;
+
+   key.program_string_id = bfp->id;
+
+   drm_intel_bo *old_prog_bo = brw->wm.prog_bo;
+   struct brw_wm_prog_data *old_prog_data = brw->wm.prog_data;
+   brw->wm.prog_bo = NULL;
+
+   bool success = do_wm_prog(brw, prog, bfp, &key);
+
+   drm_intel_bo_unreference(brw->wm.prog_bo);
+   brw->wm.prog_bo = old_prog_bo;
+   brw->wm.prog_data = old_prog_data;
+
+   return success;
+}
diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
index d1f70ee..7570dda 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.h
+++ b/src/mesa/drivers/dri/i965/brw_fs.h
@@ -359,12 +359,14 @@ class fs_visitor : public ir_visitor
 {
 public:
 
-   fs_visitor(struct brw_wm_compile *c, struct brw_shader *shader)
+   fs_visitor(struct brw_wm_compile *c, struct gl_shader_program *prog,
+	      struct brw_shader *shader)
    {
       this->c = c;
       this->p = &c->func;
       this->brw = p->brw;
-      this->fp = brw->fragment_program;
+      this->fp = prog->FragmentProgram;
+      this->prog = prog;
       this->intel = &brw->intel;
       this->ctx = &intel->ctx;
       this->mem_ctx = ralloc_context(NULL);
@@ -544,6 +546,7 @@ public:
    struct brw_wm_compile *c;
    struct brw_compile *p;
    struct brw_shader *shader;
+   struct gl_shader_program *prog;
    void *mem_ctx;
    exec_list instructions;
 
@@ -572,6 +575,7 @@ public:
    /** @} */
 
    bool failed;
+   char *fail_msg;
 
    /* On entry to a visit() method, this is the storage for the
     * result.  On exit, the visit() called may have changed it, in
@@ -595,3 +599,4 @@ public:
 
 GLboolean brw_do_channel_expressions(struct exec_list *instructions);
 GLboolean brw_do_vector_splitting(struct exec_list *instructions);
+bool brw_fs_precompile(struct gl_context *ctx, struct gl_shader_program *prog);
diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp
index 8516c9f..9471883 100644
--- a/src/mesa/drivers/dri/i965/brw_shader.cpp
+++ b/src/mesa/drivers/dri/i965/brw_shader.cpp
@@ -56,6 +56,20 @@ brw_new_shader_program(struct gl_context *ctx, GLuint name)
    return &prog->base;
 }
 
+/**
+ * Performs a compile of the shader stages even when we don't know
+ * what non-orthogonal state will be set, in the hope that it reflects
+ * the eventual NOS used, and thus allows us to produce link failures.
+ */
+bool
+brw_shader_precompile(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   if (!brw_fs_precompile(ctx, prog))
+      return false;
+
+   return true;
+}
+
 GLboolean
 brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
 {
@@ -123,6 +137,9 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
    if (!_mesa_ir_link_shader(ctx, prog))
       return GL_FALSE;
 
+   if (!brw_shader_precompile(ctx, prog))
+      return GL_FALSE;
+
    return GL_TRUE;
 }
 
diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c
index 0f17c50..1aebd12 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.c
+++ b/src/mesa/drivers/dri/i965/brw_wm.c
@@ -34,6 +34,7 @@
 #include "brw_state.h"
 #include "main/formats.h"
 #include "main/samplerobj.h"
+#include "program/prog_parameter.h"
 
 #include "../glsl/ralloc.h"
 
@@ -184,9 +185,10 @@ brw_wm_payload_setup(struct brw_context *brw,
  * Depending on the instructions used (i.e. flow control instructions)
  * we'll use one of two code generators.
  */
-static void do_wm_prog( struct brw_context *brw,
-			struct brw_fragment_program *fp, 
-			struct brw_wm_prog_key *key)
+bool do_wm_prog(struct brw_context *brw,
+		struct gl_shader_program *prog,
+		struct brw_fragment_program *fp,
+		struct brw_wm_prog_key *key)
 {
    struct intel_context *intel = &brw->intel;
    struct brw_wm_compile *c;
@@ -202,7 +204,7 @@ static void do_wm_prog( struct brw_context *brw,
           * without triggering a segfault, no way to signal,
           * so just return.
           */
-         return;
+         return false;
       }
       c->instruction = rzalloc_array(c, struct brw_wm_instruction, BRW_WM_MAX_INSN);
       c->prog_instructions = rzalloc_array(c, struct prog_instruction, BRW_WM_MAX_INSN);
@@ -226,7 +228,10 @@ static void do_wm_prog( struct brw_context *brw,
 
    brw_init_compile(brw, &c->func, c);
 
-   if (!brw_wm_fs_emit(brw, c)) {
+   if (prog && prog->FragmentProgram) {
+      if (!brw_wm_fs_emit(brw, c, prog))
+	 return false;
+   } else {
       /* Fallback for fixed function and ARB_fp shaders. */
       c->dispatch_width = 16;
       brw_wm_payload_setup(brw, c);
@@ -274,6 +279,8 @@ static void do_wm_prog( struct brw_context *brw,
 				      program, program_size,
 				      &c->prog_data, sizeof(c->prog_data),
 				      &brw->wm.prog_data);
+
+   return true;
 }
 
 
@@ -462,6 +469,8 @@ static void brw_wm_populate_key( struct brw_context *brw,
 
 static void brw_prepare_wm_prog(struct brw_context *brw)
 {
+   struct intel_context *intel = &brw->intel;
+   struct gl_context *ctx = &intel->ctx;
    struct brw_wm_prog_key key;
    struct brw_fragment_program *fp = (struct brw_fragment_program *)
       brw->fragment_program;
@@ -474,8 +483,11 @@ static void brw_prepare_wm_prog(struct brw_context *brw)
    brw->wm.prog_bo = brw_search_cache(&brw->cache, BRW_WM_PROG,
 				      &key, sizeof(key),
 				      &brw->wm.prog_data);
-   if (brw->wm.prog_bo == NULL)
-      do_wm_prog(brw, fp, &key);
+   if (brw->wm.prog_bo == NULL) {
+      bool success = do_wm_prog(brw, ctx->Shader.CurrentFragmentProgram, fp,
+				&key);
+      assert(success);
+   }
 }
 
 
diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h
index 3010e31..e244b55 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.h
+++ b/src/mesa/drivers/dri/i965/brw_wm.h
@@ -312,7 +312,8 @@ void brw_wm_print_program( struct brw_wm_compile *c,
 void brw_wm_lookup_iz(struct intel_context *intel,
 		      struct brw_wm_compile *c);
 
-bool brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c);
+bool brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c,
+		    struct gl_shader_program *prog);
 
 /* brw_wm_emit.c */
 void emit_alu1(struct brw_compile *p,
@@ -474,5 +475,9 @@ bool brw_color_buffer_write_enabled(struct brw_context *brw);
 bool brw_render_target_supported(gl_format format);
 void brw_wm_payload_setup(struct brw_context *brw,
 			  struct brw_wm_compile *c);
+bool do_wm_prog(struct brw_context *brw,
+		struct gl_shader_program *prog,
+		struct brw_fragment_program *fp,
+		struct brw_wm_prog_key *key);
 
 #endif




More information about the mesa-commit mailing list