cb2f50d5d87564fe6ea2e095248be02cb4aa3171
[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 static void r200UserClear(GLcontext *ctx, GLuint flags)
89 {
90 if (flags & (RADEON_FRONT | RADEON_BACK)) {
91
92
93 }
94
95 if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
96 && (flags & RADEON_CLEAR_FASTZ)) {
97
98 }
99
100 }
101
102 static void r200KernelClear(GLcontext *ctx, GLuint flags)
103 {
104 r200ContextPtr rmesa = R200_CONTEXT(ctx);
105 __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
106 GLint cx, cy, cw, ch, ret;
107 GLuint i;
108
109 LOCK_HARDWARE( &rmesa->radeon );
110
111 /* Throttle the number of clear ioctls we do.
112 */
113 while ( 1 ) {
114 drm_radeon_getparam_t gp;
115 int ret;
116 int clear;
117
118 gp.param = RADEON_PARAM_LAST_CLEAR;
119 gp.value = (int *)&clear;
120 ret = drmCommandWriteRead( rmesa->radeon.dri.fd,
121 DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
122
123 if ( ret ) {
124 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
125 exit(1);
126 }
127
128 /* Clear throttling needs more thought.
129 */
130 if ( rmesa->radeon.sarea->last_clear - clear <= 25 ) {
131 break;
132 }
133
134 if (rmesa->radeon.do_usleeps) {
135 UNLOCK_HARDWARE( &rmesa->radeon );
136 DO_USLEEP( 1 );
137 LOCK_HARDWARE( &rmesa->radeon );
138 }
139 }
140
141 /* Send current state to the hardware */
142 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
143
144
145 /* compute region after locking: */
146 cx = ctx->DrawBuffer->_Xmin;
147 cy = ctx->DrawBuffer->_Ymin;
148 cw = ctx->DrawBuffer->_Xmax - cx;
149 ch = ctx->DrawBuffer->_Ymax - cy;
150
151 /* Flip top to bottom */
152 cx += dPriv->x;
153 cy = dPriv->y + dPriv->h - cy - ch;
154 for ( i = 0 ; i < dPriv->numClipRects ; ) {
155 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
156 drm_clip_rect_t *box = dPriv->pClipRects;
157 drm_clip_rect_t *b = rmesa->radeon.sarea->boxes;
158 drm_radeon_clear_t clear;
159 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
160 GLint n = 0;
161
162 if (cw != dPriv->w || ch != dPriv->h) {
163 /* clear subregion */
164 for ( ; i < nr ; i++ ) {
165 GLint x = box[i].x1;
166 GLint y = box[i].y1;
167 GLint w = box[i].x2 - x;
168 GLint h = box[i].y2 - y;
169
170 if ( x < cx ) w -= cx - x, x = cx;
171 if ( y < cy ) h -= cy - y, y = cy;
172 if ( x + w > cx + cw ) w = cx + cw - x;
173 if ( y + h > cy + ch ) h = cy + ch - y;
174 if ( w <= 0 ) continue;
175 if ( h <= 0 ) continue;
176
177 b->x1 = x;
178 b->y1 = y;
179 b->x2 = x + w;
180 b->y2 = y + h;
181 b++;
182 n++;
183 }
184 } else {
185 /* clear whole window */
186 for ( ; i < nr ; i++ ) {
187 *b++ = box[i];
188 n++;
189 }
190 }
191
192 rmesa->radeon.sarea->nbox = n;
193
194 clear.flags = flags;
195 clear.clear_color = rmesa->radeon.state.color.clear;
196 clear.clear_depth = rmesa->radeon.state.depth.clear; /* needed for hyperz */
197 clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
198 clear.depth_mask = rmesa->radeon.state.stencil.clear;
199 clear.depth_boxes = depth_boxes;
200
201 n--;
202 b = rmesa->radeon.sarea->boxes;
203 for ( ; n >= 0 ; n-- ) {
204 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
205 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
206 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
207 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
208 depth_boxes[n].f[CLEAR_DEPTH] = ctx->Depth.Clear;
209 }
210
211 ret = drmCommandWrite( rmesa->radeon.dri.fd, DRM_RADEON_CLEAR,
212 &clear, sizeof(clear));
213
214
215 if ( ret ) {
216 UNLOCK_HARDWARE( &rmesa->radeon );
217 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
218 exit( 1 );
219 }
220 }
221 UNLOCK_HARDWARE( &rmesa->radeon );
222 }
223 /* ================================================================
224 * Buffer clear
225 */
226 static void r200Clear( GLcontext *ctx, GLbitfield mask )
227 {
228 r200ContextPtr rmesa = R200_CONTEXT(ctx);
229 __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
230 GLuint flags = 0;
231 GLuint color_mask = 0;
232 GLint ret;
233
234 if ( R200_DEBUG & DEBUG_IOCTL ) {
235 fprintf( stderr, "r200Clear\n");
236 }
237
238 {
239 LOCK_HARDWARE( &rmesa->radeon );
240 UNLOCK_HARDWARE( &rmesa->radeon );
241 if ( dPriv->numClipRects == 0 )
242 return;
243 }
244
245 r200Flush( ctx );
246
247 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
248 flags |= RADEON_FRONT;
249 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
250 mask &= ~BUFFER_BIT_FRONT_LEFT;
251 }
252
253 if ( mask & BUFFER_BIT_BACK_LEFT ) {
254 flags |= RADEON_BACK;
255 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
256 mask &= ~BUFFER_BIT_BACK_LEFT;
257 }
258
259 if ( mask & BUFFER_BIT_DEPTH ) {
260 flags |= RADEON_DEPTH;
261 mask &= ~BUFFER_BIT_DEPTH;
262 }
263
264 if ( (mask & BUFFER_BIT_STENCIL) && rmesa->radeon.state.stencil.hwBuffer ) {
265 flags |= RADEON_STENCIL;
266 mask &= ~BUFFER_BIT_STENCIL;
267 }
268
269 if ( mask ) {
270 if (R200_DEBUG & DEBUG_FALLBACKS)
271 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
272 _swrast_Clear( ctx, mask );
273 }
274
275 if ( !flags )
276 return;
277
278 if (rmesa->using_hyperz) {
279 flags |= RADEON_USE_COMP_ZBUF;
280 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
281 flags |= RADEON_USE_HIERZ; */
282 if (!(rmesa->radeon.state.stencil.hwBuffer) ||
283 ((flags & RADEON_DEPTH) && (flags & RADEON_STENCIL) &&
284 ((rmesa->radeon.state.stencil.clear & R200_STENCIL_WRITE_MASK) == R200_STENCIL_WRITE_MASK))) {
285 flags |= RADEON_CLEAR_FASTZ;
286 }
287 }
288
289 if (rmesa->radeon.radeonScreen->kernel_mm)
290 r200UserClear(ctx, flags);
291 else
292 r200KernelClear(ctx, flags);
293
294 rmesa->hw.all_dirty = GL_TRUE;
295 }
296
297
298 void r200Flush( GLcontext *ctx )
299 {
300 r200ContextPtr rmesa = R200_CONTEXT( ctx );
301
302 if (R200_DEBUG & DEBUG_IOCTL)
303 fprintf(stderr, "%s\n", __FUNCTION__);
304
305 if (rmesa->swtcl.flush)
306 rmesa->swtcl.flush( ctx );
307
308 if (rmesa->tcl.flush)
309 rmesa->tcl.flush( ctx );
310
311 r200EmitState( rmesa );
312
313 if (rmesa->radeon.cmdbuf.cs->cdw)
314 rcommonFlushCmdBuf( &rmesa->radeon, __FUNCTION__ );
315 }
316
317 /* Make sure all commands have been sent to the hardware and have
318 * completed processing.
319 */
320 void r200Finish( GLcontext *ctx )
321 {
322 r200Flush( ctx );
323 radeon_common_finish(ctx);
324 }
325
326
327 /* This version of AllocateMemoryMESA allocates only GART memory, and
328 * only does so after the point at which the driver has been
329 * initialized.
330 *
331 * Theoretically a valid context isn't required. However, in this
332 * implementation, it is, as I'm using the hardware lock to protect
333 * the kernel data structures, and the current context to get the
334 * device fd.
335 */
336 void *r200AllocateMemoryMESA(__DRIscreen *screen, GLsizei size,
337 GLfloat readfreq, GLfloat writefreq,
338 GLfloat priority)
339 {
340 GET_CURRENT_CONTEXT(ctx);
341 r200ContextPtr rmesa;
342 int region_offset;
343 drm_radeon_mem_alloc_t alloc;
344 int ret;
345
346 if (R200_DEBUG & DEBUG_IOCTL)
347 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
348 writefreq, priority);
349
350 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map)
351 return NULL;
352
353 if (getenv("R200_NO_ALLOC"))
354 return NULL;
355
356 alloc.region = RADEON_MEM_REGION_GART;
357 alloc.alignment = 0;
358 alloc.size = size;
359 alloc.region_offset = &region_offset;
360
361 ret = drmCommandWriteRead( rmesa->radeon.radeonScreen->driScreen->fd,
362 DRM_RADEON_ALLOC,
363 &alloc, sizeof(alloc));
364
365 if (ret) {
366 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
367 return NULL;
368 }
369
370 {
371 char *region_start = (char *)rmesa->radeon.radeonScreen->gartTextures.map;
372 return (void *)(region_start + region_offset);
373 }
374 }
375
376
377 /* Called via glXFreeMemoryMESA() */
378 void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer)
379 {
380 GET_CURRENT_CONTEXT(ctx);
381 r200ContextPtr rmesa;
382 ptrdiff_t region_offset;
383 drm_radeon_mem_free_t memfree;
384 int ret;
385
386 if (R200_DEBUG & DEBUG_IOCTL)
387 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
388
389 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map) {
390 fprintf(stderr, "%s: no context\n", __FUNCTION__);
391 return;
392 }
393
394 region_offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
395
396 if (region_offset < 0 ||
397 region_offset > rmesa->radeon.radeonScreen->gartTextures.size) {
398 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
399 rmesa->radeon.radeonScreen->gartTextures.size);
400 return;
401 }
402
403 memfree.region = RADEON_MEM_REGION_GART;
404 memfree.region_offset = region_offset;
405
406 ret = drmCommandWrite( rmesa->radeon.radeonScreen->driScreen->fd,
407 DRM_RADEON_FREE,
408 &memfree, sizeof(memfree));
409
410 if (ret)
411 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
412 }
413
414 /* Called via glXGetMemoryOffsetMESA() */
415 GLuint r200GetMemoryOffsetMESA(__DRIscreen *screen, const GLvoid *pointer)
416 {
417 GET_CURRENT_CONTEXT(ctx);
418 r200ContextPtr rmesa;
419 GLuint card_offset;
420
421 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
422 fprintf(stderr, "%s: no context\n", __FUNCTION__);
423 return ~0;
424 }
425
426 if (!r200IsGartMemory( rmesa, pointer, 0 ))
427 return ~0;
428
429 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
430
431 return card_offset - rmesa->radeon.radeonScreen->gart_base;
432 }
433
434 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
435 GLint size )
436 {
437 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
438 int valid = (size >= 0 &&
439 offset >= 0 &&
440 offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
441
442 if (R200_DEBUG & DEBUG_IOCTL)
443 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
444
445 return valid;
446 }
447
448
449 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
450 {
451 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
452
453 if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
454 return ~0;
455 else
456 return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
457 }
458
459
460
461 void r200InitIoctlFuncs( struct dd_function_table *functions )
462 {
463 functions->Clear = r200Clear;
464 functions->Finish = r200Finish;
465 functions->Flush = r200Flush;
466 }
467