Merge branch 'mesa_7_6_branch'
[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
45
46 #include "radeon_common.h"
47 #include "radeon_lock.h"
48 #include "r200_context.h"
49 #include "r200_state.h"
50 #include "r200_ioctl.h"
51 #include "r200_tcl.h"
52 #include "r200_sanity.h"
53 #include "radeon_reg.h"
54
55 #include "drirenderbuffer.h"
56 #include "vblank.h"
57
58 #define R200_TIMEOUT 512
59 #define R200_IDLE_RETRY 16
60
61 static void r200KernelClear(GLcontext *ctx, GLuint flags)
62 {
63 r200ContextPtr rmesa = R200_CONTEXT(ctx);
64 __DRIdrawablePrivate *dPriv = radeon_get_drawable(&rmesa->radeon);
65 GLint cx, cy, cw, ch, ret;
66 GLuint i;
67
68 LOCK_HARDWARE( &rmesa->radeon );
69
70 /* Throttle the number of clear ioctls we do.
71 */
72 while ( 1 ) {
73 drm_radeon_getparam_t gp;
74 int ret;
75 int clear;
76
77 gp.param = RADEON_PARAM_LAST_CLEAR;
78 gp.value = (int *)&clear;
79 ret = drmCommandWriteRead( rmesa->radeon.dri.fd,
80 DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
81
82 if ( ret ) {
83 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
84 exit(1);
85 }
86
87 /* Clear throttling needs more thought.
88 */
89 if ( rmesa->radeon.sarea->last_clear - clear <= 25 ) {
90 break;
91 }
92
93 if (rmesa->radeon.do_usleeps) {
94 UNLOCK_HARDWARE( &rmesa->radeon );
95 DO_USLEEP( 1 );
96 LOCK_HARDWARE( &rmesa->radeon );
97 }
98 }
99
100 /* Send current state to the hardware */
101 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
102
103
104 /* compute region after locking: */
105 cx = ctx->DrawBuffer->_Xmin;
106 cy = ctx->DrawBuffer->_Ymin;
107 cw = ctx->DrawBuffer->_Xmax - cx;
108 ch = ctx->DrawBuffer->_Ymax - cy;
109
110 /* Flip top to bottom */
111 cx += dPriv->x;
112 cy = dPriv->y + dPriv->h - cy - ch;
113 for ( i = 0 ; i < dPriv->numClipRects ; ) {
114 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
115 drm_clip_rect_t *box = dPriv->pClipRects;
116 drm_clip_rect_t *b = rmesa->radeon.sarea->boxes;
117 drm_radeon_clear_t clear;
118 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
119 GLint n = 0;
120
121 if (cw != dPriv->w || ch != dPriv->h) {
122 /* clear subregion */
123 for ( ; i < nr ; i++ ) {
124 GLint x = box[i].x1;
125 GLint y = box[i].y1;
126 GLint w = box[i].x2 - x;
127 GLint h = box[i].y2 - y;
128
129 if ( x < cx ) w -= cx - x, x = cx;
130 if ( y < cy ) h -= cy - y, y = cy;
131 if ( x + w > cx + cw ) w = cx + cw - x;
132 if ( y + h > cy + ch ) h = cy + ch - y;
133 if ( w <= 0 ) continue;
134 if ( h <= 0 ) continue;
135
136 b->x1 = x;
137 b->y1 = y;
138 b->x2 = x + w;
139 b->y2 = y + h;
140 b++;
141 n++;
142 }
143 } else {
144 /* clear whole window */
145 for ( ; i < nr ; i++ ) {
146 *b++ = box[i];
147 n++;
148 }
149 }
150
151 rmesa->radeon.sarea->nbox = n;
152
153 clear.flags = flags;
154 clear.clear_color = rmesa->radeon.state.color.clear;
155 clear.clear_depth = rmesa->radeon.state.depth.clear; /* needed for hyperz */
156 clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
157 clear.depth_mask = rmesa->radeon.state.stencil.clear;
158 clear.depth_boxes = depth_boxes;
159
160 n--;
161 b = rmesa->radeon.sarea->boxes;
162 for ( ; n >= 0 ; n-- ) {
163 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
164 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
165 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
166 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
167 depth_boxes[n].f[CLEAR_DEPTH] = ctx->Depth.Clear;
168 }
169
170 ret = drmCommandWrite( rmesa->radeon.dri.fd, DRM_RADEON_CLEAR,
171 &clear, sizeof(clear));
172
173
174 if ( ret ) {
175 UNLOCK_HARDWARE( &rmesa->radeon );
176 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
177 exit( 1 );
178 }
179 }
180 UNLOCK_HARDWARE( &rmesa->radeon );
181 }
182 /* ================================================================
183 * Buffer clear
184 */
185 static void r200Clear( GLcontext *ctx, GLbitfield mask )
186 {
187 r200ContextPtr rmesa = R200_CONTEXT(ctx);
188 __DRIdrawablePrivate *dPriv = radeon_get_drawable(&rmesa->radeon);
189 GLuint flags = 0;
190 GLuint color_mask = 0;
191 GLuint orig_mask = mask;
192
193 if ( R200_DEBUG & RADEON_IOCTL ) {
194 if (rmesa->radeon.sarea)
195 fprintf( stderr, "r200Clear %x %d\n", mask, rmesa->radeon.sarea->pfCurrentPage);
196 else
197 fprintf( stderr, "r200Clear %x radeon->sarea is NULL\n", mask);
198 }
199
200 {
201 LOCK_HARDWARE( &rmesa->radeon );
202 UNLOCK_HARDWARE( &rmesa->radeon );
203 if ( dPriv->numClipRects == 0 )
204 return;
205 }
206
207 radeonFlush( ctx );
208
209 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
210 flags |= RADEON_FRONT;
211 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
212 mask &= ~BUFFER_BIT_FRONT_LEFT;
213 }
214
215 if ( mask & BUFFER_BIT_BACK_LEFT ) {
216 flags |= RADEON_BACK;
217 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
218 mask &= ~BUFFER_BIT_BACK_LEFT;
219 }
220
221 if ( mask & BUFFER_BIT_DEPTH ) {
222 flags |= RADEON_DEPTH;
223 mask &= ~BUFFER_BIT_DEPTH;
224 }
225
226 if ( (mask & BUFFER_BIT_STENCIL) ) {
227 flags |= RADEON_STENCIL;
228 mask &= ~BUFFER_BIT_STENCIL;
229 }
230
231 if ( mask ) {
232 if (R200_DEBUG & RADEON_FALLBACKS)
233 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
234 _swrast_Clear( ctx, mask );
235 }
236
237 if ( !flags )
238 return;
239
240 if (rmesa->using_hyperz) {
241 flags |= RADEON_USE_COMP_ZBUF;
242 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
243 flags |= RADEON_USE_HIERZ; */
244 if (!((flags & RADEON_DEPTH) && (flags & RADEON_STENCIL) &&
245 ((rmesa->radeon.state.stencil.clear & R200_STENCIL_WRITE_MASK) == R200_STENCIL_WRITE_MASK))) {
246 flags |= RADEON_CLEAR_FASTZ;
247 }
248 }
249
250 if (rmesa->radeon.radeonScreen->kernel_mm)
251 radeonUserClear(ctx, orig_mask);
252 else {
253 r200KernelClear(ctx, flags);
254 rmesa->radeon.hw.all_dirty = GL_TRUE;
255 }
256 }
257
258 /* This version of AllocateMemoryMESA allocates only GART memory, and
259 * only does so after the point at which the driver has been
260 * initialized.
261 *
262 * Theoretically a valid context isn't required. However, in this
263 * implementation, it is, as I'm using the hardware lock to protect
264 * the kernel data structures, and the current context to get the
265 * device fd.
266 */
267 void *r200AllocateMemoryMESA(__DRIscreen *screen, GLsizei size,
268 GLfloat readfreq, GLfloat writefreq,
269 GLfloat priority)
270 {
271 GET_CURRENT_CONTEXT(ctx);
272 r200ContextPtr rmesa;
273 int region_offset;
274 drm_radeon_mem_alloc_t alloc;
275 int ret;
276
277 if (R200_DEBUG & RADEON_IOCTL)
278 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
279 writefreq, priority);
280
281 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map)
282 return NULL;
283
284 if (getenv("R200_NO_ALLOC"))
285 return NULL;
286
287 alloc.region = RADEON_MEM_REGION_GART;
288 alloc.alignment = 0;
289 alloc.size = size;
290 alloc.region_offset = &region_offset;
291
292 ret = drmCommandWriteRead( rmesa->radeon.radeonScreen->driScreen->fd,
293 DRM_RADEON_ALLOC,
294 &alloc, sizeof(alloc));
295
296 if (ret) {
297 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
298 return NULL;
299 }
300
301 {
302 char *region_start = (char *)rmesa->radeon.radeonScreen->gartTextures.map;
303 return (void *)(region_start + region_offset);
304 }
305 }
306
307
308 /* Called via glXFreeMemoryMESA() */
309 void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer)
310 {
311 GET_CURRENT_CONTEXT(ctx);
312 r200ContextPtr rmesa;
313 ptrdiff_t region_offset;
314 drm_radeon_mem_free_t memfree;
315 int ret;
316
317 if (R200_DEBUG & RADEON_IOCTL)
318 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
319
320 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map) {
321 fprintf(stderr, "%s: no context\n", __FUNCTION__);
322 return;
323 }
324
325 region_offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
326
327 if (region_offset < 0 ||
328 region_offset > rmesa->radeon.radeonScreen->gartTextures.size) {
329 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
330 rmesa->radeon.radeonScreen->gartTextures.size);
331 return;
332 }
333
334 memfree.region = RADEON_MEM_REGION_GART;
335 memfree.region_offset = region_offset;
336
337 ret = drmCommandWrite( rmesa->radeon.radeonScreen->driScreen->fd,
338 DRM_RADEON_FREE,
339 &memfree, sizeof(memfree));
340
341 if (ret)
342 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
343 }
344
345 /* Called via glXGetMemoryOffsetMESA() */
346 GLuint r200GetMemoryOffsetMESA(__DRIscreen *screen, const GLvoid *pointer)
347 {
348 GET_CURRENT_CONTEXT(ctx);
349 r200ContextPtr rmesa;
350 GLuint card_offset;
351
352 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
353 fprintf(stderr, "%s: no context\n", __FUNCTION__);
354 return ~0;
355 }
356
357 if (!r200IsGartMemory( rmesa, pointer, 0 ))
358 return ~0;
359
360 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
361
362 return card_offset - rmesa->radeon.radeonScreen->gart_base;
363 }
364
365 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
366 GLint size )
367 {
368 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
369 int valid = (size >= 0 &&
370 offset >= 0 &&
371 offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
372
373 if (R200_DEBUG & RADEON_IOCTL)
374 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
375
376 return valid;
377 }
378
379
380 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
381 {
382 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
383
384 if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
385 return ~0;
386 else
387 return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
388 }
389
390
391
392 void r200InitIoctlFuncs( struct dd_function_table *functions )
393 {
394 functions->Clear = r200Clear;
395 functions->Finish = radeonFinish;
396 functions->Flush = radeonFlush;
397 }
398