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