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