X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_atom_shader.c;h=d92a542922e69e174df8ecc5cf778b37acaa8764;hb=916110e17f2e04d685978e6b385b3fe0d3231fe9;hp=c311d04393107efa4ee882c7af49170e084ed44c;hpb=652901e95b4ed406293d0e1fabee857c054119b1;p=mesa.git diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c index c311d043931..d92a542922e 100644 --- a/src/mesa/state_tracker/st_atom_shader.c +++ b/src/mesa/state_tracker/st_atom_shader.c @@ -1,8 +1,8 @@ /************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * + * Copyright 2003 VMware, Inc. * All Rights Reserved. - * + * * 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 @@ -10,19 +10,19 @@ * distribute, sub license, 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE 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. - * + * **************************************************************************/ /** @@ -35,34 +35,59 @@ * Brian Paul */ -#include "main/imports.h" + #include "main/mtypes.h" +#include "main/framebuffer.h" +#include "main/state.h" +#include "main/texobj.h" +#include "main/texstate.h" #include "program/program.h" #include "pipe/p_context.h" - +#include "pipe/p_shader_tokens.h" #include "util/u_simple_shaders.h" - #include "cso_cache/cso_context.h" +#include "util/u_debug.h" #include "st_context.h" #include "st_atom.h" #include "st_program.h" +#include "st_texture.h" +#include "st_util.h" -/** - * Return pointer to a pass-through fragment shader. - * This shader is used when a texture is missing/incomplete. - */ -static void * -get_passthrough_fs(struct st_context *st) +static unsigned +get_texture_target(struct gl_context *ctx, const unsigned unit) { - if (!st->passthrough_fs) { - st->passthrough_fs = - util_make_fragment_passthrough_shader(st->pipe); + struct gl_texture_object *texObj = _mesa_get_tex_unit(ctx, unit)->_Current; + gl_texture_index index; + + if (texObj) { + index = _mesa_tex_target_to_index(ctx, texObj->Target); + } else { + /* fallback for missing texture */ + index = TEXTURE_2D_INDEX; } - return st->passthrough_fs; + /* Map mesa texture target to TGSI texture target. + * Copied from st_mesa_to_tgsi.c, the shadow part is omitted */ + switch(index) { + case TEXTURE_2D_MULTISAMPLE_INDEX: return TGSI_TEXTURE_2D_MSAA; + case TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: return TGSI_TEXTURE_2D_ARRAY_MSAA; + case TEXTURE_BUFFER_INDEX: return TGSI_TEXTURE_BUFFER; + case TEXTURE_1D_INDEX: return TGSI_TEXTURE_1D; + case TEXTURE_2D_INDEX: return TGSI_TEXTURE_2D; + case TEXTURE_3D_INDEX: return TGSI_TEXTURE_3D; + case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE; + case TEXTURE_CUBE_ARRAY_INDEX: return TGSI_TEXTURE_CUBE_ARRAY; + case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT; + case TEXTURE_1D_ARRAY_INDEX: return TGSI_TEXTURE_1D_ARRAY; + case TEXTURE_2D_ARRAY_INDEX: return TGSI_TEXTURE_2D_ARRAY; + case TEXTURE_EXTERNAL_INDEX: return TGSI_TEXTURE_2D; + default: + debug_assert(0); + return TGSI_TEXTURE_1D; + } } @@ -70,129 +95,241 @@ get_passthrough_fs(struct st_context *st) * Update fragment program state/atom. This involves translating the * Mesa fragment program into a gallium fragment program and binding it. */ -static void -update_fp( struct st_context *st ) +void +st_update_fp( struct st_context *st ) { - struct st_fragment_program *stfp; - struct st_fp_variant_key key; + struct st_program *stfp; assert(st->ctx->FragmentProgram._Current); - stfp = st_fragment_program(st->ctx->FragmentProgram._Current); - assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB); - - memset(&key, 0, sizeof(key)); - key.st = st; - - st->fp_variant = st_get_fp_variant(st, stfp, &key); - - st_reference_fragprog(st, &st->fp, stfp); - - if (st->missing_textures) { - /* use a pass-through frag shader that uses no textures */ - void *fs = get_passthrough_fs(st); - cso_set_fragment_shader_handle(st->cso_context, fs); - } - else { - cso_set_fragment_shader_handle(st->cso_context, - st->fp_variant->driver_shader); + stfp = st_program(st->ctx->FragmentProgram._Current); + assert(stfp->Base.Target == GL_FRAGMENT_PROGRAM_ARB); + + void *shader; + + if (st->shader_has_one_variant[MESA_SHADER_FRAGMENT] && + !stfp->ati_fs && /* ATI_fragment_shader always has multiple variants */ + !stfp->Base.ExternalSamplersUsed && /* external samplers need variants */ + stfp->variants && + !st_fp_variant(stfp->variants)->key.drawpixels && + !st_fp_variant(stfp->variants)->key.bitmap) { + shader = stfp->variants->driver_shader; + } else { + struct st_fp_variant_key key; + + /* use memset, not an initializer to be sure all memory is zeroed */ + memset(&key, 0, sizeof(key)); + + key.st = st->has_shareable_shaders ? NULL : st; + + key.lower_flatshade = st->lower_flatshade && + st->ctx->Light.ShadeModel == GL_FLAT; + + /* _NEW_COLOR */ + key.lower_alpha_func = COMPARE_FUNC_NEVER; + if (st->lower_alpha_test && _mesa_is_alpha_test_enabled(st->ctx)) + key.lower_alpha_func = st->ctx->Color.AlphaFunc; + + /* _NEW_LIGHT | _NEW_PROGRAM */ + key.lower_two_sided_color = st->lower_two_sided_color && + _mesa_vertex_program_two_side_enabled(st->ctx); + + /* gl_driver_flags::NewFragClamp */ + key.clamp_color = st->clamp_frag_color_in_shader && + st->ctx->Color._ClampFragmentColor; + + /* _NEW_MULTISAMPLE | _NEW_BUFFERS */ + key.persample_shading = + st->force_persample_in_shader && + _mesa_is_multisample_enabled(st->ctx) && + st->ctx->Multisample.SampleShading && + st->ctx->Multisample.MinSampleShadingValue * + _mesa_geometric_samples(st->ctx->DrawBuffer) > 1; + + key.lower_depth_clamp = + st->clamp_frag_depth_in_shader && + (st->ctx->Transform.DepthClampNear || + st->ctx->Transform.DepthClampFar); + + if (stfp->ati_fs) { + key.fog = st->ctx->Fog._PackedEnabledMode; + + for (unsigned u = 0; u < MAX_NUM_FRAGMENT_REGISTERS_ATI; u++) { + key.texture_targets[u] = get_texture_target(st->ctx, u); + } + } + + key.external = st_get_external_sampler_key(st, &stfp->Base); + + shader = st_get_fp_variant(st, stfp, &key)->base.driver_shader; } -} + st_reference_prog(st, &st->fp, stfp); -const struct st_tracked_state st_update_fp = { - "st_update_fp", /* name */ - { /* dirty */ - 0, /* mesa */ - ST_NEW_FRAGMENT_PROGRAM /* st */ - }, - update_fp /* update */ -}; - + cso_set_fragment_shader_handle(st->cso_context, shader); +} /** * Update vertex program state/atom. This involves translating the * Mesa vertex program into a gallium fragment program and binding it. */ -static void -update_vp( struct st_context *st ) +void +st_update_vp( struct st_context *st ) { - struct st_vertex_program *stvp; - struct st_vp_variant_key key; + struct st_program *stvp; /* find active shader and params -- Should be covered by * ST_NEW_VERTEX_PROGRAM */ assert(st->ctx->VertexProgram._Current); - stvp = st_vertex_program(st->ctx->VertexProgram._Current); - assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB); - - memset(&key, 0, sizeof key); - key.st = st; /* variants are per-context */ - - /* When this is true, we will add an extra input to the vertex - * shader translation (for edgeflags), an extra output with - * edgeflag semantics, and extend the vertex shader to pass through - * the input to the output. We'll need to use similar logic to set - * up the extra vertex_element input for edgeflags. - * _NEW_POLYGON, ST_NEW_EDGEFLAGS_DATA - */ - key.passthrough_edgeflags = (st->vertdata_edgeflags && ( - st->ctx->Polygon.FrontMode != GL_FILL || - st->ctx->Polygon.BackMode != GL_FILL)); + stvp = st_program(st->ctx->VertexProgram._Current); + assert(stvp->Base.Target == GL_VERTEX_PROGRAM_ARB); + + if (st->shader_has_one_variant[MESA_SHADER_VERTEX] && + stvp->variants && + st_common_variant(stvp->variants)->key.passthrough_edgeflags == st->vertdata_edgeflags && + !st_common_variant(stvp->variants)->key.is_draw_shader) { + st->vp_variant = st_common_variant(stvp->variants); + } else { + struct st_common_variant_key key; + + memset(&key, 0, sizeof(key)); + + key.st = st->has_shareable_shaders ? NULL : st; + + /* When this is true, we will add an extra input to the vertex + * shader translation (for edgeflags), an extra output with + * edgeflag semantics, and extend the vertex shader to pass through + * the input to the output. We'll need to use similar logic to set + * up the extra vertex_element input for edgeflags. + */ + key.passthrough_edgeflags = st->vertdata_edgeflags; + + key.clamp_color = st->clamp_vert_color_in_shader && + st->ctx->Light._ClampVertexColor && + (stvp->Base.info.outputs_written & + (VARYING_SLOT_COL0 | + VARYING_SLOT_COL1 | + VARYING_SLOT_BFC0 | + VARYING_SLOT_BFC1)); + + key.lower_depth_clamp = + !st->gp && !st->tep && + st->clamp_frag_depth_in_shader && + (st->ctx->Transform.DepthClampNear || + st->ctx->Transform.DepthClampFar); + + if (key.lower_depth_clamp) + key.clip_negative_one_to_one = + st->ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE; + + /* _NEW_POINT */ + key.lower_point_size = st->lower_point_size && + !st_point_size_per_vertex(st->ctx); + + /* _NEW_TRANSFORM */ + if (st->lower_ucp && st_user_clip_planes_enabled(st->ctx) && + !st->ctx->GeometryProgram._Current) + key.lower_ucp = st->ctx->Transform.ClipPlanesEnabled; + + st->vp_variant = st_get_vp_variant(st, stvp, &key); + } - st->vp_variant = st_get_vp_variant(st, stvp, &key); + st_reference_prog(st, &st->vp, stvp); - st_reference_vertprog(st, &st->vp, stvp); + cso_set_vertex_shader_handle(st->cso_context, + st->vp_variant->base.driver_shader); +} - cso_set_vertex_shader_handle(st->cso_context, - st->vp_variant->driver_shader); - st->vertex_result_to_slot = stvp->result_to_output; -} +static void * +st_update_common_program(struct st_context *st, struct gl_program *prog, + unsigned pipe_shader, struct st_program **dst) +{ + struct st_program *stp; + if (!prog) { + st_reference_prog(st, dst, NULL); + return NULL; + } -const struct st_tracked_state st_update_vp = { - "st_update_vp", /* name */ - { /* dirty */ - _NEW_POLYGON, /* mesa */ - ST_NEW_VERTEX_PROGRAM | ST_NEW_EDGEFLAGS_DATA /* st */ - }, - update_vp /* update */ -}; + stp = st_program(prog); + st_reference_prog(st, dst, stp); + if (st->shader_has_one_variant[prog->info.stage] && stp->variants) + return stp->variants->driver_shader; + struct st_common_variant_key key; -static void -update_gp( struct st_context *st ) -{ - struct st_geometry_program *stgp; - struct st_gp_variant_key key; + /* use memset, not an initializer to be sure all memory is zeroed */ + memset(&key, 0, sizeof(key)); - if (!st->ctx->GeometryProgram._Current) { - cso_set_geometry_shader_handle(st->cso_context, NULL); - return; + key.st = st->has_shareable_shaders ? NULL : st; + + if (pipe_shader == PIPE_SHADER_GEOMETRY || + pipe_shader == PIPE_SHADER_TESS_EVAL) { + key.clamp_color = st->clamp_vert_color_in_shader && + st->ctx->Light._ClampVertexColor && + (stp->Base.info.outputs_written & + (VARYING_SLOT_COL0 | + VARYING_SLOT_COL1 | + VARYING_SLOT_BFC0 | + VARYING_SLOT_BFC1)); + + key.lower_depth_clamp = + (pipe_shader == PIPE_SHADER_GEOMETRY || !st->gp) && + st->clamp_frag_depth_in_shader && + (st->ctx->Transform.DepthClampNear || + st->ctx->Transform.DepthClampFar); + + if (key.lower_depth_clamp) + key.clip_negative_one_to_one = + st->ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE; + + if (st->lower_ucp && st_user_clip_planes_enabled(st->ctx) && + pipe_shader == PIPE_SHADER_GEOMETRY) + key.lower_ucp = st->ctx->Transform.ClipPlanesEnabled; } - stgp = st_geometry_program(st->ctx->GeometryProgram._Current); - assert(stgp->Base.Base.Target == MESA_GEOMETRY_PROGRAM); + return st_get_common_variant(st, stp, &key)->driver_shader; +} - memset(&key, 0, sizeof(key)); - key.st = st; - st->gp_variant = st_get_gp_variant(st, stgp, &key); +void +st_update_gp(struct st_context *st) +{ + void *shader = st_update_common_program(st, + st->ctx->GeometryProgram._Current, + PIPE_SHADER_GEOMETRY, &st->gp); + cso_set_geometry_shader_handle(st->cso_context, shader); +} + + +void +st_update_tcp(struct st_context *st) +{ + void *shader = st_update_common_program(st, + st->ctx->TessCtrlProgram._Current, + PIPE_SHADER_TESS_CTRL, &st->tcp); + cso_set_tessctrl_shader_handle(st->cso_context, shader); +} - st_reference_geomprog(st, &st->gp, stgp); - cso_set_geometry_shader_handle(st->cso_context, - st->gp_variant->driver_shader); +void +st_update_tep(struct st_context *st) +{ + void *shader = st_update_common_program(st, + st->ctx->TessEvalProgram._Current, + PIPE_SHADER_TESS_EVAL, &st->tep); + cso_set_tesseval_shader_handle(st->cso_context, shader); } -const struct st_tracked_state st_update_gp = { - "st_update_gp", /* name */ - { /* dirty */ - 0, /* mesa */ - ST_NEW_GEOMETRY_PROGRAM /* st */ - }, - update_gp /* update */ -}; + +void +st_update_cp(struct st_context *st) +{ + void *shader = st_update_common_program(st, + st->ctx->ComputeProgram._Current, + PIPE_SHADER_COMPUTE, &st->cp); + cso_set_compute_shader_handle(st->cso_context, shader); +}