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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user