radeon_ioctl.c revision 16c704e8f7cd9b7d7c5d6667cb38e016e3b608d1
1/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c,v 1.11 2003/01/29 22:04:59 dawes Exp $ */
2/**************************************************************************
3
4Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5                     VA Linux Systems Inc., Fremont, California.
6
7All Rights Reserved.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice (including the
18next paragraph) shall be included in all copies or substantial
19portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29**************************************************************************/
30
31/*
32 * Authors:
33 *   Kevin E. Martin <martin@valinux.com>
34 *   Gareth Hughes <gareth@valinux.com>
35 *   Keith Whitwell <keith@tungstengraphics.com>
36 */
37
38#include <sched.h>
39#include <errno.h>
40
41#include "glheader.h"
42#include "imports.h"
43#include "simple_list.h"
44#include "swrast/swrast.h"
45
46#include "radeon_context.h"
47#include "radeon_state.h"
48#include "radeon_ioctl.h"
49#include "radeon_tcl.h"
50#include "radeon_sanity.h"
51
52#include "radeon_macros.h"  /* for INREG() */
53
54#include "vblank.h"
55
56#define RADEON_TIMEOUT             512
57#define RADEON_IDLE_RETRY           16
58
59
60static void radeonWaitForIdle( radeonContextPtr rmesa );
61
62/* =============================================================
63 * Kernel command buffer handling
64 */
65
66static void print_state_atom( struct radeon_state_atom *state )
67{
68   int i;
69
70   fprintf(stderr, "emit %s/%d\n", state->name, state->cmd_size);
71
72   if (RADEON_DEBUG & DEBUG_VERBOSE)
73      for (i = 0 ; i < state->cmd_size ; i++)
74	 fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]);
75
76}
77
78static void radeon_emit_state_list( radeonContextPtr rmesa,
79				    struct radeon_state_atom *list )
80{
81   struct radeon_state_atom *state, *tmp;
82   char *dest;
83   int i, size, texunits;
84
85   /* It appears that some permutations of state atoms lock up the
86    * chip.  Therefore we make sure that state atoms are emitted in a
87    * fixed order. First mark all dirty state atoms and then go
88    * through all state atoms in a well defined order and emit only
89    * the marked ones.
90    * FIXME: This requires knowledge of which state atoms exist.
91    * FIXME: Is the zbs hack below still needed?
92    */
93   size = 0;
94   foreach_s( state, tmp, list ) {
95      if (state->check( rmesa->glCtx )) {
96	 size += state->cmd_size;
97	 state->dirty = GL_TRUE;
98	 move_to_head( &(rmesa->hw.clean), state );
99	 if (RADEON_DEBUG & DEBUG_STATE)
100	    print_state_atom( state );
101      }
102      else if (RADEON_DEBUG & DEBUG_STATE)
103	 fprintf(stderr, "skip state %s\n", state->name);
104   }
105   /* short cut */
106   if (!size)
107       return;
108
109   dest = radeonAllocCmdBuf( rmesa, size * 4, __FUNCTION__);
110   texunits = rmesa->glCtx->Const.MaxTextureUnits;
111
112#define EMIT_ATOM(ATOM) \
113do { \
114   if (rmesa->hw.ATOM.dirty) { \
115      rmesa->hw.ATOM.dirty = GL_FALSE; \
116      memcpy( dest, rmesa->hw.ATOM.cmd, rmesa->hw.ATOM.cmd_size * 4); \
117      dest += rmesa->hw.ATOM.cmd_size * 4; \
118   } \
119} while (0)
120
121   EMIT_ATOM (ctx);
122   EMIT_ATOM (set);
123   EMIT_ATOM (lin);
124   EMIT_ATOM (msk);
125   EMIT_ATOM (vpt);
126   EMIT_ATOM (tcl);
127   EMIT_ATOM (msc);
128   for (i = 0; i < texunits; ++i) {
129       EMIT_ATOM (tex[i]);
130       EMIT_ATOM (txr[i]);
131   }
132   EMIT_ATOM (zbs);
133   EMIT_ATOM (mtl);
134   for (i = 0; i < 3 + texunits; ++i)
135       EMIT_ATOM (mat[i]);
136   for (i = 0; i < 8; ++i)
137       EMIT_ATOM (lit[i]);
138   for (i = 0; i < 6; ++i)
139       EMIT_ATOM (ucp[i]);
140   EMIT_ATOM (eye);
141   EMIT_ATOM (grd);
142   EMIT_ATOM (fog);
143   EMIT_ATOM (glt);
144
145#undef EMIT_ATOM
146}
147
148
149void radeonEmitState( radeonContextPtr rmesa )
150{
151   struct radeon_state_atom *state, *tmp;
152
153   if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS))
154      fprintf(stderr, "%s\n", __FUNCTION__);
155
156   /* Somewhat overkill:
157    */
158   if (rmesa->lost_context) {
159      if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS|DEBUG_IOCTL))
160	 fprintf(stderr, "%s - lost context\n", __FUNCTION__);
161
162      foreach_s( state, tmp, &(rmesa->hw.clean) )
163	 move_to_tail(&(rmesa->hw.dirty), state );
164
165      rmesa->lost_context = 0;
166   }
167   else if (1) {
168      /* This is a darstardly kludge to work around a lockup that I
169       * haven't otherwise figured out.
170       */
171      move_to_tail(&(rmesa->hw.dirty), &(rmesa->hw.zbs) );
172   }
173
174   if (!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) {
175     foreach_s( state, tmp, &(rmesa->hw.dirty) ) {
176       if (state->is_tcl) {
177	 move_to_head( &(rmesa->hw.clean), state );
178       }
179     }
180   }
181
182   radeon_emit_state_list( rmesa, &rmesa->hw.dirty );
183}
184
185
186
187/* Fire a section of the retained (indexed_verts) buffer as a regular
188 * primtive.
189 */
190extern void radeonEmitVbufPrim( radeonContextPtr rmesa,
191				GLuint vertex_format,
192				GLuint primitive,
193				GLuint vertex_nr )
194{
195   drm_radeon_cmd_header_t *cmd;
196
197
198   assert(!(primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
199
200   radeonEmitState( rmesa );
201
202   if (RADEON_DEBUG & DEBUG_IOCTL)
203      fprintf(stderr, "%s cmd_used/4: %d\n", __FUNCTION__,
204	      rmesa->store.cmd_used/4);
205
206#if RADEON_OLD_PACKETS
207   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, 6 * sizeof(*cmd),
208						  __FUNCTION__ );
209   cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
210   cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM | (3 << 16);
211   cmd[2].i = rmesa->ioctl.vertex_offset;
212   cmd[3].i = vertex_nr;
213   cmd[4].i = vertex_format;
214   cmd[5].i = (primitive |
215	       RADEON_CP_VC_CNTL_PRIM_WALK_LIST |
216	       RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
217	       RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE |
218	       (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT));
219
220   if (RADEON_DEBUG & DEBUG_PRIMS)
221      fprintf(stderr, "%s: header 0x%x offt 0x%x vfmt 0x%x vfcntl %x \n",
222	      __FUNCTION__,
223	      cmd[1].i, cmd[2].i, cmd[4].i, cmd[5].i);
224#else
225   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, 4 * sizeof(*cmd),
226						  __FUNCTION__ );
227   cmd[0].i = 0;
228   cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
229   cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_VBUF | (1 << 16);
230   cmd[2].i = vertex_format;
231   cmd[3].i = (primitive |
232	       RADEON_CP_VC_CNTL_PRIM_WALK_LIST |
233	       RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
234	       RADEON_CP_VC_CNTL_MAOS_ENABLE |
235	       RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE |
236	       (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT));
237
238
239   if (RADEON_DEBUG & DEBUG_PRIMS)
240      fprintf(stderr, "%s: header 0x%x vfmt 0x%x vfcntl %x \n",
241	      __FUNCTION__,
242	      cmd[1].i, cmd[2].i, cmd[3].i);
243#endif
244}
245
246
247void radeonFlushElts( radeonContextPtr rmesa )
248{
249   int *cmd = (int *)(rmesa->store.cmd_buf + rmesa->store.elts_start);
250   int dwords;
251#if RADEON_OLD_PACKETS
252   int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 24)) / 2;
253#else
254   int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 16)) / 2;
255#endif
256
257   if (RADEON_DEBUG & DEBUG_IOCTL)
258      fprintf(stderr, "%s\n", __FUNCTION__);
259
260   assert( rmesa->dma.flush == radeonFlushElts );
261   rmesa->dma.flush = 0;
262
263   /* Cope with odd number of elts:
264    */
265   rmesa->store.cmd_used = (rmesa->store.cmd_used + 2) & ~2;
266   dwords = (rmesa->store.cmd_used - rmesa->store.elts_start) / 4;
267
268#if RADEON_OLD_PACKETS
269   cmd[1] |= (dwords - 3) << 16;
270   cmd[5] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT;
271#else
272   cmd[1] |= (dwords - 3) << 16;
273   cmd[3] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT;
274#endif
275}
276
277
278GLushort *radeonAllocEltsOpenEnded( radeonContextPtr rmesa,
279				    GLuint vertex_format,
280				    GLuint primitive,
281				    GLuint min_nr )
282{
283   drm_radeon_cmd_header_t *cmd;
284   GLushort *retval;
285
286   if (RADEON_DEBUG & DEBUG_IOCTL)
287      fprintf(stderr, "%s %d\n", __FUNCTION__, min_nr);
288
289   assert((primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND));
290
291   radeonEmitState( rmesa );
292
293#if RADEON_OLD_PACKETS
294   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa,
295						  24 + min_nr*2,
296						  __FUNCTION__ );
297   cmd[0].i = 0;
298   cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
299   cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM;
300   cmd[2].i = rmesa->ioctl.vertex_offset;
301   cmd[3].i = 0xffff;
302   cmd[4].i = vertex_format;
303   cmd[5].i = (primitive |
304	       RADEON_CP_VC_CNTL_PRIM_WALK_IND |
305	       RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
306	       RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE);
307
308   retval = (GLushort *)(cmd+6);
309#else
310   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa,
311						  16 + min_nr*2,
312						  __FUNCTION__ );
313   cmd[0].i = 0;
314   cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP;
315   cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_INDX;
316   cmd[2].i = vertex_format;
317   cmd[3].i = (primitive |
318	       RADEON_CP_VC_CNTL_PRIM_WALK_IND |
319	       RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA |
320	       RADEON_CP_VC_CNTL_MAOS_ENABLE |
321	       RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE);
322
323   retval = (GLushort *)(cmd+4);
324#endif
325
326   if (RADEON_DEBUG & DEBUG_PRIMS)
327      fprintf(stderr, "%s: header 0x%x vfmt 0x%x prim %x \n",
328	      __FUNCTION__,
329	      cmd[1].i, vertex_format, primitive);
330
331   assert(!rmesa->dma.flush);
332   rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
333   rmesa->dma.flush = radeonFlushElts;
334
335   rmesa->store.elts_start = ((char *)cmd) - rmesa->store.cmd_buf;
336
337   return retval;
338}
339
340
341
342void radeonEmitVertexAOS( radeonContextPtr rmesa,
343			  GLuint vertex_size,
344			  GLuint offset )
345{
346#if RADEON_OLD_PACKETS
347   rmesa->ioctl.vertex_size = vertex_size;
348   rmesa->ioctl.vertex_offset = offset;
349#else
350   drm_radeon_cmd_header_t *cmd;
351
352   if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_IOCTL))
353      fprintf(stderr, "%s:  vertex_size 0x%x offset 0x%x \n",
354	      __FUNCTION__, vertex_size, offset);
355
356   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, 5 * sizeof(int),
357						  __FUNCTION__ );
358
359   cmd[0].i = 0;
360   cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
361   cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | (2 << 16);
362   cmd[2].i = 1;
363   cmd[3].i = vertex_size | (vertex_size << 8);
364   cmd[4].i = offset;
365#endif
366}
367
368
369void radeonEmitAOS( radeonContextPtr rmesa,
370		    struct radeon_dma_region **component,
371		    GLuint nr,
372		    GLuint offset )
373{
374#if RADEON_OLD_PACKETS
375   assert( nr == 1 );
376   assert( component[0]->aos_size == component[0]->aos_stride );
377   rmesa->ioctl.vertex_size = component[0]->aos_size;
378   rmesa->ioctl.vertex_offset =
379      (component[0]->aos_start + offset * component[0]->aos_stride * 4);
380#else
381   drm_radeon_cmd_header_t *cmd;
382   int sz = 3 + (nr/2 * 3) + (nr & 1) * 2;
383   int i;
384   int *tmp;
385
386   if (RADEON_DEBUG & DEBUG_IOCTL)
387      fprintf(stderr, "%s\n", __FUNCTION__);
388
389
390   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, sz * sizeof(int),
391						  __FUNCTION__ );
392   cmd[0].i = 0;
393   cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
394   cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | ((sz-3) << 16);
395   cmd[2].i = nr;
396   tmp = &cmd[0].i;
397   cmd += 3;
398
399   for (i = 0 ; i < nr ; i++) {
400      if (i & 1) {
401	 cmd[0].i |= ((component[i]->aos_stride << 24) |
402		      (component[i]->aos_size << 16));
403	 cmd[2].i = (component[i]->aos_start +
404		     offset * component[i]->aos_stride * 4);
405	 cmd += 3;
406      }
407      else {
408	 cmd[0].i = ((component[i]->aos_stride << 8) |
409		     (component[i]->aos_size << 0));
410	 cmd[1].i = (component[i]->aos_start +
411		     offset * component[i]->aos_stride * 4);
412      }
413   }
414
415   if (RADEON_DEBUG & DEBUG_VERTS) {
416      fprintf(stderr, "%s:\n", __FUNCTION__);
417      for (i = 0 ; i < sz ; i++)
418	 fprintf(stderr, "   %d: %x\n", i, tmp[i]);
419   }
420#endif
421}
422
423/* using already shifted color_fmt! */
424void radeonEmitBlit( radeonContextPtr rmesa, /* FIXME: which drmMinor is required? */
425		   GLuint color_fmt,
426		   GLuint src_pitch,
427		   GLuint src_offset,
428		   GLuint dst_pitch,
429		   GLuint dst_offset,
430		   GLint srcx, GLint srcy,
431		   GLint dstx, GLint dsty,
432		   GLuint w, GLuint h )
433{
434   drm_radeon_cmd_header_t *cmd;
435
436   if (RADEON_DEBUG & DEBUG_IOCTL)
437      fprintf(stderr, "%s src %x/%x %d,%d dst: %x/%x %d,%d sz: %dx%d\n",
438	      __FUNCTION__,
439	      src_pitch, src_offset, srcx, srcy,
440	      dst_pitch, dst_offset, dstx, dsty,
441	      w, h);
442
443   assert( (src_pitch & 63) == 0 );
444   assert( (dst_pitch & 63) == 0 );
445   assert( (src_offset & 1023) == 0 );
446   assert( (dst_offset & 1023) == 0 );
447   assert( w < (1<<16) );
448   assert( h < (1<<16) );
449
450   cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, 8 * sizeof(int),
451						  __FUNCTION__ );
452
453
454   cmd[0].i = 0;
455   cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
456   cmd[1].i = RADEON_CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16);
457   cmd[2].i = (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
458	       RADEON_GMC_DST_PITCH_OFFSET_CNTL |
459	       RADEON_GMC_BRUSH_NONE |
460	       color_fmt |
461	       RADEON_GMC_SRC_DATATYPE_COLOR |
462	       RADEON_ROP3_S |
463	       RADEON_DP_SRC_SOURCE_MEMORY |
464	       RADEON_GMC_CLR_CMP_CNTL_DIS |
465	       RADEON_GMC_WR_MSK_DIS );
466
467   cmd[3].i = ((src_pitch/64)<<22) | (src_offset >> 10);
468   cmd[4].i = ((dst_pitch/64)<<22) | (dst_offset >> 10);
469   cmd[5].i = (srcx << 16) | srcy;
470   cmd[6].i = (dstx << 16) | dsty; /* dst */
471   cmd[7].i = (w << 16) | h;
472}
473
474
475void radeonEmitWait( radeonContextPtr rmesa, GLuint flags )
476{
477   if (rmesa->dri.drmMinor >= 6) {
478      drm_radeon_cmd_header_t *cmd;
479
480      assert( !(flags & ~(RADEON_WAIT_2D|RADEON_WAIT_3D)) );
481
482      cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, 1 * sizeof(int),
483						   __FUNCTION__ );
484      cmd[0].i = 0;
485      cmd[0].wait.cmd_type = RADEON_CMD_WAIT;
486      cmd[0].wait.flags = flags;
487   }
488}
489
490
491static int radeonFlushCmdBufLocked( radeonContextPtr rmesa,
492				    const char * caller )
493{
494   int ret, i;
495   drm_radeon_cmd_buffer_t cmd;
496
497   if (RADEON_DEBUG & DEBUG_IOCTL) {
498      fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
499
500      if (RADEON_DEBUG & DEBUG_VERBOSE)
501	 for (i = 0 ; i < rmesa->store.cmd_used ; i += 4 )
502	    fprintf(stderr, "%d: %x\n", i/4,
503		    *(int *)(&rmesa->store.cmd_buf[i]));
504   }
505
506   if (RADEON_DEBUG & DEBUG_DMA)
507      fprintf(stderr, "%s: Releasing %d buffers\n", __FUNCTION__,
508	      rmesa->dma.nr_released_bufs);
509
510
511   if (RADEON_DEBUG & DEBUG_SANITY) {
512      if (rmesa->state.scissor.enabled)
513	 ret = radeonSanityCmdBuffer( rmesa,
514				      rmesa->state.scissor.numClipRects,
515				      rmesa->state.scissor.pClipRects);
516      else
517	 ret = radeonSanityCmdBuffer( rmesa,
518				      rmesa->numClipRects,
519				      rmesa->pClipRects);
520      if (ret) {
521	 fprintf(stderr, "drmSanityCommandWrite: %d\n", ret);
522	 goto out;
523      }
524   }
525
526
527   cmd.bufsz = rmesa->store.cmd_used;
528   cmd.buf = rmesa->store.cmd_buf;
529
530   if (rmesa->state.scissor.enabled) {
531      cmd.nbox = rmesa->state.scissor.numClipRects;
532      cmd.boxes = rmesa->state.scissor.pClipRects;
533   } else {
534      cmd.nbox = rmesa->numClipRects;
535      cmd.boxes = rmesa->pClipRects;
536   }
537
538   ret = drmCommandWrite( rmesa->dri.fd,
539			  DRM_RADEON_CMDBUF,
540			  &cmd, sizeof(cmd) );
541
542   if (ret)
543      fprintf(stderr, "drmCommandWrite: %d\n", ret);
544
545 out:
546   rmesa->store.primnr = 0;
547   rmesa->store.statenr = 0;
548   rmesa->store.cmd_used = 0;
549   rmesa->dma.nr_released_bufs = 0;
550   rmesa->lost_context = 1;
551   return ret;
552}
553
554
555/* Note: does not emit any commands to avoid recursion on
556 * radeonAllocCmdBuf.
557 */
558void radeonFlushCmdBuf( radeonContextPtr rmesa, const char *caller )
559{
560   int ret;
561
562
563   LOCK_HARDWARE( rmesa );
564
565   ret = radeonFlushCmdBufLocked( rmesa, caller );
566
567   UNLOCK_HARDWARE( rmesa );
568
569   if (ret) {
570      fprintf(stderr, "drm_radeon_cmd_buffer_t: %d (exiting)\n", ret);
571      exit(ret);
572   }
573}
574
575/* =============================================================
576 * Hardware vertex buffer handling
577 */
578
579
580void radeonRefillCurrentDmaRegion( radeonContextPtr rmesa )
581{
582   struct radeon_dma_buffer *dmabuf;
583   int fd = rmesa->dri.fd;
584   int index = 0;
585   int size = 0;
586   drmDMAReq dma;
587   int ret;
588
589   if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
590      fprintf(stderr, "%s\n", __FUNCTION__);
591
592   if (rmesa->dma.flush) {
593      rmesa->dma.flush( rmesa );
594   }
595
596   if (rmesa->dma.current.buf)
597      radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ );
598
599   if (rmesa->dma.nr_released_bufs > 4)
600      radeonFlushCmdBuf( rmesa, __FUNCTION__ );
601
602   dma.context = rmesa->dri.hwContext;
603   dma.send_count = 0;
604   dma.send_list = NULL;
605   dma.send_sizes = NULL;
606   dma.flags = 0;
607   dma.request_count = 1;
608   dma.request_size = RADEON_BUFFER_SIZE;
609   dma.request_list = &index;
610   dma.request_sizes = &size;
611   dma.granted_count = 0;
612
613   LOCK_HARDWARE(rmesa);	/* no need to validate */
614
615   ret = drmDMA( fd, &dma );
616
617   if (ret != 0) {
618      /* Free some up this way?
619       */
620      if (rmesa->dma.nr_released_bufs) {
621	 radeonFlushCmdBufLocked( rmesa, __FUNCTION__ );
622      }
623
624      if (RADEON_DEBUG & DEBUG_DMA)
625	 fprintf(stderr, "Waiting for buffers\n");
626
627      radeonWaitForIdleLocked( rmesa );
628      ret = drmDMA( fd, &dma );
629
630      if ( ret != 0 ) {
631	 UNLOCK_HARDWARE( rmesa );
632	 fprintf( stderr, "Error: Could not get dma buffer... exiting\n" );
633	 exit( -1 );
634      }
635   }
636
637   UNLOCK_HARDWARE(rmesa);
638
639   if (RADEON_DEBUG & DEBUG_DMA)
640      fprintf(stderr, "Allocated buffer %d\n", index);
641
642   dmabuf = CALLOC_STRUCT( radeon_dma_buffer );
643   dmabuf->buf = &rmesa->radeonScreen->buffers->list[index];
644   dmabuf->refcount = 1;
645
646   rmesa->dma.current.buf = dmabuf;
647   rmesa->dma.current.address = dmabuf->buf->address;
648   rmesa->dma.current.end = dmabuf->buf->total;
649   rmesa->dma.current.start = 0;
650   rmesa->dma.current.ptr = 0;
651
652   rmesa->c_vertexBuffers++;
653}
654
655void radeonReleaseDmaRegion( radeonContextPtr rmesa,
656			     struct radeon_dma_region *region,
657			     const char *caller )
658{
659   if (RADEON_DEBUG & DEBUG_IOCTL)
660      fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
661
662   if (!region->buf)
663      return;
664
665   if (rmesa->dma.flush)
666      rmesa->dma.flush( rmesa );
667
668   if (--region->buf->refcount == 0) {
669      drm_radeon_cmd_header_t *cmd;
670
671      if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
672	 fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__,
673		 region->buf->buf->idx);
674
675      cmd = (drm_radeon_cmd_header_t *)radeonAllocCmdBuf( rmesa, sizeof(*cmd),
676						     __FUNCTION__ );
677      cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD;
678      cmd->dma.buf_idx = region->buf->buf->idx;
679      FREE(region->buf);
680      rmesa->dma.nr_released_bufs++;
681   }
682
683   region->buf = 0;
684   region->start = 0;
685}
686
687/* Allocates a region from rmesa->dma.current.  If there isn't enough
688 * space in current, grab a new buffer (and discard what was left of current)
689 */
690void radeonAllocDmaRegion( radeonContextPtr rmesa,
691			   struct radeon_dma_region *region,
692			   int bytes,
693			   int alignment )
694{
695   if (RADEON_DEBUG & DEBUG_IOCTL)
696      fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
697
698   if (rmesa->dma.flush)
699      rmesa->dma.flush( rmesa );
700
701   if (region->buf)
702      radeonReleaseDmaRegion( rmesa, region, __FUNCTION__ );
703
704   alignment--;
705   rmesa->dma.current.start = rmesa->dma.current.ptr =
706      (rmesa->dma.current.ptr + alignment) & ~alignment;
707
708   if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end )
709      radeonRefillCurrentDmaRegion( rmesa );
710
711   region->start = rmesa->dma.current.start;
712   region->ptr = rmesa->dma.current.start;
713   region->end = rmesa->dma.current.start + bytes;
714   region->address = rmesa->dma.current.address;
715   region->buf = rmesa->dma.current.buf;
716   region->buf->refcount++;
717
718   rmesa->dma.current.ptr += bytes; /* bug - if alignment > 7 */
719   rmesa->dma.current.start =
720      rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
721}
722
723void radeonAllocDmaRegionVerts( radeonContextPtr rmesa,
724				struct radeon_dma_region *region,
725				int numverts,
726				int vertsize,
727				int alignment )
728{
729   radeonAllocDmaRegion( rmesa, region, vertsize * numverts, alignment );
730}
731
732/* ================================================================
733 * SwapBuffers with client-side throttling
734 */
735
736static int32_t radeonGetLastFrame (radeonContextPtr rmesa)
737{
738   unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map;
739   int ret;
740   int32_t frame;
741
742   if (rmesa->dri.screen->drmMinor >= 4) {
743      drm_radeon_getparam_t gp;
744
745      gp.param = RADEON_PARAM_LAST_FRAME;
746      gp.value = (int *)&frame;
747      ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM,
748				 &gp, sizeof(gp) );
749   }
750   else
751      ret = -EINVAL;
752
753#ifndef __alpha__
754   if ( ret == -EINVAL ) {
755      frame = INREG( RADEON_LAST_FRAME_REG );
756      ret = 0;
757   }
758#endif
759   if ( ret ) {
760      fprintf( stderr, "%s: drm_radeon_getparam_t: %d\n", __FUNCTION__, ret );
761      exit(1);
762   }
763
764   return frame;
765}
766
767static void radeonEmitIrqLocked( radeonContextPtr rmesa )
768{
769   drm_radeon_irq_emit_t ie;
770   int ret;
771
772   ie.irq_seq = &rmesa->iw.irq_seq;
773   ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_IRQ_EMIT,
774			      &ie, sizeof(ie) );
775   if ( ret ) {
776      fprintf( stderr, "%s: drm_radeon_irq_emit_t: %d\n", __FUNCTION__, ret );
777      exit(1);
778   }
779}
780
781
782static void radeonWaitIrq( radeonContextPtr rmesa )
783{
784   int ret;
785
786   do {
787      ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_IRQ_WAIT,
788			     &rmesa->iw, sizeof(rmesa->iw) );
789   } while (ret && (errno == EINTR || errno == EAGAIN));
790
791   if ( ret ) {
792      fprintf( stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, ret );
793      exit(1);
794   }
795}
796
797
798static void radeonWaitForFrameCompletion( radeonContextPtr rmesa )
799{
800   drm_radeon_sarea_t *sarea = rmesa->sarea;
801
802   if (rmesa->do_irqs) {
803      if (radeonGetLastFrame(rmesa) < sarea->last_frame) {
804	 if (!rmesa->irqsEmitted) {
805	    while (radeonGetLastFrame (rmesa) < sarea->last_frame)
806	       ;
807	 }
808	 else {
809	    UNLOCK_HARDWARE( rmesa );
810	    radeonWaitIrq( rmesa );
811	    LOCK_HARDWARE( rmesa );
812	 }
813	 rmesa->irqsEmitted = 10;
814      }
815
816      if (rmesa->irqsEmitted) {
817	 radeonEmitIrqLocked( rmesa );
818	 rmesa->irqsEmitted--;
819      }
820   }
821   else {
822      while (radeonGetLastFrame (rmesa) < sarea->last_frame) {
823	 UNLOCK_HARDWARE( rmesa );
824	 if (rmesa->do_usleeps)
825	    DO_USLEEP( 1 );
826	 LOCK_HARDWARE( rmesa );
827      }
828   }
829}
830
831/* Copy the back color buffer to the front color buffer.
832 */
833void radeonCopyBuffer( const __DRIdrawablePrivate *dPriv )
834{
835   radeonContextPtr rmesa;
836   GLint nbox, i, ret;
837   GLboolean   missed_target;
838   int64_t ust;
839
840   assert(dPriv);
841   assert(dPriv->driContextPriv);
842   assert(dPriv->driContextPriv->driverPrivate);
843
844   rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
845
846   if ( RADEON_DEBUG & DEBUG_IOCTL ) {
847      fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, rmesa->glCtx );
848   }
849
850   RADEON_FIREVERTICES( rmesa );
851   LOCK_HARDWARE( rmesa );
852
853   /* Throttle the frame rate -- only allow one pending swap buffers
854    * request at a time.
855    */
856   radeonWaitForFrameCompletion( rmesa );
857   UNLOCK_HARDWARE( rmesa );
858   driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
859   LOCK_HARDWARE( rmesa );
860
861   nbox = dPriv->numClipRects; /* must be in locked region */
862
863   for ( i = 0 ; i < nbox ; ) {
864      GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
865      drm_clip_rect_t *box = dPriv->pClipRects;
866      drm_clip_rect_t *b = rmesa->sarea->boxes;
867      GLint n = 0;
868
869      for ( ; i < nr ; i++ ) {
870	 *b++ = box[i];
871	 n++;
872      }
873      rmesa->sarea->nbox = n;
874
875      ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
876
877      if ( ret ) {
878	 fprintf( stderr, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret );
879	 UNLOCK_HARDWARE( rmesa );
880	 exit( 1 );
881      }
882   }
883
884   UNLOCK_HARDWARE( rmesa );
885   rmesa->swap_count++;
886   (*rmesa->get_ust)( & ust );
887   if ( missed_target ) {
888      rmesa->swap_missed_count++;
889      rmesa->swap_missed_ust = ust - rmesa->swap_ust;
890   }
891
892   rmesa->swap_ust = ust;
893}
894
895void radeonPageFlip( const __DRIdrawablePrivate *dPriv )
896{
897   radeonContextPtr rmesa;
898   GLint ret;
899   GLboolean   missed_target;
900
901   assert(dPriv);
902   assert(dPriv->driContextPriv);
903   assert(dPriv->driContextPriv->driverPrivate);
904
905   rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
906
907   if ( RADEON_DEBUG & DEBUG_IOCTL ) {
908      fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
909	      rmesa->sarea->pfCurrentPage);
910   }
911
912   RADEON_FIREVERTICES( rmesa );
913   LOCK_HARDWARE( rmesa );
914
915   /* Need to do this for the perf box placement:
916    */
917   if (dPriv->numClipRects)
918   {
919      drm_clip_rect_t *box = dPriv->pClipRects;
920      drm_clip_rect_t *b = rmesa->sarea->boxes;
921      b[0] = box[0];
922      rmesa->sarea->nbox = 1;
923   }
924
925   /* Throttle the frame rate -- only allow a few pending swap buffers
926    * request at a time.
927    */
928   radeonWaitForFrameCompletion( rmesa );
929   UNLOCK_HARDWARE( rmesa );
930   driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
931   if ( missed_target ) {
932      rmesa->swap_missed_count++;
933      (void) (*rmesa->get_ust)( & rmesa->swap_missed_ust );
934   }
935   LOCK_HARDWARE( rmesa );
936
937   ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
938
939   UNLOCK_HARDWARE( rmesa );
940
941   if ( ret ) {
942      fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
943      exit( 1 );
944   }
945
946   rmesa->swap_count++;
947   (void) (*rmesa->get_ust)( & rmesa->swap_ust );
948
949   if ( rmesa->sarea->pfCurrentPage == 1 ) {
950	 rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset;
951	 rmesa->state.color.drawPitch  = rmesa->radeonScreen->frontPitch;
952   } else {
953	 rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset;
954	 rmesa->state.color.drawPitch  = rmesa->radeonScreen->backPitch;
955   }
956
957   RADEON_STATECHANGE( rmesa, ctx );
958   rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset
959					   + rmesa->radeonScreen->fbLocation;
960   rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH]  = rmesa->state.color.drawPitch;
961}
962
963
964/* ================================================================
965 * Buffer clear
966 */
967#define RADEON_MAX_CLEARS	256
968
969static void radeonClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
970			 GLint cx, GLint cy, GLint cw, GLint ch )
971{
972   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
973   __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
974   drm_radeon_sarea_t *sarea = rmesa->sarea;
975   unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map;
976   int32_t clear;
977   GLuint flags = 0;
978   GLuint color_mask = 0;
979   GLint ret, i;
980
981   if ( RADEON_DEBUG & DEBUG_IOCTL ) {
982      fprintf( stderr, "%s:  all=%d cx=%d cy=%d cw=%d ch=%d\n",
983	       __FUNCTION__, all, cx, cy, cw, ch );
984   }
985
986   radeonEmitState( rmesa );
987
988   /* Need to cope with lostcontext here as kernel relies on
989    * some residual state:
990    */
991   RADEON_FIREVERTICES( rmesa );
992
993   if ( mask & DD_FRONT_LEFT_BIT ) {
994      flags |= RADEON_FRONT;
995      color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
996      mask &= ~DD_FRONT_LEFT_BIT;
997   }
998
999   if ( mask & DD_BACK_LEFT_BIT ) {
1000      flags |= RADEON_BACK;
1001      color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
1002      mask &= ~DD_BACK_LEFT_BIT;
1003   }
1004
1005   if ( mask & DD_DEPTH_BIT ) {
1006      if ( ctx->Depth.Mask ) flags |= RADEON_DEPTH; /* FIXME: ??? */
1007      mask &= ~DD_DEPTH_BIT;
1008   }
1009
1010   if ( (mask & DD_STENCIL_BIT) && rmesa->state.stencil.hwBuffer ) {
1011      flags |= RADEON_STENCIL;
1012      mask &= ~DD_STENCIL_BIT;
1013   }
1014
1015   if ( mask ) {
1016      if (RADEON_DEBUG & DEBUG_FALLBACKS)
1017	 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
1018      _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
1019   }
1020
1021   if ( !flags )
1022      return;
1023
1024
1025   /* Flip top to bottom */
1026   cx += dPriv->x;
1027   cy  = dPriv->y + dPriv->h - cy - ch;
1028
1029   LOCK_HARDWARE( rmesa );
1030
1031   /* Throttle the number of clear ioctls we do.
1032    */
1033   while ( 1 ) {
1034      int ret;
1035
1036      if (rmesa->dri.screen->drmMinor >= 4) {
1037	drm_radeon_getparam_t gp;
1038
1039	gp.param = RADEON_PARAM_LAST_CLEAR;
1040	gp.value = (int *)&clear;
1041	ret = drmCommandWriteRead( rmesa->dri.fd,
1042				   DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
1043      } else
1044	ret = -EINVAL;
1045
1046#ifndef __alpha__
1047      if ( ret == -EINVAL ) {
1048	 clear = INREG( RADEON_LAST_CLEAR_REG );
1049	 ret = 0;
1050      }
1051#endif
1052      if ( ret ) {
1053	 fprintf( stderr, "%s: drm_radeon_getparam_t: %d\n", __FUNCTION__, ret );
1054	 exit(1);
1055      }
1056      if ( RADEON_DEBUG & DEBUG_IOCTL ) {
1057	 fprintf( stderr, "%s( %d )\n", __FUNCTION__, (int)clear );
1058	 if ( ret ) fprintf( stderr, " ( RADEON_LAST_CLEAR register read directly )\n" );
1059      }
1060
1061      if ( sarea->last_clear - clear <= RADEON_MAX_CLEARS ) {
1062	 break;
1063      }
1064
1065      if ( rmesa->do_usleeps ) {
1066	 UNLOCK_HARDWARE( rmesa );
1067	 DO_USLEEP( 1 );
1068	 LOCK_HARDWARE( rmesa );
1069      }
1070   }
1071
1072   for ( i = 0 ; i < dPriv->numClipRects ; ) {
1073      GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
1074      drm_clip_rect_t *box = dPriv->pClipRects;
1075      drm_clip_rect_t *b = rmesa->sarea->boxes;
1076      drm_radeon_clear_t clear;
1077      drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
1078      GLint n = 0;
1079
1080      if ( !all ) {
1081	 for ( ; i < nr ; i++ ) {
1082	    GLint x = box[i].x1;
1083	    GLint y = box[i].y1;
1084	    GLint w = box[i].x2 - x;
1085	    GLint h = box[i].y2 - y;
1086
1087	    if ( x < cx ) w -= cx - x, x = cx;
1088	    if ( y < cy ) h -= cy - y, y = cy;
1089	    if ( x + w > cx + cw ) w = cx + cw - x;
1090	    if ( y + h > cy + ch ) h = cy + ch - y;
1091	    if ( w <= 0 ) continue;
1092	    if ( h <= 0 ) continue;
1093
1094	    b->x1 = x;
1095	    b->y1 = y;
1096	    b->x2 = x + w;
1097	    b->y2 = y + h;
1098	    b++;
1099	    n++;
1100	 }
1101      } else {
1102	 for ( ; i < nr ; i++ ) {
1103	    *b++ = box[i];
1104	    n++;
1105	 }
1106      }
1107
1108      rmesa->sarea->nbox = n;
1109
1110      clear.flags       = flags;
1111      clear.clear_color = rmesa->state.color.clear;
1112      clear.clear_depth = rmesa->state.depth.clear;
1113      clear.color_mask  = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
1114      clear.depth_mask  = rmesa->state.stencil.clear;
1115      clear.depth_boxes = depth_boxes;
1116
1117      n--;
1118      b = rmesa->sarea->boxes;
1119      for ( ; n >= 0 ; n-- ) {
1120	 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
1121	 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
1122	 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
1123	 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
1124	 depth_boxes[n].f[CLEAR_DEPTH] =
1125	    (float)rmesa->state.depth.clear;
1126      }
1127
1128      ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_CLEAR,
1129			     &clear, sizeof(drm_radeon_clear_t));
1130
1131      if ( ret ) {
1132	 UNLOCK_HARDWARE( rmesa );
1133	 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
1134	 exit( 1 );
1135      }
1136   }
1137
1138   UNLOCK_HARDWARE( rmesa );
1139}
1140
1141
1142void radeonWaitForIdleLocked( radeonContextPtr rmesa )
1143{
1144    int fd = rmesa->dri.fd;
1145    int to = 0;
1146    int ret, i = 0;
1147
1148    rmesa->c_drawWaits++;
1149
1150    do {
1151        do {
1152            ret = drmCommandNone( fd, DRM_RADEON_CP_IDLE);
1153        } while ( ret && errno == EBUSY && i++ < RADEON_IDLE_RETRY );
1154    } while ( ( ret == -EBUSY ) && ( to++ < RADEON_TIMEOUT ) );
1155
1156    if ( ret < 0 ) {
1157	UNLOCK_HARDWARE( rmesa );
1158	fprintf( stderr, "Error: Radeon timed out... exiting\n" );
1159	exit( -1 );
1160    }
1161}
1162
1163
1164static void radeonWaitForIdle( radeonContextPtr rmesa )
1165{
1166   LOCK_HARDWARE(rmesa);
1167   radeonWaitForIdleLocked( rmesa );
1168   UNLOCK_HARDWARE(rmesa);
1169}
1170
1171
1172void radeonFlush( GLcontext *ctx )
1173{
1174   radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
1175
1176   if (RADEON_DEBUG & DEBUG_IOCTL)
1177      fprintf(stderr, "%s\n", __FUNCTION__);
1178
1179   if (rmesa->dma.flush)
1180      rmesa->dma.flush( rmesa );
1181
1182   if (!is_empty_list(&rmesa->hw.dirty))
1183      radeonEmitState( rmesa );
1184
1185   if (rmesa->store.cmd_used)
1186      radeonFlushCmdBuf( rmesa, __FUNCTION__ );
1187}
1188
1189/* Make sure all commands have been sent to the hardware and have
1190 * completed processing.
1191 */
1192void radeonFinish( GLcontext *ctx )
1193{
1194   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
1195   radeonFlush( ctx );
1196
1197   if (rmesa->do_irqs) {
1198      LOCK_HARDWARE( rmesa );
1199      radeonEmitIrqLocked( rmesa );
1200      UNLOCK_HARDWARE( rmesa );
1201      radeonWaitIrq( rmesa );
1202   }
1203   else
1204      radeonWaitForIdle( rmesa );
1205}
1206
1207
1208void radeonInitIoctlFuncs( GLcontext *ctx )
1209{
1210    ctx->Driver.Clear = radeonClear;
1211    ctx->Driver.Finish = radeonFinish;
1212    ctx->Driver.Flush = radeonFlush;
1213}
1214
1215