Merge branch 'origin'
[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 GLuint get_max_index( GLuint count, GLuint type,
41 const GLvoid *indices )
42 {
43 GLint i;
44
45 /* Compute max element. This is only needed for upload of non-VBO,
46 * non-constant data elements.
47 *
48 * XXX: Postpone this calculation until it is known that it is
49 * needed. Otherwise could scan this pointlessly in the all-vbo
50 * case.
51 */
52 switch(type) {
53 case GL_UNSIGNED_INT: {
54 const GLuint *ui_indices = (const GLuint *)indices;
55 GLuint max_ui = 0;
56 for (i = 0; i < count; i++)
57 if (ui_indices[i] > max_ui)
58 max_ui = ui_indices[i];
59 return max_ui;
60 }
61 case GL_UNSIGNED_SHORT: {
62 const GLushort *us_indices = (const GLushort *)indices;
63 GLuint max_us = 0;
64 for (i = 0; i < count; i++)
65 if (us_indices[i] > max_us)
66 max_us = us_indices[i];
67 return max_us;
68 }
69 case GL_UNSIGNED_BYTE: {
70 const GLubyte *ub_indices = (const GLubyte *)indices;
71 GLuint max_ub = 0;
72 for (i = 0; i < count; i++)
73 if (ub_indices[i] > max_ub)
74 max_ub = ub_indices[i];
75 return max_ub;
76 }
77 default:
78 return 0;
79 }
80 }
81
82
83
84
85 /***********************************************************************
86 * API functions.
87 */
88
89 static void GLAPIENTRY
90 brw_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
91 {
92 GET_CURRENT_CONTEXT(ctx);
93 struct brw_exec_context *exec = IMM_CONTEXT(ctx)->exec;
94 struct brw_draw_prim prim[1];
95 GLboolean ok;
96
97 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
98 return;
99
100 FLUSH_CURRENT( ctx, 0 );
101
102 if (ctx->NewState)
103 _mesa_update_state( ctx );
104
105 prim[0].begin = 1;
106 prim[0].end = 1;
107 prim[0].weak = 0;
108 prim[0].pad = 0;
109
110 if (exec->array.inputs[0]->BufferObj->Name) {
111 /* Use vertex attribute as a hint to tell us if we expect all
112 * arrays to be in VBO's and if so, don't worry about avoiding
113 * the upload of elements < start.
114 */
115 prim[0].mode = mode;
116 prim[0].start = start;
117 prim[0].count = count;
118 prim[0].indexed = 0;
119
120 ok = brw_draw_prims( ctx, exec->array.inputs, prim, 1, NULL, 0, start + count, 0 );
121 }
122 else {
123 /* If not using VBO's, we don't want to upload any more elements
124 * than necessary from the arrays as they will not be valid next
125 * time the application tries to draw with them.
126 */
127 prim[0].mode = mode;
128 prim[0].start = 0;
129 prim[0].count = count;
130 prim[0].indexed = 0;
131
132 ok = brw_draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count, 0 );
133 }
134
135 if (!ok) {
136 brw_fallback(ctx);
137 CALL_DrawArrays(ctx->Exec, ( mode, start, count ));
138 brw_unfallback(ctx);
139 }
140 }
141
142
143
144 static void GLAPIENTRY
145 brw_exec_DrawRangeElements(GLenum mode,
146 GLuint start, GLuint end,
147 GLsizei count, GLenum type, const GLvoid *indices)
148 {
149 GET_CURRENT_CONTEXT(ctx);
150 struct brw_exec_context *exec = IMM_CONTEXT(ctx)->exec;
151 struct brw_draw_index_buffer ib;
152 struct brw_draw_prim prim[1];
153
154 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices ))
155 return;
156
157 FLUSH_CURRENT( ctx, 0 );
158
159 if (ctx->NewState)
160 _mesa_update_state( ctx );
161
162 ib.count = count;
163 ib.type = type;
164 ib.obj = ctx->Array.ElementArrayBufferObj;
165 ib.ptr = indices;
166
167 if (ctx->Array.ElementArrayBufferObj->Name) {
168 /* Use the fact that indices are in a VBO as a hint that the
169 * program has put all the arrays in VBO's and we don't have to
170 * worry about performance implications of start > 0.
171 *
172 * XXX: consider passing start as min_index to draw_prims instead.
173 */
174 ib.rebase = 0;
175 }
176 else {
177 ib.rebase = start;
178 }
179
180 prim[0].begin = 1;
181 prim[0].end = 1;
182 prim[0].weak = 0;
183 prim[0].pad = 0;
184 prim[0].mode = mode;
185 prim[0].start = 0;
186 prim[0].count = count;
187 prim[0].indexed = 1;
188
189 if (!brw_draw_prims( ctx, exec->array.inputs, prim, 1, &ib, ib.rebase, end+1, 0 )) {
190 brw_fallback(ctx);
191 CALL_DrawRangeElements(ctx->Exec, (mode, start, end, count, type, indices));
192 brw_unfallback(ctx);
193 }
194 }
195
196
197 static void GLAPIENTRY
198 brw_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
199 {
200 GET_CURRENT_CONTEXT(ctx);
201 GLuint max_index;
202
203 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
204 return;
205
206 if (ctx->Array.ElementArrayBufferObj->Name) {
207 const GLvoid *map = ctx->Driver.MapBuffer(ctx,
208 GL_ELEMENT_ARRAY_BUFFER_ARB,
209 GL_DYNAMIC_READ_ARB,
210 ctx->Array.ElementArrayBufferObj);
211
212 max_index = get_max_index(count, type, ADD_POINTERS(map, indices));
213
214 ctx->Driver.UnmapBuffer(ctx,
215 GL_ELEMENT_ARRAY_BUFFER_ARB,
216 ctx->Array.ElementArrayBufferObj);
217 }
218 else {
219 max_index = get_max_index(count, type, indices);
220 }
221
222 brw_exec_DrawRangeElements(mode, 0, max_index, count, type, indices);
223 }
224
225
226 /***********************************************************************
227 * Initialization
228 */
229
230
231 static void init_arrays( GLcontext *ctx,
232 const struct gl_client_array *arrays[] )
233 {
234 struct gl_array_object *obj = ctx->Array.ArrayObj;
235 GLuint i;
236
237 memset(arrays, 0, sizeof(*arrays) * BRW_ATTRIB_MAX);
238
239 arrays[BRW_ATTRIB_POS] = &obj->Vertex;
240 arrays[BRW_ATTRIB_NORMAL] = &obj->Normal;
241 arrays[BRW_ATTRIB_COLOR0] = &obj->Color;
242 arrays[BRW_ATTRIB_COLOR1] = &obj->SecondaryColor;
243 arrays[BRW_ATTRIB_FOG] = &obj->FogCoord;
244
245 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
246 arrays[BRW_ATTRIB_TEX0 + i] = &obj->TexCoord[i];
247
248 arrays[BRW_ATTRIB_INDEX] = &obj->Index;
249 arrays[BRW_ATTRIB_EDGEFLAG] = &obj->EdgeFlag;
250
251 for (i = BRW_ATTRIB_GENERIC0; i <= BRW_ATTRIB_GENERIC15; i++)
252 arrays[i] = &obj->VertexAttrib[i - BRW_ATTRIB_GENERIC0];
253 }
254
255
256
257
258 void brw_exec_array_init( struct brw_exec_context *exec )
259 {
260 GLcontext *ctx = exec->ctx;
261
262 init_arrays(ctx, exec->array.inputs);
263
264 #if 1
265 exec->vtxfmt.DrawArrays = brw_exec_DrawArrays;
266 exec->vtxfmt.DrawElements = brw_exec_DrawElements;
267 exec->vtxfmt.DrawRangeElements = brw_exec_DrawRangeElements;
268 #else
269 exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
270 exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
271 exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements;
272 #endif
273
274 exec->array.index_obj = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
275 }
276
277
278 void brw_exec_array_destroy( struct brw_exec_context *exec )
279 {
280 GLcontext *ctx = exec->ctx;
281
282 ctx->Driver.DeleteBuffer(ctx, exec->array.index_obj);
283 }