1/************************************************************************** 2 * 3 * Copyright 2010 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#include "draw/draw_private.h" 29#include "draw/draw_vs.h" 30#include "draw/draw_gs.h" 31#include "draw/draw_context.h" 32#include "draw/draw_vbuf.h" 33#include "draw/draw_vertex.h" 34#include "draw/draw_pt.h" 35 36#include "pipe/p_state.h" 37 38#include "util/u_math.h" 39#include "util/u_memory.h" 40 41struct pt_so_emit { 42 struct draw_context *draw; 43 44 unsigned input_vertex_stride; 45 const float (*inputs)[4]; 46 const float *pre_clip_pos; 47 boolean has_so; 48 boolean use_pre_clip_pos; 49 int pos_idx; 50 unsigned emitted_primitives; 51 unsigned generated_primitives; 52 unsigned stream; 53}; 54 55static const struct pipe_stream_output_info * 56draw_so_info(const struct draw_context *draw) 57{ 58 const struct pipe_stream_output_info *state = NULL; 59 60 if (draw->gs.geometry_shader) { 61 state = &draw->gs.geometry_shader->state.stream_output; 62 } else { 63 state = &draw->vs.vertex_shader->state.stream_output; 64 } 65 66 return state; 67} 68 69static inline boolean 70draw_has_so(const struct draw_context *draw) 71{ 72 const struct pipe_stream_output_info *state = draw_so_info(draw); 73 74 if (state && state->num_outputs > 0) 75 return TRUE; 76 77 return FALSE; 78} 79 80void draw_pt_so_emit_prepare(struct pt_so_emit *emit, boolean use_pre_clip_pos) 81{ 82 struct draw_context *draw = emit->draw; 83 84 emit->use_pre_clip_pos = use_pre_clip_pos; 85 emit->has_so = draw_has_so(draw); 86 if (use_pre_clip_pos) 87 emit->pos_idx = draw_current_shader_position_output(draw); 88 89 /* if we have a state with outputs make sure we have 90 * buffers to output to */ 91 if (emit->has_so) { 92 boolean has_valid_buffer = FALSE; 93 unsigned i; 94 for (i = 0; i < draw->so.num_targets; ++i) { 95 if (draw->so.targets[i]) { 96 has_valid_buffer = TRUE; 97 break; 98 } 99 } 100 emit->has_so = has_valid_buffer; 101 } 102 103 if (!emit->has_so) 104 return; 105 106 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 107 */ 108 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 109} 110 111static void so_emit_prim(struct pt_so_emit *so, 112 unsigned *indices, 113 unsigned num_vertices) 114{ 115 unsigned slot, i; 116 unsigned input_vertex_stride = so->input_vertex_stride; 117 struct draw_context *draw = so->draw; 118 const float (*input_ptr)[4]; 119 const float *pcp_ptr = NULL; 120 const struct pipe_stream_output_info *state = draw_so_info(draw); 121 float *buffer; 122 int buffer_total_bytes[PIPE_MAX_SO_BUFFERS]; 123 boolean buffer_written[PIPE_MAX_SO_BUFFERS] = {0}; 124 125 input_ptr = so->inputs; 126 if (so->use_pre_clip_pos) 127 pcp_ptr = so->pre_clip_pos; 128 129 ++so->generated_primitives; 130 131 for (i = 0; i < draw->so.num_targets; i++) { 132 struct draw_so_target *target = draw->so.targets[i]; 133 if (target) { 134 buffer_total_bytes[i] = target->internal_offset; 135 } else { 136 buffer_total_bytes[i] = 0; 137 } 138 } 139 140 /* check have we space to emit prim first - if not don't do anything */ 141 for (i = 0; i < num_vertices; ++i) { 142 unsigned ob; 143 for (slot = 0; slot < state->num_outputs; ++slot) { 144 unsigned num_comps = state->output[slot].num_components; 145 int ob = state->output[slot].output_buffer; 146 unsigned dst_offset = state->output[slot].dst_offset * sizeof(float); 147 unsigned write_size = num_comps * sizeof(float); 148 149 if (state->output[slot].stream != so->stream) 150 continue; 151 /* If a buffer is missing then that's equivalent to 152 * an overflow */ 153 if (!draw->so.targets[ob]) { 154 return; 155 } 156 if ((buffer_total_bytes[ob] + write_size + dst_offset) > 157 draw->so.targets[ob]->target.buffer_size) { 158 return; 159 } 160 } 161 for (ob = 0; ob < draw->so.num_targets; ++ob) { 162 buffer_total_bytes[ob] += state->stride[ob] * sizeof(float); 163 } 164 } 165 166 for (i = 0; i < num_vertices; ++i) { 167 const float (*input)[4]; 168 const float *pre_clip_pos = NULL; 169 unsigned ob; 170 171 input = (const float (*)[4])( 172 (const char *)input_ptr + (indices[i] * input_vertex_stride)); 173 174 if (pcp_ptr) 175 pre_clip_pos = (const float *)( 176 (const char *)pcp_ptr + (indices[i] * input_vertex_stride)); 177 178 for (slot = 0; slot < state->num_outputs; ++slot) { 179 unsigned idx = state->output[slot].register_index; 180 unsigned start_comp = state->output[slot].start_component; 181 unsigned num_comps = state->output[slot].num_components; 182 unsigned stream = state->output[slot].stream; 183 184 if (stream != so->stream) 185 continue; 186 ob = state->output[slot].output_buffer; 187 buffer_written[ob] = TRUE; 188 189 buffer = (float *)((char *)draw->so.targets[ob]->mapping + 190 draw->so.targets[ob]->target.buffer_offset + 191 draw->so.targets[ob]->internal_offset) + 192 state->output[slot].dst_offset; 193 194 if (idx == so->pos_idx && pcp_ptr && so->stream == 0) 195 memcpy(buffer, &pre_clip_pos[start_comp], 196 num_comps * sizeof(float)); 197 else 198 memcpy(buffer, &input[idx][start_comp], 199 num_comps * sizeof(float)); 200#if 0 201 { 202 int j; 203 debug_printf("VERT[%d], stream = %d, offset = %d, slot[%d] sc = %d, num_c = %d, idx = %d = [", 204 i, stream, 205 draw->so.targets[ob]->internal_offset, 206 slot, start_comp, num_comps, idx); 207 for (j = 0; j < num_comps; ++j) { 208 unsigned *ubuffer = (unsigned*)buffer; 209 debug_printf("%d (0x%x), ", ubuffer[j], ubuffer[j]); 210 } 211 debug_printf("]\n"); 212 } 213#endif 214 } 215 for (ob = 0; ob < draw->so.num_targets; ++ob) { 216 struct draw_so_target *target = draw->so.targets[ob]; 217 if (target && buffer_written[ob]) { 218 target->internal_offset += state->stride[ob] * sizeof(float); 219 } 220 } 221 } 222 ++so->emitted_primitives; 223} 224 225static void so_point(struct pt_so_emit *so, int idx) 226{ 227 unsigned indices[1]; 228 229 indices[0] = idx; 230 231 so_emit_prim(so, indices, 1); 232} 233 234static void so_line(struct pt_so_emit *so, int i0, int i1) 235{ 236 unsigned indices[2]; 237 238 indices[0] = i0; 239 indices[1] = i1; 240 241 so_emit_prim(so, indices, 2); 242} 243 244static void so_tri(struct pt_so_emit *so, int i0, int i1, int i2) 245{ 246 unsigned indices[3]; 247 248 indices[0] = i0; 249 indices[1] = i1; 250 indices[2] = i2; 251 252 so_emit_prim(so, indices, 3); 253} 254 255 256#define FUNC so_run_linear 257#define GET_ELT(idx) (start + (idx)) 258#include "draw_so_emit_tmp.h" 259 260 261#define FUNC so_run_elts 262#define LOCAL_VARS const ushort *elts = input_prims->elts; 263#define GET_ELT(idx) (elts[start + (idx)]) 264#include "draw_so_emit_tmp.h" 265 266 267void draw_pt_so_emit( struct pt_so_emit *emit, 268 int num_vertex_streams, 269 const struct draw_vertex_info *input_verts, 270 const struct draw_prim_info *input_prims ) 271{ 272 struct draw_context *draw = emit->draw; 273 struct vbuf_render *render = draw->render; 274 unsigned start, i, stream; 275 276 if (!emit->has_so) 277 return; 278 279 if (!draw->so.num_targets) 280 return; 281 282 /* XXX: need to flush to get prim_vbuf.c to release its allocation??*/ 283 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 284 285 for (stream = 0; stream < num_vertex_streams; stream++) { 286 emit->emitted_primitives = 0; 287 emit->generated_primitives = 0; 288 if (emit->use_pre_clip_pos) 289 emit->pre_clip_pos = input_verts[stream].verts->clip_pos; 290 291 emit->input_vertex_stride = input_verts[stream].stride; 292 emit->inputs = (const float (*)[4])input_verts[stream].verts->data; 293 emit->stream = stream; 294 for (start = i = 0; i < input_prims[stream].primitive_count; 295 start += input_prims[stream].primitive_lengths[i], i++) 296 { 297 unsigned count = input_prims[stream].primitive_lengths[i]; 298 299 if (input_prims->linear) { 300 so_run_linear(emit, &input_prims[stream], &input_verts[stream], 301 start, count); 302 } else { 303 so_run_elts(emit, &input_prims[stream], &input_verts[stream], 304 start, count); 305 } 306 } 307 render->set_stream_output_info(render, 308 stream, 309 emit->emitted_primitives, 310 emit->generated_primitives); 311 } 312} 313 314 315struct pt_so_emit *draw_pt_so_emit_create( struct draw_context *draw ) 316{ 317 struct pt_so_emit *emit = CALLOC_STRUCT(pt_so_emit); 318 if (!emit) 319 return NULL; 320 321 emit->draw = draw; 322 323 return emit; 324} 325 326void draw_pt_so_emit_destroy( struct pt_so_emit *emit ) 327{ 328 FREE(emit); 329} 330