From ccf52b6784d93742314ab91d262288c924e51d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Sun, 5 Mar 2006 21:52:03 +0000 Subject: [PATCH] Move over to libdrm. At least one lockup remaining with multiple clients when at least one client is using textures. --- configs/linux-dri | 4 +- src/mesa/drivers/dri/i915/Makefile | 4 +- src/mesa/drivers/dri/i915/bufmgr.h | 188 --- src/mesa/drivers/dri/i915/bufmgr_fake.c | 1165 ---------------- src/mesa/drivers/dri/i915/bufmgr_old.c | 1171 ----------------- src/mesa/drivers/dri/i915/i830_vtbl.c | 6 +- src/mesa/drivers/dri/i915/i915_context.c | 2 +- src/mesa/drivers/dri/i915/i915_vtbl.c | 6 +- src/mesa/drivers/dri/i915/intel_batchbuffer.c | 56 +- src/mesa/drivers/dri/i915/intel_batchbuffer.h | 7 +- src/mesa/drivers/dri/i915/intel_blit.c | 28 +- .../drivers/dri/i915/intel_buffer_objects.c | 4 +- src/mesa/drivers/dri/i915/intel_bufmgr.c | 325 +++++ src/mesa/drivers/dri/i915/intel_bufmgr.h | 132 ++ src/mesa/drivers/dri/i915/intel_context.c | 21 +- src/mesa/drivers/dri/i915/intel_ioctl.c | 2 +- src/mesa/drivers/dri/i915/intel_mipmap_tree.c | 2 +- src/mesa/drivers/dri/i915/intel_pixel_copy.c | 2 +- src/mesa/drivers/dri/i915/intel_pixel_draw.c | 2 +- src/mesa/drivers/dri/i915/intel_pixel_read.c | 2 +- src/mesa/drivers/dri/i915/intel_regions.c | 26 +- src/mesa/drivers/dri/i915/intel_regions.h | 2 +- src/mesa/drivers/dri/i915/intel_tex_copy.c | 2 +- .../drivers/dri/i915/intel_tex_validate.c | 2 +- 24 files changed, 537 insertions(+), 2624 deletions(-) delete mode 100644 src/mesa/drivers/dri/i915/bufmgr.h delete mode 100644 src/mesa/drivers/dri/i915/bufmgr_fake.c delete mode 100644 src/mesa/drivers/dri/i915/bufmgr_old.c create mode 100644 src/mesa/drivers/dri/i915/intel_bufmgr.c create mode 100644 src/mesa/drivers/dri/i915/intel_bufmgr.h diff --git a/configs/linux-dri b/configs/linux-dri index bf42c847afe..85b6ea0f703 100644 --- a/configs/linux-dri +++ b/configs/linux-dri @@ -13,7 +13,7 @@ CXX = g++ #MKDEP = gcc -M #MKDEP_OPTIONS = -MF depend -OPT_FLAGS = -g +OPT_FLAGS = -g -march=pentium4 -fprefetch-loop-arrays PIC_FLAGS = -fPIC # Add '-DGLX_USE_TLS' to ARCH_FLAGS to enable TLS support. @@ -63,7 +63,7 @@ WINDOW_SYSTEM=dri # gamma are missing because they have not been converted to use the new # interface. -DRI_DIRS = i810 i915 mach64 mga r128 r200 r300 radeon s3v \ +DRI_DIRS = i915 mach64 mga r128 r200 r300 radeon s3v \ savage sis tdfx trident unichrome ffb DRI_DIRS = i915 diff --git a/src/mesa/drivers/dri/i915/Makefile b/src/mesa/drivers/dri/i915/Makefile index d1c0c1c260d..7cc407ffcca 100644 --- a/src/mesa/drivers/dri/i915/Makefile +++ b/src/mesa/drivers/dri/i915/Makefile @@ -12,7 +12,6 @@ DRIVER_SOURCES = \ i830_tex.c \ i830_texstate.c \ i830_vtbl.c \ - bufmgr_fake.c \ intel_render.c \ intel_regions.c \ intel_buffer_objects.c \ @@ -46,7 +45,8 @@ DRIVER_SOURCES = \ intel_screen.c \ intel_span.c \ intel_state.c \ - intel_tris.c + intel_tris.c \ + intel_bufmgr.c diff --git a/src/mesa/drivers/dri/i915/bufmgr.h b/src/mesa/drivers/dri/i915/bufmgr.h deleted file mode 100644 index 471729bb2b4..00000000000 --- a/src/mesa/drivers/dri/i915/bufmgr.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef BUFMGR_H -#define BUFMGR_H - -#include "intel_context.h" - -/* Note that this is destined to be external to Mesa, so don't use GL - * types like GLuint, etc. - */ - -/* The buffer manager context. Opaque. - */ -struct bufmgr; - -#define BM_LIST_MAX 32 - -/* List of buffers to validate. Probably better managed by the client: - */ -struct bm_buffer_list { - struct { - unsigned buffer; - unsigned *offset_return; - unsigned *memtype_return; - } elem[BM_LIST_MAX]; - - unsigned nr; -}; - - -struct bufmgr *bm_fake_intel_Attach( struct intel_context *intel ); - -/* struct bufmgr *bmCreate( ... ); */ -/* struct bufmgr *bmAttach( ... ); */ - -/* Define an address space. Doesn't really do anything, but the - * information could be used to validate the bmInitPool() requests. - */ -void bmInitMemType( struct bufmgr *, - unsigned mem_type, - unsigned long size ); - - -/* Create a pool of a given memory type, from a certain offset and a - * certain size. - * - * Also passed in is a virtual pointer to the start of the pool. This - * is useful in the faked-out version in i915 so that MapBuffer can - * return a pointer to a buffer residing in AGP space. - * - * Flags passed into a pool are inherited by all buffers allocated in - * that pool. So pools representing the static front,back,depth - * buffer allocations should have MEM_AGP|NO_UPLOAD|NO_EVICT|NO_MOVE to match - * the behaviour of the legacy allocations. - * - * Returns -1 for failure, pool number for success. - */ -int bmInitPool( struct bufmgr *, - unsigned long low_offset, - void *low_virtual, - unsigned long size, - unsigned flags); - - -/* Flags for validate and other calls. If both NO_UPLOAD and NO_EVICT - * are specified, ValidateBuffers is essentially a query. - */ -#define BM_MEM_LOCAL 0x1 -#define BM_MEM_AGP 0x2 -#define BM_MEM_VRAM 0x4 /* not yet used */ -#define BM_WRITE 0x8 /* not yet used */ -#define BM_READ 0x10 /* not yet used */ -#define BM_NO_UPLOAD 0x20 -#define BM_NO_EVICT 0x40 -#define BM_NO_MOVE 0x80 /* not yet used */ -#define BM_NO_ALLOC 0x100 /* legacy "fixed" buffers only */ -#define BM_CLIENT 0x200 /* for map - pointer will be accessed - * without dri lock */ -#define BM_NO_TTM 0x400 - -#define BM_MEM_MASK (BM_MEM_LOCAL|BM_MEM_AGP|BM_MEM_VRAM) - - - -/* Stick closely to ARB_vbo semantics - they're well defined and - * understood, and drivers can just pass the calls through without too - * much thunking. - */ -void bmGenBuffers(struct bufmgr *, unsigned n, unsigned *buffers); -void bmDeleteBuffers(struct bufmgr *, unsigned n, unsigned *buffers); - - -/* Hook to inform faked buffer manager about fixed-position - * front,depth,back buffers. These may move to a fully memory-managed - * scheme, or they may continue to be managed as is. - */ -unsigned bmBufferStatic(struct bufmgr *, - unsigned buffer, - unsigned size, - unsigned pool); - - - -/* The driver has more intimate knowledge of the hardare than a GL - * client would, so flags here is more proscriptive than the usage - * values in the ARB_vbo interface: - */ -void bmBufferData(struct bufmgr *, - unsigned buffer, - unsigned size, - const void *data, - unsigned flags ); - -void bmBufferSubData(struct bufmgr *, - unsigned buffer, - unsigned offset, - unsigned size, - const void *data ); - -void bmBufferGetSubData(struct bufmgr *, - unsigned buffer, - unsigned offset, - unsigned size, - void *data ); - -void *bmMapBuffer( struct bufmgr *, - unsigned buffer, - unsigned access ); - -void bmUnmapBuffer( struct bufmgr *, - unsigned buffer ); - -/* To be called prior to emitting commands to hardware which reference - * these buffers. - * - * NewBufferList() and AddBuffer() build up a list of buffers to be - * validated. The buffer list provides information on where the - * buffers should be placed and whether their contents need to be - * preserved on copying. The offset data elements are return values - * from this function telling the driver exactly where the buffers are - * currently located. - * - * ValidateBufferList() performs the actual validation and returns the - * buffer pools and offsets within the pools. - * - * FenceBufferList() must be called to set fences and other - * housekeeping before unlocking after a successful call to - * ValidateBufferList(). The buffer manager knows how to emit and test - * fences directly through the drm and without callbacks to the - * driver. - */ -struct bm_buffer_list *bmNewBufferList( void ); - -void bmAddBuffer( struct bm_buffer_list *list, - unsigned buffer, - unsigned flags, - unsigned *pool_return, - unsigned *offset_return ); - -int bmValidateBufferList( struct bufmgr *, - struct bm_buffer_list *, - unsigned flags ); - -unsigned bmFenceBufferList( struct bufmgr *, - struct bm_buffer_list * ); - -void bmFreeBufferList( struct bm_buffer_list * ); - - -/* This functionality is used by the buffer manager, not really sure - * if we need to be exposing it in this way, probably libdrm will - * offer equivalent calls. - * - * For now they can stay, but will likely change/move before final: - */ -unsigned bmSetFence( struct bufmgr * ); -int bmTestFence( struct bufmgr *, unsigned fence ); -void bmFinishFence( struct bufmgr *, unsigned fence ); - -void bmFlushReadCaches( struct bufmgr *bm ); -void bmFlushDrawCache( struct bufmgr *bm ); - -void bm_fake_NotifyContendedLockTake( struct bufmgr * ); - -extern int INTEL_DEBUG; -#define DEBUG_BUFMGR 0x2000 - -#define DBG(...) do { if (INTEL_DEBUG & DEBUG_BUFMGR) _mesa_printf(__VA_ARGS__); } while(0) - -#endif diff --git a/src/mesa/drivers/dri/i915/bufmgr_fake.c b/src/mesa/drivers/dri/i915/bufmgr_fake.c deleted file mode 100644 index d246d5c5f37..00000000000 --- a/src/mesa/drivers/dri/i915/bufmgr_fake.c +++ /dev/null @@ -1,1165 +0,0 @@ -/* Fake version of the buffer manager so that we can prototype the - * changes in a driver fairly quickly. Basically wraps the old style - * memory management in the new programming interface. - * - * This version imports code from the via memory manager to closer - * approximate the behaviour of a true memory manager. In particular, - * in this version we do not expect to lose texture memory contents on - * context switches. - */ -#include "bufmgr.h" - -#include "intel_context.h" -#include "intel_ioctl.h" - -#include "hash.h" -#include "simple_list.h" -#include "mm.h" -#include "imports.h" -#include -#include -#include - -static int ttmcount = 0; - -/* - * Define this if the texture TTMs should be cached. If it is not defined, - * Texture downloads will be slow since the TTM pages are not write-combined. - * Backdoor mapping will very probably fix this. (texdown-pool) - */ - -#undef CACHED_TTMS - -/* - * Batchbuffer memory location: - * 0 Is the global texture pool (as without ttms) - * 1 Is a memory-managed large pinned uncached TTM. Should work as 0, but - * doesn't. The only difference is that the TTM memory is accessed - * directly instead of through the aperture. Runs for a while. - * 2 Is dynamic TTMS. This is what we want. Doesn't work either, but runs - * for a while, depending on application. multiarb works fine for example. - */ - -#define BATCH_LOCATION 1 - -#if (BATCH_LOCATION == 2) -#warning Batch buffers using dynamic TTMS. Making TTMS uncached. -#undef CACHED_TTMS -#endif - -struct _mesa_HashTable; - -static int delayed_free( struct bufmgr *bm ); - -#define BM_POOL_MAX 8 - - -/* Wrapper around mm.c's mem_block, which understands that you must - * wait for fences to expire before memory can be freed. This is - * specific to our use of memcpy and/or ttms for uploads - an upload - * that was processed through the command queue wouldn't need to care - * about fences. - */ -struct block { - struct block *next, *prev; - int mem_type; - struct pool *pool; /* BM_MEM_AGP */ - struct mem_block *mem; /* BM_MEM_AGP */ - unsigned fence; /* BM_MEM_AGP, Split to read_fence, write_fence */ - void *virtual; - struct buffer *buf; - drm_ttm_arg_t drm_ttm; - drm_ttm_buf_arg_t drm_buf; - int has_ttm; -}; - - -struct buffer { - unsigned id; /* debug only */ - unsigned size; - unsigned alignment; - unsigned mapped; - unsigned flags; - struct block *block; -}; - -struct pool { - unsigned flags; - struct mem_block *heap; - void *virtual; - struct block lru; - struct block freed; - drm_ttm_arg_t drm_ttm; - drm_ttm_buf_arg_t drm_buf; -}; - -struct bufmgr { - struct intel_context *intel; - struct pool pool[BM_POOL_MAX]; - unsigned nr_pools; - - struct _mesa_HashTable *hash; - - unsigned buf_nr; /* for generating ids */ -}; - - - -static struct block *alloc_from_pool( struct bufmgr *bm, - unsigned pool_nr, - unsigned size, - unsigned align ) -{ - struct pool *pool = &bm->pool[pool_nr]; - struct block *block = (struct block *)calloc(sizeof *block, 1); - if (!block) - return NULL; - - DBG("alloc_from_pool %d sz 0x%x\n", pool_nr, size); - assert(align >= 7); - - block->mem = mmAllocMem(pool->heap, size, align, 0); - if (!block->mem) { - DBG("\t- failed\n"); - free(block); - return NULL; - } - - make_empty_list(block); - block->pool = pool; - block->mem_type = pool->flags & BM_MEM_MASK; - block->virtual = pool->virtual + block->mem->ofs; - block->has_ttm = 0; - - DBG("\t- offset 0x%x\n", block->mem->ofs); - return block; -} - - -static struct block *alloc_local( unsigned size ) -{ - struct block *block = (struct block *)calloc(sizeof *block, 1); - if (!block) - return NULL; - - DBG("alloc_local 0x%x\n", size); - - block->mem_type = BM_MEM_LOCAL; - block->virtual = ALIGN_MALLOC(size, 1<<7); - if (!block->virtual) { - free(block); - return NULL; - } - - return block; -} - - - - -static struct block *alloc_block( struct bufmgr *bm, - unsigned size, - unsigned align, - int flags ) -{ - GLuint i; - int ret; - struct block *block; - unsigned alignment = ( 1 << align ); - - if (!(flags & BM_NO_TTM) -#if (BATCH_LOCATION != 2) -#warning Disabling dynamic batch buffers - && !(flags & BM_CLIENT) -#endif - ) { - - block = (struct block *)calloc(sizeof *block, 1); - if (!block) return NULL; - - make_empty_list(block); - block->pool = bm->pool + 0; - block->mem_type = flags; - block->has_ttm = 0; - - block->drm_ttm.op = ttm_add; - block->drm_ttm.size = ((size + alignment -1) >> align) << align; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - assert(ret == 0); - block->drm_buf.ttm_handle = block->drm_ttm.handle; - block->drm_buf.ttm_page_offset = 0; - block->drm_buf.num_pages = block->drm_ttm.size / getpagesize(); - block->drm_buf.next = NULL; - -#ifdef CACHED_TTMS - block->drm_buf.flags = DRM_MM_NEW | DRM_MM_CACHED; -#else - block->drm_buf.flags = DRM_MM_NEW; -#endif - block->has_ttm = 2; - if (block->has_ttm > 1) - block->virtual = NULL; - ttmcount += block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - DBG("ttm handle is 0x%x\n", block->drm_ttm.handle); - - return block; - } - - if (!(flags & (BM_CLIENT))) { - for (i = 0; i < bm->nr_pools; i++) { - struct block *block; - - if (bm->pool[i].flags & BM_NO_ALLOC) - continue; - - if ((bm->pool[i].flags & flags & BM_MEM_MASK) == 0) - continue; - - block = alloc_from_pool(bm, i, size, align); - if (block) return block; - } - } - - - if (flags & BM_MEM_LOCAL) - return alloc_local(size); - - return NULL; -} - -static int bmAllocMem( struct bufmgr *bm, - struct buffer *buf, - GLuint flags ) -{ - delayed_free(bm); - - buf->block = alloc_block(bm, - buf->size, - buf->alignment, - buf->flags | flags); - - if (buf->block) - buf->block->buf = buf; - else - _mesa_printf("bmAllocMem failed memflags %x\n", buf->flags & BM_MEM_MASK); - - /* Sleep here or fail??? - */ -/* assert(buf->block); */ - return buf->block != NULL; -} - - -/* Release the card storage associated with buf: - */ -static void free_block( struct bufmgr *bm, struct block *block ) -{ - int ret; - - if (!block) - return; - - DBG("free block (mem: %d, sz %d) from buf %d\n", - block->mem_type, - block->buf->size, - block->buf->id); - - switch (block->mem_type) { - case BM_MEM_AGP: - case BM_MEM_VRAM: - remove_from_list(block); - - if (!block->has_ttm) - DBG(" - offset %x\n", block->mem->ofs); - else - DBG(" - offset %x\n", block->drm_buf.aper_offset*getpagesize()); - - if (bmTestFence(bm, block->fence)) { - if (!block->has_ttm) { - mmFreeMem(block->mem); - } else { - block->drm_ttm.op = ttm_remove; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - ttmcount -= block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - assert(ret == 0); - } - free(block); - } - else { - DBG(" - place on delayed_free list\n"); - block->buf = NULL; - insert_at_tail(&block->pool->freed, block); - } - break; - - case BM_MEM_LOCAL: - DBG(" - free local memory\n"); - ALIGN_FREE(block->virtual); - free(block); - break; - - default: - DBG(" - unknown memory type\n"); - free(block); - break; - } -} - -static int delayed_free( struct bufmgr *bm ) -{ - struct block *block, *tmp; - int ret = 0; - int rettm; - int i; - - for (i = 0; i < bm->nr_pools; i++) { - foreach_s(block, tmp, &bm->pool[i].freed ) { - if (bmTestFence(bm, block->fence)) { - remove_from_list(block); - if (!block->has_ttm) { - mmFreeMem(block->mem); - ret += block->mem->size; - } else { - block->drm_ttm.op = ttm_remove; - rettm = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - ttmcount -= block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - assert(rettm == 0); - ret += block->drm_buf.num_pages*getpagesize(); - } - free(block); - } - } - } - - DBG("%s: %d\n", __FUNCTION__, ret); - return ret; -} - - -static int move_buffers( struct bufmgr *bm, - struct buffer *buffers[], - int nr, - int flags ) -{ - struct block *newMem[BM_LIST_MAX]; - GLint i; - GLuint nr_uploads = 0; - drm_ttm_arg_t arg; - struct block *block, *last_block; - int ret; - drm_ttm_buf_arg_t *cur; - int size; - - DBG("%s\n", __FUNCTION__); - - memset(newMem, 0, sizeof(newMem)); - - /* First do all the allocations (or fail): - */ - for (i = 0; i < nr; i++) { - if (!buffers[i]->block) { - - if (flags & BM_NO_ALLOC) - goto cleanup; - - newMem[i] = alloc_block(bm, - buffers[i]->size, - buffers[i]->alignment, - flags & BM_MEM_MASK); - - if (!newMem[i]) - goto cleanup; - - } - } - - /* - * Tell kernel where TTMS should be. - */ - - arg.num_bufs = 0; - last_block = NULL; - size = 0; - - for (i = 0; i has_ttm) { - buffers[i]->block = newMem[i]; - newMem[i] = NULL; - } - block = buffers[i]->block; - if (block->has_ttm) { - if ((flags & BM_MEM_MASK) == BM_MEM_AGP || - (((flags & BM_MEM_MASK) == BM_MEM_LOCAL) && - (block->mem_type == BM_MEM_AGP))) { - if (arg.num_bufs == 0) - arg.first = &block->drm_buf; - else - last_block->drm_buf.next = &block->drm_buf; - size += block->drm_buf.num_pages; - arg.num_bufs++; - last_block = block; - block->drm_buf.op = ((flags & BM_MEM_MASK) == BM_MEM_AGP) ? - ttm_validate : ttm_unbind; - block->drm_buf.fence_type = 0; - block->mem_type = flags & BM_MEM_MASK; - } - } - } - arg.op = ttm_bufs; - arg.do_fence = 0; - DBG("Num validated TTM bufs is %d pages %d\n", arg.num_bufs, size); - if (arg.num_bufs) { - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &arg); - assert(ret==0); - cur = arg.first; - for(i=0; i< arg.num_bufs; ++i) { - if (cur->ret) { - fprintf(stderr,"Kernel Error. Check dmesg.\n"); - fflush(stderr); - assert(0); - } - cur = cur->next; - } - } - - /* - * End TTM code. - */ - - - for (i=0; i< nr; ++i) { - if (!(buffers[i]->block->mem_type & flags)) { - if (flags & BM_NO_UPLOAD) - goto cleanup; - - /* Known issue: this assert will get hit on texture swapping. - * There's not much to do about that at this stage - it's a - * todo item. - */ - assert(!buffers[i]->mapped); - - DBG("try to move buffer %d size 0x%x to pools 0x%x\n", - buffers[i]->id, buffers[i]->size, flags & BM_MEM_MASK); - - newMem[i] = alloc_block(bm, - buffers[i]->size, - buffers[i]->alignment, - (flags & BM_MEM_MASK) | BM_NO_TTM); - - if (!newMem[i]) - goto cleanup; - - } - } - - - /* Now copy all the image data and free the old texture memory. - */ - for (i = 0; i < nr; i++) { - if (newMem[i]) { - if (buffers[i]->block) { - /* XXX: To be replaced with DMA, GTT bind, and other - * mechanisms in final version. Memcpy (or sse_memcpy) is - * probably pretty good for local->agp uploads. - */ - DBG("memcpy %d bytes\n", buffers[i]->size); - memcpy(newMem[i]->virtual, - buffers[i]->block->virtual, - buffers[i]->size); - - free_block(bm, buffers[i]->block); - nr_uploads++; - } - - buffers[i]->block = newMem[i]; - buffers[i]->block->buf = buffers[i]; - } - } - - /* Tell hardware that its texture and other caches may be invalid: - */ - if (nr_uploads && (flags & (BM_MEM_AGP|BM_MEM_VRAM))) - bmFlushReadCaches(bm); - - DBG("%s - success\n", __FUNCTION__); - return 1; - - cleanup: - /* Release any allocations made prior to failure: - */ - for (i = 0; i < nr; i++) { - if (newMem[i]) - free_block(bm, newMem[i]); - } - - DBG("%s - fail\n", __FUNCTION__); - return 0; -} - - -static unsigned evict_lru( struct bufmgr *bm, - unsigned flags) -{ - int i; - - DBG("%s\n", __FUNCTION__); - - if (flags & BM_NO_EVICT) - return 0; - - /* XXX: this is broken with >1 active pool - all the first pool - * will be evicted before starting on the second. Actually, maybe - * you want that in some situations... - */ - for (i = 0; i < bm->nr_pools; i++) { - if ((bm->pool[i].flags & flags & BM_MEM_MASK) && - !(bm->pool[i].flags & BM_NO_EVICT)) { - struct block *block = bm->pool[i].lru.next; - unsigned size = block->buf->size; - - if (block == &bm->pool[i].lru || - !bmTestFence(bm, block->fence)) - return 0; - - move_buffers(bm, &block->buf, 1, BM_MEM_LOCAL); - return size; - } - } - - return 0; -} - -#if 0 -/* Speculatively move texture images which haven't been used in a - * while back to local memory. - */ -static void viaSwapOutWork( struct bufmgr *bm ) -{ - unsigned total = 0; - unsigned target; - - if (bm->thrashing) { - target = 6*1024*1024; - } - else if (bmIsTexMemLow(bm)) { - target = 64*1024; - } - else { - return; - } - - while (1) { - unsigned size = evict_lru(bm); - if (!size) - return; - - total += size; - if (total >= target) - return; - } -} -#endif - - - - - - - - - - - - -/*********************************************************************** - * Public functions - */ - - -/* The initialization functions are skewed in the fake implementation. - * This call would be to attach to an existing manager, rather than to - * create a local one. - */ -struct bufmgr *bm_fake_intel_Attach( struct intel_context *intel ) -{ - struct bufmgr *bm = (struct bufmgr *)calloc(sizeof(*bm), 1); - - bm->intel = intel; - bm->hash = _mesa_NewHashTable(); - - return bm; -} - - -void bmInitMemType( struct bufmgr *bm, - unsigned mem_type, - unsigned long size ) -{ - /* Nothing really to do. Could store and use to validate - * bmInitPool requests. - */ -} - - -/* The virtual pointer would go away in a true implementation. - */ -int bmInitPool( struct bufmgr *bm, - unsigned long low_offset, - void *low_virtual, - unsigned long size, - unsigned flags) -{ - GLuint i; - struct pool *pool; - - if (bm->nr_pools >= BM_POOL_MAX) - return -1; - - i = bm->nr_pools++; - - DBG("bmInitPool %d low_offset %x sz %x\n", - i, low_offset, size); - - pool = bm->pool + i; - pool->flags = flags; - - make_empty_list(&bm->pool[i].lru); - make_empty_list(&bm->pool[i].freed); - - if (flags == BM_MEM_AGP) { -#if (BATCH_LOCATION == 1) -#warning Replacing pool 0 with a large uncached pinned TTM. - int ret; - drmAddress ttmAddress; - - size = 1024*1024; - DBG("Creating Pinned ttm, size %d\n", size); - pool->drm_ttm.op = ttm_add; - pool->drm_ttm.size = size; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - if (ret) return -1; - ret = drmMap(bm->intel->driFd, pool->drm_ttm.handle, size, &ttmAddress); - DBG("Virtual is 0x%lx\n", (unsigned long) ttmAddress); - if (ret) { - pool->drm_ttm.op = ttm_add; - ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - return -1; - } - pool->drm_buf.ttm_handle = pool->drm_ttm.handle; - pool->drm_buf.ttm_page_offset = 0; - pool->drm_buf.num_pages = pool->drm_ttm.size / getpagesize(); - pool->drm_buf.next = NULL; - pool->drm_buf.flags = DRM_MM_NEW | DRM_MM_NO_EVICT; - pool->drm_buf.op = ttm_validate; - pool->drm_ttm.op = ttm_bufs; - pool->drm_ttm.num_bufs = 1; - pool->drm_ttm.first = &pool->drm_buf; - drmGetLock(bm->intel->driFd, bm->intel->hHWContext, 0); - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - drmUnlock(bm->intel->driFd, bm->intel->hHWContext); - low_offset = pool->drm_buf.aper_offset * getpagesize(); - pool->heap = mmInit( low_offset , size ); - pool->virtual = (char *) ttmAddress - low_offset; - DBG("Pinned buf offset is 0x%lx\n", low_offset); -#else - pool->heap = mmInit( low_offset , size ); - pool->virtual = low_virtual - low_offset; -#endif - } else { - pool->heap = mmInit( low_offset, size ); - pool->virtual = low_virtual - low_offset; - } - return i; -} - -#if 0 -void bmAssertTTM(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, buffers[i]); - DBG("0x%x\n", buf->flags); - assert(buf->block); - assert(buf->block->has_ttm); - } -} -#endif - -void bmGenBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = calloc(sizeof(*buf), 1); - buf->id = ++bm->buf_nr; - buf->alignment = 12; /* page-alignment to fit in with AGP swapping */ - buf->flags = BM_MEM_AGP|BM_MEM_VRAM|BM_MEM_LOCAL; - buffers[i] = buf->id; - _mesa_HashInsert(bm->hash, buffers[i], buf); - } -} - - -void bmDeleteBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, buffers[i]); - if (buf) { - free_block(bm, buf->block); - free(buf); - _mesa_HashRemove(bm->hash, buffers[i]); - } - assert(_mesa_HashLookup(bm->hash, buffers[i]) == NULL); - } -} - - - - -/* Hook to inform faked buffer manager about fixed-position - * front,depth,back buffers. These may move to a fully memory-managed - * scheme, or they may continue to be managed as is. It will probably - * be useful to pass a fixed offset here one day. - */ -unsigned bmBufferStatic(struct bufmgr *bm, - unsigned buffer, - unsigned size, - unsigned pool ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - assert(!buf->block); - assert(bm->pool[pool].flags & BM_NO_EVICT); - assert(bm->pool[pool].flags & BM_NO_MOVE); - - buf->size = size; - buf->flags = bm->pool[pool].flags; - buf->alignment = 12; - buf->block = alloc_from_pool(bm, pool, buf->size, buf->alignment); - if (!buf->block) - return 0; - - buf->block->buf = buf; - return buf->block->mem->ofs; -} - - - -/* If buffer size changes, free and reallocate. Otherwise update in - * place. - */ -void bmBufferData(struct bufmgr *bm, - unsigned buffer, - unsigned size, - const void *data, - unsigned flags ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferData %d sz 0x%x data: %p\n", buffer, size, data); - - assert(!buf->mapped); - - if (buf->block) { - if ((buf->block->mem_type != BM_MEM_LOCAL && !bmTestFence(bm, buf->block->fence)) || - (buf->size && buf->size != size) || - (data == NULL)) { - free_block(bm, buf->block); - buf->block = NULL; - } - } - - buf->size = size; - - if (data != NULL) { - bmAllocMem(bm, buf, buf->flags | flags); -#if 0 - memcpy(buf->block->virtual, data, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(bmMapBuffer(bm, buf->id, flags), data, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - -/* Update the buffer in place, in whatever space it is currently resident: - */ -void bmBufferSubData(struct bufmgr *bm, - unsigned buffer, - unsigned offset, - unsigned size, - const void *data ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); - - if (buf->block == 0) - bmAllocMem(bm, buf, buf->flags); - - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (size) { -#if 0 - memcpy(buf->block->virtual + offset, data, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(bmMapBuffer(bm, buf->id, 0) + offset, data, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - - - -/* Extract data from the buffer: - */ -void bmBufferGetSubData(struct bufmgr *bm, - unsigned buffer, - unsigned offset, - unsigned size, - void *data ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); - - if (buf->block == 0) - return; - - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (size) { -#if 0 - memcpy(data, buf->block->virtual + offset, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(data, bmMapBuffer(bm, buf->id, 0) + offset, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - - - - -/* Return a pointer to whatever space the buffer is currently resident in: - */ -void *bmMapBuffer( struct bufmgr *bm, - unsigned buffer, - unsigned flags ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - int ret; - - DBG("bmMapBuffer %d\n", buffer); - DBG("Map: Block is 0x%x\n", &buf->block); - - - if (buf->mapped) - return NULL; - -/* - * Hack to recognize batchbuffers. - */ - - if (buf->block == 0) - bmAllocMem(bm, buf, flags); - - if (buf->block == 0) - return NULL; - - buf->mapped = 1; - - /* Finish any outstanding operations to/from this memory: - */ - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (buf->block->has_ttm > 0) { - ret = drmMap(bm->intel->driFd, buf->block->drm_ttm.handle, - buf->block->drm_ttm.size, &buf->block->virtual); - if (ret) { - fprintf(stderr,"TTM Map failed. Handle is 0x%x, size is %lu\n", - buf->block->drm_ttm.handle, buf->block->drm_ttm.size); - assert(0); - } - } - DBG("Mapped buf %u 0x%x\n", buffer, buf->block->virtual); - return buf->block->virtual; -} - -void bmUnmapBuffer( struct bufmgr *bm, unsigned buffer ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - if (!buf) - return; - - DBG("bmUnmapBuffer %d\n", buffer); - - if (buf->block->has_ttm > 0) { - drmUnmap(buf->block->virtual, buf->size); - DBG("Unmapped buf %u 0x%x\n", buffer, buf->block->virtual); - buf->block->virtual = NULL; - } - - - buf->mapped = 0; -} - - -/* Add a mechanism to tell the manager about some fixed buffers such - * as the (fixed) front, back and depth buffers. Something like this - * may be needed even in a finalized version if we keep the static - * management of these buffers. - * - * These are excluded from the buffer memory management in this file, - * but are presented to the driver by the same interface. In the - * future they may become managed. - */ -#if 0 -void bm_fake_SetFixedBufferParams( struct bufmgr *bm - unsigned buffer, - unsigned offset, - unsigned size ) -{ -} -#endif - - -/* Build the list of buffers to validate: - */ -struct bm_buffer_list *bmNewBufferList( void ) -{ - struct bm_buffer_list *list = calloc(sizeof(*list), 1); - DBG("bmNewBufferList\n"); - return list; -} - -void bmAddBuffer( struct bm_buffer_list *list, - unsigned buffer, - unsigned flags, - unsigned *memtype_return, - unsigned *offset_return ) -{ - assert(list->nr < BM_LIST_MAX); - - - list->elem[list->nr].buffer = buffer; - list->elem[list->nr].memtype_return = memtype_return; - list->elem[list->nr].offset_return = offset_return; - - DBG("bmAddBuffer nr %d buf %d\n", - list->nr, buffer); - - list->nr++; -} - -void bmFreeBufferList( struct bm_buffer_list *list ) -{ - free(list); -} - - - - -/* To be called prior to emitting commands to hardware which reference - * these buffers. The buffer_usage list provides information on where - * the buffers should be placed and whether their contents need to be - * preserved on copying. The offset and pool data elements are return - * values from this function telling the driver exactly where the - * buffers are currently located. - */ -int bmValidateBufferList( struct bufmgr *bm, - struct bm_buffer_list *list, - unsigned flags ) -{ - struct buffer *bufs[BM_LIST_MAX]; - unsigned i; - int count; - - - DBG("%s\n", __FUNCTION__); - - if (list->nr > BM_LIST_MAX) - return 0; - - for (i = 0; i < list->nr; i++) { - bufs[i] = _mesa_HashLookup(bm->hash, list->elem[i].buffer); - } - - /* The old story: evict one texture after another until allocation - * succeeds. This is a pretty poor strategy but really hard to do - * better without more infrastucture... Which is coming - hooray! - */ - - count = 0; - while (!move_buffers(bm, bufs, list->nr, flags)) { - delayed_free(bm); - if (count++ > 10) { - intelWaitIrq( bm->intel, bm->intel->sarea->last_dispatch); - } - } - - for (i = 0; i < list->nr; i++) { - if (bufs[i]->block->has_ttm > 1) { - if (list->elem[i].offset_return) - list->elem[i].offset_return[0] = bufs[i]->block->drm_buf.aper_offset*getpagesize(); - DBG("TTM OFFS 0x%x\n", bufs[i]->block->drm_buf.aper_offset*getpagesize()); - } else { - if (list->elem[i].offset_return) - list->elem[i].offset_return[0] = bufs[i]->block->mem->ofs; - DBG("Pinned Offs 0x%x\n", bufs[i]->block->mem->ofs); - } - if (list->elem[i].memtype_return) - list->elem[i].memtype_return[0] = bufs[i]->block->mem_type; - } - return 1; -} - - -/* After commands are emitted but before unlocking, this must be - * called so that the buffer manager can correctly age the buffers. - * The buffer manager keeps track of the list of validated buffers, so - * already knows what to apply the fence to. - * - * The buffer manager knows how to emit and test fences directly - * through the drm and without callbacks or whatever into the driver. - */ -unsigned bmFenceBufferList( struct bufmgr *bm, struct bm_buffer_list *list ) -{ - - drm_ttm_arg_t arg; - int ret; - -#if 0 - arg.op = ttm_bufs; - arg.do_fence = 1; - arg.num_bufs = 0; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &arg); - assert(ret == 0); -#endif - - DBG("%s (%d bufs)\n", __FUNCTION__, list->nr); - - if (list->nr) { - unsigned i; - unsigned fence = bmSetFence( bm ); - - /* Move all buffers to head of resident list and set their fences - */ - for (i = 0; i < list->nr; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, list->elem[i].buffer); - - if (!buf->block->has_ttm) { - move_to_head(&buf->block->pool->lru, buf->block); - } - buf->block->fence = fence; - } - - return fence; - } - else - return 0; -} - - -/* This functionality is used by the buffer manager, not really sure - * if we need to be exposing it in this way, probably libdrm will - * offer equivalent calls. - * - * For now they can stay, but will likely change/move before final: - */ -unsigned bmSetFence( struct bufmgr *bm ) -{ - /* - * drmEmitFence basically does the same for intel, but userspace - * doesn't know, and calls the kernel to do this. Bypass libdrm. - */ - - return bm->intel->sarea->last_enqueue; -} - -int bmTestFence( struct bufmgr *bm, unsigned fence ) -{ - drmFence dFence = {0, fence}; - int retired; - - assert(!drmTestFence(bm->intel->driFd, dFence, 0, &retired)); - return retired; -} - -void bmFinishFence( struct bufmgr *bm, unsigned fence ) -{ - drmFence dFence = {0, fence}; - assert(!drmWaitFence(bm->intel->driFd, dFence)); -} - -/* There is a need to tell the hardware to flush various caches - * before we can start reading and writing video memory. - * - * TODO: Need a flag value to tell hardware which caches have changed? - * Who would we rely on to populate the flag? - */ - - -/* If new data is uploaded/mapped to video or agp memory, need to - * flush the texture and other read caches to ensure the new version - * is picked up. Can be done immediately after the upload (ie. within - * ValidateBuffers). - */ -void bmFlushReadCaches( struct bufmgr *bm ) -{ -} - -/* If a buffer which has been written to is going to be evicted, read - * by bmGetBufferData or mappped with bmMapBuffer, need to flush the - * write cache first. Probably want to make sure this happens - * immediately after the last write and before the fence (how to - * tell?). If we wait until just prior the evict/read/map, would then - * have to emit another fence and wait for the hw queue to drain to be - * sure the caches had flushed. - * - * A possible strategy: - * - every once in a while, when there is no last_draw_flush_fence outstanding, - * emit a draw-cache flush just prior to the fence. - * - note the fence (last_draw_flush_fence) - * - note the most recently retired value of last_draw_flush_fence in - * last_retired_draw_flush_fence - * - keep track of which fence each buffer is last written to in - * buffer.last_write_fence - * - on evict/read/map, check: - * - if buffer.last_write_fence > last_draw_flush_fence { - * emit_flush - * last_draw_flush_fence = emit fence - * } - * if last_write_fence > last_retired_draw_flush_fence { - * finish_fence(last_draw_flush_fence) - * last_retired_draw_flush_fence = last_draw_fence - * } - * - */ -void bmFlushDrawCache( struct bufmgr *bm ) -{ -} - -/* Specifically ignore texture memory sharing. - */ -void bm_fake_NotifyContendedLockTake( struct bufmgr *bm ) -{ - fprintf(stderr, "did we just lose texture memory? oh well, never mind\n"); -} - - diff --git a/src/mesa/drivers/dri/i915/bufmgr_old.c b/src/mesa/drivers/dri/i915/bufmgr_old.c deleted file mode 100644 index 1f0f910b9f3..00000000000 --- a/src/mesa/drivers/dri/i915/bufmgr_old.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* Fake version of the buffer manager so that we can prototype the - * changes in a driver fairly quickly. Basically wraps the old style - * memory management in the new programming interface. - * - * This version imports code from the via memory manager to closer - * approximate the behaviour of a true memory manager. In particular, - * in this version we do not expect to lose texture memory contents on - * context switches. - */ -#include "bufmgr.h" - -#include "intel_context.h" -#include "intel_ioctl.h" - -#include "hash.h" -#include "simple_list.h" -#include "mm.h" -#include "imports.h" -#include -#include -#include - -static int ttmcount = 0; - -/* - * Define this if the texture TTMs should be cached. If it is not defined, - * Texture downloads will be slow since the TTM pages are not write-combined. - * Backdoor mapping will very probably fix this. (texdown-pool) - */ - -#define NO_TTM - -#undef CACHED_TTMS - -/* - * Batchbuffer memory location: - * 0 Is the global texture pool (as without ttms) - * 1 Is a memory-managed large pinned uncached TTM. Should work as 0, but - * doesn't. The only difference is that the TTM memory is accessed - * directly instead of through the aperture. Runs for a while. - * 2 Is dynamic TTMS. This is what we want. Doesn't work either, but runs - * for a while, depending on application. multiarb works fine for example. - */ - -#define BATCH_LOCATION 1 - -#ifdef NO_TTM -#undef BATCH_LOCATION -#define BATCH_LOCATION 0 -#endif - -#if (BATCH_LOCATION == 2) -#warning Batch buffers using dynamic TTMS. Making TTMS uncached. -#undef CACHED_TTMS -#endif - -struct _mesa_HashTable; - -static int delayed_free( struct bufmgr *bm ); - -#define BM_POOL_MAX 8 - - -/* Wrapper around mm.c's mem_block, which understands that you must - * wait for fences to expire before memory can be freed. This is - * specific to our use of memcpy and/or ttms for uploads - an upload - * that was processed through the command queue wouldn't need to care - * about fences. - */ -struct block { - struct block *next, *prev; - int mem_type; - struct pool *pool; /* BM_MEM_AGP */ - struct mem_block *mem; /* BM_MEM_AGP */ - unsigned fence; /* BM_MEM_AGP, Split to read_fence, write_fence */ - void *virtual; - struct buffer *buf; - drm_ttm_arg_t drm_ttm; - drm_ttm_buf_arg_t drm_buf; - int has_ttm; -}; - - -struct buffer { - unsigned id; /* debug only */ - unsigned size; - unsigned alignment; - unsigned mapped; - unsigned flags; - struct block *block; -}; - -struct pool { - unsigned flags; - struct mem_block *heap; - void *virtual; - struct block lru; - struct block freed; - drm_ttm_arg_t drm_ttm; - drm_ttm_buf_arg_t drm_buf; -}; - -struct bufmgr { - struct intel_context *intel; - struct pool pool[BM_POOL_MAX]; - unsigned nr_pools; - - struct _mesa_HashTable *hash; - - unsigned buf_nr; /* for generating ids */ -}; - - - -static struct block *alloc_from_pool( struct bufmgr *bm, - unsigned pool_nr, - unsigned size, - unsigned align ) -{ - struct pool *pool = &bm->pool[pool_nr]; - struct block *block = (struct block *)calloc(sizeof *block, 1); - if (!block) - return NULL; - - DBG("alloc_from_pool %d sz 0x%x\n", pool_nr, size); - assert(align >= 7); - - block->mem = mmAllocMem(pool->heap, size, align, 0); - if (!block->mem) { - DBG("\t- failed\n"); - free(block); - return NULL; - } - - make_empty_list(block); - block->pool = pool; - block->mem_type = pool->flags & BM_MEM_MASK; - block->virtual = pool->virtual + block->mem->ofs; - block->has_ttm = 0; - - DBG("\t- offset 0x%x\n", block->mem->ofs); - return block; -} - - -static struct block *alloc_local( unsigned size ) -{ - struct block *block = (struct block *)calloc(sizeof *block, 1); - if (!block) - return NULL; - - DBG("alloc_local 0x%x\n", size); - - block->mem_type = BM_MEM_LOCAL; - block->virtual = ALIGN_MALLOC(size, 1<<7); - if (!block->virtual) { - free(block); - return NULL; - } - - return block; -} - - - - -static struct block *alloc_block( struct bufmgr *bm, - unsigned size, - unsigned align, - int flags ) -{ - GLuint i; - int ret; - struct block *block; - unsigned alignment = ( 1 << align ); - -#ifdef NO_TTM - flags |= BM_NO_TTM; -#endif - - if (!(flags & BM_NO_TTM) -#if (BATCH_LOCATION != 2) -#warning Disabling dynamic batch buffers - && !(flags & BM_CLIENT) -#endif - ) { - - block = (struct block *)calloc(sizeof *block, 1); - if (!block) return NULL; - - make_empty_list(block); - block->pool = bm->pool + 0; - block->mem_type = flags; - block->has_ttm = 0; - - block->drm_ttm.op = ttm_add; - block->drm_ttm.size = ((size + alignment -1) >> align) << align; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - assert(ret == 0); - block->drm_buf.ttm_handle = block->drm_ttm.handle; - block->drm_buf.ttm_page_offset = 0; - block->drm_buf.num_pages = block->drm_ttm.size / getpagesize(); - block->drm_buf.next = NULL; - -#ifdef CACHED_TTMS - block->drm_buf.flags = DRM_TTM_FLAG_NEW | DRM_TTM_FLAG_CACHED; -#else - block->drm_buf.flags = DRM_TTM_FLAG_NEW; -#endif - block->has_ttm = 2; - if (block->has_ttm > 1) - block->virtual = NULL; - ttmcount += block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - DBG("ttm handle is 0x%x\n", block->drm_ttm.handle); - - return block; - } - - if (!(flags & (BM_CLIENT))) { - for (i = 0; i < bm->nr_pools; i++) { - struct block *block; - - if (bm->pool[i].flags & BM_NO_ALLOC) - continue; - - if ((bm->pool[i].flags & flags & BM_MEM_MASK) == 0) - continue; - - block = alloc_from_pool(bm, i, size, align); - if (block) return block; - } - } - - - if (flags & BM_MEM_LOCAL) - return alloc_local(size); - - return NULL; -} - -static int bmAllocMem( struct bufmgr *bm, - struct buffer *buf, - GLuint flags ) -{ - delayed_free(bm); - - buf->block = alloc_block(bm, - buf->size, - buf->alignment, - buf->flags | flags); - - if (buf->block) - buf->block->buf = buf; - else - _mesa_printf("bmAllocMem failed memflags %x\n", buf->flags & BM_MEM_MASK); - - /* Sleep here or fail??? - */ -/* assert(buf->block); */ - return buf->block != NULL; -} - - -/* Release the card storage associated with buf: - */ -static void free_block( struct bufmgr *bm, struct block *block ) -{ - int ret; - - if (!block) - return; - - DBG("free block (mem: %d, sz %d) from buf %d\n", - block->mem_type, - block->buf->size, - block->buf->id); - - switch (block->mem_type) { - case BM_MEM_AGP: - case BM_MEM_VRAM: - remove_from_list(block); - - if (!block->has_ttm) - DBG(" - offset %x\n", block->mem->ofs); - else - DBG(" - offset %x\n", block->drm_buf.aper_offset*getpagesize()); - - if (bmTestFence(bm, block->fence)) { - if (!block->has_ttm) { - mmFreeMem(block->mem); - } else { - block->drm_ttm.op = ttm_remove; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - ttmcount -= block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - assert(ret == 0); - } - free(block); - } - else { - DBG(" - place on delayed_free list\n"); - block->buf = NULL; - insert_at_tail(&block->pool->freed, block); - } - break; - - case BM_MEM_LOCAL: - DBG(" - free local memory\n"); - ALIGN_FREE(block->virtual); - free(block); - break; - - default: - DBG(" - unknown memory type\n"); - free(block); - break; - } -} - -static int delayed_free( struct bufmgr *bm ) -{ - struct block *block, *tmp; - int ret = 0; - int rettm; - int i; - - for (i = 0; i < bm->nr_pools; i++) { - foreach_s(block, tmp, &bm->pool[i].freed ) { - if (bmTestFence(bm, block->fence)) { - remove_from_list(block); - if (!block->has_ttm) { - mmFreeMem(block->mem); - ret += block->mem->size; - } else { - block->drm_ttm.op = ttm_remove; - rettm = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &block->drm_ttm); - ttmcount -= block->drm_buf.num_pages; - DBG("ttmcount pages is %d\n", ttmcount); - assert(rettm == 0); - ret += block->drm_buf.num_pages*getpagesize(); - } - free(block); - } - } - } - - DBG("%s: %d\n", __FUNCTION__, ret); - return ret; -} - - -static int move_buffers( struct bufmgr *bm, - struct buffer *buffers[], - int nr, - int flags ) -{ - struct block *newMem[BM_LIST_MAX]; - GLint i; - GLuint nr_uploads = 0; - drm_ttm_arg_t arg; - struct block *block, *last_block; - int ret; - drm_ttm_buf_arg_t *cur; - int size; - - DBG("%s\n", __FUNCTION__); - - memset(newMem, 0, sizeof(newMem)); - - /* First do all the allocations (or fail): - */ - for (i = 0; i < nr; i++) { - if (!buffers[i]->block) { - - if (flags & BM_NO_ALLOC) - goto cleanup; - - newMem[i] = alloc_block(bm, - buffers[i]->size, - buffers[i]->alignment, - flags & BM_MEM_MASK); - - if (!newMem[i]) - goto cleanup; - - } - } - - /* - * Tell kernel where TTMS should be. - */ - - arg.num_bufs = 0; - last_block = NULL; - size = 0; - - for (i = 0; i has_ttm) { - buffers[i]->block = newMem[i]; - newMem[i] = NULL; - } - block = buffers[i]->block; - if (block->has_ttm) { - if ((flags & BM_MEM_MASK) == BM_MEM_AGP || - (((flags & BM_MEM_MASK) == BM_MEM_LOCAL) && - (block->mem_type == BM_MEM_AGP))) { - if (arg.num_bufs == 0) - arg.first = &block->drm_buf; - else - last_block->drm_buf.next = &block->drm_buf; - size += block->drm_buf.num_pages; - arg.num_bufs++; - last_block = block; - block->drm_buf.op = ((flags & BM_MEM_MASK) == BM_MEM_AGP) ? - ttm_validate : ttm_unbind; - block->mem_type = flags & BM_MEM_MASK; - } - } - } - arg.op = ttm_bufs; - arg.do_fence = 0; - DBG("Num validated TTM bufs is %d pages %d\n", arg.num_bufs, size); - if (arg.num_bufs) { - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &arg); - assert(ret==0); - cur = arg.first; - for(i=0; i< arg.num_bufs; ++i) { - if (cur->ret) { - fprintf(stderr,"Kernel Error. Check dmesg.\n"); - fflush(stderr); - assert(0); - } - cur = cur->next; - } - } - - /* - * End TTM code. - */ - - - for (i=0; i< nr; ++i) { - if (!(buffers[i]->block->mem_type & flags)) { - if (flags & BM_NO_UPLOAD) - goto cleanup; - - /* Known issue: this assert will get hit on texture swapping. - * There's not much to do about that at this stage - it's a - * todo item. - */ - assert(!buffers[i]->mapped); - - DBG("try to move buffer %d size 0x%x to pools 0x%x\n", - buffers[i]->id, buffers[i]->size, flags & BM_MEM_MASK); - - newMem[i] = alloc_block(bm, - buffers[i]->size, - buffers[i]->alignment, - (flags & BM_MEM_MASK) | BM_NO_TTM); - - if (!newMem[i]) - goto cleanup; - - } - } - - - /* Now copy all the image data and free the old texture memory. - */ - for (i = 0; i < nr; i++) { - if (newMem[i]) { - if (buffers[i]->block) { - /* XXX: To be replaced with DMA, GTT bind, and other - * mechanisms in final version. Memcpy (or sse_memcpy) is - * probably pretty good for local->agp uploads. - */ - DBG("memcpy %d bytes\n", buffers[i]->size); - memcpy(newMem[i]->virtual, - buffers[i]->block->virtual, - buffers[i]->size); - - free_block(bm, buffers[i]->block); - nr_uploads++; - } - - buffers[i]->block = newMem[i]; - buffers[i]->block->buf = buffers[i]; - } - } - - /* Tell hardware that its texture and other caches may be invalid: - */ - if (nr_uploads && (flags & (BM_MEM_AGP|BM_MEM_VRAM))) - bmFlushReadCaches(bm); - - DBG("%s - success\n", __FUNCTION__); - return 1; - - cleanup: - /* Release any allocations made prior to failure: - */ - for (i = 0; i < nr; i++) { - if (newMem[i]) - free_block(bm, newMem[i]); - } - - DBG("%s - fail\n", __FUNCTION__); - return 0; -} - - -static unsigned evict_lru( struct bufmgr *bm, - unsigned flags) -{ - int i; - - DBG("%s\n", __FUNCTION__); - - if (flags & BM_NO_EVICT) - return 0; - - /* XXX: this is broken with >1 active pool - all the first pool - * will be evicted before starting on the second. Actually, maybe - * you want that in some situations... - */ - for (i = 0; i < bm->nr_pools; i++) { - if ((bm->pool[i].flags & flags & BM_MEM_MASK) && - !(bm->pool[i].flags & BM_NO_EVICT)) { - struct block *block = bm->pool[i].lru.next; - unsigned size = block->buf->size; - - if (block == &bm->pool[i].lru || - !bmTestFence(bm, block->fence)) - return 0; - - move_buffers(bm, &block->buf, 1, BM_MEM_LOCAL); - return size; - } - } - - return 0; -} - -#if 0 -/* Speculatively move texture images which haven't been used in a - * while back to local memory. - */ -static void viaSwapOutWork( struct bufmgr *bm ) -{ - unsigned total = 0; - unsigned target; - - if (bm->thrashing) { - target = 6*1024*1024; - } - else if (bmIsTexMemLow(bm)) { - target = 64*1024; - } - else { - return; - } - - while (1) { - unsigned size = evict_lru(bm); - if (!size) - return; - - total += size; - if (total >= target) - return; - } -} -#endif - - - - - - - - - - - - -/*********************************************************************** - * Public functions - */ - - -/* The initialization functions are skewed in the fake implementation. - * This call would be to attach to an existing manager, rather than to - * create a local one. - */ -struct bufmgr *bm_fake_intel_Attach( struct intel_context *intel ) -{ - struct bufmgr *bm = (struct bufmgr *)calloc(sizeof(*bm), 1); - - bm->intel = intel; - bm->hash = _mesa_NewHashTable(); - - return bm; -} - - -void bmInitMemType( struct bufmgr *bm, - unsigned mem_type, - unsigned long size ) -{ - /* Nothing really to do. Could store and use to validate - * bmInitPool requests. - */ -} - - -/* The virtual pointer would go away in a true implementation. - */ -int bmInitPool( struct bufmgr *bm, - unsigned long low_offset, - void *low_virtual, - unsigned long size, - unsigned flags) -{ - GLuint i; - struct pool *pool; - - if (bm->nr_pools >= BM_POOL_MAX) - return -1; - - i = bm->nr_pools++; - - DBG("bmInitPool %d low_offset %x sz %x\n", - i, low_offset, size); - - pool = bm->pool + i; - pool->flags = flags; - - make_empty_list(&bm->pool[i].lru); - make_empty_list(&bm->pool[i].freed); - - if (flags == BM_MEM_AGP) { -#if (BATCH_LOCATION == 1) -#warning Replacing pool 0 with a large uncached pinned TTM. - int ret; - drmAddress ttmAddress; - - size = 1024*1024; - DBG("Creating Pinned ttm, size %d\n", size); - pool->drm_ttm.op = ttm_add; - pool->drm_ttm.size = size; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - if (ret) return -1; - ret = drmMap(bm->intel->driFd, pool->drm_ttm.handle, size, &ttmAddress); - DBG("Virtual is 0x%lx\n", (unsigned long) ttmAddress); - if (ret) { - pool->drm_ttm.op = ttm_add; - ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - return -1; - } - pool->drm_buf.ttm_handle = pool->drm_ttm.handle; - pool->drm_buf.ttm_page_offset = 0; - pool->drm_buf.num_pages = pool->drm_ttm.size / getpagesize(); - pool->drm_buf.next = NULL; - pool->drm_buf.flags = DRM_TTM_FLAG_NEW | DRM_TTM_FLAG_PINNED; - pool->drm_buf.op = ttm_validate; - pool->drm_ttm.op = ttm_bufs; - pool->drm_ttm.num_bufs = 1; - pool->drm_ttm.first = &pool->drm_buf; - drmGetLock(bm->intel->driFd, bm->intel->hHWContext, 0); - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &pool->drm_ttm); - drmUnlock(bm->intel->driFd, bm->intel->hHWContext); - low_offset = pool->drm_buf.aper_offset * getpagesize(); - pool->heap = mmInit( low_offset , size ); - pool->virtual = (char *) ttmAddress - low_offset; - DBG("Pinned buf offset is 0x%lx\n", low_offset); -#else - pool->heap = mmInit( low_offset , size ); - pool->virtual = low_virtual - low_offset; -#endif - } else { - pool->heap = mmInit( low_offset, size ); - pool->virtual = low_virtual - low_offset; - } - return i; -} - -#if 0 -void bmAssertTTM(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, buffers[i]); - DBG("0x%x\n", buf->flags); - assert(buf->block); - assert(buf->block->has_ttm); - } -} -#endif - -void bmGenBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = calloc(sizeof(*buf), 1); - buf->id = ++bm->buf_nr; - buf->alignment = 12; /* page-alignment to fit in with AGP swapping */ - buf->flags = BM_MEM_AGP|BM_MEM_VRAM|BM_MEM_LOCAL; - buffers[i] = buf->id; - _mesa_HashInsert(bm->hash, buffers[i], buf); - } -} - - -void bmDeleteBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers) -{ - unsigned i; - - for (i = 0; i < n; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, buffers[i]); - if (buf) { - free_block(bm, buf->block); - free(buf); - _mesa_HashRemove(bm->hash, buffers[i]); - } - assert(_mesa_HashLookup(bm->hash, buffers[i]) == NULL); - } -} - - - - -/* Hook to inform faked buffer manager about fixed-position - * front,depth,back buffers. These may move to a fully memory-managed - * scheme, or they may continue to be managed as is. It will probably - * be useful to pass a fixed offset here one day. - */ -unsigned bmBufferStatic(struct bufmgr *bm, - unsigned buffer, - unsigned size, - unsigned pool ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - assert(!buf->block); - assert(bm->pool[pool].flags & BM_NO_EVICT); - assert(bm->pool[pool].flags & BM_NO_MOVE); - - buf->size = size; - buf->flags = bm->pool[pool].flags; - buf->alignment = 12; - buf->block = alloc_from_pool(bm, pool, buf->size, buf->alignment); - if (!buf->block) - return 0; - - buf->block->buf = buf; - return buf->block->mem->ofs; -} - - - -/* If buffer size changes, free and reallocate. Otherwise update in - * place. - */ -void bmBufferData(struct bufmgr *bm, - unsigned buffer, - unsigned size, - const void *data, - unsigned flags ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferData %d sz 0x%x data: %p\n", buffer, size, data); - - assert(!buf->mapped); - - if (buf->block) { - if ((buf->block->mem_type != BM_MEM_LOCAL && !bmTestFence(bm, buf->block->fence)) || - (buf->size && buf->size != size) || - (data == NULL)) { - free_block(bm, buf->block); - buf->block = NULL; - } - } - - buf->size = size; - - if (data != NULL) { - bmAllocMem(bm, buf, buf->flags | flags); -#if 0 - memcpy(buf->block->virtual, data, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(bmMapBuffer(bm, buf->id, flags), data, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - -/* Update the buffer in place, in whatever space it is currently resident: - */ -void bmBufferSubData(struct bufmgr *bm, - unsigned buffer, - unsigned offset, - unsigned size, - const void *data ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); - - if (buf->block == 0) - bmAllocMem(bm, buf, buf->flags); - - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (size) { -#if 0 - memcpy(buf->block->virtual + offset, data, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(bmMapBuffer(bm, buf->id, 0) + offset, data, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - - - -/* Extract data from the buffer: - */ -void bmBufferGetSubData(struct bufmgr *bm, - unsigned buffer, - unsigned offset, - unsigned size, - void *data ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - - DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); - - if (buf->block == 0) - return; - - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (size) { -#if 0 - memcpy(data, buf->block->virtual + offset, size); -#else - /* Do an implicit map/unmap to get this working for now: - */ - memcpy(data, bmMapBuffer(bm, buf->id, 0) + offset, size); - bmUnmapBuffer(bm, buf->id); -#endif - } -} - - - - -/* Return a pointer to whatever space the buffer is currently resident in: - */ -void *bmMapBuffer( struct bufmgr *bm, - unsigned buffer, - unsigned flags ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - int ret; - - DBG("bmMapBuffer %d\n", buffer); - DBG("Map: Block is 0x%x\n", &buf->block); - - - if (buf->mapped) - return NULL; - -/* - * Hack to recognize batchbuffers. - */ - - if (buf->block == 0) - bmAllocMem(bm, buf, flags); - - if (buf->block == 0) - return NULL; - - buf->mapped = 1; - - /* Finish any outstanding operations to/from this memory: - */ - if (buf->block->mem_type != BM_MEM_LOCAL) - bmFinishFence(bm, buf->block->fence); - - if (buf->block->has_ttm > 0) { - ret = drmMap(bm->intel->driFd, buf->block->drm_ttm.handle, - buf->block->drm_ttm.size, &buf->block->virtual); - if (ret) { - fprintf(stderr,"TTM Map failed. Handle is 0x%x, size is %lu\n", - buf->block->drm_ttm.handle, buf->block->drm_ttm.size); - assert(0); - } - } - DBG("Mapped buf %u 0x%x\n", buffer, buf->block->virtual); - return buf->block->virtual; -} - -void bmUnmapBuffer( struct bufmgr *bm, unsigned buffer ) -{ - struct buffer *buf = (struct buffer *)_mesa_HashLookup( bm->hash, buffer ); - if (!buf) - return; - - DBG("bmUnmapBuffer %d\n", buffer); - - if (buf->block->has_ttm > 0) { - drmUnmap(buf->block->virtual, buf->size); - DBG("Unmapped buf %u 0x%x\n", buffer, buf->block->virtual); - buf->block->virtual = NULL; - } - - - buf->mapped = 0; -} - - -/* Add a mechanism to tell the manager about some fixed buffers such - * as the (fixed) front, back and depth buffers. Something like this - * may be needed even in a finalized version if we keep the static - * management of these buffers. - * - * These are excluded from the buffer memory management in this file, - * but are presented to the driver by the same interface. In the - * future they may become managed. - */ -#if 0 -void bm_fake_SetFixedBufferParams( struct bufmgr *bm - unsigned buffer, - unsigned offset, - unsigned size ) -{ -} -#endif - - -/* Build the list of buffers to validate: - */ -struct bm_buffer_list *bmNewBufferList( void ) -{ - struct bm_buffer_list *list = calloc(sizeof(*list), 1); - DBG("bmNewBufferList\n"); - return list; -} - -void bmAddBuffer( struct bm_buffer_list *list, - unsigned buffer, - unsigned flags, - unsigned *memtype_return, - unsigned *offset_return ) -{ - assert(list->nr < BM_LIST_MAX); - - - list->elem[list->nr].buffer = buffer; - list->elem[list->nr].memtype_return = memtype_return; - list->elem[list->nr].offset_return = offset_return; - - DBG("bmAddBuffer nr %d buf %d\n", - list->nr, buffer); - - list->nr++; -} - -void bmFreeBufferList( struct bm_buffer_list *list ) -{ - free(list); -} - - - - -/* To be called prior to emitting commands to hardware which reference - * these buffers. The buffer_usage list provides information on where - * the buffers should be placed and whether their contents need to be - * preserved on copying. The offset and pool data elements are return - * values from this function telling the driver exactly where the - * buffers are currently located. - */ -int bmValidateBufferList( struct bufmgr *bm, - struct bm_buffer_list *list, - unsigned flags ) -{ - struct buffer *bufs[BM_LIST_MAX]; - unsigned i; - int count; - - - DBG("%s\n", __FUNCTION__); - - if (list->nr > BM_LIST_MAX) - return 0; - - for (i = 0; i < list->nr; i++) { - bufs[i] = _mesa_HashLookup(bm->hash, list->elem[i].buffer); - } - - /* The old story: evict one texture after another until allocation - * succeeds. This is a pretty poor strategy but really hard to do - * better without more infrastucture... Which is coming - hooray! - */ - - count = 0; - while (!move_buffers(bm, bufs, list->nr, flags)) { - delayed_free(bm); - if (count++ > 10) { - intelWaitIrq( bm->intel, bm->intel->sarea->last_dispatch); - } - } - - for (i = 0; i < list->nr; i++) { - if (bufs[i]->block->has_ttm > 1) { - if (list->elem[i].offset_return) - list->elem[i].offset_return[0] = bufs[i]->block->drm_buf.aper_offset*getpagesize(); - DBG("TTM OFFS 0x%x\n", bufs[i]->block->drm_buf.aper_offset*getpagesize()); - } else { - if (list->elem[i].offset_return) - list->elem[i].offset_return[0] = bufs[i]->block->mem->ofs; - DBG("Pinned Offs 0x%x\n", bufs[i]->block->mem->ofs); - } - if (list->elem[i].memtype_return) - list->elem[i].memtype_return[0] = bufs[i]->block->mem_type; - } - return 1; -} - - -/* After commands are emitted but before unlocking, this must be - * called so that the buffer manager can correctly age the buffers. - * The buffer manager keeps track of the list of validated buffers, so - * already knows what to apply the fence to. - * - * The buffer manager knows how to emit and test fences directly - * through the drm and without callbacks or whatever into the driver. - */ -unsigned bmFenceBufferList( struct bufmgr *bm, struct bm_buffer_list *list ) -{ - - drm_ttm_arg_t arg; - int ret; - - arg.op = ttm_bufs; - arg.do_fence = 1; - arg.num_bufs = 0; - ret = ioctl(bm->intel->driFd, DRM_IOCTL_TTM, &arg); - assert(ret == 0); - - DBG("%s (%d bufs)\n", __FUNCTION__, list->nr); - - if (list->nr) { - unsigned i; - unsigned fence = bmSetFence( bm ); - - /* Move all buffers to head of resident list and set their fences - */ - for (i = 0; i < list->nr; i++) { - struct buffer *buf = _mesa_HashLookup(bm->hash, list->elem[i].buffer); - - if (!buf->block->has_ttm) { - move_to_head(&buf->block->pool->lru, buf->block); - } - buf->block->fence = fence; - } - - return fence; - } - else - return 0; -} - - -/* This functionality is used by the buffer manager, not really sure - * if we need to be exposing it in this way, probably libdrm will - * offer equivalent calls. - * - * For now they can stay, but will likely change/move before final: - */ -unsigned bmSetFence( struct bufmgr *bm ) -{ - assert(bm->intel->locked); - - return intelEmitIrqLocked( bm->intel ); -} - -int bmTestFence( struct bufmgr *bm, unsigned fence ) -{ -/* if (fence % 1024 == 0) */ -/* _mesa_printf("%d %d\n", fence, bm->intel->sarea->last_dispatch); */ - - DBG("fence: %d %d\n", fence, bm->intel->sarea->last_dispatch); - return fence <= bm->intel->sarea->last_dispatch; -} - -void bmFinishFence( struct bufmgr *bm, unsigned fence ) -{ - if (!bmTestFence(bm, fence)) - intelWaitIrq( bm->intel, fence ); -} - - -/* There is a need to tell the hardware to flush various caches - * before we can start reading and writing video memory. - * - * TODO: Need a flag value to tell hardware which caches have changed? - * Who would we rely on to populate the flag? - */ - - -/* If new data is uploaded/mapped to video or agp memory, need to - * flush the texture and other read caches to ensure the new version - * is picked up. Can be done immediately after the upload (ie. within - * ValidateBuffers). - */ -void bmFlushReadCaches( struct bufmgr *bm ) -{ -} - -/* If a buffer which has been written to is going to be evicted, read - * by bmGetBufferData or mappped with bmMapBuffer, need to flush the - * write cache first. Probably want to make sure this happens - * immediately after the last write and before the fence (how to - * tell?). If we wait until just prior the evict/read/map, would then - * have to emit another fence and wait for the hw queue to drain to be - * sure the caches had flushed. - * - * A possible strategy: - * - every once in a while, when there is no last_draw_flush_fence outstanding, - * emit a draw-cache flush just prior to the fence. - * - note the fence (last_draw_flush_fence) - * - note the most recently retired value of last_draw_flush_fence in - * last_retired_draw_flush_fence - * - keep track of which fence each buffer is last written to in - * buffer.last_write_fence - * - on evict/read/map, check: - * - if buffer.last_write_fence > last_draw_flush_fence { - * emit_flush - * last_draw_flush_fence = emit fence - * } - * if last_write_fence > last_retired_draw_flush_fence { - * finish_fence(last_draw_flush_fence) - * last_retired_draw_flush_fence = last_draw_fence - * } - * - */ -void bmFlushDrawCache( struct bufmgr *bm ) -{ -} - -/* Specifically ignore texture memory sharing. - */ -void bm_fake_NotifyContendedLockTake( struct bufmgr *bm ) -{ - fprintf(stderr, "did we just lose texture memory? oh well, never mind\n"); -} - - diff --git a/src/mesa/drivers/dri/i915/i830_vtbl.c b/src/mesa/drivers/dri/i915/i830_vtbl.c index e2f7e6ba4b2..65be9d790c3 100644 --- a/src/mesa/drivers/dri/i915/i830_vtbl.c +++ b/src/mesa/drivers/dri/i915/i830_vtbl.c @@ -384,11 +384,11 @@ static void i830_emit_state( struct intel_context *intel ) BEGIN_BATCH(I830_DEST_SETUP_SIZE+2, 0); OUT_BATCH(state->Buffer[I830_DESTREG_CBUFADDR0]); OUT_BATCH(state->Buffer[I830_DESTREG_CBUFADDR1]); - OUT_RELOC(state->draw_region->buffer, BM_MEM_AGP|BM_WRITE, 0); + OUT_RELOC(state->draw_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0); OUT_BATCH(state->Buffer[I830_DESTREG_DBUFADDR0]); OUT_BATCH(state->Buffer[I830_DESTREG_DBUFADDR1]); - OUT_RELOC(state->depth_region->buffer, BM_MEM_AGP|BM_WRITE, 0); + OUT_RELOC(state->depth_region->buffer, DRM_MM_TT |DRM_MM_WRITE, 0); OUT_BATCH(state->Buffer[I830_DESTREG_DV0]); OUT_BATCH(state->Buffer[I830_DESTREG_DV1]); @@ -415,7 +415,7 @@ static void i830_emit_state( struct intel_context *intel ) if (state->tex_buffer[i]) { OUT_RELOC(state->tex_buffer[i], - BM_MEM_AGP|BM_READ, + DRM_MM_TT|DRM_MM_READ, state->tex_offset[i] | TM0S0_USE_FENCE); } else { diff --git a/src/mesa/drivers/dri/i915/i915_context.c b/src/mesa/drivers/dri/i915/i915_context.c index 0fe88794df6..5d389533b02 100644 --- a/src/mesa/drivers/dri/i915/i915_context.c +++ b/src/mesa/drivers/dri/i915/i915_context.c @@ -41,7 +41,7 @@ #include "utils.h" #include "i915_reg.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" #include "intel_regions.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i915/i915_vtbl.c b/src/mesa/drivers/dri/i915/i915_vtbl.c index e3e6d06ab29..fb39e03fcd7 100644 --- a/src/mesa/drivers/dri/i915/i915_vtbl.c +++ b/src/mesa/drivers/dri/i915/i915_vtbl.c @@ -248,11 +248,11 @@ static void i915_emit_state( struct intel_context *intel ) BEGIN_BATCH(I915_DEST_SETUP_SIZE+2, 0); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR1]); - OUT_RELOC(state->draw_region->buffer, BM_MEM_AGP|BM_WRITE, 0); + OUT_RELOC(state->draw_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0); OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR1]); - OUT_RELOC(state->depth_region->buffer, BM_MEM_AGP|BM_WRITE, 0); + OUT_RELOC(state->depth_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0); OUT_BATCH(state->Buffer[I915_DESTREG_DV0]); OUT_BATCH(state->Buffer[I915_DESTREG_DV1]); @@ -291,7 +291,7 @@ static void i915_emit_state( struct intel_context *intel ) if (state->tex_buffer[i]) { OUT_RELOC(state->tex_buffer[i], - BM_MEM_AGP|BM_READ, + DRM_MM_TT|DRM_MM_READ, state->tex_offset[i]); } else { diff --git a/src/mesa/drivers/dri/i915/intel_batchbuffer.c b/src/mesa/drivers/dri/i915/intel_batchbuffer.c index 09f7edfdf75..c546d84e7b6 100644 --- a/src/mesa/drivers/dri/i915/intel_batchbuffer.c +++ b/src/mesa/drivers/dri/i915/intel_batchbuffer.c @@ -27,7 +27,7 @@ #include "intel_batchbuffer.h" #include "intel_ioctl.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /* Relocations in kernel space: * - pass dma buffer seperately @@ -91,18 +91,19 @@ static void intel_batchbuffer_reset( struct intel_batchbuffer *batch ) if (!batch->list) batch->list = bmNewBufferList(); - batch->list->nr = 0; + drmMMClearBufList(batch->list); + batch->list_count = 0; batch->nr_relocs = 0; batch->flags = 0; - bmAddBuffer( batch->list, + bmAddBuffer( batch->bm, + batch->list, batch->buffer, - 0, + DRM_MM_TT, NULL, - &batch->offset[batch->list->nr]); + &batch->offset[batch->list_count++]); - batch->map = bmMapBuffer(batch->bm, batch->buffer, - BM_MEM_AGP|BM_MEM_LOCAL|BM_CLIENT|BM_WRITE); + batch->map = bmMapBuffer(batch->bm, batch->buffer, DRM_MM_WRITE); batch->ptr = batch->map; } @@ -116,7 +117,7 @@ struct intel_batchbuffer *intel_batchbuffer_alloc( struct intel_context *intel ) batch->intel = intel; batch->bm = intel->bm; - bmGenBuffers(intel->bm, 1, &batch->buffer); + bmGenBuffers(intel->bm, 1, &batch->buffer, BM_BATCHBUFFER); intel_batchbuffer_reset( batch ); return batch; } @@ -140,43 +141,36 @@ static void do_flush_locked( struct intel_batchbuffer *batch, bmValidateBufferList( batch->bm, batch->list, - BM_MEM_AGP ); + DRM_MM_TT ); /* Apply the relocations. This nasty map indicates to me that the * whole task should be done internally by the memory manager, and * that dma buffers probably need to be pinned within agp space. */ - ptr = (GLuint *)bmMapBuffer(batch->bm, batch->buffer, - BM_NO_MOVE|BM_NO_UPLOAD| - BM_NO_EVICT|BM_MEM_AGP| - BM_WRITE); + ptr = (GLuint *)bmMapBuffer(batch->bm, batch->buffer, DRM_MM_WRITE); + for (i = 0; i < batch->nr_relocs; i++) { struct buffer_reloc *r = &batch->reloc[i]; - - assert(r->elem < batch->list->nr); - - DBG("apply fixup at offset 0x%x, elem %d (buf %d, offset 0x%x), delta 0x%x\n", - r->offset, r->elem, batch->list->elem[r->elem].buffer, - batch->offset[r->elem], r->delta); - + + assert(r->elem < batch->list_count); ptr[r->offset/4] = batch->offset[r->elem] + r->delta; } if (INTEL_DEBUG & DEBUG_DMA) intel_dump_batchbuffer( 0, ptr, used ); - - bmUnmapBuffer(batch->bm, batch->buffer); /* Fire the batch buffer, which was uploaded above: */ + +#if 1 intel_batch_ioctl(batch->intel, batch->offset[0], used, ignore_cliprects); - +#endif batch->last_fence = bmFenceBufferList(batch->bm, batch->list); } @@ -248,19 +242,15 @@ GLboolean intel_batchbuffer_emit_reloc( struct intel_batchbuffer *batch, assert(batch->nr_relocs <= MAX_RELOCS); - for (i = 0; i < batch->list->nr; i++) - if (buffer == batch->list->elem[i].buffer) - break; - - if (i == batch->list->nr) { - if (i == BM_LIST_MAX) - return GL_FALSE; - - bmAddBuffer(batch->list, + i = bmScanBufferList(batch->bm, batch->list, buffer); + if (i == -1) { + i = batch->list_count; + bmAddBuffer(batch->bm, + batch->list, buffer, flags, NULL, - &batch->offset[i]); + &batch->offset[batch->list_count++]); } { diff --git a/src/mesa/drivers/dri/i915/intel_batchbuffer.h b/src/mesa/drivers/dri/i915/intel_batchbuffer.h index 8ac3fadc551..a635645b1b2 100644 --- a/src/mesa/drivers/dri/i915/intel_batchbuffer.h +++ b/src/mesa/drivers/dri/i915/intel_batchbuffer.h @@ -2,7 +2,7 @@ #define INTEL_BATCHBUFFER_H #include "mtypes.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" struct intel_context; @@ -30,8 +30,9 @@ struct intel_batchbuffer { /* In progress: */ - GLuint offset[BM_LIST_MAX]; - struct bm_buffer_list *list; + unsigned long offset[MAX_RELOCS]; + struct _drmMMBufList *list; + GLuint list_count; GLubyte *map; GLubyte *ptr; diff --git a/src/mesa/drivers/dri/i915/intel_blit.c b/src/mesa/drivers/dri/i915/intel_blit.c index 43b52ccd2b2..36adc2105df 100644 --- a/src/mesa/drivers/dri/i915/intel_blit.c +++ b/src/mesa/drivers/dri/i915/intel_blit.c @@ -39,7 +39,7 @@ #include "intel_blit.h" #include "intel_regions.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" @@ -58,8 +58,6 @@ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv ) assert(dPriv->driContextPriv->driverPrivate); intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate; - intelFlush( &intel->ctx ); - bmFinishFence(intel->bm, intel->last_swap_fence); @@ -106,17 +104,17 @@ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv ) OUT_BATCH( (pbox->y2 << 16) | pbox->x2 ); if (intel->sarea->pf_current_page == 0) - OUT_RELOC( intel->front_region->buffer, BM_MEM_AGP|BM_WRITE, 0 ); + OUT_RELOC( intel->front_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); else - OUT_RELOC( intel->back_region->buffer, BM_MEM_AGP|BM_WRITE, 0 ); + OUT_RELOC( intel->back_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); OUT_BATCH( (pbox->y1 << 16) | pbox->x1 ); OUT_BATCH( BR13 & 0xffff ); if (intel->sarea->pf_current_page == 0) - OUT_RELOC( intel->back_region->buffer, BM_MEM_AGP|BM_READ, 0 ); + OUT_RELOC( intel->back_region->buffer, DRM_MM_TT|DRM_MM_READ, 0 ); else - OUT_RELOC( intel->front_region->buffer, BM_MEM_AGP|BM_READ, 0 ); + OUT_RELOC( intel->front_region->buffer, DRM_MM_TT|DRM_MM_READ, 0 ); ADVANCE_BATCH(); } @@ -164,7 +162,7 @@ void intelEmitFillBlit( struct intel_context *intel, OUT_BATCH( BR13 ); OUT_BATCH( (y << 16) | x ); OUT_BATCH( ((y+h) << 16) | (x+w) ); - OUT_RELOC( dst_buffer, BM_MEM_AGP|BM_WRITE, dst_offset ); + OUT_RELOC( dst_buffer, DRM_MM_TT|DRM_MM_WRITE, dst_offset ); OUT_BATCH( color ); ADVANCE_BATCH(); } @@ -234,10 +232,10 @@ void intelEmitCopyBlit( struct intel_context *intel, OUT_BATCH( BR13 ); OUT_BATCH( (dst_y << 16) | dst_x ); OUT_BATCH( (dst_y2 << 16) | dst_x2 ); - OUT_RELOC( dst_buffer, BM_MEM_AGP|BM_WRITE, dst_offset ); + OUT_RELOC( dst_buffer, DRM_MM_TT|DRM_MM_WRITE, dst_offset ); OUT_BATCH( (src_y << 16) | src_x ); OUT_BATCH( ((GLint)src_pitch&0xffff) ); - OUT_RELOC( src_buffer, BM_MEM_AGP|BM_READ, src_offset ); + OUT_RELOC( src_buffer, DRM_MM_TT|DRM_MM_READ, src_offset ); ADVANCE_BATCH(); } else { @@ -246,10 +244,10 @@ void intelEmitCopyBlit( struct intel_context *intel, OUT_BATCH( BR13 ); OUT_BATCH( (0 << 16) | dst_x ); OUT_BATCH( (h << 16) | dst_x2 ); - OUT_RELOC( dst_buffer, BM_MEM_AGP|BM_WRITE, dst_offset + dst_y * dst_pitch ); + OUT_RELOC( dst_buffer, DRM_MM_TT|DRM_MM_WRITE, dst_offset + dst_y * dst_pitch ); OUT_BATCH( (0 << 16) | src_x ); OUT_BATCH( ((GLint)src_pitch&0xffff) ); - OUT_RELOC( src_buffer, BM_MEM_AGP|BM_READ, src_offset + src_y * src_pitch ); + OUT_RELOC( src_buffer, DRM_MM_TT|DRM_MM_READ, src_offset + src_y * src_pitch ); ADVANCE_BATCH(); } } @@ -345,7 +343,7 @@ void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all, OUT_BATCH( BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); - OUT_RELOC( intel->front_region->buffer, BM_MEM_AGP|BM_WRITE, 0 ); + OUT_RELOC( intel->front_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); OUT_BATCH( clear_color ); ADVANCE_BATCH(); } @@ -356,7 +354,7 @@ void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all, OUT_BATCH( BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); - OUT_RELOC( intel->back_region->buffer, BM_MEM_AGP|BM_WRITE, 0 ); + OUT_RELOC( intel->back_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); OUT_BATCH( clear_color ); ADVANCE_BATCH(); } @@ -367,7 +365,7 @@ void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all, OUT_BATCH( BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); - OUT_RELOC( intel->depth_region->buffer, BM_MEM_AGP|BM_WRITE, 0 ); + OUT_RELOC( intel->depth_region->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); OUT_BATCH( clear_depth ); ADVANCE_BATCH(); } diff --git a/src/mesa/drivers/dri/i915/intel_buffer_objects.c b/src/mesa/drivers/dri/i915/intel_buffer_objects.c index 11fe2ed27e5..73e5635eb77 100644 --- a/src/mesa/drivers/dri/i915/intel_buffer_objects.c +++ b/src/mesa/drivers/dri/i915/intel_buffer_objects.c @@ -32,7 +32,7 @@ #include "intel_context.h" #include "intel_buffer_objects.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /* There is some duplication between mesa's bufferobjects and our @@ -51,7 +51,7 @@ static struct gl_buffer_object *intel_bufferobj_alloc( GLcontext *ctx, /* XXX: We generate our own handle, which is different to 'name' above. */ - bmGenBuffers(intel->bm, 1, &obj->buffer); + bmGenBuffers(intel->bm, 1, &obj->buffer, 0); return &obj->Base; } diff --git a/src/mesa/drivers/dri/i915/intel_bufmgr.c b/src/mesa/drivers/dri/i915/intel_bufmgr.c new file mode 100644 index 00000000000..5b2f17e335c --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_bufmgr.c @@ -0,0 +1,325 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#include "intel_bufmgr.h" + +#include "intel_context.h" +#include "intel_ioctl.h" + +#include "hash.h" +#include "simple_list.h" +#include "mm.h" +#include "imports.h" +#include +#include +#include + +struct _mesa_HashTable; +struct bufmgr +{ + struct intel_context *intel; + struct _mesa_HashTable *hash; + + unsigned buf_nr; /* for generating ids */ + drmMMPool batchPool; +}; + +/*********************************************************************** + * Public functions + */ + +/* The initialization functions are skewed in the fake implementation. + * This call would be to attach to an existing manager, rather than to + * create a local one. + */ + +struct bufmgr * +bm_intel_Attach(struct intel_context *intel) +{ + struct bufmgr *bm = (struct bufmgr *)calloc(sizeof(*bm), 1); + + bm->intel = intel; + bm->hash = _mesa_NewHashTable(); + + drmGetLock(bm->intel->driFd, bm->intel->hHWContext, 0); + assert(!drmMMAllocBufferPool(bm->intel->driFd, mmPoolRing, 0, + BM_BATCHBUFFER | DRM_MM_TT | + DRM_MM_NO_EVICT , + 1024 * 1024, 4096, &bm->batchPool)); + + drmUnlock(bm->intel->driFd, bm->intel->hHWContext); + return bm; +} + +void +bmGenBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers, unsigned flags) +{ + unsigned i; + unsigned bFlags = + (flags) ? flags : DRM_MM_TT | DRM_MM_VRAM | DRM_MM_SYSTEM; + for (i = 0; i < n; i++) { + drmMMBuf *buf = calloc(sizeof(*buf), 1); + + assert(!drmMMInitBuffer(bm->intel->driFd, bFlags, 12, buf)); + buf->client_priv = ++bm->buf_nr; + buffers[i] = buf->client_priv; + _mesa_HashInsert(bm->hash, buffers[i], buf); + } +} + +void +bmSetShared(struct bufmgr *bm, unsigned buffer, unsigned flags, + unsigned long offset, void *virtual) +{ + drmMMBuf *buf = _mesa_HashLookup(bm->hash, buffer); + + buf->flags = DRM_MM_NO_EVICT | DRM_MM_NO_MOVE | DRM_MM_SHARED; + buf->flags |= flags & DRM_MM_MEMTYPE_MASK; + buf->offset = offset; + buf->virtual = virtual; + assert(!drmMMAllocBuffer(bm->intel->driFd, 0, NULL, 0, buf)); +} + +void +bmDeleteBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers) +{ + unsigned i; + + assert(0); + for (i = 0; i < n; i++) { + drmMMBuf *buf = _mesa_HashLookup(bm->hash, buffers[i]); + + drmMMFreeBuffer(bm->intel->driFd, buf); + } +} + +/* If buffer size changes, free and reallocate. Otherwise update in + * place. + */ + +void +bmBufferData(struct bufmgr *bm, + unsigned buffer, unsigned size, const void *data, unsigned flags) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + DBG("bmBufferData %d sz 0x%x data: %p\n", buffer, size, data); + + assert(!buf->mapped); + + if (buf->flags & BM_BATCHBUFFER) { + + assert(!drmMMFreeBuffer(bm->intel->driFd, buf)); + assert(!drmMMAllocBuffer(bm->intel->driFd, size, &bm->batchPool, 1, + buf)); + + } else if (!(buf->flags & DRM_MM_SHARED)) { + + if (buf->size < size || drmBufIsBusy(bm->intel->driFd, buf)) { + assert(!drmMMFreeBuffer(bm->intel->driFd, buf)); + } + if (!buf->block) { + assert(!drmMMAllocBuffer(bm->intel->driFd, size, NULL, 0, buf)); + } + + } + + if (data != NULL) { + + memcpy(bmMapBuffer(bm, buf->client_priv, flags), data, size); + bmUnmapBuffer(bm, buf->client_priv); + + } +} + +/* Update the buffer in place, in whatever space it is currently resident: + */ +void +bmBufferSubData(struct bufmgr *bm, + unsigned buffer, + unsigned offset, unsigned size, const void *data) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); + + drmBufWaitBusy(bm->intel->driFd, buf); + + if (size) { + memcpy(bmMapBuffer(bm, buf->client_priv, 0) + offset, data, size); + bmUnmapBuffer(bm, buf->client_priv); + } +} + +/* Extract data from the buffer: + */ +void +bmBufferGetSubData(struct bufmgr *bm, + unsigned buffer, + unsigned offset, unsigned size, void *data) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size); + + drmBufWaitBusy(bm->intel->driFd, buf); + + if (size) { + memcpy(data, bmMapBuffer(bm, buf->client_priv, 0) + offset, size); + bmUnmapBuffer(bm, buf->client_priv); + } +} + +/* Return a pointer to whatever space the buffer is currently resident in: + */ +void * +bmMapBuffer(struct bufmgr *bm, unsigned buffer, unsigned flags) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + DBG("bmMapBuffer %d\n", buffer); + DBG("Map: Block is 0x%x\n", &buf->block); + + assert(!buf->mapped); + return drmMMMapBuffer(bm->intel->driFd, buf); +} + +void +bmUnmapBuffer(struct bufmgr *bm, unsigned buffer) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + if (!buf) + return; + + DBG("bmUnmapBuffer %d\n", buffer); + + drmMMUnmapBuffer(bm->intel->driFd, buf); +} + +/* Build the list of buffers to validate: + */ +struct _drmMMBufList * +bmNewBufferList(void) +{ + return drmMMInitListHead(); +} + +int +bmAddBuffer(struct bufmgr *bm, + struct _drmMMBufList *list, + unsigned buffer, + unsigned flags, + unsigned *memtype_return, unsigned long *offset_return) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + return drmMMBufListAdd(list, buf, 0, flags, memtype_return, offset_return); +} + +void +bmFreeBufferList(struct _drmMMBufList *list) +{ + drmMMFreeBufList(list); +} + +int +bmScanBufferList(struct bufmgr *bm, + struct _drmMMBufList *list, unsigned buffer) +{ + drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer); + + return drmMMScanBufList(list, buf); +} + +/* To be called prior to emitting commands to hardware which reference + * these buffers. The buffer_usage list provides information on where + * the buffers should be placed and whether their contents need to be + * preserved on copying. The offset and pool data elements are return + * values from this function telling the driver exactly where the + * buffers are currently located. + */ + +int +bmValidateBufferList(struct bufmgr *bm, + struct _drmMMBufList *list, unsigned flags) +{ + return drmMMValidateBuffers(bm->intel->driFd, list); +} + +/* After commands are emitted but before unlocking, this must be + * called so that the buffer manager can correctly age the buffers. + * The buffer manager keeps track of the list of validated buffers, so + * already knows what to apply the fence to. + * + * The buffer manager knows how to emit and test fences directly + * through the drm and without callbacks or whatever into the driver. + */ +unsigned +bmFenceBufferList(struct bufmgr *bm, struct _drmMMBufList *list) +{ + drmFence fence; + + assert(!drmMMFenceBuffers(bm->intel->driFd, list)); + assert(!drmEmitFence(bm->intel->driFd, 0, &fence)); + + return fence.fenceSeq; +} + +/* This functionality is used by the buffer manager, not really sure + * if we need to be exposing it in this way, probably libdrm will + * offer equivalent calls. + * + * For now they can stay, but will likely change/move before final: + */ +unsigned +bmSetFence(struct bufmgr *bm) +{ + drmFence dFence; + + assert(!drmEmitFence(bm->intel->driFd, 0, &dFence)); + + return dFence.fenceSeq; +} + +int +bmTestFence(struct bufmgr *bm, unsigned fence) +{ + drmFence dFence = { 0, fence }; + int retired; + + assert(!drmTestFence(bm->intel->driFd, dFence, 0, &retired)); + return retired; +} + +void +bmFinishFence(struct bufmgr *bm, unsigned fence) +{ + drmFence dFence = { 0, fence }; + assert(!drmWaitFence(bm->intel->driFd, dFence)); +} diff --git a/src/mesa/drivers/dri/i915/intel_bufmgr.h b/src/mesa/drivers/dri/i915/intel_bufmgr.h new file mode 100644 index 00000000000..93b467b9027 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_bufmgr.h @@ -0,0 +1,132 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#ifndef BUFMGR_H +#define BUFMGR_H + +#include "intel_context.h" + +/* Note that this is destined to be external to Mesa, so don't use GL + * types like GLuint, etc. + */ + +/* The buffer manager context. Opaque. + */ +struct bufmgr; + +struct bufmgr *bm_intel_Attach(struct intel_context *intel); + +#define BM_BATCHBUFFER 0x01000000 /* for map - pointer will be accessed + * without dri lock */ + +/* Stick closely to ARB_vbo semantics - they're well defined and + * understood, and drivers can just pass the calls through without too + * much thunking. + */ +void bmGenBuffers(struct bufmgr *, unsigned n, unsigned *buffers, + unsigned flags); + +void bmDeleteBuffers(struct bufmgr *, unsigned n, unsigned *buffers); + +/* The driver has more intimate knowledge of the hardare than a GL + * client would, so flags here is more proscriptive than the usage + * values in the ARB_vbo interface: + */ +void bmBufferData(struct bufmgr *, + unsigned buffer, + unsigned size, const void *data, unsigned flags); + +void bmBufferSubData(struct bufmgr *, + unsigned buffer, + unsigned offset, unsigned size, const void *data); + +void bmBufferGetSubData(struct bufmgr *, + unsigned buffer, + unsigned offset, unsigned size, void *data); + +void *bmMapBuffer(struct bufmgr *, unsigned buffer, unsigned access); + +void bmUnmapBuffer(struct bufmgr *, unsigned buffer); + +/* To be called prior to emitting commands to hardware which reference + * these buffers. + * + * NewBufferList() and AddBuffer() build up a list of buffers to be + * validated. The buffer list provides information on where the + * buffers should be placed and whether their contents need to be + * preserved on copying. The offset data elements are return values + * from this function telling the driver exactly where the buffers are + * currently located. + * + * ValidateBufferList() performs the actual validation and returns the + * buffer pools and offsets within the pools. + * + * FenceBufferList() must be called to set fences and other + * housekeeping before unlocking after a successful call to + * ValidateBufferList(). The buffer manager knows how to emit and test + * fences directly through the drm and without callbacks to the + * driver. + */ +struct _drmMMBufList *bmNewBufferList(void); + +int bmAddBuffer(struct bufmgr *bm, + struct _drmMMBufList *list, + unsigned buffer, + unsigned flags, + unsigned *pool_return, unsigned long *offset_return); + +int bmValidateBufferList(struct bufmgr *, + struct _drmMMBufList *, unsigned flags); + +unsigned bmFenceBufferList(struct bufmgr *, struct _drmMMBufList *); + +void bmFreeBufferList(struct _drmMMBufList *); + +int bmScanBufferList(struct bufmgr *bm, + struct _drmMMBufList *list, unsigned buffer); + +/* This functionality is used by the buffer manager, not really sure + * if we need to be exposing it in this way, probably libdrm will + * offer equivalent calls. + * + * For now they can stay, but will likely change/move before final: + */ +unsigned bmSetFence(struct bufmgr *); +int bmTestFence(struct bufmgr *, unsigned fence); +void bmFinishFence(struct bufmgr *, unsigned fence); + +void bmSetShared(struct bufmgr *bm, unsigned buffer, + unsigned flags, unsigned long offset, void *virtual); + +extern int INTEL_DEBUG; + +#define DEBUG_BUFMGR 0x2000 + +#define DBG(...) do { if (INTEL_DEBUG & DEBUG_BUFMGR) _mesa_printf(__VA_ARGS__); } while(0) + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_context.c b/src/mesa/drivers/dri/i915/intel_context.c index d006c0c5fdd..0b966e730e6 100644 --- a/src/mesa/drivers/dri/i915/intel_context.c +++ b/src/mesa/drivers/dri/i915/intel_context.c @@ -59,7 +59,7 @@ #include "intel_regions.h" #include "intel_buffer_objects.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" #include "utils.h" #ifndef INTEL_DEBUG @@ -251,13 +251,16 @@ void intelFlush( GLcontext *ctx ) /* XXX: Need to do an MI_FLUSH here. Actually, the bufmgr_fake.c * code will have done one already. */ + + bmFinishFence( intel->bm, intel->batch->last_fence ); + } void intelFinish( GLcontext *ctx ) { struct intel_context *intel = intel_context( ctx ); intelFlush( ctx ); - bmFinishFence( intel->bm, intel->last_fence ); + bmFinishFence( intel->bm, intel->batch->last_fence ); } @@ -385,19 +388,19 @@ GLboolean intelInitContext( struct intel_context *intel, /* Buffer manager: */ - intel->bm = bm_fake_intel_Attach( intel ); - + intel->bm = bm_intel_Attach( intel ); +#if 0 bmInitPool(intel->bm, intel->intelScreen->tex.offset, /* low offset */ intel->intelScreen->tex.map, /* low virtual */ intel->intelScreen->tex.size, - BM_MEM_AGP); - + DRM_MM_TT); +#endif /* These are still static, but create regions for them. */ intel->front_region = intel_region_create_static(intel, - BM_MEM_AGP, + DRM_MM_TT, intelScreen->front.offset, intelScreen->front.map, intelScreen->cpp, @@ -407,7 +410,7 @@ GLboolean intelInitContext( struct intel_context *intel, intel->back_region = intel_region_create_static(intel, - BM_MEM_AGP, + DRM_MM_TT, intelScreen->back.offset, intelScreen->back.map, intelScreen->cpp, @@ -418,7 +421,7 @@ GLboolean intelInitContext( struct intel_context *intel, */ intel->depth_region = intel_region_create_static(intel, - BM_MEM_AGP, + DRM_MM_TT, intelScreen->depth.offset, intelScreen->depth.map, intelScreen->cpp, diff --git a/src/mesa/drivers/dri/i915/intel_ioctl.c b/src/mesa/drivers/dri/i915/intel_ioctl.c index 4b2c2a71ac4..f9d9f466d82 100644 --- a/src/mesa/drivers/dri/i915/intel_ioctl.c +++ b/src/mesa/drivers/dri/i915/intel_ioctl.c @@ -41,7 +41,7 @@ #include "intel_blit.h" #include "intel_regions.h" #include "drm.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" int intelEmitIrqLocked( struct intel_context *intel ) diff --git a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c index 8453c809c8c..6635b88f44b 100644 --- a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c @@ -28,7 +28,7 @@ #include "intel_context.h" #include "intel_mipmap_tree.h" #include "intel_regions.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" #include "enums.h" static GLenum target_to_target( GLenum target ) diff --git a/src/mesa/drivers/dri/i915/intel_pixel_copy.c b/src/mesa/drivers/dri/i915/intel_pixel_copy.c index fa4e2bdc0eb..f378830a0cf 100644 --- a/src/mesa/drivers/dri/i915/intel_pixel_copy.c +++ b/src/mesa/drivers/dri/i915/intel_pixel_copy.c @@ -39,7 +39,7 @@ #include "intel_regions.h" #include "intel_tris.h" #include "intel_pixel.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" static struct intel_region *copypix_src_region( struct intel_context *intel, diff --git a/src/mesa/drivers/dri/i915/intel_pixel_draw.c b/src/mesa/drivers/dri/i915/intel_pixel_draw.c index b7a97a7dc9d..4d67070d000 100644 --- a/src/mesa/drivers/dri/i915/intel_pixel_draw.c +++ b/src/mesa/drivers/dri/i915/intel_pixel_draw.c @@ -42,7 +42,7 @@ #include "intel_pixel.h" #include "intel_buffer_objects.h" #include "intel_tris.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" diff --git a/src/mesa/drivers/dri/i915/intel_pixel_read.c b/src/mesa/drivers/dri/i915/intel_pixel_read.c index bdd8c74f2cb..eb4ca0d9a3a 100644 --- a/src/mesa/drivers/dri/i915/intel_pixel_read.c +++ b/src/mesa/drivers/dri/i915/intel_pixel_read.c @@ -42,7 +42,7 @@ #include "intel_pixel.h" #include "intel_buffer_objects.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /* For many applications, the new ability to pull the source buffers * back out of the GTT and then do the packing/conversion operations diff --git a/src/mesa/drivers/dri/i915/intel_regions.c b/src/mesa/drivers/dri/i915/intel_regions.c index 1ec8d49c706..f55a002fdaa 100644 --- a/src/mesa/drivers/dri/i915/intel_regions.c +++ b/src/mesa/drivers/dri/i915/intel_regions.c @@ -42,7 +42,7 @@ #include "intel_context.h" #include "intel_regions.h" #include "intel_blit.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /* XXX: Thread safety? */ @@ -80,7 +80,7 @@ struct intel_region *intel_region_alloc( struct intel_context *intel, region->height = height; /* needed? */ region->refcount = 1; - bmGenBuffers(intel->bm, 1, ®ion->buffer); + bmGenBuffers(intel->bm, 1, ®ion->buffer, 0); bmBufferData(intel->bm, region->buffer, pitch * cpp * height, NULL, 0); return region; @@ -120,9 +120,6 @@ struct intel_region *intel_region_create_static( struct intel_context *intel, GLuint height ) { struct intel_region *region = calloc(sizeof(*region), 1); - GLuint size = cpp * pitch * height; - GLint pool; - DBG("%s\n", __FUNCTION__); region->cpp = cpp; @@ -130,22 +127,13 @@ struct intel_region *intel_region_create_static( struct intel_context *intel, region->height = height; /* needed? */ region->refcount = 1; - /* Recipe for creating a static buffer - create a static pool with - * the right offset and size, generate a buffer and use a special - * call to bind it to all of the memory in that pool. + /* + * We use a "shared" buffer type to indicate buffers created and + * shared by others. */ - pool = bmInitPool(intel->bm, offset, virtual, size, - (BM_MEM_AGP | - BM_NO_UPLOAD | - BM_NO_EVICT | - BM_NO_MOVE)); - if (pool < 0) { - _mesa_printf("bmInitPool failed for static region\n"); - exit(1); - } - bmGenBuffers(intel->bm, 1, ®ion->buffer); - bmBufferStatic(intel->bm, region->buffer, size, pool); + bmGenBuffers(intel->bm, 1, ®ion->buffer, DRM_MM_TT | DRM_MM_SHARED); + bmSetShared(intel->bm, region->buffer, DRM_MM_TT, offset, virtual); return region; } diff --git a/src/mesa/drivers/dri/i915/intel_regions.h b/src/mesa/drivers/dri/i915/intel_regions.h index 16b6fc9eea8..0132932dd42 100644 --- a/src/mesa/drivers/dri/i915/intel_regions.h +++ b/src/mesa/drivers/dri/i915/intel_regions.h @@ -29,7 +29,7 @@ #define INTEL_REGIONS_H #include "mtypes.h" -#include "bufmgr.h" /* for DBG! */ +#include "intel_bufmgr.h" /* for DBG! */ struct intel_context; /* A layer on top of the bufmgr buffers that adds a few useful things: diff --git a/src/mesa/drivers/dri/i915/intel_tex_copy.c b/src/mesa/drivers/dri/i915/intel_tex_copy.c index 3394ea649f8..d0307aaaee5 100644 --- a/src/mesa/drivers/dri/i915/intel_tex_copy.c +++ b/src/mesa/drivers/dri/i915/intel_tex_copy.c @@ -38,7 +38,7 @@ #include "intel_tex.h" #include "intel_blit.h" #include "intel_pixel.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /* Do the best we can using the blitter. A future project is to use * the texture engine and fragment programs for these copies. diff --git a/src/mesa/drivers/dri/i915/intel_tex_validate.c b/src/mesa/drivers/dri/i915/intel_tex_validate.c index 9b4d8995446..b9cb9f1f3a6 100644 --- a/src/mesa/drivers/dri/i915/intel_tex_validate.c +++ b/src/mesa/drivers/dri/i915/intel_tex_validate.c @@ -4,7 +4,7 @@ #include "intel_context.h" #include "intel_mipmap_tree.h" #include "intel_tex.h" -#include "bufmgr.h" +#include "intel_bufmgr.h" /** * Compute which mipmap levels that really need to be sent to the hardware.