1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2003 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <stdio.h> 30bf215546Sopenharmony_ci#include "main/arrayobj.h" 31bf215546Sopenharmony_ci#include "main/glheader.h" 32bf215546Sopenharmony_ci#include "main/context.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "pipe/p_defines.h" 35bf215546Sopenharmony_ci#include "st_context.h" 36bf215546Sopenharmony_ci#include "st_atom.h" 37bf215546Sopenharmony_ci#include "st_program.h" 38bf215546Sopenharmony_ci#include "st_manager.h" 39bf215546Sopenharmony_ci#include "st_util.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include "util/u_cpu_detect.h" 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_citypedef void (*update_func_t)(struct st_context *st); 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci/* The list state update functions. */ 47bf215546Sopenharmony_cistatic update_func_t update_functions[ST_NUM_ATOMS]; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_cistatic void 50bf215546Sopenharmony_ciinit_atoms_once(void) 51bf215546Sopenharmony_ci{ 52bf215546Sopenharmony_ci#define ST_STATE(FLAG, st_update) update_functions[FLAG##_INDEX] = st_update; 53bf215546Sopenharmony_ci#include "st_atom_list.h" 54bf215546Sopenharmony_ci#undef ST_STATE 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci if (util_get_cpu_caps()->has_popcnt) 57bf215546Sopenharmony_ci update_functions[ST_NEW_VERTEX_ARRAYS_INDEX] = st_update_array_with_popcnt; 58bf215546Sopenharmony_ci} 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_civoid st_init_atoms( struct st_context *st ) 61bf215546Sopenharmony_ci{ 62bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(update_functions) <= 64); 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci static once_flag flag = ONCE_FLAG_INIT; 65bf215546Sopenharmony_ci call_once(&flag, init_atoms_once); 66bf215546Sopenharmony_ci} 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_civoid st_destroy_atoms( struct st_context *st ) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci /* no-op */ 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci/* Too complex to figure out, just check every time: 76bf215546Sopenharmony_ci */ 77bf215546Sopenharmony_cistatic void check_program_state( struct st_context *st ) 78bf215546Sopenharmony_ci{ 79bf215546Sopenharmony_ci struct gl_context *ctx = st->ctx; 80bf215546Sopenharmony_ci struct gl_program *old_vp = st->vp; 81bf215546Sopenharmony_ci struct gl_program *old_tcp = st->tcp; 82bf215546Sopenharmony_ci struct gl_program *old_tep = st->tep; 83bf215546Sopenharmony_ci struct gl_program *old_gp = st->gp; 84bf215546Sopenharmony_ci struct gl_program *old_fp = st->fp; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci struct gl_program *new_vp = ctx->VertexProgram._Current; 87bf215546Sopenharmony_ci struct gl_program *new_tcp = ctx->TessCtrlProgram._Current; 88bf215546Sopenharmony_ci struct gl_program *new_tep = ctx->TessEvalProgram._Current; 89bf215546Sopenharmony_ci struct gl_program *new_gp = ctx->GeometryProgram._Current; 90bf215546Sopenharmony_ci struct gl_program *new_fp = ctx->FragmentProgram._Current; 91bf215546Sopenharmony_ci uint64_t dirty = 0; 92bf215546Sopenharmony_ci unsigned num_viewports = 1; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci /* Flag states used by both new and old shaders to unbind shader resources 95bf215546Sopenharmony_ci * properly when transitioning to shaders that don't use them. 96bf215546Sopenharmony_ci */ 97bf215546Sopenharmony_ci if (unlikely(new_vp != old_vp)) { 98bf215546Sopenharmony_ci ctx->Array.NewVertexElements = true; 99bf215546Sopenharmony_ci if (old_vp) 100bf215546Sopenharmony_ci dirty |= old_vp->affected_states; 101bf215546Sopenharmony_ci if (new_vp) 102bf215546Sopenharmony_ci dirty |= ST_NEW_VERTEX_PROGRAM(st, new_vp); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (unlikely(new_tcp != old_tcp)) { 106bf215546Sopenharmony_ci if (old_tcp) 107bf215546Sopenharmony_ci dirty |= old_tcp->affected_states; 108bf215546Sopenharmony_ci if (new_tcp) 109bf215546Sopenharmony_ci dirty |= new_tcp->affected_states; 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci if (unlikely(new_tep != old_tep)) { 113bf215546Sopenharmony_ci if (old_tep) 114bf215546Sopenharmony_ci dirty |= old_tep->affected_states; 115bf215546Sopenharmony_ci if (new_tep) 116bf215546Sopenharmony_ci dirty |= new_tep->affected_states; 117bf215546Sopenharmony_ci } 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci if (unlikely(new_gp != old_gp)) { 120bf215546Sopenharmony_ci if (old_gp) 121bf215546Sopenharmony_ci dirty |= old_gp->affected_states; 122bf215546Sopenharmony_ci if (new_gp) 123bf215546Sopenharmony_ci dirty |= new_gp->affected_states; 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci if (unlikely(new_fp != old_fp)) { 127bf215546Sopenharmony_ci if (old_fp) 128bf215546Sopenharmony_ci dirty |= old_fp->affected_states; 129bf215546Sopenharmony_ci if (new_fp) 130bf215546Sopenharmony_ci dirty |= new_fp->affected_states; 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci /* Find out the number of viewports. This determines how many scissors 134bf215546Sopenharmony_ci * and viewport states we need to update. 135bf215546Sopenharmony_ci */ 136bf215546Sopenharmony_ci struct gl_program *last_prim_shader = new_gp ? new_gp : 137bf215546Sopenharmony_ci new_tep ? new_tep : new_vp; 138bf215546Sopenharmony_ci if (last_prim_shader && 139bf215546Sopenharmony_ci last_prim_shader->info.outputs_written & ( 140bf215546Sopenharmony_ci VARYING_BIT_VIEWPORT | VARYING_BIT_VIEWPORT_MASK)) 141bf215546Sopenharmony_ci num_viewports = ctx->Const.MaxViewports; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci if (st->state.num_viewports != num_viewports) { 144bf215546Sopenharmony_ci st->state.num_viewports = num_viewports; 145bf215546Sopenharmony_ci dirty |= ST_NEW_VIEWPORT; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (ctx->Scissor.EnableFlags & u_bit_consecutive(0, num_viewports)) 148bf215546Sopenharmony_ci dirty |= ST_NEW_SCISSOR; 149bf215546Sopenharmony_ci } 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (st->lower_point_size && st->ctx->LastVertexStageDirty && 152bf215546Sopenharmony_ci !st->ctx->VertexProgram.PointSizeEnabled && !st->ctx->PointSizeIsSet) { 153bf215546Sopenharmony_ci if (new_gp) { 154bf215546Sopenharmony_ci st->dirty |= ST_NEW_GS_CONSTANTS; 155bf215546Sopenharmony_ci } else if (new_tep) { 156bf215546Sopenharmony_ci st->dirty |= ST_NEW_TES_CONSTANTS; 157bf215546Sopenharmony_ci } else { 158bf215546Sopenharmony_ci st->dirty |= ST_NEW_VS_CONSTANTS; 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci st->ctx->LastVertexStageDirty = false; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci st->dirty |= dirty; 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_civoid st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags) 167bf215546Sopenharmony_ci{ 168bf215546Sopenharmony_ci bool edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL || 169bf215546Sopenharmony_ci st->ctx->Polygon.BackMode != GL_FILL; 170bf215546Sopenharmony_ci bool vertdata_edgeflags = edgeflags_enabled && per_vertex_edgeflags; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci if (vertdata_edgeflags != st->vertdata_edgeflags) { 173bf215546Sopenharmony_ci st->vertdata_edgeflags = vertdata_edgeflags; 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci struct gl_program *vp = st->ctx->VertexProgram._Current; 176bf215546Sopenharmony_ci if (vp) 177bf215546Sopenharmony_ci st->dirty |= ST_NEW_VERTEX_PROGRAM(st, vp); 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci bool edgeflag_culls_prims = edgeflags_enabled && !vertdata_edgeflags && 181bf215546Sopenharmony_ci !st->ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0]; 182bf215546Sopenharmony_ci if (edgeflag_culls_prims != st->edgeflag_culls_prims) { 183bf215546Sopenharmony_ci st->edgeflag_culls_prims = edgeflag_culls_prims; 184bf215546Sopenharmony_ci st->dirty |= ST_NEW_RASTERIZER; 185bf215546Sopenharmony_ci } 186bf215546Sopenharmony_ci} 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_cistatic void check_attrib_edgeflag(struct st_context *st) 189bf215546Sopenharmony_ci{ 190bf215546Sopenharmony_ci st_update_edgeflags(st, _mesa_draw_edge_flag_array_enabled(st->ctx)); 191bf215546Sopenharmony_ci} 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci/*********************************************************************** 194bf215546Sopenharmony_ci * Update all derived state: 195bf215546Sopenharmony_ci */ 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_civoid st_validate_state( struct st_context *st, enum st_pipeline pipeline ) 198bf215546Sopenharmony_ci{ 199bf215546Sopenharmony_ci struct gl_context *ctx = st->ctx; 200bf215546Sopenharmony_ci uint64_t dirty, pipeline_mask; 201bf215546Sopenharmony_ci uint32_t dirty_lo, dirty_hi; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci /* Get Mesa driver state. 204bf215546Sopenharmony_ci * 205bf215546Sopenharmony_ci * Inactive states are shader states not used by shaders at the moment. 206bf215546Sopenharmony_ci */ 207bf215546Sopenharmony_ci st->dirty |= ctx->NewDriverState & st->active_states & ST_ALL_STATES_MASK; 208bf215546Sopenharmony_ci ctx->NewDriverState &= ~st->dirty; 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci /* Get pipeline state. */ 211bf215546Sopenharmony_ci switch (pipeline) { 212bf215546Sopenharmony_ci case ST_PIPELINE_RENDER: 213bf215546Sopenharmony_ci case ST_PIPELINE_RENDER_NO_VARRAYS: 214bf215546Sopenharmony_ci if (st->ctx->API == API_OPENGL_COMPAT) 215bf215546Sopenharmony_ci check_attrib_edgeflag(st); 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci if (st->gfx_shaders_may_be_dirty) { 218bf215546Sopenharmony_ci check_program_state(st); 219bf215546Sopenharmony_ci st->gfx_shaders_may_be_dirty = false; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci st_manager_validate_framebuffers(st); 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci if (pipeline == ST_PIPELINE_RENDER) 225bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK; 226bf215546Sopenharmony_ci else 227bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK_NO_VARRAYS; 228bf215546Sopenharmony_ci break; 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci case ST_PIPELINE_CLEAR: 231bf215546Sopenharmony_ci st_manager_validate_framebuffers(st); 232bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_CLEAR_STATE_MASK; 233bf215546Sopenharmony_ci break; 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci case ST_PIPELINE_META: 236bf215546Sopenharmony_ci if (st->gfx_shaders_may_be_dirty) { 237bf215546Sopenharmony_ci check_program_state(st); 238bf215546Sopenharmony_ci st->gfx_shaders_may_be_dirty = false; 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci st_manager_validate_framebuffers(st); 242bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_META_STATE_MASK; 243bf215546Sopenharmony_ci break; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci case ST_PIPELINE_UPDATE_FRAMEBUFFER: 246bf215546Sopenharmony_ci st_manager_validate_framebuffers(st); 247bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_UPDATE_FB_STATE_MASK; 248bf215546Sopenharmony_ci break; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci case ST_PIPELINE_COMPUTE: { 251bf215546Sopenharmony_ci struct gl_program *old_cp = st->cp; 252bf215546Sopenharmony_ci struct gl_program *new_cp = ctx->ComputeProgram._Current; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci if (new_cp != old_cp) { 255bf215546Sopenharmony_ci if (old_cp) 256bf215546Sopenharmony_ci st->dirty |= old_cp->affected_states; 257bf215546Sopenharmony_ci assert(new_cp); 258bf215546Sopenharmony_ci st->dirty |= new_cp->affected_states; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci st->compute_shader_may_be_dirty = false; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci /* 264bf215546Sopenharmony_ci * We add the ST_NEW_FB_STATE bit here as well, because glBindFramebuffer 265bf215546Sopenharmony_ci * acts as a barrier that breaks feedback loops between the framebuffer 266bf215546Sopenharmony_ci * and textures bound to the framebuffer, even when those textures are 267bf215546Sopenharmony_ci * accessed by compute shaders; so we must inform the driver of new 268bf215546Sopenharmony_ci * framebuffer state. 269bf215546Sopenharmony_ci */ 270bf215546Sopenharmony_ci pipeline_mask = ST_PIPELINE_COMPUTE_STATE_MASK | ST_NEW_FB_STATE; 271bf215546Sopenharmony_ci break; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci default: 275bf215546Sopenharmony_ci unreachable("Invalid pipeline specified"); 276bf215546Sopenharmony_ci } 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci dirty = st->dirty & pipeline_mask; 279bf215546Sopenharmony_ci if (!dirty) 280bf215546Sopenharmony_ci return; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci dirty_lo = dirty; 283bf215546Sopenharmony_ci dirty_hi = dirty >> 32; 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci /* Update states. 286bf215546Sopenharmony_ci * 287bf215546Sopenharmony_ci * Don't use u_bit_scan64, it may be slower on 32-bit. 288bf215546Sopenharmony_ci */ 289bf215546Sopenharmony_ci while (dirty_lo) 290bf215546Sopenharmony_ci update_functions[u_bit_scan(&dirty_lo)](st); 291bf215546Sopenharmony_ci while (dirty_hi) 292bf215546Sopenharmony_ci update_functions[32 + u_bit_scan(&dirty_hi)](st); 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci /* Clear the render or compute state bits. */ 295bf215546Sopenharmony_ci st->dirty &= ~pipeline_mask; 296bf215546Sopenharmony_ci} 297