1 /********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26 #include "draw/draw_vbuf.h" 27 #include "draw/draw_context.h" 28 #include "draw/draw_vertex.h" 29 30 #include "util/u_debug.h" 31 #include "util/u_inlines.h" 32 #include "util/u_math.h" 33 #include "util/u_memory.h" 34 35 #include "svga_context.h" 36 #include "svga_state.h" 37 #include "svga_swtnl.h" 38 39 #include "svga_types.h" 40 #include "svga_reg.h" 41 #include "svga3d_reg.h" 42 #include "svga_draw.h" 43 #include "svga_swtnl_private.h" 44 45 46 static const struct vertex_info * 47 svga_vbuf_render_get_vertex_info( struct vbuf_render *render ) 48 { 49 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 50 struct svga_context *svga = svga_render->svga; 51 52 svga_swtnl_update_vdecl(svga); 53 54 return &svga_render->vertex_info; 55 } 56 57 58 static boolean 59 svga_vbuf_render_allocate_vertices( struct vbuf_render *render, 60 ushort vertex_size, 61 ushort nr_vertices ) 62 { 63 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 64 struct svga_context *svga = svga_render->svga; 65 struct pipe_screen *screen = svga->pipe.screen; 66 size_t size = (size_t)nr_vertices * (size_t)vertex_size; 67 boolean new_vbuf = FALSE; 68 boolean new_ibuf = FALSE; 69 70 if (svga_render->vertex_size != vertex_size) 71 svga->swtnl.new_vdecl = TRUE; 72 svga_render->vertex_size = (size_t)vertex_size; 73 74 if (svga->swtnl.new_vbuf) 75 new_ibuf = new_vbuf = TRUE; 76 svga->swtnl.new_vbuf = FALSE; 77 78 if (svga_render->vbuf_size < svga_render->vbuf_offset + svga_render->vbuf_used + size) 79 new_vbuf = TRUE; 80 81 if (new_vbuf) 82 pipe_resource_reference(&svga_render->vbuf, NULL); 83 if (new_ibuf) 84 pipe_resource_reference(&svga_render->ibuf, NULL); 85 86 if (!svga_render->vbuf) { 87 svga_render->vbuf_size = MAX2(size, svga_render->vbuf_alloc_size); 88 svga_render->vbuf = pipe_buffer_create(screen, 89 PIPE_BIND_VERTEX_BUFFER, 90 PIPE_USAGE_STREAM, 91 svga_render->vbuf_size); 92 if(!svga_render->vbuf) { 93 svga_context_flush(svga, NULL); 94 assert(!svga_render->vbuf); 95 svga_render->vbuf = pipe_buffer_create(screen, 96 PIPE_BIND_VERTEX_BUFFER, 97 PIPE_USAGE_STREAM, 98 svga_render->vbuf_size); 99 /* The buffer allocation may fail if we run out of memory. 100 * The draw module's vbuf code should handle that without crashing. 101 */ 102 } 103 104 svga->swtnl.new_vdecl = TRUE; 105 svga_render->vbuf_offset = 0; 106 } else { 107 svga_render->vbuf_offset += svga_render->vbuf_used; 108 } 109 110 svga_render->vbuf_used = 0; 111 112 if (svga->swtnl.new_vdecl) 113 svga_render->vdecl_offset = svga_render->vbuf_offset; 114 115 return TRUE; 116 } 117 118 static void * 119 svga_vbuf_render_map_vertices( struct vbuf_render *render ) 120 { 121 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 122 struct svga_context *svga = svga_render->svga; 123 124 if (svga_render->vbuf) { 125 char *ptr = (char*)pipe_buffer_map(&svga->pipe, 126 svga_render->vbuf, 127 PIPE_TRANSFER_WRITE | 128 PIPE_TRANSFER_FLUSH_EXPLICIT | 129 PIPE_TRANSFER_DISCARD_RANGE | 130 PIPE_TRANSFER_UNSYNCHRONIZED, 131 &svga_render->vbuf_transfer); 132 if (ptr) 133 return ptr + svga_render->vbuf_offset; 134 else 135 return NULL; 136 } 137 else { 138 /* we probably ran out of memory when allocating the vertex buffer */ 139 return NULL; 140 } 141 } 142 143 static void 144 svga_vbuf_render_unmap_vertices( struct vbuf_render *render, 145 ushort min_index, 146 ushort max_index ) 147 { 148 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 149 struct svga_context *svga = svga_render->svga; 150 unsigned offset, length; 151 size_t used = svga_render->vertex_size * ((size_t)max_index + 1); 152 153 offset = svga_render->vbuf_offset + svga_render->vertex_size * min_index; 154 length = svga_render->vertex_size * (max_index + 1 - min_index); 155 pipe_buffer_flush_mapped_range(&svga->pipe, 156 svga_render->vbuf_transfer, 157 offset, length); 158 pipe_buffer_unmap(&svga->pipe, svga_render->vbuf_transfer); 159 svga_render->min_index = min_index; 160 svga_render->max_index = max_index; 161 svga_render->vbuf_used = MAX2(svga_render->vbuf_used, used); 162 } 163 164 static void 165 svga_vbuf_render_set_primitive( struct vbuf_render *render, 166 unsigned prim ) 167 { 168 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 169 svga_render->prim = prim; 170 } 171 172 static void 173 svga_vbuf_submit_state( struct svga_vbuf_render *svga_render ) 174 { 175 struct svga_context *svga = svga_render->svga; 176 SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS]; 177 enum pipe_error ret; 178 int i; 179 180 /* if the vdecl or vbuf hasn't changed do nothing */ 181 if (!svga->swtnl.new_vdecl) 182 return; 183 184 memcpy(vdecl, svga_render->vdecl, sizeof(vdecl)); 185 186 /* flush the hw state */ 187 ret = svga_hwtnl_flush(svga->hwtnl); 188 if (ret != PIPE_OK) { 189 svga_context_flush(svga, NULL); 190 ret = svga_hwtnl_flush(svga->hwtnl); 191 /* if we hit this path we might become synced with hw */ 192 svga->swtnl.new_vbuf = TRUE; 193 assert(ret == 0); 194 } 195 196 svga_hwtnl_reset_vdecl(svga->hwtnl, svga_render->vdecl_count); 197 198 for (i = 0; i < svga_render->vdecl_count; i++) { 199 vdecl[i].array.offset += svga_render->vdecl_offset; 200 201 svga_hwtnl_vdecl( svga->hwtnl, 202 i, 203 &vdecl[i], 204 svga_render->vbuf ); 205 } 206 207 /* We have already taken care of flatshading, so let the hwtnl 208 * module use whatever is most convenient: 209 */ 210 if (svga->state.sw.need_pipeline) { 211 svga_hwtnl_set_flatshade(svga->hwtnl, FALSE, FALSE); 212 svga_hwtnl_set_unfilled(svga->hwtnl, PIPE_POLYGON_MODE_FILL); 213 } 214 else { 215 svga_hwtnl_set_flatshade( svga->hwtnl, 216 svga->curr.rast->templ.flatshade, 217 svga->curr.rast->templ.flatshade_first ); 218 219 svga_hwtnl_set_unfilled( svga->hwtnl, 220 svga->curr.rast->hw_unfilled ); 221 } 222 223 svga->swtnl.new_vdecl = FALSE; 224 } 225 226 static void 227 svga_vbuf_render_draw_arrays( struct vbuf_render *render, 228 unsigned start, 229 uint nr ) 230 { 231 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 232 struct svga_context *svga = svga_render->svga; 233 unsigned bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size; 234 enum pipe_error ret = PIPE_OK; 235 236 /* off to hardware */ 237 svga_vbuf_submit_state(svga_render); 238 239 /* Need to call update_state() again as the draw module may have 240 * altered some of our state behind our backs. Testcase: 241 * redbook/polys.c 242 */ 243 svga_update_state_retry( svga, SVGA_STATE_HW_DRAW ); 244 245 ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr); 246 if (ret != PIPE_OK) { 247 svga_context_flush(svga, NULL); 248 ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr); 249 svga->swtnl.new_vbuf = TRUE; 250 assert(ret == PIPE_OK); 251 } 252 } 253 254 255 static void 256 svga_vbuf_render_draw_elements( struct vbuf_render *render, 257 const ushort *indices, 258 uint nr_indices) 259 { 260 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 261 struct svga_context *svga = svga_render->svga; 262 struct pipe_screen *screen = svga->pipe.screen; 263 int bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size; 264 boolean ret; 265 size_t size = 2 * nr_indices; 266 267 assert(( svga_render->vbuf_offset - svga_render->vdecl_offset) % svga_render->vertex_size == 0); 268 269 if (svga_render->ibuf_size < svga_render->ibuf_offset + size) 270 pipe_resource_reference(&svga_render->ibuf, NULL); 271 272 if (!svga_render->ibuf) { 273 svga_render->ibuf_size = MAX2(size, svga_render->ibuf_alloc_size); 274 svga_render->ibuf = pipe_buffer_create(screen, 275 PIPE_BIND_INDEX_BUFFER, 276 PIPE_USAGE_STREAM, 277 svga_render->ibuf_size); 278 svga_render->ibuf_offset = 0; 279 } 280 281 pipe_buffer_write_nooverlap(&svga->pipe, svga_render->ibuf, 282 svga_render->ibuf_offset, 2 * nr_indices, indices); 283 284 /* off to hardware */ 285 svga_vbuf_submit_state(svga_render); 286 287 /* Need to call update_state() again as the draw module may have 288 * altered some of our state behind our backs. Testcase: 289 * redbook/polys.c 290 */ 291 svga_update_state_retry( svga, SVGA_STATE_HW_DRAW ); 292 293 ret = svga_hwtnl_draw_range_elements(svga->hwtnl, 294 svga_render->ibuf, 295 2, 296 bias, 297 svga_render->min_index, 298 svga_render->max_index, 299 svga_render->prim, 300 svga_render->ibuf_offset / 2, nr_indices); 301 if(ret != PIPE_OK) { 302 svga_context_flush(svga, NULL); 303 ret = svga_hwtnl_draw_range_elements(svga->hwtnl, 304 svga_render->ibuf, 305 2, 306 bias, 307 svga_render->min_index, 308 svga_render->max_index, 309 svga_render->prim, 310 svga_render->ibuf_offset / 2, nr_indices); 311 svga->swtnl.new_vbuf = TRUE; 312 assert(ret == PIPE_OK); 313 } 314 315 svga_render->ibuf_offset += size; 316 } 317 318 319 static void 320 svga_vbuf_render_release_vertices( struct vbuf_render *render ) 321 { 322 323 } 324 325 326 static void 327 svga_vbuf_render_destroy( struct vbuf_render *render ) 328 { 329 struct svga_vbuf_render *svga_render = svga_vbuf_render(render); 330 331 pipe_resource_reference(&svga_render->vbuf, NULL); 332 pipe_resource_reference(&svga_render->ibuf, NULL); 333 FREE(svga_render); 334 } 335 336 337 /** 338 * Create a new primitive render. 339 */ 340 struct vbuf_render * 341 svga_vbuf_render_create( struct svga_context *svga ) 342 { 343 struct svga_vbuf_render *svga_render = CALLOC_STRUCT(svga_vbuf_render); 344 345 svga_render->svga = svga; 346 svga_render->ibuf_size = 0; 347 svga_render->vbuf_size = 0; 348 svga_render->ibuf_alloc_size = 4*1024; 349 svga_render->vbuf_alloc_size = 64*1024; 350 svga_render->base.max_vertex_buffer_bytes = 64*1024/10; 351 svga_render->base.max_indices = 65536; 352 svga_render->base.get_vertex_info = svga_vbuf_render_get_vertex_info; 353 svga_render->base.allocate_vertices = svga_vbuf_render_allocate_vertices; 354 svga_render->base.map_vertices = svga_vbuf_render_map_vertices; 355 svga_render->base.unmap_vertices = svga_vbuf_render_unmap_vertices; 356 svga_render->base.set_primitive = svga_vbuf_render_set_primitive; 357 svga_render->base.draw_elements = svga_vbuf_render_draw_elements; 358 svga_render->base.draw_arrays = svga_vbuf_render_draw_arrays; 359 svga_render->base.release_vertices = svga_vbuf_render_release_vertices; 360 svga_render->base.destroy = svga_vbuf_render_destroy; 361 362 return &svga_render->base; 363 } 364