Merge branch 'origin'
[mesa.git] / src / mesa / drivers / dri / r300 / radeon_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 "glheader.h"
39 #include "imports.h"
40 #include "macros.h"
41 #include "context.h"
42 #include "swrast/swrast.h"
43 #include "r300_context.h"
44 #include "radeon_ioctl.h"
45 #include "r300_ioctl.h"
46 #include "r300_state.h"
47 #include "radeon_reg.h"
48
49 #include "drirenderbuffer.h"
50 #include "vblank.h"
51
52 static void radeonWaitForIdle(radeonContextPtr radeon);
53
54 /* ================================================================
55 * SwapBuffers with client-side throttling
56 */
57
58 static uint32_t radeonGetLastFrame(radeonContextPtr radeon)
59 {
60 drm_radeon_getparam_t gp;
61 int ret;
62 uint32_t frame;
63
64 gp.param = RADEON_PARAM_LAST_FRAME;
65 gp.value = (int *)&frame;
66 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
67 &gp, sizeof(gp));
68 if (ret) {
69 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
70 ret);
71 exit(1);
72 }
73
74 return frame;
75 }
76
77 uint32_t radeonGetAge(radeonContextPtr radeon)
78 {
79 drm_radeon_getparam_t gp;
80 int ret;
81 uint32_t age;
82
83 gp.param = RADEON_PARAM_LAST_CLEAR;
84 gp.value = (int *)&age;
85 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
86 &gp, sizeof(gp));
87 if (ret) {
88 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
89 ret);
90 exit(1);
91 }
92
93 return age;
94 }
95
96 static void radeonEmitIrqLocked(radeonContextPtr radeon)
97 {
98 drm_radeon_irq_emit_t ie;
99 int ret;
100
101 ie.irq_seq = &radeon->iw.irq_seq;
102 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_IRQ_EMIT,
103 &ie, sizeof(ie));
104 if (ret) {
105 fprintf(stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__,
106 ret);
107 exit(1);
108 }
109 }
110
111 static void radeonWaitIrq(radeonContextPtr radeon)
112 {
113 int ret;
114
115 do {
116 ret = drmCommandWrite(radeon->dri.fd, DRM_RADEON_IRQ_WAIT,
117 &radeon->iw, sizeof(radeon->iw));
118 } while (ret && (errno == EINTR || errno == EBUSY));
119
120 if (ret) {
121 fprintf(stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__,
122 ret);
123 exit(1);
124 }
125 }
126
127 static void radeonWaitForFrameCompletion(radeonContextPtr radeon)
128 {
129 drm_radeon_sarea_t *sarea = radeon->sarea;
130
131 if (radeon->do_irqs) {
132 if (radeonGetLastFrame(radeon) < sarea->last_frame) {
133 if (!radeon->irqsEmitted) {
134 while (radeonGetLastFrame(radeon) <
135 sarea->last_frame) ;
136 } else {
137 UNLOCK_HARDWARE(radeon);
138 radeonWaitIrq(radeon);
139 LOCK_HARDWARE(radeon);
140 }
141 radeon->irqsEmitted = 10;
142 }
143
144 if (radeon->irqsEmitted) {
145 radeonEmitIrqLocked(radeon);
146 radeon->irqsEmitted--;
147 }
148 } else {
149 while (radeonGetLastFrame(radeon) < sarea->last_frame) {
150 UNLOCK_HARDWARE(radeon);
151 if (radeon->do_usleeps)
152 DO_USLEEP(1);
153 LOCK_HARDWARE(radeon);
154 }
155 }
156 }
157
158 /* Copy the back color buffer to the front color buffer.
159 */
160 void radeonCopyBuffer(const __DRIdrawablePrivate * dPriv,
161 const drm_clip_rect_t * rect)
162 {
163 radeonContextPtr radeon;
164 GLint nbox, i, ret;
165 GLboolean missed_target;
166 int64_t ust;
167
168 assert(dPriv);
169 assert(dPriv->driContextPriv);
170 assert(dPriv->driContextPriv->driverPrivate);
171
172 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
173
174 if (RADEON_DEBUG & DEBUG_IOCTL) {
175 fprintf(stderr, "\n%s( %p )\n\n", __FUNCTION__,
176 (void *)radeon->glCtx);
177 }
178
179 r300Flush(radeon->glCtx);
180
181 LOCK_HARDWARE(radeon);
182
183 /* Throttle the frame rate -- only allow one pending swap buffers
184 * request at a time.
185 */
186 radeonWaitForFrameCompletion(radeon);
187 if (!rect)
188 {
189 UNLOCK_HARDWARE(radeon);
190 driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags,
191 &missed_target);
192 LOCK_HARDWARE(radeon);
193 }
194
195 nbox = dPriv->numClipRects; /* must be in locked region */
196
197 for (i = 0; i < nbox;) {
198 GLint nr = MIN2(i + RADEON_NR_SAREA_CLIPRECTS, nbox);
199 drm_clip_rect_t *box = dPriv->pClipRects;
200 drm_clip_rect_t *b = radeon->sarea->boxes;
201 GLint n = 0;
202
203 for ( ; i < nr ; i++ ) {
204
205 *b = box[i];
206
207 if (rect)
208 {
209 if (rect->x1 > b->x1)
210 b->x1 = rect->x1;
211 if (rect->y1 > b->y1)
212 b->y1 = rect->y1;
213 if (rect->x2 < b->x2)
214 b->x2 = rect->x2;
215 if (rect->y2 < b->y2)
216 b->y2 = rect->y2;
217
218 if (b->x1 < b->x2 && b->y1 < b->y2)
219 b++;
220 }
221 else
222 b++;
223
224 n++;
225 }
226 radeon->sarea->nbox = n;
227
228 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_SWAP);
229
230 if (ret) {
231 fprintf(stderr, "DRM_RADEON_SWAP: return = %d\n",
232 ret);
233 UNLOCK_HARDWARE(radeon);
234 exit(1);
235 }
236 }
237
238 UNLOCK_HARDWARE(radeon);
239 if (!rect)
240 {
241 ((r300ContextPtr)radeon)->hw.all_dirty = GL_TRUE;
242
243 radeon->swap_count++;
244 (*dri_interface->getUST) (&ust);
245 if (missed_target) {
246 radeon->swap_missed_count++;
247 radeon->swap_missed_ust = ust - radeon->swap_ust;
248 }
249
250 radeon->swap_ust = ust;
251
252 sched_yield();
253 }
254 }
255
256 void radeonPageFlip(const __DRIdrawablePrivate * dPriv)
257 {
258 radeonContextPtr radeon;
259 GLint ret;
260 GLboolean missed_target;
261
262 assert(dPriv);
263 assert(dPriv->driContextPriv);
264 assert(dPriv->driContextPriv->driverPrivate);
265
266 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
267
268 if (RADEON_DEBUG & DEBUG_IOCTL) {
269 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
270 radeon->sarea->pfCurrentPage);
271 }
272
273 r300Flush(radeon->glCtx);
274 LOCK_HARDWARE(radeon);
275
276 if (!dPriv->numClipRects) {
277 UNLOCK_HARDWARE(radeon);
278 usleep(10000); /* throttle invisible client 10ms */
279 return;
280 }
281
282 /* Need to do this for the perf box placement:
283 */
284 {
285 drm_clip_rect_t *box = dPriv->pClipRects;
286 drm_clip_rect_t *b = radeon->sarea->boxes;
287 b[0] = box[0];
288 radeon->sarea->nbox = 1;
289 }
290
291 /* Throttle the frame rate -- only allow a few pending swap buffers
292 * request at a time.
293 */
294 radeonWaitForFrameCompletion(radeon);
295 UNLOCK_HARDWARE(radeon);
296 driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags,
297 &missed_target);
298 if (missed_target) {
299 radeon->swap_missed_count++;
300 (void)(*dri_interface->getUST) (&radeon->swap_missed_ust);
301 }
302 LOCK_HARDWARE(radeon);
303
304 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_FLIP);
305
306 UNLOCK_HARDWARE(radeon);
307
308 if (ret) {
309 fprintf(stderr, "DRM_RADEON_FLIP: return = %d\n", ret);
310 exit(1);
311 }
312
313 radeon->swap_count++;
314 (void)(*dri_interface->getUST) (&radeon->swap_ust);
315
316 driFlipRenderbuffers(radeon->glCtx->WinSysDrawBuffer,
317 radeon->sarea->pfCurrentPage);
318
319 if (radeon->sarea->pfCurrentPage == 1) {
320 radeon->state.color.drawOffset = radeon->radeonScreen->frontOffset;
321 radeon->state.color.drawPitch = radeon->radeonScreen->frontPitch;
322 } else {
323 radeon->state.color.drawOffset = radeon->radeonScreen->backOffset;
324 radeon->state.color.drawPitch = radeon->radeonScreen->backPitch;
325 }
326
327 if (IS_R300_CLASS(radeon->radeonScreen)) {
328 r300ContextPtr r300 = (r300ContextPtr)radeon;
329 R300_STATECHANGE(r300, cb);
330 r300->hw.cb.cmd[R300_CB_OFFSET] = r300->radeon.state.color.drawOffset +
331 r300->radeon.radeonScreen->fbLocation;
332 r300->hw.cb.cmd[R300_CB_PITCH] = r300->radeon.state.color.drawPitch;
333
334 if (r300->radeon.radeonScreen->cpp == 4)
335 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_ARGB8888;
336 else
337 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_RGB565;
338
339 if (r300->radeon.sarea->tiling_enabled)
340 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_TILE_ENABLE;
341 }
342 }
343
344 void radeonWaitForIdleLocked(radeonContextPtr radeon)
345 {
346 int ret;
347 int i = 0;
348
349 do {
350 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE);
351 if (ret)
352 DO_USLEEP(1);
353 } while (ret && ++i < 100);
354
355 if (ret < 0) {
356 UNLOCK_HARDWARE(radeon);
357 fprintf(stderr, "Error: R300 timed out... exiting\n");
358 exit(-1);
359 }
360 }
361
362 static void radeonWaitForIdle(radeonContextPtr radeon)
363 {
364 LOCK_HARDWARE(radeon);
365 radeonWaitForIdleLocked(radeon);
366 UNLOCK_HARDWARE(radeon);
367 }
368
369 void radeonFlush(GLcontext * ctx)
370 {
371 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
372
373 if (IS_R300_CLASS(radeon->radeonScreen))
374 r300Flush(ctx);
375 }
376
377
378 /* Make sure all commands have been sent to the hardware and have
379 * completed processing.
380 */
381 void radeonFinish(GLcontext * ctx)
382 {
383 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
384
385 radeonFlush(ctx);
386
387 if (radeon->do_irqs) {
388 LOCK_HARDWARE(radeon);
389 radeonEmitIrqLocked(radeon);
390 UNLOCK_HARDWARE(radeon);
391 radeonWaitIrq(radeon);
392 } else
393 radeonWaitForIdle(radeon);
394 }