1/************************************************************************** 2 * 3 * Copyright 2003 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include <stdio.h> 30#include "main/glheader.h" 31#include "main/context.h" 32 33#include "pipe/p_defines.h" 34#include "st_context.h" 35#include "st_atom.h" 36#include "st_program.h" 37#include "st_manager.h" 38 39 40/* The list state update functions. */ 41static const struct st_tracked_state *atoms[] = 42{ 43#define ST_STATE(FLAG, st_update) &st_update, 44#include "st_atom_list.h" 45#undef ST_STATE 46}; 47 48 49void st_init_atoms( struct st_context *st ) 50{ 51 STATIC_ASSERT(ARRAY_SIZE(atoms) <= 64); 52} 53 54 55void st_destroy_atoms( struct st_context *st ) 56{ 57 /* no-op */ 58} 59 60 61/* Too complex to figure out, just check every time: 62 */ 63static void check_program_state( struct st_context *st ) 64{ 65 struct gl_context *ctx = st->ctx; 66 struct st_vertex_program *old_vp = st->vp; 67 struct st_tessctrl_program *old_tcp = st->tcp; 68 struct st_tesseval_program *old_tep = st->tep; 69 struct st_geometry_program *old_gp = st->gp; 70 struct st_fragment_program *old_fp = st->fp; 71 72 struct gl_program *new_vp = ctx->VertexProgram._Current; 73 struct gl_program *new_tcp = ctx->TessCtrlProgram._Current; 74 struct gl_program *new_tep = ctx->TessEvalProgram._Current; 75 struct gl_program *new_gp = ctx->GeometryProgram._Current; 76 struct gl_program *new_fp = ctx->FragmentProgram._Current; 77 uint64_t dirty = 0; 78 79 /* Flag states used by both new and old shaders to unbind shader resources 80 * properly when transitioning to shaders that don't use them. 81 */ 82 if (unlikely(new_vp != &old_vp->Base)) { 83 if (old_vp) 84 dirty |= old_vp->affected_states; 85 if (new_vp) 86 dirty |= ST_NEW_VERTEX_PROGRAM(st, st_vertex_program(new_vp)); 87 } 88 89 if (unlikely(new_tcp != &old_tcp->Base)) { 90 if (old_tcp) 91 dirty |= old_tcp->affected_states; 92 if (new_tcp) 93 dirty |= st_tessctrl_program(new_tcp)->affected_states; 94 } 95 96 if (unlikely(new_tep != &old_tep->Base)) { 97 if (old_tep) 98 dirty |= old_tep->affected_states; 99 if (new_tep) 100 dirty |= st_tesseval_program(new_tep)->affected_states; 101 } 102 103 if (unlikely(new_gp != &old_gp->Base)) { 104 if (old_gp) 105 dirty |= old_gp->affected_states; 106 if (new_gp) 107 dirty |= st_geometry_program(new_gp)->affected_states; 108 } 109 110 if (unlikely(new_fp != &old_fp->Base)) { 111 if (old_fp) 112 dirty |= old_fp->affected_states; 113 if (new_fp) 114 dirty |= st_fragment_program(new_fp)->affected_states; 115 } 116 117 st->dirty |= dirty; 118 st->gfx_shaders_may_be_dirty = false; 119} 120 121static void check_attrib_edgeflag(struct st_context *st) 122{ 123 const struct gl_vertex_array **arrays = st->ctx->Array._DrawArrays; 124 GLboolean vertdata_edgeflags, edgeflag_culls_prims, edgeflags_enabled; 125 struct gl_program *vp = st->ctx->VertexProgram._Current; 126 127 if (!arrays) 128 return; 129 130 edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL || 131 st->ctx->Polygon.BackMode != GL_FILL; 132 133 vertdata_edgeflags = edgeflags_enabled && 134 arrays[VERT_ATTRIB_EDGEFLAG]->StrideB != 0; 135 if (vertdata_edgeflags != st->vertdata_edgeflags) { 136 st->vertdata_edgeflags = vertdata_edgeflags; 137 if (vp) 138 st->dirty |= ST_NEW_VERTEX_PROGRAM(st, st_vertex_program(vp)); 139 } 140 141 edgeflag_culls_prims = edgeflags_enabled && !vertdata_edgeflags && 142 !st->ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0]; 143 if (edgeflag_culls_prims != st->edgeflag_culls_prims) { 144 st->edgeflag_culls_prims = edgeflag_culls_prims; 145 st->dirty |= ST_NEW_RASTERIZER; 146 } 147} 148 149 150/*********************************************************************** 151 * Update all derived state: 152 */ 153 154void st_validate_state( struct st_context *st, enum st_pipeline pipeline ) 155{ 156 struct gl_context *ctx = st->ctx; 157 uint64_t dirty, pipeline_mask; 158 uint32_t dirty_lo, dirty_hi; 159 160 /* Get Mesa driver state. 161 * 162 * Inactive states are shader states not used by shaders at the moment. 163 */ 164 st->dirty |= ctx->NewDriverState & st->active_states & ST_ALL_STATES_MASK; 165 ctx->NewDriverState = 0; 166 167 /* Get pipeline state. */ 168 switch (pipeline) { 169 case ST_PIPELINE_RENDER: 170 if (st->ctx->API == API_OPENGL_COMPAT) 171 check_attrib_edgeflag(st); 172 173 check_program_state(st); 174 st_manager_validate_framebuffers(st); 175 176 pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK; 177 break; 178 179 case ST_PIPELINE_COMPUTE: { 180 struct st_compute_program *old_cp = st->cp; 181 struct gl_program *new_cp = ctx->ComputeProgram._Current; 182 183 if (new_cp != &old_cp->Base) { 184 if (old_cp) 185 st->dirty |= old_cp->affected_states; 186 assert(new_cp); 187 st->dirty |= st_compute_program(new_cp)->affected_states; 188 } 189 190 st->compute_shader_may_be_dirty = false; 191 192 /* 193 * We add the ST_NEW_FB_STATE bit here as well, because glBindFramebuffer 194 * acts as a barrier that breaks feedback loops between the framebuffer 195 * and textures bound to the framebuffer, even when those textures are 196 * accessed by compute shaders; so we must inform the driver of new 197 * framebuffer state. 198 */ 199 pipeline_mask = ST_PIPELINE_COMPUTE_STATE_MASK | ST_NEW_FB_STATE; 200 break; 201 } 202 203 default: 204 unreachable("Invalid pipeline specified"); 205 } 206 207 dirty = st->dirty & pipeline_mask; 208 if (!dirty) 209 return; 210 211 dirty_lo = dirty; 212 dirty_hi = dirty >> 32; 213 214 /* Update states. 215 * 216 * Don't use u_bit_scan64, it may be slower on 32-bit. 217 */ 218 while (dirty_lo) 219 atoms[u_bit_scan(&dirty_lo)]->update(st); 220 while (dirty_hi) 221 atoms[32 + u_bit_scan(&dirty_hi)]->update(st); 222 223 /* Clear the render or compute state bits. */ 224 st->dirty &= ~pipeline_mask; 225} 226