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