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