- Fixed potential memory leaks and use of freed memory.
[AROS.git] / workbench / devs / monitors / IntelGMA / aros_winsys.c
blobf38421f0613c211aacfee1dcfae621b61d749a43
1 /*
2 Copyright © 2011-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
8 #include <aros/debug.h>
10 #include "intelG45_intern.h"
11 #include "intelG45_regs.h"
12 #include "aros_winsys.h"
14 #include "util/u_memory.h"
15 #include "i915/i915_winsys.h"
16 #include "i915/i915_debug.h"
18 #include "i915/i915_reg.h"
21 #ifdef GALLIUM_SIMULATION
22 #undef LOCK_HW
23 #undef START_RING
24 #undef OUT_RING
25 #undef ADVANCE_RING
26 #undef WAIT_IDLE
27 #undef DO_FLUSH
28 #undef UNLOCK_HW
29 #define LOCK_HW
30 #define START_RING(x)
31 #define OUT_RING(x)
32 #define ADVANCE_RING()
33 #define WAIT_IDLE()
34 #define DO_FLUSH()
35 #define UNLOCK_HW
36 #warning GALLIUM_SIMULATION MODE!
37 #endif
39 #define IMPLEMENT() bug("[GMA winsys]------IMPLEMENT(%s)\n", __func__)
41 struct status
43 BOOL reserved;
44 ULONG flush_num;
47 static struct status hw_status[1024];
48 //static APTR *bb_map;
49 static ULONG flush_num;
50 ULONG allocated_mem=0;
51 static struct SignalSemaphore BatchBufferLock;
52 static struct SignalSemaphore UnusedBuffersListLock;
53 struct List unusedbuffers;
55 extern struct g45staticdata sd;
56 #define sd ((struct g45staticdata*)&(sd))
57 #define LOCK_BB { ObtainSemaphore(&BatchBufferLock); }
58 #define UNLOCK_BB { ReleaseSemaphore(&BatchBufferLock); }
60 #define BASEADDRESS(p) ((IPTR)(p) - (IPTR)sd->Card.Framebuffer)
61 struct i915_winsys_batchbuffer *batchbuffer_create(struct i915_winsys *iws);
63 ULONG reserve_status_index()
65 for(;;){
66 int i;
67 for(i=100;i<1024;i++)
69 if( ! hw_status[i].reserved )
71 hw_status[i].reserved = TRUE;
72 hw_status[i].flush_num = flush_num;
73 D(bug("[GMA winsys] reserve_status_index=%d flush_num %d\n",i,flush_num));
74 return i;
77 (bug("[GMA winsys] reserve_status_index: not free index,wait a moment...\n"));
78 delay_ms(sd,1);
80 return 0;
83 VOID free_status_index(ULONG i)
85 hw_status[i].reserved = FALSE;
86 hw_status[i].flush_num = 0;
87 D(bug("[GMA winsys] free_status_index(%d)\n",i));
90 BOOL get_status(ULONG i)
92 #ifdef GALLIUM_SIMULATION
93 return 0;
94 #endif
95 if( ! hw_status[i].reserved ) bug("[GMA winsys] get_status ERROR,index not reserved %d\n",i);
96 return readl( &sd->HardwareStatusPage[ i ]);
99 VOID set_status(ULONG i,ULONG v)
101 #ifndef GALLIUM_SIMULATION
102 if( ! hw_status[i].reserved ) bug("[GMA winsys] set_status ERROR,index not reserved %d\n",i);
103 writel( v, &sd->HardwareStatusPage[ i ] );
104 readl( &sd->HardwareStatusPage[ i ] );
105 #endif
108 static APTR alloc_gfx_mem(ULONG size)
110 APTR result;
112 #ifdef GALLIUM_SIMULATION
113 return malloc(size);
114 #endif
116 result = AllocGfxMem(sd, size);
118 if( result == 0 )
120 LOCK_HW
121 DO_FLUSH();
122 WAIT_IDLE();
123 UNLOCK_HW
124 destroy_unused_buffers();
126 result = AllocGfxMem(sd, size);
129 if(result)
131 allocated_mem+=size;
132 D(bug("[GMA winsys] alloc_gfx_mem(%d) = %p allocated_mem %d\n",
133 size, result, allocated_mem));
136 return result;
139 static VOID free_gfx_mem(APTR ptr, ULONG size)
141 #ifdef GALLIUM_SIMULATION
142 free(ptr);return;
143 #endif
145 FreeGfxMem(sd, ptr, size);
146 allocated_mem-=size;
147 D(bug("[GMA winsys] free_gfx_mem(%p, %d) allocated_mem %d\n", ptr, size, allocated_mem));
150 VOID init_aros_winsys()
152 // clean hw_status table, reserve first 100, (0-15 is reserved, and
153 // bitmapclass uses at least 16-20)
154 int i;
155 for(i=100;i<1024;i++)
157 hw_status[i].reserved = FALSE;
160 NEWLIST(&unusedbuffers);
161 InitSemaphore(&BatchBufferLock);
162 InitSemaphore(&UnusedBuffersListLock);
165 /*******************************************************************
166 * Batchbuffer functions.
167 ******************************************************************/
169 #define BATCH_RESERVED 16
171 static void batchbuffer_reset(struct aros_batchbuffer *batch)
174 D(bug("[GMA winsys] batchbuffer_reset\n"));
175 memset(batch->base.map, 0, batch->actual_size);
176 batch->base.ptr = batch->base.map;
177 batch->base.size = batch->actual_size - BATCH_RESERVED;
178 batch->base.relocs = 0;
182 * Create a new batchbuffer.
184 struct i915_winsys_batchbuffer *batchbuffer_create(struct i915_winsys *iws)
186 D(bug("[GMA winsys] batchbuffer_create\n"));
187 struct aros_winsys *idws = aros_winsys(iws);
188 struct aros_batchbuffer *batch = CALLOC_STRUCT(aros_batchbuffer);
190 batch->actual_size = idws->max_batch_size;
191 batch->base.map = MALLOC(batch->actual_size);
193 batch->allocated_size = batch->actual_size + 4096;
194 if( !(batch->allocated_map = alloc_gfx_mem(batch->allocated_size) ) )
195 return NULL;
196 batch->gfxmap = (APTR)(((IPTR)batch->allocated_map + 4095)& ~4095);
198 batch->base.ptr = NULL;
199 batch->base.size = 0;
201 batch->base.relocs = 0;
202 batch->base.iws = iws;
204 batchbuffer_reset(batch);
206 return &batch->base;
210 * Validate buffers for usage in this batchbuffer.
211 * Does space-checking and assorted other book-keeping.
213 * @batch
214 * @buffers array to buffers to validate
215 * @num_of_buffers size of the passed array
217 boolean batchbuffer_validate_buffers(struct i915_winsys_batchbuffer *batch,
218 struct i915_winsys_buffer **buffers,
219 int num_of_buffers)
221 D(bug("[GMA winsys] batchbuffer_validate_buffers\n"));
222 int i;
223 for(i=0;i<num_of_buffers;i++)
225 D(bug(" buffer %p\n",buffers[i]));
226 MAGIC_WARNING(buffers[i]);
229 // IMPLEMENT();
230 return TRUE;
234 * Emit a relocation to a buffer.
235 * Target position in batchbuffer is the same as ptr.
237 * @batch
238 * @reloc buffer address to be inserted into target.
239 * @usage how is the hardware going to use the buffer.
240 * @offset add this to the reloc buffers address
241 * @target buffer where to write the address, null for batchbuffer.
242 * @fenced relocation needs a fence.
244 int batchbuffer_reloc(struct i915_winsys_batchbuffer *batch,
245 struct i915_winsys_buffer *reloc,
246 enum i915_winsys_buffer_usage usage,
247 unsigned offset, boolean fenced)
249 IF_BAD_MAGIC(reloc) return -1;
251 struct reloc *rl = &aros_batchbuffer(batch)->relocs[ batch->relocs ];
252 batch->relocs++;
254 if( batch->relocs >= MAX_RELOCS )
256 bug("[GMA winsys] MAX_RELOCS ERROR\n");
257 *(uint32_t *)(batch->ptr) = 0;
258 batch->ptr += 4;
259 return -1;
262 rl->buf = reloc;
263 rl->usage = usage;
264 rl->offset = offset;
265 rl->ptr = (uint32_t *)batch->ptr;
266 *(uint32_t *)(batch->ptr) = RELOC_MAGIC;
267 batch->ptr += 4;
268 D(bug("[GMA winsys] batchbuffer_reloc reloc %p offset %d fenced %s base=%p \n",reloc,offset,fenced ? "true" : "false",*(uint32_t *)(batch->ptr)));
270 return 0;
274 * Flush a bufferbatch.
277 #define MI_BATCH_NON_SECURE (1)
279 void batchbuffer_flush(struct i915_winsys_batchbuffer *batch,
280 struct pipe_fence_handle **fence)
282 D(bug("[GMA winsys] batchbuffer_flush size=%d\n",batch->ptr - batch->map));
283 struct aros_batchbuffer *abatch = aros_batchbuffer(batch);
285 if( (batch->ptr - batch->map) & 4) {
286 *(uint32_t *)(batch->ptr) = 0; /* MI_NOOP */
287 batch->ptr += 4;
290 *(uint32_t *)(batch->ptr) = MI_BATCH_BUFFER_END;
291 batch->ptr += 4;
292 // i915_dump_batchbuffer( batch );
294 #ifdef GALLIUM_SIMULATION
295 batchbuffer_reset( abatch );
296 return;
297 #endif
299 LOCK_BB
301 flush_num++;if(flush_num==0)flush_num=1;
302 ULONG index = reserve_status_index();
304 // relocations
305 ObtainSemaphore(&UnusedBuffersListLock);
306 int i;
307 for(i=0;i<batch->relocs;i++)
309 struct reloc *rl = &abatch->relocs[ i ];
310 D(bug("[GMA winsys] batchbuffer_flush reloc %p\n",rl->buf));
312 if( i >= MAX_RELOCS ||
313 rl->buf->map == 0 ||
314 rl->buf->magic != MAGIC ||
315 *(uint32_t *)(rl->ptr) != RELOC_MAGIC
318 batchbuffer_reset( abatch );
319 UNLOCK_BB
320 ReleaseSemaphore(&UnusedBuffersListLock);
321 bug("[GMA winsys] batchbuffer_flush ERROR:Rotten reloc, num %d buf %p map %p\n",i,rl->buf,rl->buf->map);
322 return;
325 if( rl->buf->flush_num != flush_num )
327 while( buffer_is_busy(0, rl->buf) ){}
330 rl->buf->flush_num = flush_num;
331 rl->buf->status_index = index;
333 *(uint32_t *)(rl->ptr) = BASEADDRESS( rl->buf->map ) + rl->offset;
335 ReleaseSemaphore(&UnusedBuffersListLock);
337 // copy to gfxmem
338 memcpy(abatch->gfxmap, batch->map, batch->ptr - batch->map );
340 LOCK_HW
342 // set status
343 set_status( index , 1 );
345 //run
346 START_RING(6);
348 // flush
349 ULONG cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
350 cmd &= ~MI_NO_WRITE_FLUSH;
351 cmd |= MI_READ_FLUSH;
352 cmd |= MI_EXE_FLUSH;
353 //OUT_RING(cmd);
354 //OUT_RING(0);
356 // start batchbuffer
357 OUT_RING( MI_BATCH_BUFFER_START | (2 << 6) );
358 OUT_RING( BASEADDRESS( abatch->gfxmap ) | MI_BATCH_NON_SECURE);
360 // OUT_RING(cmd);
361 // OUT_RING(0);
363 // clean status
364 OUT_RING((0x21 << 23) | 1);
365 OUT_RING( index << 2 );
366 OUT_RING(0);
367 OUT_RING(0);
369 ADVANCE_RING();
371 UNLOCK_HW
373 batchbuffer_reset( abatch );
375 UNLOCK_BB
380 * Destroy a batchbuffer.
382 void batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch)
384 (bug("[GMA winsys] batchbuffer_destroy %p\n",ibatch));
385 struct aros_batchbuffer *batch = aros_batchbuffer(ibatch);
386 FREE(ibatch->map);
387 free_gfx_mem(batch->allocated_map, batch->allocated_size);
388 FREE(batch);
390 LOCK_HW
391 DO_FLUSH();
392 WAIT_IDLE();
393 ObtainSemaphore(&UnusedBuffersListLock);
394 destroy_unused_buffers();
395 ReleaseSemaphore(&UnusedBuffersListLock);
396 UNLOCK_HW
399 /*******************************************************************
400 * Buffer functions.
401 *****************************************************************/
403 static char *i915_type_to_name(enum i915_winsys_buffer_type type)
405 char *name;
406 if (type == I915_NEW_TEXTURE) {
407 name = "gallium3d_texture";
408 } else if (type == I915_NEW_VERTEX) {
409 name = "gallium3d_vertex";
410 } else if (type == I915_NEW_SCANOUT) {
411 name = "gallium3d_scanout";
412 } else {
413 name = "gallium3d_unknown";
415 return name;
419 void destroy_unused_buffers()
422 D(bug("[GMA winsys] destroy_unused_buffers allocated_mem %d\n",allocated_mem));
423 if( AttemptSemaphore(&UnusedBuffersListLock) )
425 struct Node *node,*next;
426 struct i915_winsys_buffer *buf;
427 int i=0;
428 ForeachNodeSafe(&unusedbuffers,node,next)
430 i++;
431 buf = (struct i915_winsys_buffer *)node;
433 if( ! buffer_is_busy(0, buf ) )
435 i--;
436 D(bug("[GMA winsys] destroy %p\n",buf));
437 Remove(node);
438 buf->magic = 0;
439 free_gfx_mem(buf->allocated_map, buf->allocated_size);
440 FREE(buf);
444 D(if(i) bug("[GMA winsys] unused_buffers left:%d\n",i));
445 ReleaseSemaphore(&UnusedBuffersListLock);
451 * Create a buffer.
453 struct i915_winsys_buffer *
454 buffer_create(struct i915_winsys *iws,
455 unsigned size,
456 enum i915_winsys_buffer_type type)
459 struct i915_winsys_buffer *buf;
462 if( AttemptSemaphore(&UnusedBuffersListLock) )
464 if( (buf = (struct i915_winsys_buffer *)GetTail(&unusedbuffers)) )
466 if( buf->size == size )
468 if( ! buffer_is_busy(0, buf ) )
470 D(bug("[GMA winsys] buffer_create: cheap secondhand buffer found:%p\n", buf));
471 Remove((struct Node *)buf);
472 ReleaseSemaphore(&UnusedBuffersListLock);
473 return buf;
477 ReleaseSemaphore(&UnusedBuffersListLock);
481 buf = CALLOC_STRUCT(i915_winsys_buffer);
482 if (!buf)
483 return NULL;
485 // allocate page aligned gfx memory
486 buf->allocated_size = size + 4096;
487 if( !(buf->allocated_map = alloc_gfx_mem(buf->allocated_size) ) )
489 FREE(buf);
490 return NULL;
492 buf->map = (APTR)(((IPTR)buf->allocated_map + 4095)& ~4095);
493 buf->size = size;
494 buf->magic = MAGIC;
495 D(bug("[GMA winsys] buffer_create size %d type %s = %p map %p\n",size,i915_type_to_name(type),buf,buf->map));
497 return buf;
503 * Create a tiled buffer.
505 * *stride, height are in bytes. The winsys tries to allocate the buffer with
506 * the tiling mode provide in *tiling. If tiling is no possible, *tiling will
507 * be set to I915_TILE_NONE. The calculated stride (incorporateing hw/kernel
508 * requirements) is always returned in *stride.
510 struct i915_winsys_buffer *
511 buffer_create_tiled(struct i915_winsys *iws,
512 unsigned *stride, unsigned height,
513 enum i915_winsys_buffer_tile *tiling,
514 enum i915_winsys_buffer_type type)
516 D(bug("[GMA winsys] buffer_create_tiled stride=%d heigh=%d type:%s\n",*stride,height,i915_type_to_name(type)));
517 // Tiling is not implemented.
518 *tiling = I915_TILE_NONE;
519 return buffer_create( iws, *stride * height, type );
524 * Creates a buffer from a handle.
525 * Used to implement pipe_screen::resource_from_handle.
526 * Also provides the stride information needed for the
527 * texture via the stride argument.
529 struct i915_winsys_buffer *
530 buffer_from_handle(struct i915_winsys *iws,
531 struct winsys_handle *whandle,
532 enum i915_winsys_buffer_tile *tiling,
533 unsigned *stride)
535 D(bug("[GMA winsys] buffer_from_handle\n"));
536 IMPLEMENT();
537 return NULL;
542 * Used to implement pipe_screen::resource_get_handle.
543 * The winsys might need the stride information.
545 boolean buffer_get_handle(struct i915_winsys *iws,
546 struct i915_winsys_buffer *buffer,
547 struct winsys_handle *whandle,
548 unsigned stride)
550 D(bug("[GMA winsys] buffer_get_handle\n"));
551 IMPLEMENT();
552 return FALSE;
557 * Map a buffer.
559 void *buffer_map(struct i915_winsys *iws,
560 struct i915_winsys_buffer *buffer,
561 boolean write)
563 IF_BAD_MAGIC(buffer)
565 //for(;;);
566 return 0;
568 D(bug("[GMA winsys] buffer_map %p\n",buffer));
569 while( buffer_is_busy(iws, buffer )){};
570 return buffer->map;
575 * Unmap a buffer.
577 void buffer_unmap(struct i915_winsys *iws,
578 struct i915_winsys_buffer *buffer)
580 MAGIC_WARNING(buffer);
581 D(bug("[GMA winsys] buffer_unmap %p\n",buffer));
582 // IMPLEMENT();
587 * Write to a buffer.
589 * Arguments follows pipe_buffer_write.
591 int buffer_write(struct i915_winsys *iws,
592 struct i915_winsys_buffer *dst,
593 size_t offset,
594 size_t size,
595 const void *data)
597 D(bug("[GMA winsys] buffer_write offset=%d size=%d\n",offset,size));
598 IMPLEMENT();
599 return 0;
603 void buffer_destroy(struct i915_winsys *iws,
604 struct i915_winsys_buffer *buf)
606 IF_BAD_MAGIC(buf) return;
607 D(bug("[GMA winsys] buffer_destroy %p\n", buf));
609 if(0)
611 while( buffer_is_busy(0, buf ) ){};
612 buf->magic = 0;
613 free_gfx_mem(buf->allocated_map, buf->allocated_size);
614 FREE(buf);
616 else
618 ObtainSemaphore(&UnusedBuffersListLock);
619 AddTail( &unusedbuffers, (struct Node *)buf );
620 ReleaseSemaphore(&UnusedBuffersListLock);
626 * Check if a buffer is busy.
628 boolean buffer_is_busy(struct i915_winsys *iws,
629 struct i915_winsys_buffer *buf)
631 MAGIC_WARNING(buf);
633 int i=buf->status_index;
634 D(bug("[GMA winsys] buffer_is_busy %p index %d flush_num %d\n",buf,i,buf->flush_num));
635 if(i)
637 if( hw_status[i].reserved &&
638 hw_status[i].flush_num == buf->flush_num )
640 if( get_status(i) )
642 return TRUE;
644 else
646 buf->status_index = 0;
647 free_status_index(i);
651 return FALSE;
657 /****************************************************************
658 * Fence functions.
659 *************************************************************/
662 * Reference fence and set ptr to fence.
664 void fence_reference(struct i915_winsys *iws,
665 struct pipe_fence_handle **ptr,
666 struct pipe_fence_handle *fence)
668 D(bug("[GMA winsys] fence_reference\n"));
669 IMPLEMENT();
674 * Check if a fence has finished.
676 int fence_signalled(struct i915_winsys *iws,
677 struct pipe_fence_handle *fence)
679 D(bug("[GMA winsys] fence_signalled\n"));
680 IMPLEMENT();
681 return 0;
686 * Wait on a fence to finish.
688 int fence_finish(struct i915_winsys *iws,
689 struct pipe_fence_handle *fence)
691 D(bug("[GMA winsys] fence_finish\n"));
692 IMPLEMENT();
693 return 0;
697 void winsys_destroy(struct i915_winsys *ws)
699 D(bug("[GMA winsys] winsys_destroy\n"));
700 struct aros_winsys *aws = aros_winsys(ws);
701 FREE(aws);
704 struct aros_winsys *
705 winsys_create()
707 D(bug("[GMA winsys] winsys_create\n"));
708 struct aros_winsys *aws;
710 aws = CALLOC_STRUCT(aros_winsys);
711 if (!aws) return NULL;
713 aws->base.batchbuffer_create = batchbuffer_create;
714 aws->base.validate_buffers = batchbuffer_validate_buffers;
715 aws->base.batchbuffer_reloc = batchbuffer_reloc;
716 aws->base.batchbuffer_flush = batchbuffer_flush;
717 aws->base.batchbuffer_destroy = batchbuffer_destroy;
719 aws->base.buffer_create = buffer_create;
720 aws->base.buffer_create_tiled = buffer_create_tiled;
721 aws->base.buffer_from_handle = buffer_from_handle;
722 aws->base.buffer_get_handle = buffer_get_handle;
723 aws->base.buffer_map = buffer_map;
724 aws->base.buffer_unmap = buffer_unmap;
725 aws->base.buffer_write = buffer_write;
726 aws->base.buffer_destroy = buffer_destroy;
727 aws->base.buffer_is_busy = buffer_is_busy;
729 aws->base.fence_reference = fence_reference;
730 aws->base.fence_signalled = fence_signalled;
731 aws->base.fence_finish = fence_finish;
733 aws->base.destroy = winsys_destroy;
735 aws->base.pci_id = sd->ProductID;
736 #ifdef GALLIUM_SIMULATION
737 aws->base.pci_id = 0x27AE;
738 #endif
739 aws->max_batch_size = 16 * 4096;
741 return aws;