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