X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fi965%2Fbrw_wm.c;h=1faf2eaa346cd9e1ae32d1098bba97260eaa8481;hb=005c8e01062e8e88a86904b955d5422742bd32e7;hp=b8ea6f2df8d14252d6c00da2e27613760c14c473;hpb=a7bdd4cba8ddcab8dff59ecaaa7efbd436c6c307;p=mesa.git diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c index b8ea6f2df8d..1faf2eaa346 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.c +++ b/src/mesa/drivers/dri/i965/brw_wm.c @@ -1,53 +1,51 @@ /* - Copyright (C) Intel Corp. 2006. All Rights Reserved. - Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to - develop this 3D driver. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice (including the - next paragraph) shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - **********************************************************************/ - /* - * Authors: - * Keith Whitwell - */ - + * Copyright (C) Intel Corp. 2006. All Rights Reserved. + * Intel funded Tungsten Graphics to + * develop this 3D driver. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ #include "brw_context.h" #include "brw_wm.h" #include "brw_state.h" +#include "brw_shader.h" #include "main/enums.h" #include "main/formats.h" #include "main/fbobject.h" #include "main/samplerobj.h" +#include "main/framebuffer.h" #include "program/prog_parameter.h" #include "program/program.h" +#include "intel_mipmap_tree.h" -#include "glsl/ralloc.h" +#include "util/ralloc.h" /** * Return a bitfield where bit n is set if barycentric interpolation mode n * (see enum brw_wm_barycentric_interp_mode) is needed by the fragment shader. */ -static unsigned +unsigned brw_compute_barycentric_interp_modes(struct brw_context *brw, bool shade_model_flat, + bool persample_shading, const struct gl_fragment_program *fprog) { unsigned barycentric_interp_modes = 0; @@ -60,7 +58,10 @@ brw_compute_barycentric_interp_modes(struct brw_context *brw, for (attr = 0; attr < VARYING_SLOT_MAX; ++attr) { enum glsl_interp_qualifier interp_qualifier = fprog->InterpQualifier[attr]; - bool is_centroid = fprog->IsCentroid & BITFIELD64_BIT(attr); + bool is_centroid = (fprog->IsCentroid & BITFIELD64_BIT(attr)) && + !persample_shading; + bool is_sample = (fprog->IsSample & BITFIELD64_BIT(attr)) || + persample_shading; bool is_gl_Color = attr == VARYING_SLOT_COL0 || attr == VARYING_SLOT_COL1; /* Ignore unused inputs. */ @@ -81,8 +82,12 @@ brw_compute_barycentric_interp_modes(struct brw_context *brw, if (is_centroid) { barycentric_interp_modes |= 1 << BRW_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC; + } else if (is_sample) { + barycentric_interp_modes |= + 1 << BRW_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC; } - if (!is_centroid || brw->needs_unlit_centroid_workaround) { + if ((!is_centroid && !is_sample) || + brw->needs_unlit_centroid_workaround) { barycentric_interp_modes |= 1 << BRW_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC; } @@ -92,8 +97,12 @@ brw_compute_barycentric_interp_modes(struct brw_context *brw, if (is_centroid) { barycentric_interp_modes |= 1 << BRW_WM_PERSPECTIVE_CENTROID_BARYCENTRIC; + } else if (is_sample) { + barycentric_interp_modes |= + 1 << BRW_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC; } - if (!is_centroid || brw->needs_unlit_centroid_workaround) { + if ((!is_centroid && !is_sample) || + brw->needs_unlit_centroid_workaround) { barycentric_interp_modes |= 1 << BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC; } @@ -103,53 +112,81 @@ brw_compute_barycentric_interp_modes(struct brw_context *brw, return barycentric_interp_modes; } +static uint8_t +computed_depth_mode(struct gl_fragment_program *fp) +{ + if (fp->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + switch (fp->FragDepthLayout) { + case FRAG_DEPTH_LAYOUT_NONE: + case FRAG_DEPTH_LAYOUT_ANY: + return BRW_PSCDEPTH_ON; + case FRAG_DEPTH_LAYOUT_GREATER: + return BRW_PSCDEPTH_ON_GE; + case FRAG_DEPTH_LAYOUT_LESS: + return BRW_PSCDEPTH_ON_LE; + case FRAG_DEPTH_LAYOUT_UNCHANGED: + return BRW_PSCDEPTH_OFF; + } + } + return BRW_PSCDEPTH_OFF; +} + bool brw_wm_prog_data_compare(const void *in_a, const void *in_b) { const struct brw_wm_prog_data *a = in_a; const struct brw_wm_prog_data *b = in_b; - /* Compare all the struct (including the base) up to the pointers. */ - if (memcmp(a, b, offsetof(struct brw_wm_prog_data, param))) - return false; - - if (memcmp(a->param, b->param, a->nr_params * sizeof(void *))) + /* Compare the base structure. */ + if (!brw_stage_prog_data_compare(&a->base, &b->base)) return false; - if (memcmp(a->pull_param, b->pull_param, a->nr_pull_params * sizeof(void *))) + /* Compare the rest of the structure. */ + const unsigned offset = sizeof(struct brw_stage_prog_data); + if (memcmp(((char *) a) + offset, ((char *) b) + offset, + sizeof(struct brw_wm_prog_data) - offset)) return false; return true; } -void -brw_wm_prog_data_free(const void *in_prog_data) -{ - const struct brw_wm_prog_data *prog_data = in_prog_data; - - ralloc_free((void *)prog_data->param); - ralloc_free((void *)prog_data->pull_param); -} - /** * All Mesa program -> GPU code generation goes through this function. * Depending on the instructions used (i.e. flow control instructions) * we'll use one of two code generators. */ -bool do_wm_prog(struct brw_context *brw, - struct gl_shader_program *prog, - struct brw_fragment_program *fp, - struct brw_wm_prog_key *key) +bool +brw_codegen_wm_prog(struct brw_context *brw, + struct gl_shader_program *prog, + struct brw_fragment_program *fp, + struct brw_wm_prog_key *key) { - struct brw_wm_compile *c; + struct gl_context *ctx = &brw->ctx; + void *mem_ctx = ralloc_context(NULL); + struct brw_wm_prog_data prog_data; const GLuint *program; - struct gl_shader *fs = NULL; + struct brw_shader *fs = NULL; GLuint program_size; + bool start_busy = false; + double start_time = 0; if (prog) - fs = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; + fs = (struct brw_shader *)prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; + + memset(&prog_data, 0, sizeof(prog_data)); + /* key->alpha_test_func means simulating alpha testing via discards, + * so the shader definitely kills pixels. + */ + prog_data.uses_kill = fp->program.UsesKill || key->alpha_test_func; + prog_data.uses_omask = + fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK); + prog_data.computed_depth_mode = computed_depth_mode(&fp->program); + + prog_data.early_fragment_tests = fs && fs->base.EarlyFragmentTests; - c = rzalloc(NULL, struct brw_wm_compile); + /* Use ALT floating point mode for ARB programs so that 0^0 == 1. */ + if (!prog) + prog_data.base.use_alt_mode = true; /* Allocate the references to the uniforms that will end up in the * prog_data associated with the compiled program, and which will be freed @@ -157,47 +194,67 @@ bool do_wm_prog(struct brw_context *brw, */ int param_count; if (fs) { - param_count = fs->num_uniform_components; + param_count = fs->base.num_uniform_components + + fs->base.NumImages * BRW_IMAGE_PARAM_SIZE; + prog_data.base.nr_image_params = fs->base.NumImages; } else { param_count = fp->program.Base.Parameters->NumParameters * 4; } /* The backend also sometimes adds params for texture size. */ - param_count += 2 * BRW_MAX_TEX_UNIT; - c->prog_data.param = rzalloc_array(NULL, const float *, param_count); - c->prog_data.pull_param = rzalloc_array(NULL, const float *, param_count); - - memcpy(&c->key, key, sizeof(*key)); - - c->prog_data.barycentric_interp_modes = - brw_compute_barycentric_interp_modes(brw, c->key.flat_shade, + param_count += 2 * ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; + prog_data.base.param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data.base.pull_param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data.base.image_param = + rzalloc_array(NULL, struct brw_image_param, + prog_data.base.nr_image_params); + prog_data.base.nr_params = param_count; + + prog_data.barycentric_interp_modes = + brw_compute_barycentric_interp_modes(brw, key->flat_shade, + key->persample_shading, &fp->program); - program = brw_wm_fs_emit(brw, c, &fp->program, prog, &program_size); - if (program == NULL) + if (unlikely(brw->perf_debug)) { + start_busy = (brw->batch.last_bo && + drm_intel_bo_busy(brw->batch.last_bo)); + start_time = get_time(); + } + + program = brw_wm_fs_emit(brw, mem_ctx, key, &prog_data, + &fp->program, prog, &program_size); + if (program == NULL) { + ralloc_free(mem_ctx); return false; + } - /* Scratch space is used for register spilling */ - if (c->last_scratch) { - perf_debug("Fragment shader triggered register spilling. " - "Try reducing the number of live scalar values to " - "improve performance.\n"); + if (unlikely(brw->perf_debug) && fs) { + if (fs->compiled_once) + brw_wm_debug_recompile(brw, prog, key); + fs->compiled_once = true; - c->prog_data.total_scratch = brw_get_scratch_size(c->last_scratch); + if (start_busy && !drm_intel_bo_busy(brw->batch.last_bo)) { + perf_debug("FS compile took %.03f ms and stalled the GPU\n", + (get_time() - start_time) * 1000); + } + } + if (prog_data.base.total_scratch) { brw_get_scratch_bo(brw, &brw->wm.base.scratch_bo, - c->prog_data.total_scratch * brw->max_wm_threads); + prog_data.base.total_scratch * brw->max_wm_threads); } if (unlikely(INTEL_DEBUG & DEBUG_WM)) fprintf(stderr, "\n"); - brw_upload_cache(&brw->cache, BRW_WM_PROG, - &c->key, sizeof(c->key), + brw_upload_cache(&brw->cache, BRW_CACHE_FS_PROG, + key, sizeof(struct brw_wm_prog_key), program, program_size, - &c->prog_data, sizeof(c->prog_data), + &prog_data, sizeof(prog_data), &brw->wm.base.prog_offset, &brw->wm.prog_data); - ralloc_free(c); + ralloc_free(mem_ctx); return true; } @@ -230,12 +287,16 @@ brw_debug_recompile_sampler_key(struct brw_context *brw, old_key->gl_clamp_mask[1], key->gl_clamp_mask[1]); found |= key_debug(brw, "GL_CLAMP enabled on any texture unit's 3rd coordinate", old_key->gl_clamp_mask[2], key->gl_clamp_mask[2]); - found |= key_debug(brw, "GL_MESA_ycbcr texturing\n", - old_key->yuvtex_mask, key->yuvtex_mask); - found |= key_debug(brw, "GL_MESA_ycbcr UV swapping\n", - old_key->yuvtex_swap_mask, key->yuvtex_swap_mask); found |= key_debug(brw, "gather channel quirk on any texture unit", old_key->gather_channel_quirk_mask, key->gather_channel_quirk_mask); + found |= key_debug(brw, "compressed multisample layout", + old_key->compressed_multisample_layout_mask, + key->compressed_multisample_layout_mask); + + for (unsigned int i = 0; i < MAX_SAMPLERS; i++) { + found |= key_debug(brw, "textureGather workarounds", + old_key->gen6_gather_wa[i], key->gen6_gather_wa[i]); + } return found; } @@ -253,7 +314,7 @@ brw_wm_debug_recompile(struct brw_context *brw, for (unsigned int i = 0; i < brw->cache.size; i++) { for (c = brw->cache.items[i]; c; c = c->next) { - if (c->cache_id == BRW_WM_PROG) { + if (c->cache_id == BRW_CACHE_FS_PROG) { old_key = c->key; if (old_key->program_string_id == key->program_string_id) @@ -276,6 +337,10 @@ brw_wm_debug_recompile(struct brw_context *brw, old_key->stats_wm, key->stats_wm); found |= key_debug(brw, "flat shading", old_key->flat_shade, key->flat_shade); + found |= key_debug(brw, "per-sample shading", + old_key->persample_shading, key->persample_shading); + found |= key_debug(brw, "per-sample shading and 2x MSAA", + old_key->persample_2x, key->persample_2x); found |= key_debug(brw, "number of color buffers", old_key->nr_color_regions, key->nr_color_regions); found |= key_debug(brw, "MRT alpha test or alpha-to-coverage", @@ -302,6 +367,22 @@ brw_wm_debug_recompile(struct brw_context *brw, } } +static uint8_t +gen6_gather_workaround(GLenum internalformat) +{ + switch (internalformat) { + case GL_R8I: return WA_SIGN | WA_8BIT; + case GL_R8UI: return WA_8BIT; + case GL_R16I: return WA_SIGN | WA_16BIT; + case GL_R16UI: return WA_16BIT; + default: + /* Note that even though GL_R32I and GL_R32UI have format overrides in + * the surface state, there is no shader w/a required. + */ + return 0; + } +} + void brw_populate_sampler_prog_key_data(struct gl_context *ctx, const struct gl_program *prog, @@ -319,7 +400,7 @@ brw_populate_sampler_prog_key_data(struct gl_context *ctx, int unit_id = prog->SamplerUnits[s]; const struct gl_texture_unit *unit = &ctx->Texture.Unit[unit_id]; - if (unit->_ReallyEnabled && unit->_Current->Target != GL_TEXTURE_BUFFER) { + if (unit->_Current && unit->_Current->Target != GL_TEXTURE_BUFFER) { const struct gl_texture_object *t = unit->_Current; const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit_id); @@ -334,13 +415,8 @@ brw_populate_sampler_prog_key_data(struct gl_context *ctx, if (alpha_depth || (brw->gen < 8 && !brw->is_haswell)) key->swizzles[s] = brw_get_texture_swizzle(ctx, t); - if (img->InternalFormat == GL_YCBCR_MESA) { - key->yuvtex_mask |= 1 << s; - if (img->TexFormat == MESA_FORMAT_YCBCR) - key->yuvtex_swap_mask |= 1 << s; - } - - if (sampler->MinFilter != GL_NEAREST && + if (brw->gen < 8 && + sampler->MinFilter != GL_NEAREST && sampler->MagFilter != GL_NEAREST) { if (sampler->WrapS == GL_CLAMP) key->gl_clamp_mask[0] |= 1 << s; @@ -350,28 +426,69 @@ brw_populate_sampler_prog_key_data(struct gl_context *ctx, key->gl_clamp_mask[2] |= 1 << s; } - /* gather4's channel select for green from RG32F is broken; - * requires a shader w/a on IVB; fixable with just SCS on HSW. */ - if (brw->gen >= 7 && !brw->is_haswell && prog->UsesGather) { + /* gather4's channel select for green from RG32F is broken; requires + * a shader w/a on IVB; fixable with just SCS on HSW. + */ + if (brw->gen == 7 && !brw->is_haswell && prog->UsesGather) { if (img->InternalFormat == GL_RG32F) key->gather_channel_quirk_mask |= 1 << s; } + + /* Gen6's gather4 is broken for UINT/SINT; we treat them as + * UNORM/FLOAT instead and fix it in the shader. + */ + if (brw->gen == 6 && prog->UsesGather) { + key->gen6_gather_wa[s] = gen6_gather_workaround(img->InternalFormat); + } + + /* If this is a multisample sampler, and uses the CMS MSAA layout, + * then we need to emit slightly different code to first sample the + * MCS surface. + */ + struct intel_texture_object *intel_tex = + intel_texture_object((struct gl_texture_object *)t); + + if (brw->gen >= 7 && + intel_tex->mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) { + key->compressed_multisample_layout_mask |= 1 << s; + } } } } -static void brw_wm_populate_key( struct brw_context *brw, - struct brw_wm_prog_key *key ) +static bool +brw_wm_state_dirty (struct brw_context *brw) +{ + return brw_state_dirty(brw, + _NEW_BUFFERS | + _NEW_COLOR | + _NEW_DEPTH | + _NEW_FRAG_CLAMP | + _NEW_HINT | + _NEW_LIGHT | + _NEW_LINE | + _NEW_MULTISAMPLE | + _NEW_POLYGON | + _NEW_STENCIL | + _NEW_TEXTURE, + BRW_NEW_FRAGMENT_PROGRAM | + BRW_NEW_REDUCED_PRIMITIVE | + BRW_NEW_STATS_WM | + BRW_NEW_VUE_MAP_GEOM_OUT); +} + +static void +brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = - (struct brw_fragment_program *)brw->fragment_program; + (struct brw_fragment_program *) brw->fragment_program; const struct gl_program *prog = (struct gl_program *) brw->fragment_program; GLuint lookup = 0; GLuint line_aa; bool program_uses_dfdy = fp->program.UsesDFdy; - bool multisample_fbo = ctx->DrawBuffer->Visual.samples > 1; + const bool multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; memset(key, 0, sizeof(*key)); @@ -432,13 +549,8 @@ static void brw_wm_populate_key( struct brw_context *brw, key->line_aa = line_aa; /* _NEW_HINT */ - if (brw->disable_derivative_optimization) { - key->high_quality_derivatives = - ctx->Hint.FragmentShaderDerivative != GL_FASTEST; - } else { - key->high_quality_derivatives = - ctx->Hint.FragmentShaderDerivative == GL_NICEST; - } + key->high_quality_derivatives = + ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (brw->gen < 6) key->stats_wm = brw->stats_wm; @@ -475,7 +587,7 @@ static void brw_wm_populate_key( struct brw_context *brw, * drawable height in order to invert the Y axis. */ if (fp->program.Base.InputsRead & VARYING_BIT_POS) { - key->drawable_height = ctx->DrawBuffer->Height; + key->drawable_height = _mesa_geometric_height(ctx->DrawBuffer); } if ((fp->program.Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { @@ -490,8 +602,14 @@ static void brw_wm_populate_key( struct brw_context *brw, (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ + /* Ignore sample qualifier while computing this flag. */ + key->persample_shading = + _mesa_get_min_invocations_per_fragment(ctx, &fp->program, true) > 1; + if (key->persample_shading) + key->persample_2x = _mesa_geometric_samples(ctx->DrawBuffer) == 2; + key->compute_pos_offset = - _mesa_get_min_invocations_per_fragment(ctx, &fp->program) > 1 && + _mesa_get_min_invocations_per_fragment(ctx, &fp->program, false) > 1 && fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_POS; key->compute_sample_id = @@ -511,7 +629,8 @@ static void brw_wm_populate_key( struct brw_context *brw, * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ - if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { + if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && + ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } @@ -520,47 +639,84 @@ static void brw_wm_populate_key( struct brw_context *brw, key->program_string_id = fp->id; } - -static void +void brw_upload_wm_prog(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; + struct gl_shader_program *current = ctx->_Shader->_CurrentFragmentProgram; struct brw_wm_prog_key key; struct brw_fragment_program *fp = (struct brw_fragment_program *) brw->fragment_program; + if (!brw_wm_state_dirty(brw)) + return; + brw_wm_populate_key(brw, &key); - if (!brw_search_cache(&brw->cache, BRW_WM_PROG, + if (!brw_search_cache(&brw->cache, BRW_CACHE_FS_PROG, &key, sizeof(key), &brw->wm.base.prog_offset, &brw->wm.prog_data)) { - bool success = do_wm_prog(brw, ctx->Shader._CurrentFragmentProgram, fp, - &key); + bool success = brw_codegen_wm_prog(brw, current, fp, &key); (void) success; assert(success); } brw->wm.base.prog_data = &brw->wm.prog_data->base; } +bool +brw_fs_precompile(struct gl_context *ctx, + struct gl_shader_program *shader_prog, + struct gl_program *prog) +{ + struct brw_context *brw = brw_context(ctx); + struct brw_wm_prog_key key; + + struct gl_fragment_program *fp = (struct gl_fragment_program *) prog; + struct brw_fragment_program *bfp = brw_fragment_program(fp); + bool program_uses_dfdy = fp->UsesDFdy; + + memset(&key, 0, sizeof(key)); + + if (brw->gen < 6) { + 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; + } + + if (brw->gen < 6 || _mesa_bitcount_64(fp->Base.InputsRead & + BRW_FS_VARYING_INPUT_MASK) > 16) + key.input_slots_valid = fp->Base.InputsRead | VARYING_BIT_POS; -const struct brw_tracked_state brw_wm_prog = { - .dirty = { - .mesa = (_NEW_COLOR | - _NEW_DEPTH | - _NEW_STENCIL | - _NEW_POLYGON | - _NEW_LINE | - _NEW_HINT | - _NEW_LIGHT | - _NEW_FRAG_CLAMP | - _NEW_BUFFERS | - _NEW_TEXTURE | - _NEW_MULTISAMPLE), - .brw = (BRW_NEW_FRAGMENT_PROGRAM | - BRW_NEW_REDUCED_PRIMITIVE | - BRW_NEW_VUE_MAP_GEOM_OUT | - BRW_NEW_STATS_WM) - }, - .emit = brw_upload_wm_prog -}; + brw_setup_tex_for_precompile(brw, &key.tex, &fp->Base); + if (fp->Base.InputsRead & VARYING_BIT_POS) { + key.drawable_height = ctx->DrawBuffer->Height; + } + + key.nr_color_regions = _mesa_bitcount_64(fp->Base.OutputsWritten & + ~(BITFIELD64_BIT(FRAG_RESULT_DEPTH) | + BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK))); + + if ((fp->Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { + key.render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer) || + key.nr_color_regions > 1; + } + + key.program_string_id = bfp->id; + + uint32_t old_prog_offset = brw->wm.base.prog_offset; + struct brw_wm_prog_data *old_prog_data = brw->wm.prog_data; + + bool success = brw_codegen_wm_prog(brw, shader_prog, bfp, &key); + + brw->wm.base.prog_offset = old_prog_offset; + brw->wm.prog_data = old_prog_data; + + return success; +}