slang: initialize the context
[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 "main/glheader.h"
39 #include "main/imports.h"
40 #include "main/macros.h"
41 #include "main/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 = 0;
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 = 0;
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 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
168
169 assert(dPriv);
170 assert(dPriv->driContextPriv);
171 assert(dPriv->driContextPriv->driverPrivate);
172
173 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
174
175 if (RADEON_DEBUG & DEBUG_IOCTL) {
176 fprintf(stderr, "\n%s( %p )\n\n", __FUNCTION__,
177 (void *)radeon->glCtx);
178 }
179
180 r300Flush(radeon->glCtx);
181
182 LOCK_HARDWARE(radeon);
183
184 /* Throttle the frame rate -- only allow one pending swap buffers
185 * request at a time.
186 */
187 radeonWaitForFrameCompletion(radeon);
188 if (!rect)
189 {
190 UNLOCK_HARDWARE(radeon);
191 driWaitForVBlank(dPriv, &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 continue;
220 }
221
222 b++;
223 n++;
224 }
225 radeon->sarea->nbox = n;
226
227 if (!n)
228 continue;
229
230 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_SWAP);
231
232 if (ret) {
233 fprintf(stderr, "DRM_RADEON_SWAP: return = %d\n",
234 ret);
235 UNLOCK_HARDWARE(radeon);
236 exit(1);
237 }
238 }
239
240 UNLOCK_HARDWARE(radeon);
241 if (!rect)
242 {
243 ((r300ContextPtr)radeon)->hw.all_dirty = GL_TRUE;
244
245 radeon->swap_count++;
246 (*psp->systemTime->getUST) (&ust);
247 if (missed_target) {
248 radeon->swap_missed_count++;
249 radeon->swap_missed_ust = ust - radeon->swap_ust;
250 }
251
252 radeon->swap_ust = ust;
253
254 sched_yield();
255 }
256 }
257
258 void radeonPageFlip(__DRIdrawablePrivate * dPriv)
259 {
260 radeonContextPtr radeon;
261 GLint ret;
262 GLboolean missed_target;
263 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
264
265 assert(dPriv);
266 assert(dPriv->driContextPriv);
267 assert(dPriv->driContextPriv->driverPrivate);
268
269 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
270
271 if (RADEON_DEBUG & DEBUG_IOCTL) {
272 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
273 radeon->sarea->pfCurrentPage);
274 }
275
276 r300Flush(radeon->glCtx);
277 LOCK_HARDWARE(radeon);
278
279 if (!dPriv->numClipRects) {
280 UNLOCK_HARDWARE(radeon);
281 usleep(10000); /* throttle invisible client 10ms */
282 return;
283 }
284
285 /* Need to do this for the perf box placement:
286 */
287 {
288 drm_clip_rect_t *box = dPriv->pClipRects;
289 drm_clip_rect_t *b = radeon->sarea->boxes;
290 b[0] = box[0];
291 radeon->sarea->nbox = 1;
292 }
293
294 /* Throttle the frame rate -- only allow a few pending swap buffers
295 * request at a time.
296 */
297 radeonWaitForFrameCompletion(radeon);
298 UNLOCK_HARDWARE(radeon);
299 driWaitForVBlank(dPriv, &missed_target);
300 if (missed_target) {
301 radeon->swap_missed_count++;
302 (void)(*psp->systemTime->getUST) (&radeon->swap_missed_ust);
303 }
304 LOCK_HARDWARE(radeon);
305
306 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_FLIP);
307
308 UNLOCK_HARDWARE(radeon);
309
310 if (ret) {
311 fprintf(stderr, "DRM_RADEON_FLIP: return = %d\n", ret);
312 exit(1);
313 }
314
315 radeon->swap_count++;
316 (void)(*psp->systemTime->getUST) (&radeon->swap_ust);
317
318 driFlipRenderbuffers(radeon->glCtx->WinSysDrawBuffer,
319 radeon->sarea->pfCurrentPage);
320
321 if (radeon->sarea->pfCurrentPage == 1) {
322 radeon->state.color.drawOffset = radeon->radeonScreen->frontOffset;
323 radeon->state.color.drawPitch = radeon->radeonScreen->frontPitch;
324 } else {
325 radeon->state.color.drawOffset = radeon->radeonScreen->backOffset;
326 radeon->state.color.drawPitch = radeon->radeonScreen->backPitch;
327 }
328
329 if (IS_R300_CLASS(radeon->radeonScreen)) {
330 r300ContextPtr r300 = (r300ContextPtr)radeon;
331 R300_STATECHANGE(r300, cb);
332 r300->hw.cb.cmd[R300_CB_OFFSET] = r300->radeon.state.color.drawOffset +
333 r300->radeon.radeonScreen->fbLocation;
334 r300->hw.cb.cmd[R300_CB_PITCH] = r300->radeon.state.color.drawPitch;
335
336 if (r300->radeon.radeonScreen->cpp == 4)
337 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_ARGB8888;
338 else
339 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_RGB565;
340
341 if (r300->radeon.sarea->tiling_enabled)
342 r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_TILE_ENABLE;
343 }
344 }
345
346 void radeonWaitForIdleLocked(radeonContextPtr radeon)
347 {
348 int ret;
349 int i = 0;
350
351 do {
352 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE);
353 if (ret)
354 DO_USLEEP(1);
355 } while (ret && ++i < 100);
356
357 if (ret < 0) {
358 UNLOCK_HARDWARE(radeon);
359 fprintf(stderr, "Error: R300 timed out... exiting\n");
360 exit(-1);
361 }
362 }
363
364 static void radeonWaitForIdle(radeonContextPtr radeon)
365 {
366 LOCK_HARDWARE(radeon);
367 radeonWaitForIdleLocked(radeon);
368 UNLOCK_HARDWARE(radeon);
369 }
370
371 void radeonFlush(GLcontext * ctx)
372 {
373 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
374
375 if (IS_R300_CLASS(radeon->radeonScreen))
376 r300Flush(ctx);
377 }
378
379
380 /* Make sure all commands have been sent to the hardware and have
381 * completed processing.
382 */
383 void radeonFinish(GLcontext * ctx)
384 {
385 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
386
387 radeonFlush(ctx);
388
389 if (radeon->do_irqs) {
390 LOCK_HARDWARE(radeon);
391 radeonEmitIrqLocked(radeon);
392 UNLOCK_HARDWARE(radeon);
393 radeonWaitIrq(radeon);
394 } else
395 radeonWaitForIdle(radeon);
396 }