1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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 "util/u_memory.h" 29 #include "draw/draw_context.h" 30 #include "draw/draw_private.h" 31 #include "draw/draw_vbuf.h" 32 #include "draw/draw_vertex.h" 33 #include "draw/draw_pt.h" 34 #include "translate/translate.h" 35 #include "translate/translate_cache.h" 36 37 struct pt_emit { 38 struct draw_context *draw; 39 40 struct translate *translate; 41 42 struct translate_cache *cache; 43 unsigned prim; 44 45 const struct vertex_info *vinfo; 46 }; 47 48 49 void 50 draw_pt_emit_prepare(struct pt_emit *emit, 51 unsigned prim, 52 unsigned *max_vertices) 53 { 54 struct draw_context *draw = emit->draw; 55 const struct vertex_info *vinfo; 56 unsigned dst_offset; 57 struct translate_key hw_key; 58 unsigned i; 59 60 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 61 */ 62 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 63 64 /* XXX: may need to defensively reset this later on as clipping can 65 * clobber this state in the render backend. 66 */ 67 emit->prim = prim; 68 69 draw->render->set_primitive(draw->render, emit->prim); 70 71 /* Must do this after set_primitive() above: 72 */ 73 emit->vinfo = vinfo = draw->render->get_vertex_info(draw->render); 74 75 /* Translate from pipeline vertices to hw vertices. 76 */ 77 dst_offset = 0; 78 for (i = 0; i < vinfo->num_attribs; i++) { 79 unsigned emit_sz = 0; 80 unsigned src_buffer = 0; 81 unsigned output_format; 82 unsigned src_offset = (vinfo->attrib[i].src_index * 4 * sizeof(float) ); 83 84 output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit); 85 emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit); 86 87 /* doesn't handle EMIT_OMIT */ 88 assert(emit_sz != 0); 89 90 if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) { 91 src_buffer = 1; 92 src_offset = 0; 93 } 94 95 hw_key.element[i].type = TRANSLATE_ELEMENT_NORMAL; 96 hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 97 hw_key.element[i].input_buffer = src_buffer; 98 hw_key.element[i].input_offset = src_offset; 99 hw_key.element[i].instance_divisor = 0; 100 hw_key.element[i].output_format = output_format; 101 hw_key.element[i].output_offset = dst_offset; 102 103 dst_offset += emit_sz; 104 } 105 106 hw_key.nr_elements = vinfo->num_attribs; 107 hw_key.output_stride = vinfo->size * 4; 108 109 if (!emit->translate || 110 translate_key_compare(&emit->translate->key, &hw_key) != 0) { 111 translate_key_sanitize(&hw_key); 112 emit->translate = translate_cache_find(emit->cache, &hw_key); 113 } 114 115 *max_vertices = (draw->render->max_vertex_buffer_bytes / 116 (vinfo->size * 4)); 117 } 118 119 120 void 121 draw_pt_emit(struct pt_emit *emit, 122 const struct draw_vertex_info *vert_info, 123 const struct draw_prim_info *prim_info) 124 { 125 const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data; 126 unsigned vertex_count = vert_info->count; 127 unsigned stride = vert_info->stride; 128 const ushort *elts = prim_info->elts; 129 struct draw_context *draw = emit->draw; 130 struct translate *translate = emit->translate; 131 struct vbuf_render *render = draw->render; 132 unsigned start, i; 133 void *hw_verts; 134 135 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 136 */ 137 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 138 139 if (vertex_count == 0) 140 return; 141 142 /* XXX: and work out some way to coordinate the render primitive 143 * between vbuf.c and here... 144 */ 145 draw->render->set_primitive(draw->render, emit->prim); 146 147 render->allocate_vertices(render, 148 (ushort)translate->key.output_stride, 149 (ushort)vertex_count); 150 151 hw_verts = render->map_vertices( render ); 152 if (!hw_verts) { 153 debug_warn_once("map of vertex buffer failed (out of memory?)"); 154 return; 155 } 156 157 translate->set_buffer(translate, 158 0, 159 vertex_data, 160 stride, 161 ~0); 162 163 translate->set_buffer(translate, 164 1, 165 &draw->rasterizer->point_size, 166 0, 167 ~0); 168 169 /* fetch/translate vertex attribs to fill hw_verts[] */ 170 translate->run(translate, 171 0, 172 vertex_count, 173 draw->instance_id, 174 hw_verts ); 175 176 render->unmap_vertices(render, 0, vertex_count - 1); 177 178 for (start = i = 0; 179 i < prim_info->primitive_count; 180 start += prim_info->primitive_lengths[i], i++) 181 { 182 render->draw_elements(render, 183 elts + start, 184 prim_info->primitive_lengths[i]); 185 } 186 187 render->release_vertices(render); 188 } 189 190 191 void 192 draw_pt_emit_linear(struct pt_emit *emit, 193 const struct draw_vertex_info *vert_info, 194 const struct draw_prim_info *prim_info) 195 { 196 const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data; 197 unsigned stride = vert_info->stride; 198 unsigned count = vert_info->count; 199 struct draw_context *draw = emit->draw; 200 struct translate *translate = emit->translate; 201 struct vbuf_render *render = draw->render; 202 void *hw_verts; 203 unsigned start, i; 204 205 #if 0 206 debug_printf("Linear emit\n"); 207 #endif 208 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 209 */ 210 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 211 212 /* XXX: and work out some way to coordinate the render primitive 213 * between vbuf.c and here... 214 */ 215 draw->render->set_primitive(draw->render, emit->prim); 216 217 if (!render->allocate_vertices(render, 218 (ushort)translate->key.output_stride, 219 (ushort)count)) 220 goto fail; 221 222 hw_verts = render->map_vertices( render ); 223 if (!hw_verts) 224 goto fail; 225 226 translate->set_buffer(translate, 0, 227 vertex_data, stride, count - 1); 228 229 translate->set_buffer(translate, 1, 230 &draw->rasterizer->point_size, 231 0, ~0); 232 233 translate->run(translate, 234 0, 235 count, 236 draw->instance_id, 237 hw_verts); 238 239 if (0) { 240 unsigned i; 241 for (i = 0; i < count; i++) { 242 debug_printf("\n\n%s vertex %d:\n", __FUNCTION__, i); 243 draw_dump_emitted_vertex( emit->vinfo, 244 (const uint8_t *)hw_verts + 245 translate->key.output_stride * i ); 246 } 247 } 248 249 render->unmap_vertices( render, 0, count - 1 ); 250 251 for (start = i = 0; 252 i < prim_info->primitive_count; 253 start += prim_info->primitive_lengths[i], i++) 254 { 255 render->draw_arrays(render, 256 start, 257 prim_info->primitive_lengths[i]); 258 } 259 260 render->release_vertices(render); 261 262 return; 263 264 fail: 265 debug_warn_once("allocate or map of vertex buffer failed (out of memory?)"); 266 return; 267 } 268 269 270 struct pt_emit * 271 draw_pt_emit_create(struct draw_context *draw) 272 { 273 struct pt_emit *emit = CALLOC_STRUCT(pt_emit); 274 if (!emit) 275 return NULL; 276 277 emit->draw = draw; 278 emit->cache = translate_cache_create(); 279 if (!emit->cache) { 280 FREE(emit); 281 return NULL; 282 } 283 284 return emit; 285 } 286 287 288 void 289 draw_pt_emit_destroy(struct pt_emit *emit) 290 { 291 if (emit->cache) 292 translate_cache_destroy(emit->cache); 293 294 FREE(emit); 295 } 296