1 /* 2 * Copyright (C) 2009-2010 Francisco Jerez. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27 /* 28 * Vertex submission helper definitions shared among the software and 29 * hardware TnL paths. 30 */ 31 32 #include "nouveau_gldefs.h" 33 34 #include "main/light.h" 35 #include "vbo/vbo.h" 36 #include "tnl/tnl.h" 37 38 #define OUT_INDICES_L(r, i, d, n) \ 39 BATCH_OUT_L(i + d, n); \ 40 (void)r 41 #define OUT_INDICES_I16(r, i, d, n) \ 42 BATCH_OUT_I16(r->ib.extract_u(&r->ib, 0, i) + d, \ 43 r->ib.extract_u(&r->ib, 0, i + 1) + d) 44 #define OUT_INDICES_I32(r, i, d, n) \ 45 BATCH_OUT_I32(r->ib.extract_u(&r->ib, 0, i) + d) 46 47 /* 48 * Emit <n> vertices using BATCH_OUT_<out>, MAX_OUT_<out> at a time, 49 * grouping them in packets of length MAX_PACKET. 50 * 51 * out: hardware index data type. 52 * ctx: GL context. 53 * start: element within the index buffer to begin with. 54 * delta: integer correction that will be added to each index found in 55 * the index buffer. 56 */ 57 #define EMIT_VBO(out, ctx, start, delta, n) do { \ 58 struct nouveau_render_state *render = to_render_state(ctx); \ 59 int _npush = n; \ 60 \ 61 while (_npush) { \ 62 int _npack = MIN2(_npush, MAX_PACKET * MAX_OUT_##out); \ 63 _npush -= _npack; \ 64 \ 65 BATCH_PACKET_##out((_npack + MAX_OUT_##out - 1) \ 66 / MAX_OUT_##out); \ 67 while (_npack) { \ 68 int _nout = MIN2(_npack, MAX_OUT_##out);\ 69 _npack -= _nout; \ 70 \ 71 OUT_INDICES_##out(render, start, delta, \ 72 _nout); \ 73 start += _nout; \ 74 } \ 75 } \ 76 } while (0) 77 78 /* 79 * Emit the <n>-th element of the array <a>, using IMM_OUT. 80 */ 81 #define EMIT_IMM(ctx, a, n) do { \ 82 struct nouveau_attr_info *info = \ 83 &TAG(vertex_attrs)[(a)->attr]; \ 84 int m; \ 85 \ 86 if (!info->emit) { \ 87 IMM_PACKET(info->imm_method, info->imm_fields); \ 88 \ 89 for (m = 0; m < (a)->fields; m++) \ 90 IMM_OUT((a)->extract_f(a, n, m)); \ 91 \ 92 for (m = (a)->fields; m < info->imm_fields; m++) \ 93 IMM_OUT(((float []){0, 0, 0, 1})[m]); \ 94 \ 95 } else { \ 96 info->emit(ctx, a, (a)->buf + n * (a)->stride); \ 97 } \ 98 } while (0) 99 100 static void 101 dispatch_l(struct gl_context *ctx, unsigned int start, int delta, 102 unsigned int n) 103 { 104 struct nouveau_pushbuf *push = context_push(ctx); 105 RENDER_LOCALS(ctx); 106 107 EMIT_VBO(L, ctx, start, delta, n); 108 } 109 110 static void 111 dispatch_i32(struct gl_context *ctx, unsigned int start, int delta, 112 unsigned int n) 113 { 114 struct nouveau_pushbuf *push = context_push(ctx); 115 RENDER_LOCALS(ctx); 116 117 EMIT_VBO(I32, ctx, start, delta, n); 118 } 119 120 static void 121 dispatch_i16(struct gl_context *ctx, unsigned int start, int delta, 122 unsigned int n) 123 { 124 struct nouveau_pushbuf *push = context_push(ctx); 125 RENDER_LOCALS(ctx); 126 127 EMIT_VBO(I32, ctx, start, delta, n & 1); 128 EMIT_VBO(I16, ctx, start, delta, n & ~1); 129 } 130 131 /* 132 * Select an appropriate dispatch function for the given index buffer. 133 */ 134 static dispatch_t 135 get_array_dispatch(struct nouveau_array *a) 136 { 137 if (!a->fields) 138 return dispatch_l; 139 else if (a->type == GL_UNSIGNED_INT) 140 return dispatch_i32; 141 else 142 return dispatch_i16; 143 } 144 145 /* 146 * Returns how many vertices you can draw using <n> pushbuf dwords. 147 */ 148 static inline unsigned 149 get_max_vertices(struct gl_context *ctx, const struct _mesa_index_buffer *ib, 150 int n) 151 { 152 struct nouveau_render_state *render = to_render_state(ctx); 153 154 if (render->mode == IMM) { 155 return MAX2(0, n - 4) / (render->vertex_size / 4 + 156 render->attr_count); 157 } else { 158 unsigned max_out; 159 160 if (ib) { 161 switch (ib->index_size) { 162 case 4: 163 max_out = MAX_OUT_I32; 164 break; 165 166 case 2: 167 max_out = MAX_OUT_I16; 168 break; 169 170 case 1: 171 max_out = MAX_OUT_I16; 172 break; 173 174 default: 175 assert(0); 176 max_out = 0; 177 break; 178 } 179 } else { 180 max_out = MAX_OUT_L; 181 } 182 183 return MAX2(0, n - 7) * max_out * MAX_PACKET / (1 + MAX_PACKET); 184 } 185 } 186 187 static void 188 TAG(emit_material)(struct gl_context *ctx, struct nouveau_array *a, 189 const void *v) 190 { 191 int attr = a->attr - VERT_ATTRIB_GENERIC0; 192 int state = ((int []) { 193 NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT, 194 NOUVEAU_STATE_MATERIAL_BACK_AMBIENT, 195 NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE, 196 NOUVEAU_STATE_MATERIAL_BACK_DIFFUSE, 197 NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR, 198 NOUVEAU_STATE_MATERIAL_BACK_SPECULAR, 199 NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT, 200 NOUVEAU_STATE_MATERIAL_BACK_AMBIENT, 201 NOUVEAU_STATE_MATERIAL_FRONT_SHININESS, 202 NOUVEAU_STATE_MATERIAL_BACK_SHININESS 203 }) [attr]; 204 205 COPY_4V(ctx->Light.Material.Attrib[attr], (float *)v); 206 _mesa_update_material(ctx, 1 << attr); 207 208 context_drv(ctx)->emit[state](ctx, state); 209 } 210