Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / i810 / i810ioctl.c
1
2 #include <unistd.h> /* for usleep() */
3
4 #include "main/glheader.h"
5 #include "main/mtypes.h"
6 #include "main/macros.h"
7 #include "main/dd.h"
8 #include "swrast/swrast.h"
9 #include "main/mm.h"
10
11 #include "i810screen.h"
12 #include "i810_dri.h"
13
14 #include "main/context.h"
15 #include "i810ioctl.h"
16 #include "i810state.h"
17
18 static drmBufPtr i810_get_buffer_ioctl( i810ContextPtr imesa )
19 {
20    drmI810DMA dma;
21    drmBufPtr buf;
22    int retcode, i = 0;
23    
24    while (1) {
25       retcode = drmCommandWriteRead(imesa->driFd, DRM_I810_GETBUF,
26                                     &dma, sizeof(drmI810DMA));
27
28       if (dma.granted == 1 && retcode == 0) 
29          break;
30       
31       if (++i > 1000) {
32          drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
33          i = 0;
34       }
35    }
36
37    buf = &(imesa->i810Screen->bufs->list[dma.request_idx]);
38    buf->idx = dma.request_idx;
39    buf->used = 0;
40    buf->total = dma.request_size;
41    buf->address = (drmAddress)dma.virtual;
42
43    return buf;
44 }
45
46
47
48 #define DEPTH_SCALE ((1<<16)-1)
49
50 static void i810Clear( struct gl_context *ctx, GLbitfield mask )
51 {
52    i810ContextPtr imesa = I810_CONTEXT( ctx );
53    __DRIdrawable *dPriv = imesa->driDrawable;
54    const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask[0]);
55    drmI810Clear clear;
56    unsigned int i;
57
58    clear.flags = 0;
59    clear.clear_color = imesa->ClearColor;
60    clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE);
61
62    I810_FIREVERTICES( imesa );
63         
64    if ((mask & BUFFER_BIT_FRONT_LEFT) && colorMask == ~0U) {
65       clear.flags |= I810_FRONT;
66       mask &= ~BUFFER_BIT_FRONT_LEFT;
67    }
68
69    if ((mask & BUFFER_BIT_BACK_LEFT) && colorMask == ~0U) {
70       clear.flags |= I810_BACK;
71       mask &= ~BUFFER_BIT_BACK_LEFT;
72    }
73
74    if (mask & BUFFER_BIT_DEPTH) {
75       if (ctx->Depth.Mask) 
76          clear.flags |= I810_DEPTH;
77       mask &= ~BUFFER_BIT_DEPTH;
78    }
79
80    if (clear.flags) {
81       GLint cx, cy, cw, ch;
82
83       LOCK_HARDWARE( imesa );
84
85       /* compute region after locking: */
86       cx = ctx->DrawBuffer->_Xmin;
87       cy = ctx->DrawBuffer->_Ymin;
88       cw = ctx->DrawBuffer->_Xmax - cx;
89       ch = ctx->DrawBuffer->_Ymax - cy;
90
91       /* flip top to bottom */
92       cy = dPriv->h-cy-ch;
93       cx += imesa->drawX;
94       cy += imesa->drawY;
95
96       for (i = 0 ; i < imesa->numClipRects ; ) 
97       {          
98          unsigned int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, imesa->numClipRects);
99          drm_clip_rect_t *box = imesa->pClipRects;       
100          drm_clip_rect_t *b = (drm_clip_rect_t *)imesa->sarea->boxes;
101          int n = 0;
102
103          if (cw != dPriv->w || ch != dPriv->h) {
104             /* clear sub region */
105             for ( ; i < nr ; i++) {
106                GLint x = box[i].x1;
107                GLint y = box[i].y1;
108                GLint w = box[i].x2 - x;
109                GLint h = box[i].y2 - y;
110
111                if (x < cx) w -= cx - x, x = cx; 
112                if (y < cy) h -= cy - y, y = cy;
113                if (x + w > cx + cw) w = cx + cw - x;
114                if (y + h > cy + ch) h = cy + ch - y;
115                if (w <= 0) continue;
116                if (h <= 0) continue;
117
118                b->x1 = x;
119                b->y1 = y;
120                b->x2 = x + w;
121                b->y2 = y + h;
122                b++;
123                n++;
124             }
125          } else {
126             /* clear whole buffer */
127             for ( ; i < nr ; i++) {
128                *b++ = box[i];
129                n++;
130             }
131          }
132
133          imesa->sarea->nbox = n;
134          drmCommandWrite(imesa->driFd, DRM_I810_CLEAR,
135                          &clear, sizeof(drmI810Clear));
136       }
137
138       UNLOCK_HARDWARE( imesa );
139       imesa->upload_cliprects = GL_TRUE;
140    }
141
142    if (mask) 
143       _swrast_Clear( ctx, mask );
144 }
145
146
147
148
149 /*
150  * Copy the back buffer to the front buffer. 
151  */
152 void i810CopyBuffer( const __DRIdrawable *dPriv ) 
153 {
154    i810ContextPtr imesa;
155    drm_clip_rect_t *pbox;
156    int nbox, i, tmp;
157
158    assert(dPriv);
159    assert(dPriv->driContextPriv);
160    assert(dPriv->driContextPriv->driverPrivate);
161
162    imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
163
164    I810_FIREVERTICES( imesa );
165    LOCK_HARDWARE( imesa );
166    
167    pbox = (drm_clip_rect_t *)dPriv->pClipRects;
168    nbox = dPriv->numClipRects;
169
170    for (i = 0 ; i < nbox ; )
171    {
172       int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
173       drm_clip_rect_t *b = (drm_clip_rect_t *)imesa->sarea->boxes;
174
175       imesa->sarea->nbox = nr - i;
176
177       for ( ; i < nr ; i++) 
178          *b++ = pbox[i];
179
180       drmCommandNone(imesa->driFd, DRM_I810_SWAP);
181    }
182
183    tmp = GET_ENQUEUE_AGE(imesa);
184    UNLOCK_HARDWARE( imesa );
185
186    /* multiarb will suck the life out of the server without this throttle:
187     */
188    if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) {
189       i810WaitAge(imesa, imesa->lastSwap);
190    }
191
192    imesa->lastSwap = tmp;
193    imesa->upload_cliprects = GL_TRUE;
194 }
195
196
197 /*
198  * XXX implement when full-screen extension is done.
199  */
200 void i810PageFlip( const __DRIdrawable *dPriv ) 
201 {
202   i810ContextPtr imesa;
203   int tmp, ret;
204
205   assert(dPriv);
206   assert(dPriv->driContextPriv);
207   assert(dPriv->driContextPriv->driverPrivate);
208     
209   imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
210
211   I810_FIREVERTICES( imesa );
212   LOCK_HARDWARE( imesa );
213   
214   if (dPriv->pClipRects) {
215      memcpy(&(imesa->sarea->boxes[0]), &(dPriv->pClipRects[0]),
216             sizeof(drm_clip_rect_t));
217      imesa->sarea->nbox = 1;
218   }
219   ret = drmCommandNone(imesa->driFd, DRM_I810_FLIP);
220   if (ret) {
221     fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
222     UNLOCK_HARDWARE( imesa );
223     exit(1);
224   }
225
226   tmp = GET_ENQUEUE_AGE(imesa);
227   UNLOCK_HARDWARE( imesa );
228   
229    /* multiarb will suck the life out of the server without this throttle:
230     */
231   if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) {
232     i810WaitAge(imesa, imesa->lastSwap);
233    }
234
235   /*  i810SetDrawBuffer( imesa->glCtx, imesa->glCtx->Color.DriverDrawBuffer );*/
236   i810DrawBuffer( imesa->glCtx, imesa->glCtx->Color.DrawBuffer[0] );
237   imesa->upload_cliprects = GL_TRUE;
238   imesa->lastSwap = tmp;
239   return;
240 }
241
242
243 /* This waits for *everybody* to finish rendering -- overkill.
244  */
245 void i810DmaFinish( i810ContextPtr imesa  ) 
246 {
247    I810_FIREVERTICES( imesa );
248
249    LOCK_HARDWARE( imesa );
250    i810RegetLockQuiescent( imesa );
251    UNLOCK_HARDWARE( imesa );
252 }
253
254
255 void i810RegetLockQuiescent( i810ContextPtr imesa  ) 
256 {
257    drmUnlock(imesa->driFd, imesa->hHWContext);
258    i810GetLock( imesa, DRM_LOCK_QUIESCENT ); 
259 }
260
261 void i810WaitAgeLocked( i810ContextPtr imesa, int age  ) 
262 {
263    int i = 0, j;
264
265    while (++i < 5000) {
266       drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
267       if (GET_DISPATCH_AGE(imesa) >= age)
268          return;
269       for (j = 0 ; j < 1000 ; j++)
270          ;
271    }
272
273    drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
274 }
275
276
277 void i810WaitAge( i810ContextPtr imesa, int age  ) 
278 {
279    int i = 0, j;
280
281    while (++i < 5000) {
282       drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
283       if (GET_DISPATCH_AGE(imesa) >= age)
284          return;
285       for (j = 0 ; j < 1000 ; j++)
286          ;
287    }
288
289    i = 0;
290    while (++i < 1000) {
291       drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
292       if (GET_DISPATCH_AGE(imesa) >= age)
293          return;
294       usleep(1000);
295    }
296
297    LOCK_HARDWARE(imesa);
298    drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
299    UNLOCK_HARDWARE(imesa);
300 }
301
302
303
304
305 static int intersect_rect( drm_clip_rect_t *out,
306                            drm_clip_rect_t *a,
307                            drm_clip_rect_t *b )
308 {
309    *out = *a;
310    if (b->x1 > out->x1) out->x1 = b->x1;
311    if (b->x2 < out->x2) out->x2 = b->x2;
312    if (out->x1 >= out->x2) return 0;
313
314    if (b->y1 > out->y1) out->y1 = b->y1;
315    if (b->y2 < out->y2) out->y2 = b->y2;
316    if (out->y1 >= out->y2) return 0;
317    return 1;
318 }
319
320
321 static void emit_state( i810ContextPtr imesa )
322 {
323    GLuint dirty = imesa->dirty;   
324    I810SAREAPtr sarea = imesa->sarea;
325
326    if (dirty & I810_UPLOAD_BUFFERS) {
327       memcpy( sarea->BufferState, imesa->BufferSetup, 
328               sizeof(imesa->BufferSetup) );
329    }     
330
331    if (dirty & I810_UPLOAD_CTX) {
332       memcpy( sarea->ContextState, imesa->Setup, 
333               sizeof(imesa->Setup) );
334    }
335
336    if (dirty & I810_UPLOAD_TEX0) {
337       memcpy(sarea->TexState[0], 
338              imesa->CurrentTexObj[0]->Setup,
339              sizeof(imesa->CurrentTexObj[0]->Setup));
340    }
341
342    if (dirty & I810_UPLOAD_TEX1) {
343       GLuint *setup = sarea->TexState[1];
344
345       memcpy( setup,
346               imesa->CurrentTexObj[1]->Setup,
347               sizeof(imesa->CurrentTexObj[1]->Setup));
348
349       /* Need this for the case where both units are bound to the same
350        * texobj.  
351        */
352       setup[I810_TEXREG_MI1] ^= (MI1_MAP_0 ^ MI1_MAP_1);
353       setup[I810_TEXREG_MLC] ^= (MLC_MAP_0 ^ MLC_MAP_1);
354       setup[I810_TEXREG_MLL] ^= (MLL_MAP_0 ^ MLL_MAP_1);
355       setup[I810_TEXREG_MCS] ^= (MCS_COORD_0 ^ MCS_COORD_1);
356       setup[I810_TEXREG_MF]  ^= (MF_MAP_0 ^ MF_MAP_1);
357    }
358     
359    sarea->dirty = dirty;
360    imesa->dirty = 0;
361 }
362
363
364 static void age_imesa( i810ContextPtr imesa, int age )
365 {
366    if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->base.timestamp = age;
367    if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->base.timestamp = age;
368 }
369
370
371 void i810FlushPrimsLocked( i810ContextPtr imesa )
372 {
373    drm_clip_rect_t *pbox = imesa->pClipRects;
374    int nbox = imesa->numClipRects;
375    drmBufPtr buffer = imesa->vertex_buffer;
376    I810SAREAPtr sarea = imesa->sarea;
377    drmI810Vertex vertex;
378    int i;
379           
380    if (I810_DEBUG & DEBUG_STATE)
381       i810PrintDirty( __FUNCTION__, imesa->dirty );
382    
383    if (imesa->dirty)
384       emit_state( imesa );
385
386    vertex.idx = buffer->idx;
387    vertex.used = imesa->vertex_low;
388    vertex.discard = 0;
389    sarea->vertex_prim = imesa->hw_primitive;
390
391    if (!nbox) {
392       vertex.used = 0;
393    }
394    else if (nbox > I810_NR_SAREA_CLIPRECTS) {      
395       imesa->upload_cliprects = GL_TRUE;
396    }
397
398    if (!nbox || !imesa->upload_cliprects) 
399    {
400       if (nbox == 1) 
401          sarea->nbox = 0;
402       else
403          sarea->nbox = nbox;
404
405       vertex.discard = 1;       
406       drmCommandWrite(imesa->driFd, DRM_I810_VERTEX,
407                       &vertex, sizeof(drmI810Vertex));
408       age_imesa(imesa, sarea->last_enqueue);
409    }  
410    else 
411    {
412       for (i = 0 ; i < nbox ; )
413       {
414          int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, nbox);
415          drm_clip_rect_t *b = (drm_clip_rect_t *)sarea->boxes;
416
417          if (imesa->scissor) {
418             sarea->nbox = 0;
419          
420             for ( ; i < nr ; i++) {
421                b->x1 = pbox[i].x1 - imesa->drawX;
422                b->y1 = pbox[i].y1 - imesa->drawY;
423                b->x2 = pbox[i].x2 - imesa->drawX;
424                b->y2 = pbox[i].y2 - imesa->drawY;
425
426                if (intersect_rect(b, b, &imesa->scissor_rect)) {
427                   sarea->nbox++;
428                   b++;
429                }
430             }
431
432             /* Culled?
433              */
434             if (!sarea->nbox) {
435                if (nr < nbox) continue;
436                vertex.used = 0;
437             }
438          } else {
439             sarea->nbox = nr - i;
440             for ( ; i < nr ; i++, b++) {
441                b->x1 = pbox[i].x1 - imesa->drawX;
442                b->y1 = pbox[i].y1 - imesa->drawY;
443                b->x2 = pbox[i].x2 - imesa->drawX;
444                b->y2 = pbox[i].y2 - imesa->drawY;
445             }
446          }
447          
448          /* Finished with the buffer?
449           */
450          if (nr == nbox) 
451             vertex.discard = 1;
452
453          drmCommandWrite(imesa->driFd, DRM_I810_VERTEX,
454                          &vertex, sizeof(drmI810Vertex));
455          age_imesa(imesa, imesa->sarea->last_enqueue);
456       }
457    }
458
459    /* Reset imesa vars:
460     */
461    imesa->vertex_buffer = 0;
462    imesa->vertex_addr = 0;
463    imesa->vertex_low = 0;
464    imesa->vertex_high = 0;
465    imesa->vertex_last_prim = 0;
466    imesa->dirty = 0;
467    imesa->upload_cliprects = GL_FALSE;
468 }
469
470 void i810FlushPrimsGetBuffer( i810ContextPtr imesa )
471 {
472    LOCK_HARDWARE(imesa);
473
474    if (imesa->vertex_buffer) 
475       i810FlushPrimsLocked( imesa );      
476
477    imesa->vertex_buffer = i810_get_buffer_ioctl( imesa );
478    imesa->vertex_high = imesa->vertex_buffer->total;
479    imesa->vertex_addr = (char *)imesa->vertex_buffer->address;
480    imesa->vertex_low = 4;       /* leave room for instruction header */
481    imesa->vertex_last_prim = imesa->vertex_low;
482    UNLOCK_HARDWARE(imesa);
483 }
484
485
486 void i810FlushPrims( i810ContextPtr imesa ) 
487 {
488    if (imesa->vertex_buffer) {
489       LOCK_HARDWARE( imesa );
490       i810FlushPrimsLocked( imesa );
491       UNLOCK_HARDWARE( imesa );
492    }
493 }
494
495
496
497 int i810_check_copy(int fd)
498 {
499    return(drmCommandNone(fd, DRM_I810_DOCOPY));
500 }
501
502 static void i810Flush( struct gl_context *ctx )
503 {
504    i810ContextPtr imesa = I810_CONTEXT( ctx );
505    I810_FIREVERTICES( imesa );
506 }
507
508 static void i810Finish( struct gl_context *ctx  ) 
509 {
510    i810ContextPtr imesa = I810_CONTEXT( ctx );
511    i810DmaFinish( imesa );
512 }
513
514 void i810InitIoctlFuncs( struct dd_function_table *functions )
515 {
516    functions->Flush = i810Flush;
517    functions->Clear = i810Clear;
518    functions->Finish = i810Finish;
519 }