r300_render.c revision 1ef0341ea7ee08284ebafe4f347643e1190d5777
1/* 2 * Copyright 2009 Corbin Simpson <MostAwesomeDude@gmail.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22 23/* r300_render: Vertex and index buffer primitive emission. Contains both 24 * HW TCL fastpath rendering, and SW TCL Draw-assisted rendering. */ 25 26#include "draw/draw_context.h" 27#include "draw/draw_vbuf.h" 28 29#include "pipe/p_inlines.h" 30 31#include "util/u_memory.h" 32#include "util/u_prim.h" 33 34#include "r300_vbo.h" 35#include "r300_cs.h" 36#include "r300_context.h" 37#include "r300_emit.h" 38#include "r300_reg.h" 39#include "r300_render.h" 40#include "r300_state_derived.h" 41 42/* r300_render: Vertex and index buffer primitive emission. */ 43#define R300_MAX_VBO_SIZE (1024 * 1024) 44 45uint32_t r300_translate_primitive(unsigned prim) 46{ 47 switch (prim) { 48 case PIPE_PRIM_POINTS: 49 return R300_VAP_VF_CNTL__PRIM_POINTS; 50 case PIPE_PRIM_LINES: 51 return R300_VAP_VF_CNTL__PRIM_LINES; 52 case PIPE_PRIM_LINE_LOOP: 53 return R300_VAP_VF_CNTL__PRIM_LINE_LOOP; 54 case PIPE_PRIM_LINE_STRIP: 55 return R300_VAP_VF_CNTL__PRIM_LINE_STRIP; 56 case PIPE_PRIM_TRIANGLES: 57 return R300_VAP_VF_CNTL__PRIM_TRIANGLES; 58 case PIPE_PRIM_TRIANGLE_STRIP: 59 return R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP; 60 case PIPE_PRIM_TRIANGLE_FAN: 61 return R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN; 62 case PIPE_PRIM_QUADS: 63 return R300_VAP_VF_CNTL__PRIM_QUADS; 64 case PIPE_PRIM_QUAD_STRIP: 65 return R300_VAP_VF_CNTL__PRIM_QUAD_STRIP; 66 case PIPE_PRIM_POLYGON: 67 return R300_VAP_VF_CNTL__PRIM_POLYGON; 68 default: 69 return 0; 70 } 71} 72 73static boolean setup_vertex_buffers(struct r300_context *r300) 74{ 75 unsigned vbuf_count = r300->aos_count; 76 struct pipe_vertex_buffer *vbuf= r300->vertex_buffer; 77 struct pipe_vertex_element *velem= r300->vertex_element; 78 bool invalid = false; 79 80validate: 81 for (int i = 0; i < vbuf_count; i++) { 82 if (!r300->winsys->add_buffer(r300->winsys, vbuf[velem[i].vertex_buffer_index].buffer, 83 RADEON_GEM_DOMAIN_GTT, 0)) { 84 r300->context.flush(&r300->context, 0, NULL); 85 goto validate; 86 } 87 } 88 89 if (!r300->winsys->validate(r300->winsys)) { 90 r300->context.flush(&r300->context, 0, NULL); 91 if (invalid) { 92 /* Well, hell. */ 93 debug_printf("r300: Stuck in validation loop, gonna quit now."); 94 exit(1); 95 } 96 invalid = true; 97 goto validate; 98 } 99 100 return invalid; 101} 102 103/* This is the fast-path drawing & emission for HW TCL. */ 104boolean r300_draw_range_elements(struct pipe_context* pipe, 105 struct pipe_buffer* indexBuffer, 106 unsigned indexSize, 107 unsigned minIndex, 108 unsigned maxIndex, 109 unsigned mode, 110 unsigned start, 111 unsigned count) 112{ 113 struct r300_context* r300 = r300_context(pipe); 114 115 if (!u_trim_pipe_prim(mode, &count)) 116 return false; 117 118 r300_update_derived_state(r300); 119 120 setup_vertex_buffers(r300); 121 122 setup_vertex_attributes(r300); 123 124 setup_index_buffer(r300, indexBuffer, indexSize); 125 126 r300->hw_prim = r300_translate_primitive(mode); 127 128 r300_emit_dirty_state(r300); 129 130 r300_emit_aos(r300, 0); 131 132 r300_emit_draw_elements(r300, indexBuffer, indexSize, minIndex, maxIndex, 133 start, count); 134 135 return TRUE; 136} 137 138/* Simple helpers for context setup. Should probably be moved to util. */ 139boolean r300_draw_elements(struct pipe_context* pipe, 140 struct pipe_buffer* indexBuffer, 141 unsigned indexSize, unsigned mode, 142 unsigned start, unsigned count) 143{ 144 return pipe->draw_range_elements(pipe, indexBuffer, indexSize, 0, ~0, 145 mode, start, count); 146} 147 148boolean r300_draw_arrays(struct pipe_context* pipe, unsigned mode, 149 unsigned start, unsigned count) 150{ 151 struct r300_context* r300 = r300_context(pipe); 152 153 if (!u_trim_pipe_prim(mode, &count)) 154 return false; 155 156 r300_update_derived_state(r300); 157 158 setup_vertex_buffers(r300); 159 160 setup_vertex_attributes(r300); 161 162 r300->hw_prim = r300_translate_primitive(mode); 163 164 r300_emit_dirty_state(r300); 165 166 r300_emit_aos(r300, start); 167 168 r300_emit_draw_arrays(r300, count); 169 170 return TRUE; 171} 172 173/**************************************************************************** 174 * The rest of this file is for SW TCL rendering only. Please be polite and * 175 * keep these functions separated so that they are easier to locate. ~C. * 176 ***************************************************************************/ 177 178/* Draw-based drawing for SW TCL chipsets. */ 179boolean r300_swtcl_draw_range_elements(struct pipe_context* pipe, 180 struct pipe_buffer* indexBuffer, 181 unsigned indexSize, 182 unsigned minIndex, 183 unsigned maxIndex, 184 unsigned mode, 185 unsigned start, 186 unsigned count) 187{ 188 assert(0); 189 struct r300_context* r300 = r300_context(pipe); 190#if 0 191 int i; 192 193 if (!u_trim_pipe_prim(mode, &count)) { 194 return FALSE; 195 } 196 197 for (i = 0; i < r300->vertex_buffer_count; i++) { 198 void* buf = pipe_buffer_map(pipe->screen, 199 r300->vertex_buffers[i].buffer, 200 PIPE_BUFFER_USAGE_CPU_READ); 201 draw_set_mapped_vertex_buffer(r300->draw, i, buf); 202 } 203 204 if (indexBuffer) { 205 void* indices = pipe_buffer_map(pipe->screen, indexBuffer, 206 PIPE_BUFFER_USAGE_CPU_READ); 207 draw_set_mapped_element_buffer_range(r300->draw, indexSize, 208 minIndex, maxIndex, indices); 209 } else { 210 draw_set_mapped_element_buffer(r300->draw, 0, NULL); 211 } 212 213 draw_set_mapped_constant_buffer(r300->draw, 214 r300->shader_constants[PIPE_SHADER_VERTEX].constants, 215 r300->shader_constants[PIPE_SHADER_VERTEX].count * 216 (sizeof(float) * 4)); 217 218 draw_arrays(r300->draw, mode, start, count); 219 220 for (i = 0; i < r300->vertex_buffer_count; i++) { 221 pipe_buffer_unmap(pipe->screen, r300->vertex_buffers[i].buffer); 222 draw_set_mapped_vertex_buffer(r300->draw, i, NULL); 223 } 224 225 if (indexBuffer) { 226 pipe_buffer_unmap(pipe->screen, indexBuffer); 227 draw_set_mapped_element_buffer_range(r300->draw, 0, start, 228 start + count - 1, NULL); 229 } 230#endif 231 return TRUE; 232} 233 234/* Object for rendering using Draw. */ 235struct r300_render { 236 /* Parent class */ 237 struct vbuf_render base; 238 239 /* Pipe context */ 240 struct r300_context* r300; 241 242 /* Vertex information */ 243 size_t vertex_size; 244 unsigned prim; 245 unsigned hwprim; 246 247 /* VBO */ 248 struct pipe_buffer* vbo; 249 size_t vbo_size; 250 size_t vbo_offset; 251 size_t vbo_max_used; 252 void * vbo_ptr; 253}; 254 255static INLINE struct r300_render* 256r300_render(struct vbuf_render* render) 257{ 258 return (struct r300_render*)render; 259} 260 261static const struct vertex_info* 262r300_render_get_vertex_info(struct vbuf_render* render) 263{ 264 struct r300_render* r300render = r300_render(render); 265 struct r300_context* r300 = r300render->r300; 266 267 r300_update_derived_state(r300); 268 269 return &r300->vertex_info->vinfo; 270} 271 272static boolean r300_render_allocate_vertices(struct vbuf_render* render, 273 ushort vertex_size, 274 ushort count) 275{ 276 struct r300_render* r300render = r300_render(render); 277 struct r300_context* r300 = r300render->r300; 278 struct pipe_screen* screen = r300->context.screen; 279 size_t size = (size_t)vertex_size * (size_t)count; 280 281 if (size + r300render->vbo_offset > r300render->vbo_size) 282 { 283 pipe_buffer_reference(&r300->vbo, NULL); 284 r300render->vbo = pipe_buffer_create(screen, 285 64, 286 PIPE_BUFFER_USAGE_VERTEX, 287 R300_MAX_VBO_SIZE); 288 r300render->vbo_offset = 0; 289 r300render->vbo_size = R300_MAX_VBO_SIZE; 290 } 291 292 r300render->vertex_size = vertex_size; 293 r300->vbo = r300render->vbo; 294 r300->vbo_offset = r300render->vbo_offset; 295 296 return (r300render->vbo) ? TRUE : FALSE; 297} 298 299static void* r300_render_map_vertices(struct vbuf_render* render) 300{ 301 struct r300_render* r300render = r300_render(render); 302 struct pipe_screen* screen = r300render->r300->context.screen; 303 304 r300render->vbo_ptr = pipe_buffer_map(screen, r300render->vbo, 305 PIPE_BUFFER_USAGE_CPU_WRITE); 306 307 return (r300render->vbo_ptr + r300render->vbo_offset); 308} 309 310static void r300_render_unmap_vertices(struct vbuf_render* render, 311 ushort min, 312 ushort max) 313{ 314 struct r300_render* r300render = r300_render(render); 315 struct pipe_screen* screen = r300render->r300->context.screen; 316 CS_LOCALS(r300render->r300); 317 BEGIN_CS(2); 318 OUT_CS_REG(R300_VAP_VF_MAX_VTX_INDX, max); 319 END_CS; 320 321 r300render->vbo_max_used = MAX2(r300render->vbo_max_used, 322 r300render->vertex_size * (max + 1)); 323 pipe_buffer_unmap(screen, r300render->vbo); 324} 325 326static void r300_render_release_vertices(struct vbuf_render* render) 327{ 328 struct r300_render* r300render = r300_render(render); 329 330 r300render->vbo_offset += r300render->vbo_max_used; 331 r300render->vbo_max_used = 0; 332} 333 334static boolean r300_render_set_primitive(struct vbuf_render* render, 335 unsigned prim) 336{ 337 struct r300_render* r300render = r300_render(render); 338 339 r300render->prim = prim; 340 r300render->hwprim = r300_translate_primitive(prim); 341 342 return TRUE; 343} 344 345static void r300_render_draw_arrays(struct vbuf_render* render, 346 unsigned start, 347 unsigned count) 348{ 349 struct r300_render* r300render = r300_render(render); 350 struct r300_context* r300 = r300render->r300; 351 352 CS_LOCALS(r300); 353 354 r300_emit_dirty_state(r300); 355 356 DBG(r300, DBG_DRAW, "r300: Doing vbuf render, count %d\n", count); 357 358 BEGIN_CS(2); 359 OUT_CS_PKT3(R300_PACKET3_3D_DRAW_VBUF_2, 0); 360 OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST | (count << 16) | 361 r300render->hwprim); 362 END_CS; 363} 364 365static void r300_render_draw(struct vbuf_render* render, 366 const ushort* indices, 367 uint count) 368{ 369 struct r300_render* r300render = r300_render(render); 370 struct r300_context* r300 = r300render->r300; 371 int i; 372 373 CS_LOCALS(r300); 374 375 r300_emit_dirty_state(r300); 376 377 BEGIN_CS(2 + (count+1)/2); 378 OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, (count+1)/2); 379 OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) | 380 r300render->hwprim); 381 for (i = 0; i < count-1; i += 2) { 382 OUT_CS(indices[i+1] << 16 | indices[i]); 383 } 384 if (count % 2) { 385 OUT_CS(indices[count-1]); 386 } 387 END_CS; 388} 389 390static void r300_render_destroy(struct vbuf_render* render) 391{ 392 FREE(render); 393} 394 395static struct vbuf_render* r300_render_create(struct r300_context* r300) 396{ 397 struct r300_render* r300render = CALLOC_STRUCT(r300_render); 398 399 r300render->r300 = r300; 400 401 /* XXX find real numbers plz */ 402 r300render->base.max_vertex_buffer_bytes = 128 * 1024; 403 r300render->base.max_indices = 16 * 1024; 404 405 r300render->base.get_vertex_info = r300_render_get_vertex_info; 406 r300render->base.allocate_vertices = r300_render_allocate_vertices; 407 r300render->base.map_vertices = r300_render_map_vertices; 408 r300render->base.unmap_vertices = r300_render_unmap_vertices; 409 r300render->base.set_primitive = r300_render_set_primitive; 410 r300render->base.draw = r300_render_draw; 411 r300render->base.draw_arrays = r300_render_draw_arrays; 412 r300render->base.release_vertices = r300_render_release_vertices; 413 r300render->base.destroy = r300_render_destroy; 414 415 r300render->vbo = NULL; 416 r300render->vbo_size = 0; 417 r300render->vbo_offset = 0; 418 419 return &r300render->base; 420} 421 422struct draw_stage* r300_draw_stage(struct r300_context* r300) 423{ 424 struct vbuf_render* render; 425 struct draw_stage* stage; 426 427 render = r300_render_create(r300); 428 429 if (!render) { 430 return NULL; 431 } 432 433 stage = draw_vbuf_stage(r300->draw, render); 434 435 if (!stage) { 436 render->destroy(render); 437 return NULL; 438 } 439 440 draw_set_render(r300->draw, render); 441 442 return stage; 443} 444