[Mesa-dev] [PATCH 1/3] i965/fs: Do a FS compile up front at link time to produce link errors.
Eric Anholt
eric at anholt.net
Tue May 17 20:22:54 PDT 2011
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 | 130 +++++++++++++++++++++++++++++-----
src/mesa/drivers/dri/i965/brw_fs.h | 8 ++-
src/mesa/drivers/dri/i965/brw_wm.c | 26 +++++--
src/mesa/drivers/dri/i965/brw_wm.h | 7 ++-
4 files changed, 143 insertions(+), 28 deletions(-)
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index 22d034a..76df4dc 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -77,6 +77,92 @@ brw_new_shader_program(struct gl_context *ctx, GLuint name)
return &prog->base;
}
+bool
+brw_wm_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;
+ }
+
+ key.shadowtex_mask = fp->Base.ShadowSamplers;
+
+ 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;
+}
+
+/**
+ * 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_wm_precompile(ctx, prog))
+ return false;
+
+ return true;
+}
+
GLboolean
brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
{
@@ -144,6 +230,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;
}
@@ -181,15 +270,20 @@ void
fs_visitor::fail(const char *format, ...)
{
if (!failed) {
+ va_list va;
+ char *msg;
+
failed = true;
- if (INTEL_DEBUG & DEBUG_WM) {
- fprintf(stderr, "FS compile failed: ");
+ 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;
- va_list va;
- va_start(va, format);
- vfprintf(stderr, format, va);
- va_end(va);
+ if (INTEL_DEBUG & DEBUG_WM) {
+ fprintf(stderr, msg);
}
}
}
@@ -1419,9 +1513,9 @@ fs_visitor::visit(ir_texture *ir)
assert(!ir->projector);
sampler = _mesa_get_sampler_uniform_value(ir->sampler,
- ctx->Shader.CurrentFragmentProgram,
- &brw->fragment_program->Base);
- sampler = c->fp->program.Base.SamplerUnits[sampler];
+ prog,
+ &fp->Base);
+ sampler = fp->Base.SamplerUnits[sampler];
/* The 965 requires the EU to do the normalization of GL rectangle
* texture coordinates. We use the program parameter state
@@ -2807,7 +2901,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++;
}
}
@@ -3729,7 +3823,7 @@ fs_visitor::generate_code()
if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
printf("Native code for fragment shader %d (%d-wide dispatch):\n",
- ctx->Shader.CurrentFragmentProgram->Name, c->dispatch_width);
+ prog->Name, c->dispatch_width);
}
foreach_iter(exec_list_iterator, iter, this->instructions) {
@@ -4113,11 +4207,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;
@@ -4137,16 +4230,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();
}
diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
index dd63777..8bd6a14 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);
@@ -540,6 +542,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;
@@ -568,6 +571,7 @@ public:
/** @} */
bool failed;
+ char *fail_msg;
/* Result of last visit() method. */
fs_reg result;
diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c
index 6054918..d16d39f 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"
/** Return number of src args for given instruction */
GLuint brw_wm_nr_args( GLuint opcode )
@@ -182,9 +183,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;
@@ -200,7 +202,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 = calloc(1, BRW_WM_MAX_INSN * sizeof(*c->instruction));
c->prog_instructions = calloc(1, BRW_WM_MAX_INSN *
@@ -225,7 +227,10 @@ static void do_wm_prog( struct brw_context *brw,
brw_init_compile(brw, &c->func);
- 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);
@@ -273,6 +278,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;
}
@@ -467,6 +474,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;
@@ -479,8 +488,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 8ab531b..b5004c4 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.h
+++ b/src/mesa/drivers/dri/i965/brw_wm.h
@@ -314,7 +314,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,
@@ -476,5 +477,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
--
1.7.5.1
More information about the mesa-dev
mailing list