More vblank cleanups.
[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(__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, &missed_target);
191 LOCK_HARDWARE(radeon);
192 }
193
194 nbox = dPriv->numClipRects; /* must be in locked region */
195
196 for (i = 0; i < nbox;) {
197 GLint nr = MIN2(i + RADEON_NR_SAREA_CLIPRECTS, nbox);
198 drm_clip_rect_t *box = dPriv->pClipRects;
199 drm_clip_rect_t *b = radeon->sarea->boxes;
200 GLint n = 0;
201
202 for ( ; i < nr ; i++ ) {
203
204 *b = box[i];
205
206 if (rect)
207 {
208 if (rect->x1 > b->x1)
209 b->x1 = rect->x1;
210 if (rect->y1 > b->y1)
211 b->y1 = rect->y1;
212 if (rect->x2 < b->x2)
213 b->x2 = rect->x2;
214 if (rect->y2 < b->y2)
215 b->y2 = rect->y2;
216
217 if (b->x1 < b->x2 && b->y1 < b->y2)
218 b++;
219 }
220 else
221 b++;
222
223 n++;
224 }
225 radeon->sarea->nbox = n;
226
227 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_SWAP);
228
229 if (ret) {
230 fprintf(stderr, "DRM_RADEON_SWAP: return = %d\n",
231 ret);
232 UNLOCK_HARDWARE(radeon);
233 exit(1);
234 }
235 }
236
237 UNLOCK_HARDWARE(radeon);
238 if (!rect)
239 {
240 ((r300ContextPtr)radeon)->hw.all_dirty = GL_TRUE;
241
242 radeon->swap_count++;
243 (*dri_interface->getUST) (&ust);
244 if (missed_target) {
245 radeon->swap_missed_count++;
246 radeon->swap_missed_ust = ust - radeon->swap_ust;
247 }
248
249 radeon->swap_ust = ust;
250
251 sched_yield();
252 }
253 }
254
255 void radeonPageFlip(__DRIdrawablePrivate * dPriv)
256 {
257 radeonContextPtr radeon;
258 GLint ret;
259 GLboolean missed_target;
260
261 assert(dPriv);
262 assert(dPriv->driContextPriv);
263 assert(dPriv->driContextPriv->driverPrivate);
264
265 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
266
267 if (RADEON_DEBUG & DEBUG_IOCTL) {
268 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
269 radeon->sarea->pfCurrentPage);
270 }
271
272 r300Flush(radeon->glCtx);
273 LOCK_HARDWARE(radeon);
274
275 if (!dPriv->numClipRects) {
276 UNLOCK_HARDWARE(radeon);
277 usleep(10000); /* throttle invisible client 10ms */
278 return;
279 }
280
281 /* Need to do this for the perf box placement:
282 */
283 {
284 drm_clip_rect_t *box = dPriv->pClipRects;
285 drm_clip_rect_t *b = radeon->sarea->boxes;
286 b[0] = box[0];
287 radeon->sarea->nbox = 1;
288 }
289
290 /* Throttle the frame rate -- only allow a few pending swap buffers
291 * request at a time.
292 */
293 radeonWaitForFrameCompletion(radeon);
294 UNLOCK_HARDWARE(radeon);
295 driWaitForVBlank(dPriv, &missed_target);
296 if (missed_target) {
297 radeon->swap_missed_count++;
298 (void)(*dri_interface->getUST) (&radeon->swap_missed_ust);
299 }
300 LOCK_HARDWARE(radeon);
301
302 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_FLIP);
303
304 UNLOCK_HARDWARE(radeon);
305
306 if (ret) {
307 fprintf(stderr, "DRM_RADEON_FLIP: return = %d\n", ret);
308 exit(1);
309 }
310
311 radeon->swap_count++;
312 (void)(*dri_interface->getUST) (&radeon->swap_ust);
313
314 driFlipRenderbuffers(radeon->glCtx->WinSysDrawBuffer,
315 radeon->sarea->pfCurrentPage);
316
317 if (radeon->sarea->pfCurrentPage == 1) {
318 radeon->state.color.drawOffset = radeon->radeonScreen->frontOffset;
319 radeon->state.color.drawPitch = radeon->radeonScreen->frontPitch;
320 } else {
321 radeon->state.color.drawOffset = radeon->radeonScreen->backOffset;
322 radeon->state.color.drawPitch = radeon->radeonScreen->backPitch;
323 }
324
325 if (IS_R300_CLASS(radeon->radeonScreen)) {
326 r300ContextPtr r300 = (r300ContextPtr)radeon;
327 R300_STATECHANGE(r300, cb);
328 r300->hw.cb.cmd[R300_CB_OFFSET] = r300->radeon.state.color.drawOffset +
329 r300->radeon.radeonScreen->fbLocation;
330 r300->hw.cb.cmd[R300_CB_PITCH] = r300->radeon.state.color.drawPitch;
331
332 if (r300->radeon.radeonScreen->cpp == 4)
333 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_ARGB8888;
334 else
335 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_RGB565;
336
337 if (r300->radeon.sarea->tiling_enabled)
338 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_TILE_ENABLE;
339 }
340 }
341
342 void radeonWaitForIdleLocked(radeonContextPtr radeon)
343 {
344 int ret;
345 int i = 0;
346
347 do {
348 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE);
349 if (ret)
350 DO_USLEEP(1);
351 } while (ret && ++i < 100);
352
353 if (ret < 0) {
354 UNLOCK_HARDWARE(radeon);
355 fprintf(stderr, "Error: R300 timed out... exiting\n");
356 exit(-1);
357 }
358 }
359
360 static void radeonWaitForIdle(radeonContextPtr radeon)
361 {
362 LOCK_HARDWARE(radeon);
363 radeonWaitForIdleLocked(radeon);
364 UNLOCK_HARDWARE(radeon);
365 }
366
367 void radeonFlush(GLcontext * ctx)
368 {
369 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
370
371 if (IS_R300_CLASS(radeon->radeonScreen))
372 r300Flush(ctx);
373 }
374
375
376 /* Make sure all commands have been sent to the hardware and have
377 * completed processing.
378 */
379 void radeonFinish(GLcontext * ctx)
380 {
381 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
382
383 radeonFlush(ctx);
384
385 if (radeon->do_irqs) {
386 LOCK_HARDWARE(radeon);
387 radeonEmitIrqLocked(radeon);
388 UNLOCK_HARDWARE(radeon);
389 radeonWaitIrq(radeon);
390 } else
391 radeonWaitForIdle(radeon);
392 }