Add Intel i965G/Q DRI driver.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_exec_array.c
1 /**************************************************************************
2 *
3 * Copyright 2003 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 "glheader.h"
29 #include "context.h"
30 #include "state.h"
31 #include "api_validate.h"
32 #include "api_noop.h"
33 #include "dispatch.h"
34
35 #include "brw_attrib.h"
36 #include "brw_draw.h"
37 #include "brw_exec.h"
38 #include "brw_fallback.h"
39
40 static GLboolean enabled( const struct gl_client_array *array )
41 {
42 return array && array->Enabled;
43 }
44
45 static void merge_enabled_arrays( const struct gl_client_array *inputs[],
46 const struct gl_client_array *arrays[],
47 GLuint nr )
48 {
49 GLuint i;
50 for (i = 0; i < nr; i++)
51 if (!enabled(inputs[i]) && enabled(arrays[i]))
52 inputs[i] = arrays[i];
53 }
54
55
56 /* _NEW_PROGRAM, _NEW_CLIENT */
57 static void recalculate_inputs( struct brw_exec_context *exec )
58 {
59 if (exec->ctx->VertexProgram._Enabled) {
60 memcpy( exec->array.inputs,
61 exec->array.attrib_arrays,
62 sizeof(exec->array.inputs) );
63
64 merge_enabled_arrays( exec->array.inputs,
65 exec->array.legacy_arrays,
66 BRW_ATTRIB_MAX );
67 }
68 else {
69 memcpy( exec->array.inputs,
70 exec->array.legacy_arrays,
71 sizeof(exec->array.inputs) );
72 }
73
74 exec->array.recalculate_inputs = 0;
75 }
76
77
78 static GLuint get_max_index( GLuint count, GLuint type,
79 const GLvoid *indices )
80 {
81 GLint i;
82
83 /* Compute max element. This is only needed for upload of non-VBO,
84 * non-constant data elements.
85 *
86 * XXX: Postpone this calculation until it is known that it is
87 * needed. Otherwise could scan this pointlessly in the all-vbo
88 * case.
89 */
90 switch(type) {
91 case GL_UNSIGNED_INT: {
92 const GLuint *ui_indices = (const GLuint *)indices;
93 GLuint max_ui = 0;
94 for (i = 0; i < count; i++)
95 if (ui_indices[i] > max_ui)
96 max_ui = ui_indices[i];
97 return max_ui;
98 }
99 case GL_UNSIGNED_SHORT: {
100 const GLushort *us_indices = (const GLushort *)indices;
101 GLuint max_us = 0;
102 for (i = 0; i < count; i++)
103 if (us_indices[i] > max_us)
104 max_us = us_indices[i];
105 return max_us;
106 }
107 case GL_UNSIGNED_BYTE: {
108 const GLubyte *ub_indices = (const GLubyte *)indices;
109 GLuint max_ub = 0;
110 for (i = 0; i < count; i++)
111 if (ub_indices[i] > max_ub)
112 max_ub = ub_indices[i];
113 return max_ub;
114 }
115 default:
116 return 0;
117 }
118 }
119
120
121
122
123 /***********************************************************************
124 * API functions.
125 */
126
127 static void GLAPIENTRY
128 brw_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
129 {
130 GET_CURRENT_CONTEXT(ctx);
131 struct brw_exec_context *exec = IMM_CONTEXT(ctx)->exec;
132 struct brw_draw_prim prim[1];
133 GLboolean ok;
134
135 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
136 return;
137
138 FLUSH_CURRENT( ctx, 0 );
139
140 if (ctx->NewState)
141 _mesa_update_state( ctx );
142
143 /* Bind all inputs, derive varying and size information:
144 */
145 if (exec->array.recalculate_inputs)
146 recalculate_inputs( exec );
147
148 prim[0].begin = 1;
149 prim[0].end = 1;
150 prim[0].weak = 0;
151 prim[0].pad = 0;
152
153 if (exec->array.inputs[0]->BufferObj->Name) {
154 /* Use vertex attribute as a hint to tell us if we expect all
155 * arrays to be in VBO's and if so, don't worry about avoiding
156 * the upload of elements < start.
157 */
158 prim[0].mode = mode;
159 prim[0].start = start;
160 prim[0].count = count;
161 prim[0].indexed = 0;
162
163 ok = brw_draw_prims( ctx, exec->array.inputs, prim, 1, NULL, 0, start + count, 0 );
164 }
165 else {
166 /* If not using VBO's, we don't want to upload any more elements
167 * than necessary from the arrays as they will not be valid next
168 * time the application tries to draw with them.
169 */
170 prim[0].mode = mode;
171 prim[0].start = 0;
172 prim[0].count = count;
173 prim[0].indexed = 0;
174
175 ok = brw_draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count, 0 );
176 }
177
178 if (!ok) {
179 brw_fallback(ctx);
180 CALL_DrawArrays(ctx->Exec, ( mode, start, count ));
181 brw_unfallback(ctx);
182 }
183 }
184
185
186
187 static void GLAPIENTRY
188 brw_exec_DrawRangeElements(GLenum mode,
189 GLuint start, GLuint end,
190 GLsizei count, GLenum type, const GLvoid *indices)
191 {
192 GET_CURRENT_CONTEXT(ctx);
193 struct brw_exec_context *exec = IMM_CONTEXT(ctx)->exec;
194 struct brw_draw_index_buffer ib;
195 struct brw_draw_prim prim[1];
196
197 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices ))
198 return;
199
200 FLUSH_CURRENT( ctx, 0 );
201
202 if (ctx->NewState)
203 _mesa_update_state( ctx );
204
205 if (exec->array.recalculate_inputs)
206 recalculate_inputs( exec );
207
208 ib.count = count;
209 ib.type = type;
210 ib.obj = ctx->Array.ElementArrayBufferObj;
211 ib.ptr = indices;
212
213 if (ctx->Array.ElementArrayBufferObj->Name) {
214 /* Use the fact that indices are in a VBO as a hint that the
215 * program has put all the arrays in VBO's and we don't have to
216 * worry about performance implications of start > 0.
217 *
218 * XXX: consider passing start as min_index to draw_prims instead.
219 */
220 ib.rebase = 0;
221 }
222 else {
223 ib.rebase = start;
224 }
225
226 prim[0].begin = 1;
227 prim[0].end = 1;
228 prim[0].weak = 0;
229 prim[0].pad = 0;
230 prim[0].mode = mode;
231 prim[0].start = 0;
232 prim[0].count = count;
233 prim[0].indexed = 1;
234
235 if (!brw_draw_prims( ctx, exec->array.inputs, prim, 1, &ib, ib.rebase, end+1, 0 )) {
236 brw_fallback(ctx);
237 CALL_DrawRangeElements(ctx->Exec, (mode, start, end, count, type, indices));
238 brw_unfallback(ctx);
239 }
240 }
241
242
243 static void GLAPIENTRY
244 brw_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
245 {
246 GET_CURRENT_CONTEXT(ctx);
247 GLuint max_index;
248
249 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
250 return;
251
252 if (ctx->Array.ElementArrayBufferObj->Name) {
253 const GLvoid *map = ctx->Driver.MapBuffer(ctx,
254 GL_ELEMENT_ARRAY_BUFFER_ARB,
255 GL_DYNAMIC_READ_ARB,
256 ctx->Array.ElementArrayBufferObj);
257
258 max_index = get_max_index(count, type, ADD_POINTERS(map, indices));
259
260 ctx->Driver.UnmapBuffer(ctx,
261 GL_ELEMENT_ARRAY_BUFFER_ARB,
262 ctx->Array.ElementArrayBufferObj);
263 }
264 else {
265 max_index = get_max_index(count, type, indices);
266 }
267
268 brw_exec_DrawRangeElements(mode, 0, max_index, count, type, indices);
269 }
270
271
272 /***********************************************************************
273 * Initialization
274 */
275
276
277 static void init_legacy_arrays( GLcontext *ctx,
278 const struct gl_client_array *arrays[] )
279 {
280 struct gl_array_object *obj = ctx->Array.ArrayObj;
281 GLuint i;
282
283 memset(arrays, 0, sizeof(*arrays) * BRW_ATTRIB_MAX);
284
285 arrays[BRW_ATTRIB_POS] = &obj->Vertex;
286 arrays[BRW_ATTRIB_NORMAL] = &obj->Normal;
287 arrays[BRW_ATTRIB_COLOR0] = &obj->Color;
288 arrays[BRW_ATTRIB_COLOR1] = &obj->SecondaryColor;
289 arrays[BRW_ATTRIB_FOG] = &obj->FogCoord;
290
291 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
292 arrays[BRW_ATTRIB_TEX0 + i] = &obj->TexCoord[i];
293
294 arrays[BRW_ATTRIB_INDEX] = &obj->Index;
295 arrays[BRW_ATTRIB_EDGEFLAG] = &obj->EdgeFlag;
296 }
297
298
299 static void init_attrib_arrays( GLcontext *ctx,
300 const struct gl_client_array *arrays[] )
301 {
302 struct gl_array_object *obj = ctx->Array.ArrayObj;
303 GLuint i;
304
305 for (i = 0; i < BRW_ATTRIB_FIRST_MATERIAL; i++)
306 arrays[i] = &obj->VertexAttrib[i];
307 }
308
309
310
311
312 void brw_exec_array_init( struct brw_exec_context *exec )
313 {
314 GLcontext *ctx = exec->ctx;
315
316 init_legacy_arrays(ctx, exec->array.legacy_arrays);
317 init_attrib_arrays(ctx, exec->array.attrib_arrays);
318
319 #if 1
320 exec->vtxfmt.DrawArrays = brw_exec_DrawArrays;
321 exec->vtxfmt.DrawElements = brw_exec_DrawElements;
322 exec->vtxfmt.DrawRangeElements = brw_exec_DrawRangeElements;
323 #else
324 exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
325 exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
326 exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements;
327 #endif
328
329 exec->array.recalculate_inputs = 1;
330
331 exec->array.index_obj = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
332 }
333
334
335 void brw_exec_array_destroy( struct brw_exec_context *exec )
336 {
337 GLcontext *ctx = exec->ctx;
338
339 ctx->Driver.DeleteBuffer(ctx, exec->array.index_obj);
340 }