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