nv50_vbo.c revision 80e9e1ee8172d1e5a81d702681897dddd9d815f1
1/* 2 * Copyright 2008 Ben Skeggs 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "pipe/p_context.h" 24#include "pipe/p_state.h" 25 26#include "nv50_context.h" 27 28static INLINE unsigned 29nv50_prim(unsigned mode) 30{ 31 switch (mode) { 32 case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS; 33 case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES; 34 case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP; 35 case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP; 36 case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES; 37 case PIPE_PRIM_TRIANGLE_STRIP: 38 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP; 39 case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN; 40 case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS; 41 case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP; 42 case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON; 43 default: 44 break; 45 } 46 47 NOUVEAU_ERR("invalid primitive type %d\n", mode); 48 return NV50TCL_VERTEX_BEGIN_POINTS; 49} 50 51boolean 52nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start, 53 unsigned count) 54{ 55 struct nv50_context *nv50 = nv50_context(pipe); 56 struct nouveau_channel *chan = nv50->screen->tesla->channel; 57 struct nouveau_grobj *tesla = nv50->screen->tesla; 58 59 nv50_state_validate(nv50); 60 61 BEGIN_RING(chan, tesla, 0x142c, 1); 62 OUT_RING (chan, 0); 63 BEGIN_RING(chan, tesla, 0x142c, 1); 64 OUT_RING (chan, 0); 65 BEGIN_RING(chan, tesla, 0x1440, 1); 66 OUT_RING (chan, 0); 67 BEGIN_RING(chan, tesla, 0x1334, 1); 68 OUT_RING (chan, 0); 69 70 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); 71 OUT_RING (chan, nv50_prim(mode)); 72 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2); 73 OUT_RING (chan, start); 74 OUT_RING (chan, count); 75 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); 76 OUT_RING (chan, 0); 77 78 pipe->flush(pipe, 0, NULL); 79 return TRUE; 80} 81 82static INLINE void 83nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map, 84 unsigned start, unsigned count) 85{ 86 struct nouveau_channel *chan = nv50->screen->tesla->channel; 87 struct nouveau_grobj *tesla = nv50->screen->tesla; 88 89 map += start; 90 91 if (count & 1) { 92 BEGIN_RING(chan, tesla, 0x15e8, 1); 93 OUT_RING (chan, map[0]); 94 map++; 95 count--; 96 } 97 98 while (count) { 99 unsigned nr = count > 2046 ? 2046 : count; 100 int i; 101 102 BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1); 103 for (i = 0; i < nr; i += 2) 104 OUT_RING (chan, (map[1] << 16) | map[0]); 105 106 count -= nr; 107 map += nr; 108 } 109} 110 111static INLINE void 112nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map, 113 unsigned start, unsigned count) 114{ 115 struct nouveau_channel *chan = nv50->screen->tesla->channel; 116 struct nouveau_grobj *tesla = nv50->screen->tesla; 117 118 map += start; 119 120 if (count & 1) { 121 BEGIN_RING(chan, tesla, 0x15e8, 1); 122 OUT_RING (chan, map[0]); 123 map++; 124 count--; 125 } 126 127 while (count) { 128 unsigned nr = count > 2046 ? 2046 : count; 129 int i; 130 131 BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1); 132 for (i = 0; i < nr; i += 2) 133 OUT_RING (chan, (map[1] << 16) | map[0]); 134 135 count -= nr; 136 map += nr; 137 } 138} 139 140static INLINE void 141nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint8_t *map, 142 unsigned start, unsigned count) 143{ 144 struct nouveau_channel *chan = nv50->screen->tesla->channel; 145 struct nouveau_grobj *tesla = nv50->screen->tesla; 146 147 map += start; 148 149 while (count) { 150 unsigned nr = count > 2047 ? 2047 : count; 151 152 BEGIN_RING(chan, tesla, 0x400015e8, nr); 153 OUT_RINGp (chan, map, nr); 154 155 count -= nr; 156 map += nr; 157 } 158} 159 160boolean 161nv50_draw_elements(struct pipe_context *pipe, 162 struct pipe_buffer *indexBuffer, unsigned indexSize, 163 unsigned mode, unsigned start, unsigned count) 164{ 165 struct nv50_context *nv50 = nv50_context(pipe); 166 struct nouveau_channel *chan = nv50->screen->tesla->channel; 167 struct nouveau_grobj *tesla = nv50->screen->tesla; 168 struct pipe_winsys *ws = pipe->winsys; 169 void *map = ws->buffer_map(ws, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ); 170 171 nv50_state_validate(nv50); 172 173 BEGIN_RING(chan, tesla, 0x142c, 1); 174 OUT_RING (chan, 0); 175 BEGIN_RING(chan, tesla, 0x142c, 1); 176 OUT_RING (chan, 0); 177 178 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); 179 OUT_RING (chan, nv50_prim(mode)); 180 switch (indexSize) { 181 case 1: 182 nv50_draw_elements_inline_u08(nv50, map, start, count); 183 break; 184 case 2: 185 nv50_draw_elements_inline_u16(nv50, map, start, count); 186 break; 187 case 4: 188 nv50_draw_elements_inline_u32(nv50, map, start, count); 189 break; 190 default: 191 assert(0); 192 } 193 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); 194 OUT_RING (chan, 0); 195 196 pipe->flush(pipe, 0, NULL); 197 return TRUE; 198} 199 200void 201nv50_vbo_validate(struct nv50_context *nv50) 202{ 203 struct nouveau_grobj *tesla = nv50->screen->tesla; 204 struct nouveau_stateobj *vtxbuf, *vtxfmt; 205 int i; 206 207 vtxbuf = so_new(nv50->vtxelt_nr * 4, nv50->vtxelt_nr * 2); 208 vtxfmt = so_new(nv50->vtxelt_nr + 1, 0); 209 so_method(vtxfmt, tesla, 0x1ac0, nv50->vtxelt_nr); 210 211 for (i = 0; i < nv50->vtxelt_nr; i++) { 212 struct pipe_vertex_element *ve = &nv50->vtxelt[i]; 213 struct pipe_vertex_buffer *vb = 214 &nv50->vtxbuf[ve->vertex_buffer_index]; 215 struct nouveau_bo *bo = nouveau_bo(vb->buffer); 216 217 switch (ve->src_format) { 218 case PIPE_FORMAT_R32G32B32A32_FLOAT: 219 so_data(vtxfmt, 0x7e080000 | i); 220 break; 221 case PIPE_FORMAT_R32G32B32_FLOAT: 222 so_data(vtxfmt, 0x7e100000 | i); 223 break; 224 case PIPE_FORMAT_R32G32_FLOAT: 225 so_data(vtxfmt, 0x7e200000 | i); 226 break; 227 case PIPE_FORMAT_R32_FLOAT: 228 so_data(vtxfmt, 0x7e900000 | i); 229 break; 230 case PIPE_FORMAT_R8G8B8A8_UNORM: 231 so_data(vtxfmt, 0x24500000 | i); 232 break; 233 default: 234 { 235 NOUVEAU_ERR("invalid vbo format %s\n", 236 pf_name(ve->src_format)); 237 assert(0); 238 return; 239 } 240 } 241 242 so_method(vtxbuf, tesla, 0x900 + (i * 16), 3); 243 so_data (vtxbuf, 0x20000000 | vb->stride); 244 so_reloc (vtxbuf, bo, vb->buffer_offset + 245 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | 246 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 247 so_reloc (vtxbuf, bo, vb->buffer_offset + 248 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | 249 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 250 } 251 252 so_ref (vtxfmt, &nv50->state.vtxfmt); 253 so_ref (vtxbuf, &nv50->state.vtxbuf); 254 so_ref (NULL, &vtxbuf); 255 so_ref (NULL, &vtxfmt); 256} 257 258