1/************************************************************************** 2 * 3 * Copyright 2007 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 * Authors: 30 * Keith Whitwell <keithw@vmware.com> 31 * Brian Paul 32 */ 33 34#include "util/u_math.h" 35#include "util/u_memory.h" 36 37#include "pipe/p_shader_tokens.h" 38#include "pipe/p_context.h" 39#include "pipe/p_screen.h" 40 41#include "draw_private.h" 42#include "draw_context.h" 43#include "draw_vs.h" 44 45#include "translate/translate.h" 46#include "translate/translate_cache.h" 47 48#include "tgsi/tgsi_dump.h" 49#include "tgsi/tgsi_exec.h" 50 51#include "nir/nir_to_tgsi.h" 52 53DEBUG_GET_ONCE_BOOL_OPTION(gallium_dump_vs, "GALLIUM_DUMP_VS", FALSE) 54 55 56struct draw_vertex_shader * 57draw_create_vertex_shader(struct draw_context *draw, 58 const struct pipe_shader_state *shader) 59{ 60 struct draw_vertex_shader *vs = NULL; 61 struct pipe_shader_state state = *shader; 62 63 if (draw->dump_vs) { 64 tgsi_dump(shader->tokens, 0); 65 } 66 67#ifdef DRAW_LLVM_AVAILABLE 68 if (draw->pt.middle.llvm) { 69 struct pipe_screen *screen = draw->pipe->screen; 70 if (shader->type == PIPE_SHADER_IR_NIR && 71 ((!screen->get_shader_param(screen, PIPE_SHADER_VERTEX, 72 PIPE_SHADER_CAP_INTEGERS)) || 73 (screen->get_shader_param(screen, PIPE_SHADER_VERTEX, 74 PIPE_SHADER_CAP_PREFERRED_IR) == 75 PIPE_SHADER_IR_TGSI))) { 76 state.type = PIPE_SHADER_IR_TGSI; 77 state.tokens = nir_to_tgsi(shader->ir.nir, screen); 78 } 79 vs = draw_create_vs_llvm(draw, &state); 80 } 81#endif 82 83 if (!vs) { 84 vs = draw_create_vs_exec( draw, &state ); 85 } 86 87 if (vs) 88 { 89 uint i; 90 bool found_clipvertex = FALSE; 91 vs->position_output = -1; 92 for (i = 0; i < vs->info.num_outputs; i++) { 93 if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION && 94 vs->info.output_semantic_index[i] == 0) 95 vs->position_output = i; 96 else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_EDGEFLAG && 97 vs->info.output_semantic_index[i] == 0) 98 vs->edgeflag_output = i; 99 else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPVERTEX && 100 vs->info.output_semantic_index[i] == 0) { 101 found_clipvertex = TRUE; 102 vs->clipvertex_output = i; 103 } else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX) 104 vs->viewport_index_output = i; 105 else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) { 106 assert(vs->info.output_semantic_index[i] < 107 PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT); 108 vs->ccdistance_output[vs->info.output_semantic_index[i]] = i; 109 } 110 } 111 if (!found_clipvertex) 112 vs->clipvertex_output = vs->position_output; 113 } 114 115 assert(vs); 116 return vs; 117} 118 119 120void 121draw_bind_vertex_shader(struct draw_context *draw, 122 struct draw_vertex_shader *dvs) 123{ 124 draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE ); 125 126 if (dvs) 127 { 128 draw->vs.vertex_shader = dvs; 129 draw->vs.num_vs_outputs = dvs->info.num_outputs; 130 draw->vs.position_output = dvs->position_output; 131 draw->vs.edgeflag_output = dvs->edgeflag_output; 132 draw->vs.clipvertex_output = dvs->clipvertex_output; 133 draw->vs.ccdistance_output[0] = dvs->ccdistance_output[0]; 134 draw->vs.ccdistance_output[1] = dvs->ccdistance_output[1]; 135 dvs->prepare( dvs, draw ); 136 draw_update_clip_flags(draw); 137 draw_update_viewport_flags(draw); 138 } 139 else { 140 draw->vs.vertex_shader = NULL; 141 draw->vs.num_vs_outputs = 0; 142 } 143} 144 145 146void 147draw_delete_vertex_shader(struct draw_context *draw, 148 struct draw_vertex_shader *dvs) 149{ 150 unsigned i; 151 152 for (i = 0; i < dvs->nr_variants; i++) 153 dvs->variant[i]->destroy( dvs->variant[i] ); 154 155 dvs->nr_variants = 0; 156 157 dvs->delete( dvs ); 158} 159 160 161 162boolean 163draw_vs_init( struct draw_context *draw ) 164{ 165 draw->dump_vs = debug_get_option_gallium_dump_vs(); 166 167 if (!draw->llvm) { 168 draw->vs.tgsi.machine = tgsi_exec_machine_create(PIPE_SHADER_VERTEX); 169 if (!draw->vs.tgsi.machine) 170 return FALSE; 171 } 172 173 draw->vs.emit_cache = translate_cache_create(); 174 if (!draw->vs.emit_cache) 175 return FALSE; 176 177 draw->vs.fetch_cache = translate_cache_create(); 178 if (!draw->vs.fetch_cache) 179 return FALSE; 180 181 return TRUE; 182} 183 184void 185draw_vs_destroy( struct draw_context *draw ) 186{ 187 if (draw->vs.fetch_cache) 188 translate_cache_destroy(draw->vs.fetch_cache); 189 190 if (draw->vs.emit_cache) 191 translate_cache_destroy(draw->vs.emit_cache); 192 193 if (!draw->llvm) 194 tgsi_exec_machine_destroy(draw->vs.tgsi.machine); 195} 196 197 198struct draw_vs_variant * 199draw_vs_lookup_variant( struct draw_vertex_shader *vs, 200 const struct draw_vs_variant_key *key ) 201{ 202 struct draw_vs_variant *variant; 203 unsigned i; 204 205 /* Lookup existing variant: 206 */ 207 for (i = 0; i < vs->nr_variants; i++) 208 if (draw_vs_variant_key_compare(key, &vs->variant[i]->key) == 0) 209 return vs->variant[i]; 210 211 /* Else have to create a new one: 212 */ 213 variant = vs->create_variant( vs, key ); 214 if (!variant) 215 return NULL; 216 217 /* Add it to our list, could be smarter: 218 */ 219 if (vs->nr_variants < ARRAY_SIZE(vs->variant)) { 220 vs->variant[vs->nr_variants++] = variant; 221 } 222 else { 223 vs->last_variant++; 224 vs->last_variant %= ARRAY_SIZE(vs->variant); 225 vs->variant[vs->last_variant]->destroy(vs->variant[vs->last_variant]); 226 vs->variant[vs->last_variant] = variant; 227 } 228 229 /* Done 230 */ 231 return variant; 232} 233 234 235struct translate * 236draw_vs_get_fetch( struct draw_context *draw, 237 struct translate_key *key ) 238{ 239 if (!draw->vs.fetch || 240 translate_key_compare(&draw->vs.fetch->key, key) != 0) 241 { 242 translate_key_sanitize(key); 243 draw->vs.fetch = translate_cache_find(draw->vs.fetch_cache, key); 244 } 245 246 return draw->vs.fetch; 247} 248 249struct translate * 250draw_vs_get_emit( struct draw_context *draw, 251 struct translate_key *key ) 252{ 253 if (!draw->vs.emit || 254 translate_key_compare(&draw->vs.emit->key, key) != 0) 255 { 256 translate_key_sanitize(key); 257 draw->vs.emit = translate_cache_find(draw->vs.emit_cache, key); 258 } 259 260 return draw->vs.emit; 261} 262 263void 264draw_vs_attach_so(struct draw_vertex_shader *dvs, 265 const struct pipe_stream_output_info *info) 266{ 267 dvs->state.stream_output = *info; 268} 269 270void 271draw_vs_reset_so(struct draw_vertex_shader *dvs) 272{ 273 memset(&dvs->state.stream_output, 0, sizeof(dvs->state.stream_output)); 274} 275