Merge branch 'master' into radeon-rewrite
[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 = rmesa->radeon.dri.drawable;
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 = rmesa->radeon.dri.drawable;
194 GLuint flags = 0;
195 GLuint color_mask = 0;
196 GLuint orig_mask = mask;
197
198 if ( R200_DEBUG & DEBUG_IOCTL ) {
199 fprintf( stderr, "r200Clear %x %d\n", mask, rmesa->radeon.sarea->pfCurrentPage);
200 }
201
202 {
203 LOCK_HARDWARE( &rmesa->radeon );
204 UNLOCK_HARDWARE( &rmesa->radeon );
205 if ( dPriv->numClipRects == 0 )
206 return;
207 }
208
209 radeonFlush( ctx );
210
211 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
212 flags |= RADEON_FRONT;
213 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
214 mask &= ~BUFFER_BIT_FRONT_LEFT;
215 }
216
217 if ( mask & BUFFER_BIT_BACK_LEFT ) {
218 flags |= RADEON_BACK;
219 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
220 mask &= ~BUFFER_BIT_BACK_LEFT;
221 }
222
223 if ( mask & BUFFER_BIT_DEPTH ) {
224 flags |= RADEON_DEPTH;
225 mask &= ~BUFFER_BIT_DEPTH;
226 }
227
228 if ( (mask & BUFFER_BIT_STENCIL) ) {
229 flags |= RADEON_STENCIL;
230 mask &= ~BUFFER_BIT_STENCIL;
231 }
232
233 if ( mask ) {
234 if (R200_DEBUG & DEBUG_FALLBACKS)
235 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
236 _swrast_Clear( ctx, mask );
237 }
238
239 if ( !flags )
240 return;
241
242 if (rmesa->using_hyperz) {
243 flags |= RADEON_USE_COMP_ZBUF;
244 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
245 flags |= RADEON_USE_HIERZ; */
246 if (!((flags & RADEON_DEPTH) && (flags & RADEON_STENCIL) &&
247 ((rmesa->radeon.state.stencil.clear & R200_STENCIL_WRITE_MASK) == R200_STENCIL_WRITE_MASK))) {
248 flags |= RADEON_CLEAR_FASTZ;
249 }
250 }
251
252 if (rmesa->radeon.radeonScreen->kernel_mm)
253 r200UserClear(ctx, orig_mask);
254 else {
255 r200KernelClear(ctx, flags);
256 rmesa->radeon.hw.all_dirty = GL_TRUE;
257 }
258 }
259
260 /* This version of AllocateMemoryMESA allocates only GART memory, and
261 * only does so after the point at which the driver has been
262 * initialized.
263 *
264 * Theoretically a valid context isn't required. However, in this
265 * implementation, it is, as I'm using the hardware lock to protect
266 * the kernel data structures, and the current context to get the
267 * device fd.
268 */
269 void *r200AllocateMemoryMESA(__DRIscreen *screen, GLsizei size,
270 GLfloat readfreq, GLfloat writefreq,
271 GLfloat priority)
272 {
273 GET_CURRENT_CONTEXT(ctx);
274 r200ContextPtr rmesa;
275 int region_offset;
276 drm_radeon_mem_alloc_t alloc;
277 int ret;
278
279 if (R200_DEBUG & DEBUG_IOCTL)
280 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
281 writefreq, priority);
282
283 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map)
284 return NULL;
285
286 if (getenv("R200_NO_ALLOC"))
287 return NULL;
288
289 alloc.region = RADEON_MEM_REGION_GART;
290 alloc.alignment = 0;
291 alloc.size = size;
292 alloc.region_offset = &region_offset;
293
294 ret = drmCommandWriteRead( rmesa->radeon.radeonScreen->driScreen->fd,
295 DRM_RADEON_ALLOC,
296 &alloc, sizeof(alloc));
297
298 if (ret) {
299 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
300 return NULL;
301 }
302
303 {
304 char *region_start = (char *)rmesa->radeon.radeonScreen->gartTextures.map;
305 return (void *)(region_start + region_offset);
306 }
307 }
308
309
310 /* Called via glXFreeMemoryMESA() */
311 void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer)
312 {
313 GET_CURRENT_CONTEXT(ctx);
314 r200ContextPtr rmesa;
315 ptrdiff_t region_offset;
316 drm_radeon_mem_free_t memfree;
317 int ret;
318
319 if (R200_DEBUG & DEBUG_IOCTL)
320 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
321
322 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map) {
323 fprintf(stderr, "%s: no context\n", __FUNCTION__);
324 return;
325 }
326
327 region_offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
328
329 if (region_offset < 0 ||
330 region_offset > rmesa->radeon.radeonScreen->gartTextures.size) {
331 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
332 rmesa->radeon.radeonScreen->gartTextures.size);
333 return;
334 }
335
336 memfree.region = RADEON_MEM_REGION_GART;
337 memfree.region_offset = region_offset;
338
339 ret = drmCommandWrite( rmesa->radeon.radeonScreen->driScreen->fd,
340 DRM_RADEON_FREE,
341 &memfree, sizeof(memfree));
342
343 if (ret)
344 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
345 }
346
347 /* Called via glXGetMemoryOffsetMESA() */
348 GLuint r200GetMemoryOffsetMESA(__DRIscreen *screen, const GLvoid *pointer)
349 {
350 GET_CURRENT_CONTEXT(ctx);
351 r200ContextPtr rmesa;
352 GLuint card_offset;
353
354 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
355 fprintf(stderr, "%s: no context\n", __FUNCTION__);
356 return ~0;
357 }
358
359 if (!r200IsGartMemory( rmesa, pointer, 0 ))
360 return ~0;
361
362 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
363
364 return card_offset - rmesa->radeon.radeonScreen->gart_base;
365 }
366
367 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
368 GLint size )
369 {
370 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
371 int valid = (size >= 0 &&
372 offset >= 0 &&
373 offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
374
375 if (R200_DEBUG & DEBUG_IOCTL)
376 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
377
378 return valid;
379 }
380
381
382 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
383 {
384 ptrdiff_t offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
385
386 if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
387 return ~0;
388 else
389 return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
390 }
391
392
393
394 void r200InitIoctlFuncs( struct dd_function_table *functions )
395 {
396 functions->Clear = r200Clear;
397 functions->Finish = radeonFinish;
398 functions->Flush = radeonFlush;
399 }
400