OSDN Git Service

radeon: share common fog code between radeon and r200
[android-x86/external-mesa.git] / src / mesa / drivers / dri / radeon / radeon_dma.c
1 /**************************************************************************
2
3 Copyright (C) 2004 Nicolai Haehnle.
4 Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
5
6 The Weather Channel (TM) funded Tungsten Graphics to develop the
7 initial release of the Radeon 8500 driver under the XFree86 license.
8 This notice must be preserved.
9
10 All Rights Reserved.
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the "Software"),
14 to deal in the Software without restriction, including without limitation
15 on the rights to use, copy, modify, merge, publish, distribute, sub
16 license, and/or sell copies of the Software, and to permit persons to whom
17 the Software is furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice (including the next
20 paragraph) shall be included in all copies or substantial portions of the
21 Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
26 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
27 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
28 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
29 USE OR OTHER DEALINGS IN THE SOFTWARE.
30
31 **************************************************************************/
32
33 #include <errno.h>
34 #include "radeon_common.h"
35 #include "radeon_fog.h"
36 #include "main/simple_list.h"
37
38 #if defined(USE_X86_ASM)
39 #define COPY_DWORDS( dst, src, nr )                                     \
40 do {                                                                    \
41         int __tmp;                                                      \
42         __asm__ __volatile__( "rep ; movsl"                             \
43                               : "=%c" (__tmp), "=D" (dst), "=S" (__tmp) \
44                               : "0" (nr),                               \
45                                 "D" ((long)dst),                        \
46                                 "S" ((long)src) );                      \
47 } while (0)
48 #else
49 #define COPY_DWORDS( dst, src, nr )             \
50 do {                                            \
51    int j;                                       \
52    for ( j = 0 ; j < nr ; j++ )                 \
53       dst[j] = ((int *)src)[j];                 \
54    dst += nr;                                   \
55 } while (0)
56 #endif
57
58 void radeonEmitVec4(uint32_t *out, const GLvoid * data, int stride, int count)
59 {
60         int i;
61
62         if (RADEON_DEBUG & RADEON_VERTS)
63                 fprintf(stderr, "%s count %d stride %d out %p data %p\n",
64                         __FUNCTION__, count, stride, (void *)out, (void *)data);
65
66         if (stride == 4)
67                 COPY_DWORDS(out, data, count);
68         else
69                 for (i = 0; i < count; i++) {
70                         out[0] = *(int *)data;
71                         out++;
72                         data += stride;
73                 }
74 }
75
76 void radeonEmitVec8(uint32_t *out, const GLvoid * data, int stride, int count)
77 {
78         int i;
79
80         if (RADEON_DEBUG & RADEON_VERTS)
81                 fprintf(stderr, "%s count %d stride %d out %p data %p\n",
82                         __FUNCTION__, count, stride, (void *)out, (void *)data);
83
84         if (stride == 8)
85                 COPY_DWORDS(out, data, count * 2);
86         else
87                 for (i = 0; i < count; i++) {
88                         out[0] = *(int *)data;
89                         out[1] = *(int *)(data + 4);
90                         out += 2;
91                         data += stride;
92                 }
93 }
94
95 void radeonEmitVec12(uint32_t *out, const GLvoid * data, int stride, int count)
96 {
97         int i;
98
99         if (RADEON_DEBUG & RADEON_VERTS)
100                 fprintf(stderr, "%s count %d stride %d out %p data %p\n",
101                         __FUNCTION__, count, stride, (void *)out, (void *)data);
102
103         if (stride == 12) {
104                 COPY_DWORDS(out, data, count * 3);
105     }
106         else
107                 for (i = 0; i < count; i++) {
108                         out[0] = *(int *)data;
109                         out[1] = *(int *)(data + 4);
110                         out[2] = *(int *)(data + 8);
111                         out += 3;
112                         data += stride;
113                 }
114 }
115
116 void radeonEmitVec16(uint32_t *out, const GLvoid * data, int stride, int count)
117 {
118         int i;
119
120         if (RADEON_DEBUG & RADEON_VERTS)
121                 fprintf(stderr, "%s count %d stride %d out %p data %p\n",
122                         __FUNCTION__, count, stride, (void *)out, (void *)data);
123
124         if (stride == 16)
125                 COPY_DWORDS(out, data, count * 4);
126         else
127                 for (i = 0; i < count; i++) {
128                         out[0] = *(int *)data;
129                         out[1] = *(int *)(data + 4);
130                         out[2] = *(int *)(data + 8);
131                         out[3] = *(int *)(data + 12);
132                         out += 4;
133                         data += stride;
134                 }
135 }
136
137 void rcommon_emit_vector(struct gl_context * ctx, struct radeon_aos *aos,
138                          const GLvoid * data, int size, int stride, int count)
139 {
140         radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
141         uint32_t *out;
142
143         if (stride == 0) {
144                 radeonAllocDmaRegion(rmesa, &aos->bo, &aos->offset, size * 4, 32);
145                 count = 1;
146                 aos->stride = 0;
147         } else {
148                 radeonAllocDmaRegion(rmesa, &aos->bo, &aos->offset, size * count * 4, 32);
149                 aos->stride = size;
150         }
151
152         aos->components = size;
153         aos->count = count;
154
155         radeon_bo_map(aos->bo, 1);
156         out = (uint32_t*)((char*)aos->bo->ptr + aos->offset);
157         switch (size) {
158         case 1: radeonEmitVec4(out, data, stride, count); break;
159         case 2: radeonEmitVec8(out, data, stride, count); break;
160         case 3: radeonEmitVec12(out, data, stride, count); break;
161         case 4: radeonEmitVec16(out, data, stride, count); break;
162         default:
163                 assert(0);
164                 break;
165         }
166         radeon_bo_unmap(aos->bo);
167 }
168
169 void rcommon_emit_vecfog(struct gl_context *ctx, struct radeon_aos *aos,
170                          GLvoid *data, int stride, int count)
171 {
172         int i;
173         float *out;
174         int size = 1;
175         radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
176
177         if (RADEON_DEBUG & RADEON_VERTS)
178                 fprintf(stderr, "%s count %d stride %d\n",
179                         __FUNCTION__, count, stride);
180
181         if (stride == 0) {
182                 radeonAllocDmaRegion( rmesa, &aos->bo, &aos->offset, size * 4, 32 );
183                 count = 1;
184                 aos->stride = 0;
185         } else {
186                 radeonAllocDmaRegion(rmesa, &aos->bo, &aos->offset, size * count * 4, 32);
187                 aos->stride = size;
188         }
189
190         aos->components = size;
191         aos->count = count;
192
193         /* Emit the data */
194         radeon_bo_map(aos->bo, 1);
195         out = (float*)((char*)aos->bo->ptr + aos->offset);
196         for (i = 0; i < count; i++) {
197                 out[0] = radeonComputeFogBlendFactor( ctx, *(GLfloat *)data );
198                 out++;
199                 data += stride;
200         }
201         radeon_bo_unmap(aos->bo);
202 }
203
204 void radeon_init_dma(radeonContextPtr rmesa)
205 {
206         make_empty_list(&rmesa->dma.free);
207         make_empty_list(&rmesa->dma.wait);
208         make_empty_list(&rmesa->dma.reserved);
209         rmesa->dma.minimum_size = MAX_DMA_BUF_SZ;
210 }
211
212 void radeonRefillCurrentDmaRegion(radeonContextPtr rmesa, int size)
213 {
214         struct radeon_dma_bo *dma_bo = NULL;
215         /* we set minimum sizes to at least requested size
216            aligned to next 16 bytes. */
217         if (size > rmesa->dma.minimum_size)
218                 rmesa->dma.minimum_size = (size + 15) & (~15);
219
220         radeon_print(RADEON_DMA, RADEON_NORMAL, "%s size %d minimum_size %Zi\n",
221                         __FUNCTION__, size, rmesa->dma.minimum_size);
222
223         if (is_empty_list(&rmesa->dma.free)
224               || last_elem(&rmesa->dma.free)->bo->size < size) {
225                 dma_bo = CALLOC_STRUCT(radeon_dma_bo);
226                 assert(dma_bo);
227
228 again_alloc:
229                 dma_bo->bo = radeon_bo_open(rmesa->radeonScreen->bom,
230                                             0, rmesa->dma.minimum_size, 4,
231                                             RADEON_GEM_DOMAIN_GTT, 0);
232
233                 if (!dma_bo->bo) {
234                         rcommonFlushCmdBuf(rmesa, __FUNCTION__);
235                         goto again_alloc;
236                 }
237                 insert_at_head(&rmesa->dma.reserved, dma_bo);
238         } else {
239                 /* We push and pop buffers from end of list so we can keep
240                    counter on unused buffers for later freeing them from
241                    begin of list */
242                 dma_bo = last_elem(&rmesa->dma.free);
243                 remove_from_list(dma_bo);
244                 insert_at_head(&rmesa->dma.reserved, dma_bo);
245         }
246
247         rmesa->dma.current_used = 0;
248         rmesa->dma.current_vertexptr = 0;
249
250         if (radeon_cs_space_check_with_bo(rmesa->cmdbuf.cs,
251                                           first_elem(&rmesa->dma.reserved)->bo,
252                                           RADEON_GEM_DOMAIN_GTT, 0))
253                 fprintf(stderr,"failure to revalidate BOs - badness\n");
254
255         if (is_empty_list(&rmesa->dma.reserved)) {
256         /* Cmd buff have been flushed in radeon_revalidate_bos */
257                 goto again_alloc;
258         }
259         radeon_bo_map(first_elem(&rmesa->dma.reserved)->bo, 1);
260 }
261
262 /* Allocates a region from rmesa->dma.current.  If there isn't enough
263  * space in current, grab a new buffer (and discard what was left of current)
264  */
265 void radeonAllocDmaRegion(radeonContextPtr rmesa,
266                           struct radeon_bo **pbo, int *poffset,
267                           int bytes, int alignment)
268 {
269         if (RADEON_DEBUG & RADEON_IOCTL)
270                 fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
271
272         if (rmesa->dma.flush)
273                 rmesa->dma.flush(rmesa->glCtx);
274
275         assert(rmesa->dma.current_used == rmesa->dma.current_vertexptr);
276
277         alignment--;
278         rmesa->dma.current_used = (rmesa->dma.current_used + alignment) & ~alignment;
279
280         if (is_empty_list(&rmesa->dma.reserved)
281                 || rmesa->dma.current_used + bytes > first_elem(&rmesa->dma.reserved)->bo->size)
282                 radeonRefillCurrentDmaRegion(rmesa, bytes);
283
284         *poffset = rmesa->dma.current_used;
285         *pbo = first_elem(&rmesa->dma.reserved)->bo;
286         radeon_bo_ref(*pbo);
287
288         /* Always align to at least 16 bytes */
289         rmesa->dma.current_used = (rmesa->dma.current_used + bytes + 15) & ~15;
290         rmesa->dma.current_vertexptr = rmesa->dma.current_used;
291
292         assert(rmesa->dma.current_used <= first_elem(&rmesa->dma.reserved)->bo->size);
293 }
294
295 void radeonFreeDmaRegions(radeonContextPtr rmesa)
296 {
297         struct radeon_dma_bo *dma_bo;
298         struct radeon_dma_bo *temp;
299         if (RADEON_DEBUG & RADEON_DMA)
300                 fprintf(stderr, "%s\n", __FUNCTION__);
301
302         foreach_s(dma_bo, temp, &rmesa->dma.free) {
303                 remove_from_list(dma_bo);
304                 radeon_bo_unref(dma_bo->bo);
305                 FREE(dma_bo);
306         }
307
308         foreach_s(dma_bo, temp, &rmesa->dma.wait) {
309                 remove_from_list(dma_bo);
310                 radeon_bo_unref(dma_bo->bo);
311                 FREE(dma_bo);
312         }
313
314         foreach_s(dma_bo, temp, &rmesa->dma.reserved) {
315                 remove_from_list(dma_bo);
316                 radeon_bo_unref(dma_bo->bo);
317                 FREE(dma_bo);
318         }
319 }
320
321 void radeonReturnDmaRegion(radeonContextPtr rmesa, int return_bytes)
322 {
323         if (is_empty_list(&rmesa->dma.reserved))
324                 return;
325
326         if (RADEON_DEBUG & RADEON_IOCTL)
327                 fprintf(stderr, "%s %d\n", __FUNCTION__, return_bytes);
328         rmesa->dma.current_used -= return_bytes;
329         rmesa->dma.current_vertexptr = rmesa->dma.current_used;
330 }
331
332 static int radeon_bo_is_idle(struct radeon_bo* bo)
333 {
334         uint32_t domain;
335         int ret = radeon_bo_is_busy(bo, &domain);
336         if (ret == -EINVAL) {
337                 WARN_ONCE("Your libdrm or kernel doesn't have support for busy query.\n"
338                         "This may cause small performance drop for you.\n");
339         }
340         return ret != -EBUSY;
341 }
342
343 void radeonReleaseDmaRegions(radeonContextPtr rmesa)
344 {
345         struct radeon_dma_bo *dma_bo;
346         struct radeon_dma_bo *temp;
347         const int expire_at = ++rmesa->dma.free.expire_counter + DMA_BO_FREE_TIME;
348         const int time = rmesa->dma.free.expire_counter;
349
350         if (RADEON_DEBUG & RADEON_DMA) {
351                 size_t free = 0,
352                        wait = 0,
353                        reserved = 0;
354                 foreach(dma_bo, &rmesa->dma.free)
355                         ++free;
356
357                 foreach(dma_bo, &rmesa->dma.wait)
358                         ++wait;
359
360                 foreach(dma_bo, &rmesa->dma.reserved)
361                         ++reserved;
362
363                 fprintf(stderr, "%s: free %zu, wait %zu, reserved %zu, minimum_size: %zu\n",
364                       __FUNCTION__, free, wait, reserved, rmesa->dma.minimum_size);
365         }
366
367         /* move waiting bos to free list.
368            wait list provides gpu time to handle data before reuse */
369         foreach_s(dma_bo, temp, &rmesa->dma.wait) {
370                 if (dma_bo->expire_counter == time) {
371                         WARN_ONCE("Leaking dma buffer object!\n");
372                         radeon_bo_unref(dma_bo->bo);
373                         remove_from_list(dma_bo);
374                         FREE(dma_bo);
375                         continue;
376                 }
377                 /* free objects that are too small to be used because of large request */
378                 if (dma_bo->bo->size < rmesa->dma.minimum_size) {
379                    radeon_bo_unref(dma_bo->bo);
380                    remove_from_list(dma_bo);
381                    FREE(dma_bo);
382                    continue;
383                 }
384                 if (!radeon_bo_is_idle(dma_bo->bo)) {
385                         break;
386                 }
387                 remove_from_list(dma_bo);
388                 dma_bo->expire_counter = expire_at;
389                 insert_at_tail(&rmesa->dma.free, dma_bo);
390         }
391
392         /* move reserved to wait list */
393         foreach_s(dma_bo, temp, &rmesa->dma.reserved) {
394                 radeon_bo_unmap(dma_bo->bo);
395                 /* free objects that are too small to be used because of large request */
396                 if (dma_bo->bo->size < rmesa->dma.minimum_size) {
397                    radeon_bo_unref(dma_bo->bo);
398                    remove_from_list(dma_bo);
399                    FREE(dma_bo);
400                    continue;
401                 }
402                 remove_from_list(dma_bo);
403                 dma_bo->expire_counter = expire_at;
404                 insert_at_tail(&rmesa->dma.wait, dma_bo);
405         }
406
407         /* free bos that have been unused for some time */
408         foreach_s(dma_bo, temp, &rmesa->dma.free) {
409                 if (dma_bo->expire_counter != time)
410                         break;
411                 remove_from_list(dma_bo);
412                 radeon_bo_unref(dma_bo->bo);
413                 FREE(dma_bo);
414         }
415
416 }
417
418
419 /* Flush vertices in the current dma region.
420  */
421 void rcommon_flush_last_swtcl_prim( struct gl_context *ctx  )
422 {
423         radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
424         struct radeon_dma *dma = &rmesa->dma;
425
426         if (RADEON_DEBUG & RADEON_IOCTL)
427                 fprintf(stderr, "%s\n", __FUNCTION__);
428         dma->flush = NULL;
429
430         radeon_bo_unmap(rmesa->swtcl.bo);
431
432         if (!is_empty_list(&dma->reserved)) {
433             GLuint current_offset = dma->current_used;
434
435             assert (dma->current_used +
436                     rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
437                     dma->current_vertexptr);
438
439             if (dma->current_used != dma->current_vertexptr) {
440                     dma->current_used = dma->current_vertexptr;
441
442                     rmesa->vtbl.swtcl_flush(ctx, current_offset);
443             }
444             rmesa->swtcl.numverts = 0;
445         }
446         radeon_bo_unref(rmesa->swtcl.bo);
447         rmesa->swtcl.bo = NULL;
448 }
449 /* Alloc space in the current dma region.
450  */
451 void *
452 rcommonAllocDmaLowVerts( radeonContextPtr rmesa, int nverts, int vsize )
453 {
454         GLuint bytes = vsize * nverts;
455         void *head;
456         if (RADEON_DEBUG & RADEON_IOCTL)
457                 fprintf(stderr, "%s\n", __FUNCTION__);
458
459         if(is_empty_list(&rmesa->dma.reserved)
460               ||rmesa->dma.current_vertexptr + bytes > first_elem(&rmesa->dma.reserved)->bo->size) {
461                 if (rmesa->dma.flush) {
462                         rmesa->dma.flush(rmesa->glCtx);
463                 }
464
465                 radeonRefillCurrentDmaRegion(rmesa, bytes);
466
467                 return NULL;
468         }
469
470         if (!rmesa->dma.flush) {
471                 /* if cmdbuf flushed DMA restart */
472                 rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
473                 rmesa->dma.flush = rcommon_flush_last_swtcl_prim;
474         }
475
476         ASSERT( vsize == rmesa->swtcl.vertex_size * 4 );
477         ASSERT( rmesa->dma.flush == rcommon_flush_last_swtcl_prim );
478         ASSERT( rmesa->dma.current_used +
479                 rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
480                 rmesa->dma.current_vertexptr );
481
482         if (!rmesa->swtcl.bo) {
483                 rmesa->swtcl.bo = first_elem(&rmesa->dma.reserved)->bo;
484                 radeon_bo_ref(rmesa->swtcl.bo);
485                 radeon_bo_map(rmesa->swtcl.bo, 1);
486         }
487
488         head = (rmesa->swtcl.bo->ptr + rmesa->dma.current_vertexptr);
489         rmesa->dma.current_vertexptr += bytes;
490         rmesa->swtcl.numverts += nverts;
491         return head;
492 }
493
494 void radeonReleaseArrays( struct gl_context *ctx, GLuint newinputs )
495 {
496    radeonContextPtr radeon = RADEON_CONTEXT( ctx );
497    int i;
498         if (RADEON_DEBUG & RADEON_IOCTL)
499                 fprintf(stderr, "%s\n", __FUNCTION__);
500
501    if (radeon->dma.flush) {
502        radeon->dma.flush(radeon->glCtx);
503    }
504    for (i = 0; i < radeon->tcl.aos_count; i++) {
505       if (radeon->tcl.aos[i].bo) {
506          radeon_bo_unref(radeon->tcl.aos[i].bo);
507          radeon->tcl.aos[i].bo = NULL;
508
509       }
510    }
511 }