📄 dri_bufmgr_fake.c
字号:
/************************************************************************** * * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. * 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 above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 TUNGSTEN GRAPHICS 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. * **************************************************************************//* Originally a fake version of the buffer manager so that we can * prototype the changes in a driver fairly quickly, has been fleshed * out to a fully functional interim solution. * * Basically wraps the old style memory management in the new * programming interface, but is more expressive and avoids many of * the bugs in the old texture manager. */#include "mtypes.h"#include "dri_bufmgr.h"#include "drm.h"#include "simple_list.h"#include "mm.h"#include "imports.h"#define DBG(...) do { \ if (bufmgr_fake->bufmgr.debug) \ _mesa_printf(__VA_ARGS__); \} while (0)/* Internal flags: */#define BM_NO_BACKING_STORE 0x00000001#define BM_NO_FENCE_SUBDATA 0x00000002#define BM_PINNED 0x00000004/* 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 for uploads - an upload that was * processed through the command queue wouldn't need to care about * fences. */#define MAX_RELOCS 4096struct fake_buffer_reloc{ /** Buffer object that the relocation points at. */ dri_bo *target_buf; /** Offset of the relocation entry within reloc_buf. */ GLuint offset; /** Cached value of the offset when we last performed this relocation. */ GLuint last_target_offset; /** Value added to target_buf's offset to get the relocation entry. */ GLuint delta; /** Flags to validate the target buffer under. */ uint64_t validate_flags;};struct block { struct block *next, *prev; struct mem_block *mem; /* BM_MEM_AGP */ /** * Marks that the block is currently in the aperture and has yet to be * fenced. */ unsigned on_hardware:1; /** * Marks that the block is currently fenced (being used by rendering) and * can't be freed until @fence is passed. */ unsigned fenced:1; /** Fence cookie for the block. */ unsigned fence; /* Split to read_fence, write_fence */ dri_bo *bo; void *virtual;};typedef struct _bufmgr_fake { dri_bufmgr bufmgr; unsigned long low_offset; unsigned long size; void *virtual; struct mem_block *heap; struct block lru; /* only allocated, non-fence-pending blocks here */ unsigned buf_nr; /* for generating ids */ struct block on_hardware; /* after bmValidateBuffers */ struct block fenced; /* after bmFenceBuffers (mi_flush, emit irq, write dword) */ /* then to bufmgr->lru or free() */ unsigned int last_fence; unsigned fail:1; unsigned need_fence:1; GLboolean thrashing; /** * Driver callback to emit a fence, returning the cookie. * * Currently, this also requires that a write flush be emitted before * emitting the fence, but this should change. */ unsigned int (*fence_emit)(void *private); /** Driver callback to wait for a fence cookie to have passed. */ int (*fence_wait)(void *private, unsigned int fence_cookie); /** Driver-supplied argument to driver callbacks */ void *driver_priv; GLboolean debug; GLboolean performed_rendering; /* keep track of the current total size of objects we have relocs for */ unsigned long current_total_size;} dri_bufmgr_fake;typedef struct _dri_bo_fake { dri_bo bo; unsigned id; /* debug only */ const char *name; unsigned dirty:1; unsigned size_accounted:1; /*this buffers size has been accounted against the aperture */ unsigned card_dirty:1; /* has the card written to this buffer - we make need to copy it back */ unsigned int refcount; /* Flags may consist of any of the DRM_BO flags, plus * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the first two * driver private flags. */ uint64_t flags; unsigned int alignment; GLboolean is_static, validated; unsigned int map_count; /* Flags for the buffer to be validated with in command submission */ uint64_t validate_flags; /** relocation list */ struct fake_buffer_reloc *relocs; GLuint nr_relocs; struct block *block; void *backing_store; void (*invalidate_cb)(dri_bo *bo, void *ptr); void *invalidate_ptr;} dri_bo_fake;typedef struct _dri_fence_fake { dri_fence fence; const char *name; unsigned int refcount; unsigned int fence_cookie; GLboolean flushed;} dri_fence_fake;static int clear_fenced(dri_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie);static int dri_fake_check_aperture_space(dri_bo *bo);#define MAXFENCE 0x7fffffffstatic GLboolean FENCE_LTE( unsigned a, unsigned b ){ if (a == b) return GL_TRUE; if (a < b && b - a < (1<<24)) return GL_TRUE; if (a > b && MAXFENCE - a + b < (1<<24)) return GL_TRUE; return GL_FALSE;}static unsigned int_fence_emit_internal(dri_bufmgr_fake *bufmgr_fake){ bufmgr_fake->last_fence = bufmgr_fake->fence_emit(bufmgr_fake->driver_priv); return bufmgr_fake->last_fence;}static void_fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie){ int ret; ret = bufmgr_fake->fence_wait(bufmgr_fake->driver_priv, cookie); if (ret != 0) { _mesa_printf("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__); abort(); } clear_fenced(bufmgr_fake, cookie);}static GLboolean_fence_test(dri_bufmgr_fake *bufmgr_fake, unsigned fence){ /* Slight problem with wrap-around: */ return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence);}/** * Allocate a memory manager block for the buffer. */static GLbooleanalloc_block(dri_bo *bo){ dri_bo_fake *bo_fake = (dri_bo_fake *)bo; dri_bufmgr_fake *bufmgr_fake= (dri_bufmgr_fake *)bo->bufmgr; struct block *block = (struct block *)calloc(sizeof *block, 1); unsigned int align_log2 = _mesa_ffs(bo_fake->alignment) - 1; GLuint sz; if (!block) return GL_FALSE; sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1); block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0); if (!block->mem) { free(block); return GL_FALSE; } make_empty_list(block); /* Insert at head or at tail??? */ insert_at_tail(&bufmgr_fake->lru, block); block->virtual = bufmgr_fake->virtual + block->mem->ofs - bufmgr_fake->low_offset; block->bo = bo; bo_fake->block = block; return GL_TRUE;}/* Release the card storage associated with buf: */static void free_block(dri_bufmgr_fake *bufmgr_fake, struct block *block){ dri_bo_fake *bo_fake; DBG("free block %p %08x %d %d\n", block, block->mem->ofs, block->on_hardware, block->fenced); if (!block) return; bo_fake = (dri_bo_fake *)block->bo; if (!(bo_fake->flags & BM_NO_BACKING_STORE) && (bo_fake->card_dirty == 1)) { memcpy(bo_fake->backing_store, block->virtual, block->bo->size); bo_fake->card_dirty = 1; bo_fake->dirty = 1; } if (block->on_hardware) { block->bo = NULL; } else if (block->fenced) { block->bo = NULL; } else { DBG(" - free immediately\n"); remove_from_list(block); mmFreeMem(block->mem); free(block); }}static voidalloc_backing_store(dri_bo *bo){ dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; assert(!bo_fake->backing_store); assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE))); bo_fake->backing_store = ALIGN_MALLOC(bo->size, 64); DBG("alloc_backing - buf %d %p %d\n", bo_fake->id, bo_fake->backing_store, bo->size); assert(bo_fake->backing_store);}static voidfree_backing_store(dri_bo *bo){ dri_bo_fake *bo_fake = (dri_bo_fake *)bo; if (bo_fake->backing_store) { assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE))); ALIGN_FREE(bo_fake->backing_store); bo_fake->backing_store = NULL; }}static voidset_dirty(dri_bo *bo){ dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; if (bo_fake->flags & BM_NO_BACKING_STORE && bo_fake->invalidate_cb != NULL) bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr); assert(!(bo_fake->flags & BM_PINNED)); DBG("set_dirty - buf %d\n", bo_fake->id); bo_fake->dirty = 1;}static GLbooleanevict_lru(dri_bufmgr_fake *bufmgr_fake, GLuint max_fence){ struct block *block, *tmp; DBG("%s\n", __FUNCTION__); foreach_s(block, tmp, &bufmgr_fake->lru) { dri_bo_fake *bo_fake = (dri_bo_fake *)block->bo; if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) continue; if (block->fence && max_fence && !FENCE_LTE(block->fence, max_fence)) return 0; set_dirty(&bo_fake->bo); bo_fake->block = NULL; free_block(bufmgr_fake, block); return GL_TRUE; } return GL_FALSE;}#define foreach_s_rev(ptr, t, list) \ for(ptr=(list)->prev,t=(ptr)->prev; list != ptr; ptr=t, t=(t)->prev)static GLbooleanevict_mru(dri_bufmgr_fake *bufmgr_fake){ struct block *block, *tmp; DBG("%s\n", __FUNCTION__); foreach_s_rev(block, tmp, &bufmgr_fake->lru) { dri_bo_fake *bo_fake = (dri_bo_fake *)block->bo; if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) continue; set_dirty(&bo_fake->bo); bo_fake->block = NULL; free_block(bufmgr_fake, block); return GL_TRUE; } return GL_FALSE;}/** * Removes all objects from the fenced list older than the given fence. */static int clear_fenced(dri_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie){ struct block *block, *tmp; int ret = 0; foreach_s(block, tmp, &bufmgr_fake->fenced) { assert(block->fenced); if (_fence_test(bufmgr_fake, block->fence)) { block->fenced = 0; if (!block->bo) { DBG("delayed free: offset %x sz %x\n", block->mem->ofs, block->mem->size); remove_from_list(block); mmFreeMem(block->mem); free(block);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -