r200: emit elts into a separate ELT bo
[mesa.git] / src / mesa / drivers / dri / r200 / r200_ioctl.c
1 /*
2 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
3
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 **************************************************************************/
29
30 /*
31 * Authors:
32 * Keith Whitwell <keith@tungstengraphics.com>
33 */
34
35 #include <sched.h>
36 #include <errno.h>
37
38 #include "main/glheader.h"
39 #include "main/imports.h"
40 #include "main/macros.h"
41 #include "main/context.h"
42 #include "swrast/swrast.h"
43
44 #include "radeon_cs.h"
45 #include "r200_context.h"
46
47 #include "common_cmdbuf.h"
48 #include "r200_state.h"
49 #include "r200_ioctl.h"
50 #include "r200_tcl.h"
51 #include "r200_sanity.h"
52 #include "radeon_reg.h"
53
54 #include "drirenderbuffer.h"
55 #include "vblank.h"
56
57 #define R200_TIMEOUT 512
58 #define R200_IDLE_RETRY 16
59
60
61 /* At this point we were in FlushCmdBufLocked but we had lost our context, so
62 * we need to unwire our current cmdbuf, hook the one with the saved state in
63 * it, flush it, and then put the current one back. This is so commands at the
64 * start of a cmdbuf can rely on the state being kept from the previous one.
65 */
66 static void r200BackUpAndEmitLostStateLocked( r200ContextPtr rmesa )
67 {
68 GLuint nr_released_bufs;
69 struct radeon_store saved_store;
70
71 if (rmesa->backup_store.cmd_used == 0)
72 return;
73
74 if (R200_DEBUG & DEBUG_STATE)
75 fprintf(stderr, "Emitting backup state on lost context\n");
76
77 rmesa->radeon.lost_context = GL_FALSE;
78
79 nr_released_bufs = rmesa->dma.nr_released_bufs;
80 saved_store = rmesa->store;
81 rmesa->dma.nr_released_bufs = 0;
82 rmesa->store = rmesa->backup_store;
83 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
84 rmesa->dma.nr_released_bufs = nr_released_bufs;
85 rmesa->store = saved_store;
86 }
87
88 /* ================================================================
89 * Buffer clear
90 */
91 static void r200Clear( GLcontext *ctx, GLbitfield mask )
92 {
93 r200ContextPtr rmesa = R200_CONTEXT(ctx);
94 __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
95 GLuint flags = 0;
96 GLuint color_mask = 0;
97 GLint ret, i;
98 GLint cx, cy, cw, ch;
99
100 if ( R200_DEBUG & DEBUG_IOCTL ) {
101 fprintf( stderr, "r200Clear\n");
102 }
103
104 {
105 LOCK_HARDWARE( &rmesa->radeon );
106 UNLOCK_HARDWARE( &rmesa->radeon );
107 if ( dPriv->numClipRects == 0 )
108 return;
109 }
110
111 r200Flush( ctx );
112
113 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
114 flags |= RADEON_FRONT;
115 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
116 mask &= ~BUFFER_BIT_FRONT_LEFT;
117 }
118
119 if ( mask & BUFFER_BIT_BACK_LEFT ) {
120 flags |= RADEON_BACK;
121 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
122 mask &= ~BUFFER_BIT_BACK_LEFT;
123 }
124
125 if ( mask & BUFFER_BIT_DEPTH ) {
126 flags |= RADEON_DEPTH;
127 mask &= ~BUFFER_BIT_DEPTH;
128 }
129
130 if ( (mask & BUFFER_BIT_STENCIL) && rmesa->radeon.state.stencil.hwBuffer ) {
131 flags |= RADEON_STENCIL;
132 mask &= ~BUFFER_BIT_STENCIL;
133 }
134
135 if ( mask ) {
136 if (R200_DEBUG & DEBUG_FALLBACKS)
137 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
138 _swrast_Clear( ctx, mask );
139 }
140
141 if ( !flags )
142 return;
143
144 if (rmesa->using_hyperz) {
145 flags |= RADEON_USE_COMP_ZBUF;
146 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
147 flags |= RADEON_USE_HIERZ; */
148 if (!(rmesa->radeon.state.stencil.hwBuffer) ||
149 ((flags & RADEON_DEPTH) && (flags & RADEON_STENCIL) &&
150 ((rmesa->radeon.state.stencil.clear & R200_STENCIL_WRITE_MASK) == R200_STENCIL_WRITE_MASK))) {
151 flags |= RADEON_CLEAR_FASTZ;
152 }
153 }
154
155 LOCK_HARDWARE( &rmesa->radeon );
156
157 /* compute region after locking: */
158 cx = ctx->DrawBuffer->_Xmin;
159 cy = ctx->DrawBuffer->_Ymin;
160 cw = ctx->DrawBuffer->_Xmax - cx;
161 ch = ctx->DrawBuffer->_Ymax - cy;
162
163 /* Flip top to bottom */
164 cx += dPriv->x;
165 cy = dPriv->y + dPriv->h - cy - ch;
166
167 /* Throttle the number of clear ioctls we do.
168 */
169 while ( 1 ) {
170 drm_radeon_getparam_t gp;
171 int ret;
172 int clear;
173
174 gp.param = RADEON_PARAM_LAST_CLEAR;
175 gp.value = (int *)&clear;
176 ret = drmCommandWriteRead( rmesa->radeon.dri.fd,
177 DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
178
179 if ( ret ) {
180 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
181 exit(1);
182 }
183
184 /* Clear throttling needs more thought.
185 */
186 if ( rmesa->radeon.sarea->last_clear - clear <= 25 ) {
187 break;
188 }
189
190 if (rmesa->radeon.do_usleeps) {
191 UNLOCK_HARDWARE( &rmesa->radeon );
192 DO_USLEEP( 1 );
193 LOCK_HARDWARE( &rmesa->radeon );
194 }
195 }
196
197 /* Send current state to the hardware */
198 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
199
200 for ( i = 0 ; i < dPriv->numClipRects ; ) {
201 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
202 drm_clip_rect_t *box = dPriv->pClipRects;
203 drm_clip_rect_t *b = rmesa->radeon.sarea->boxes;
204 drm_radeon_clear_t clear;
205 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
206 GLint n = 0;
207
208 if (cw != dPriv->w || ch != dPriv->h) {
209 /* clear subregion */
210 for ( ; i < nr ; i++ ) {
211 GLint x = box[i].x1;
212 GLint y = box[i].y1;
213 GLint w = box[i].x2 - x;
214 GLint h = box[i].y2 - y;
215
216 if ( x < cx ) w -= cx - x, x = cx;
217 if ( y < cy ) h -= cy - y, y = cy;
218 if ( x + w > cx + cw ) w = cx + cw - x;
219 if ( y + h > cy + ch ) h = cy + ch - y;
220 if ( w <= 0 ) continue;
221 if ( h <= 0 ) continue;
222
223 b->x1 = x;
224 b->y1 = y;
225 b->x2 = x + w;
226 b->y2 = y + h;
227 b++;
228 n++;
229 }
230 } else {
231 /* clear whole window */
232 for ( ; i < nr ; i++ ) {
233 *b++ = box[i];
234 n++;
235 }
236 }
237
238 rmesa->radeon.sarea->nbox = n;
239
240 clear.flags = flags;
241 clear.clear_color = rmesa->radeon.state.color.clear;
242 clear.clear_depth = rmesa->radeon.state.depth.clear; /* needed for hyperz */
243 clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
244 clear.depth_mask = rmesa->radeon.state.stencil.clear;
245 clear.depth_boxes = depth_boxes;
246
247 n--;
248 b = rmesa->radeon.sarea->boxes;
249 for ( ; n >= 0 ; n-- ) {
250 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
251 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
252 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
253 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
254 depth_boxes[n].f[CLEAR_DEPTH] = ctx->Depth.Clear;
255 }
256
257 ret = drmCommandWrite( rmesa->radeon.dri.fd, DRM_RADEON_CLEAR,
258 &clear, sizeof(clear));
259
260
261 if ( ret ) {
262 UNLOCK_HARDWARE( &rmesa->radeon );
263 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
264 exit( 1 );
265 }
266 }
267
268 UNLOCK_HARDWARE( &rmesa->radeon );
269 rmesa->hw.all_dirty = GL_TRUE;
270 }
271
272
273 void r200Flush( GLcontext *ctx )
274 {
275 r200ContextPtr rmesa = R200_CONTEXT( ctx );
276
277 if (R200_DEBUG & DEBUG_IOCTL)
278 fprintf(stderr, "%s\n", __FUNCTION__);
279
280 if (rmesa->dma.flush)
281 rmesa->dma.flush( ctx );
282
283 if (rmesa->tcl.flush)
284 rmesa->tcl.flush( rmesa );
285
286 r200EmitState( rmesa );
287
288 if (rmesa->radeon.cmdbuf.cs->cdw)
289 rcommonFlushCmdBuf( &rmesa->radeon, __FUNCTION__ );
290 }
291
292 /* Make sure all commands have been sent to the hardware and have
293 * completed processing.
294 */
295 void r200Finish( GLcontext *ctx )
296 {
297 r200Flush( ctx );
298 radeon_common_finish(ctx);
299 }
300
301
302 /* This version of AllocateMemoryMESA allocates only GART memory, and
303 * only does so after the point at which the driver has been
304 * initialized.
305 *
306 * Theoretically a valid context isn't required. However, in this
307 * implementation, it is, as I'm using the hardware lock to protect
308 * the kernel data structures, and the current context to get the
309 * device fd.
310 */
311 void *r200AllocateMemoryMESA(__DRIscreen *screen, GLsizei size,
312 GLfloat readfreq, GLfloat writefreq,
313 GLfloat priority)
314 {
315 GET_CURRENT_CONTEXT(ctx);
316 r200ContextPtr rmesa;
317 int region_offset;
318 drm_radeon_mem_alloc_t alloc;
319 int ret;
320
321 if (R200_DEBUG & DEBUG_IOCTL)
322 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
323 writefreq, priority);
324
325 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map)
326 return NULL;
327
328 if (getenv("R200_NO_ALLOC"))
329 return NULL;
330
331 alloc.region = RADEON_MEM_REGION_GART;
332 alloc.alignment = 0;
333 alloc.size = size;
334 alloc.region_offset = &region_offset;
335
336 ret = drmCommandWriteRead( rmesa->radeon.radeonScreen->driScreen->fd,
337 DRM_RADEON_ALLOC,
338 &alloc, sizeof(alloc));
339
340 if (ret) {
341 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
342 return NULL;
343 }
344
345 {
346 char *region_start = (char *)rmesa->radeon.radeonScreen->gartTextures.map;
347 return (void *)(region_start + region_offset);
348 }
349 }
350
351
352 /* Called via glXFreeMemoryMESA() */
353 void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer)
354 {
355 GET_CURRENT_CONTEXT(ctx);
356 r200ContextPtr rmesa;
357 ptrdiff_t region_offset;
358 drm_radeon_mem_free_t memfree;
359 int ret;
360
361 if (R200_DEBUG & DEBUG_IOCTL)
362 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
363
364 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map) {
365 fprintf(stderr, "%s: no context\n", __FUNCTION__);
366 return;
367 }
368
369 region_offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
370
371 if (region_offset < 0 ||
372 region_offset > rmesa->radeon.radeonScreen->gartTextures.size) {
373 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
374 rmesa->radeon.radeonScreen->gartTextures.size);
375 return;
376 }
377
378 memfree.region = RADEON_MEM_REGION_GART;
379 memfree.region_offset = region_offset;
380
381 ret = drmCommandWrite( rmesa->radeon.radeonScreen->driScreen->fd,
382 DRM_RADEON_FREE,
383 &memfree, sizeof(memfree));
384
385 if (ret)
386 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
387 }
388
389 /* Called via glXGetMemoryOffsetMESA() */
390 GLuint r200GetMemoryOffsetMESA(__DRIscreen *screen, const GLvoid *pointer)
391 {
392 GET_CURRENT_CONTEXT(ctx);
393 r200ContextPtr rmesa;
394 GLuint card_offset;
395
396 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
397 fprintf(stderr, "%s: no context\n", __FUNCTION__);
398 return ~0;
399 }
400
401 if (!r200IsGartMemory( rmesa, pointer, 0 ))
402 return ~0;
403
404 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
405
406 return card_offset - rmesa->radeon.radeonScreen->gart_base;
407 }
408
409 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
410 GLint size )
411 {
412 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
413 int valid = (size >= 0 &&
414 offset >= 0 &&
415 offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
416
417 if (R200_DEBUG & DEBUG_IOCTL)
418 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
419
420 return valid;
421 }
422
423
424 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
425 {
426 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
427
428 if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
429 return ~0;
430 else
431 return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
432 }
433
434
435
436 void r200InitIoctlFuncs( struct dd_function_table *functions )
437 {
438 functions->Clear = r200Clear;
439 functions->Finish = r200Finish;
440 functions->Flush = r200Flush;
441 }
442