Import bufmgr code to libdrm. Not yet hooked up to the build.
parent
867c2bb461
commit
6a9eb08a87
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright © 2007 Intel Corporation
|
||||
*
|
||||
* 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, sublicense,
|
||||
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "mtypes.h"
|
||||
#include "dri_bufmgr.h"
|
||||
|
||||
/** @file dri_bufmgr.c
|
||||
*
|
||||
* Convenience functions for buffer management methods.
|
||||
*/
|
||||
|
||||
dri_bo *
|
||||
dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size,
|
||||
unsigned int alignment, uint64_t location_mask)
|
||||
{
|
||||
assert((location_mask & ~(DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_MEM_TT |
|
||||
DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_PRIV0 |
|
||||
DRM_BO_FLAG_MEM_PRIV1 | DRM_BO_FLAG_MEM_PRIV2 |
|
||||
DRM_BO_FLAG_MEM_PRIV3 | DRM_BO_FLAG_MEM_PRIV4 |
|
||||
DRM_BO_FLAG_CACHED | DRM_BO_FLAG_CACHED_MAPPED)) == 0);
|
||||
return bufmgr->bo_alloc(bufmgr, name, size, alignment, location_mask);
|
||||
}
|
||||
|
||||
dri_bo *
|
||||
dri_bo_alloc_static(dri_bufmgr *bufmgr, const char *name, unsigned long offset,
|
||||
unsigned long size, void *virtual,
|
||||
uint64_t location_mask)
|
||||
{
|
||||
assert((location_mask & ~(DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_MEM_TT |
|
||||
DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_PRIV0 |
|
||||
DRM_BO_FLAG_MEM_PRIV1 | DRM_BO_FLAG_MEM_PRIV2 |
|
||||
DRM_BO_FLAG_MEM_PRIV3 |
|
||||
DRM_BO_FLAG_MEM_PRIV4)) == 0);
|
||||
|
||||
return bufmgr->bo_alloc_static(bufmgr, name, offset, size, virtual,
|
||||
location_mask);
|
||||
}
|
||||
|
||||
void
|
||||
dri_bo_reference(dri_bo *bo)
|
||||
{
|
||||
bo->bufmgr->bo_reference(bo);
|
||||
}
|
||||
|
||||
void
|
||||
dri_bo_unreference(dri_bo *bo)
|
||||
{
|
||||
if (bo == NULL)
|
||||
return;
|
||||
|
||||
bo->bufmgr->bo_unreference(bo);
|
||||
}
|
||||
|
||||
int
|
||||
dri_bo_map(dri_bo *buf, GLboolean write_enable)
|
||||
{
|
||||
return buf->bufmgr->bo_map(buf, write_enable);
|
||||
}
|
||||
|
||||
int
|
||||
dri_bo_unmap(dri_bo *buf)
|
||||
{
|
||||
return buf->bufmgr->bo_unmap(buf);
|
||||
}
|
||||
|
||||
int
|
||||
dri_bo_subdata(dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, const void *data)
|
||||
{
|
||||
int ret;
|
||||
if (bo->bufmgr->bo_subdata)
|
||||
return bo->bufmgr->bo_subdata(bo, offset, size, data);
|
||||
if (size == 0 || data == NULL)
|
||||
return 0;
|
||||
|
||||
ret = dri_bo_map(bo, GL_TRUE);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy((unsigned char *)bo->virtual + offset, data, size);
|
||||
dri_bo_unmap(bo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dri_bo_get_subdata(dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, void *data)
|
||||
{
|
||||
int ret;
|
||||
if (bo->bufmgr->bo_subdata)
|
||||
return bo->bufmgr->bo_get_subdata(bo, offset, size, data);
|
||||
|
||||
if (size == 0 || data == NULL)
|
||||
return 0;
|
||||
|
||||
ret = dri_bo_map(bo, GL_FALSE);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy(data, (unsigned char *)bo->virtual + offset, size);
|
||||
dri_bo_unmap(bo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dri_bo_wait_rendering(dri_bo *bo)
|
||||
{
|
||||
bo->bufmgr->bo_wait_rendering(bo);
|
||||
}
|
||||
|
||||
void
|
||||
dri_bufmgr_destroy(dri_bufmgr *bufmgr)
|
||||
{
|
||||
bufmgr->destroy(bufmgr);
|
||||
}
|
||||
|
||||
|
||||
int dri_emit_reloc(dri_bo *reloc_buf,
|
||||
uint32_t read_domains, uint32_t write_domain,
|
||||
uint32_t delta, uint32_t offset, dri_bo *target_buf)
|
||||
{
|
||||
return reloc_buf->bufmgr->emit_reloc(reloc_buf, read_domains, write_domain,
|
||||
delta, offset, target_buf);
|
||||
}
|
||||
|
||||
void *dri_process_relocs(dri_bo *batch_buf)
|
||||
{
|
||||
return batch_buf->bufmgr->process_relocs(batch_buf);
|
||||
}
|
||||
|
||||
void dri_post_submit(dri_bo *batch_buf)
|
||||
{
|
||||
batch_buf->bufmgr->post_submit(batch_buf);
|
||||
}
|
||||
|
||||
void
|
||||
dri_bufmgr_set_debug(dri_bufmgr *bufmgr, GLboolean enable_debug)
|
||||
{
|
||||
bufmgr->debug = enable_debug;
|
||||
}
|
||||
|
||||
int
|
||||
dri_bufmgr_check_aperture_space(dri_bo *bo)
|
||||
{
|
||||
return bo->bufmgr->check_aperture_space(bo);
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright © 2007 Intel Corporation
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
* Keith Whitwell <keithw-at-tungstengraphics-dot-com>
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#ifndef _DRI_BUFMGR_H_
|
||||
#define _DRI_BUFMGR_H_
|
||||
#include <xf86drm.h>
|
||||
|
||||
typedef struct _dri_bufmgr dri_bufmgr;
|
||||
typedef struct _dri_bo dri_bo;
|
||||
|
||||
struct _dri_bo {
|
||||
/**
|
||||
* Size in bytes of the buffer object.
|
||||
*
|
||||
* The size may be larger than the size originally requested for the
|
||||
* allocation, such as being aligned to page size.
|
||||
*/
|
||||
unsigned long size;
|
||||
/**
|
||||
* Card virtual address (offset from the beginning of the aperture) for the
|
||||
* object. Only valid while validated.
|
||||
*/
|
||||
unsigned long offset;
|
||||
/**
|
||||
* Virtual address for accessing the buffer data. Only valid while mapped.
|
||||
*/
|
||||
void *virtual;
|
||||
/** Buffer manager context associated with this buffer object */
|
||||
dri_bufmgr *bufmgr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Context for a buffer manager instance.
|
||||
*
|
||||
* Contains public methods followed by private storage for the buffer manager.
|
||||
*/
|
||||
struct _dri_bufmgr {
|
||||
/**
|
||||
* Allocate a buffer object.
|
||||
*
|
||||
* Buffer objects are not necessarily initially mapped into CPU virtual
|
||||
* address space or graphics device aperture. They must be mapped using
|
||||
* bo_map() to be used by the CPU, and validated for use using bo_validate()
|
||||
* to be used from the graphics device.
|
||||
*/
|
||||
dri_bo *(*bo_alloc)(dri_bufmgr *bufmgr_ctx, const char *name,
|
||||
unsigned long size, unsigned int alignment,
|
||||
uint64_t location_mask);
|
||||
|
||||
/**
|
||||
* Allocates a buffer object for a static allocation.
|
||||
*
|
||||
* Static allocations are ones such as the front buffer that are offered by
|
||||
* the X Server, which are never evicted and never moved.
|
||||
*/
|
||||
dri_bo *(*bo_alloc_static)(dri_bufmgr *bufmgr_ctx, const char *name,
|
||||
unsigned long offset, unsigned long size,
|
||||
void *virtual, uint64_t location_mask);
|
||||
|
||||
/** Takes a reference on a buffer object */
|
||||
void (*bo_reference)(dri_bo *bo);
|
||||
|
||||
/**
|
||||
* Releases a reference on a buffer object, freeing the data if
|
||||
* rerefences remain.
|
||||
*/
|
||||
void (*bo_unreference)(dri_bo *bo);
|
||||
|
||||
/**
|
||||
* Maps the buffer into userspace.
|
||||
*
|
||||
* This function will block waiting for any existing execution on the
|
||||
* buffer to complete, first. The resulting mapping is available at
|
||||
* buf->virtual.
|
||||
*/
|
||||
int (*bo_map)(dri_bo *buf, GLboolean write_enable);
|
||||
|
||||
/** Reduces the refcount on the userspace mapping of the buffer object. */
|
||||
int (*bo_unmap)(dri_bo *buf);
|
||||
|
||||
/**
|
||||
* Write data into an object.
|
||||
*
|
||||
* This is an optional function, if missing,
|
||||
* dri_bo will map/memcpy/unmap.
|
||||
*/
|
||||
int (*bo_subdata) (dri_bo *buf, unsigned long offset,
|
||||
unsigned long size, const void *data);
|
||||
|
||||
/**
|
||||
* Read data from an object
|
||||
*
|
||||
* This is an optional function, if missing,
|
||||
* dri_bo will map/memcpy/unmap.
|
||||
*/
|
||||
int (*bo_get_subdata) (dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, void *data);
|
||||
|
||||
/**
|
||||
* Waits for rendering to an object by the GPU to have completed.
|
||||
*
|
||||
* This is not required for any access to the BO by bo_map, bo_subdata, etc.
|
||||
* It is merely a way for the driver to implement glFinish.
|
||||
*/
|
||||
void (*bo_wait_rendering) (dri_bo *bo);
|
||||
|
||||
/**
|
||||
* Tears down the buffer manager instance.
|
||||
*/
|
||||
void (*destroy)(dri_bufmgr *bufmgr);
|
||||
|
||||
/**
|
||||
* Add relocation entry in reloc_buf, which will be updated with the
|
||||
* target buffer's real offset on on command submission.
|
||||
*
|
||||
* Relocations remain in place for the lifetime of the buffer object.
|
||||
*
|
||||
* \param reloc_buf Buffer to write the relocation into.
|
||||
* \param flags BO flags to be used in validating the target buffer.
|
||||
* Applicable flags include:
|
||||
* - DRM_BO_FLAG_READ: The buffer will be read in the process of
|
||||
* command execution.
|
||||
* - DRM_BO_FLAG_WRITE: The buffer will be written in the process of
|
||||
* command execution.
|
||||
* - DRM_BO_FLAG_MEM_TT: The buffer should be validated in TT memory.
|
||||
* - DRM_BO_FLAG_MEM_VRAM: The buffer should be validated in video
|
||||
* memory.
|
||||
* \param delta Constant value to be added to the relocation target's offset.
|
||||
* \param offset Byte offset within batch_buf of the relocated pointer.
|
||||
* \param target Buffer whose offset should be written into the relocation
|
||||
* entry.
|
||||
*/
|
||||
int (*emit_reloc)(dri_bo *reloc_buf,
|
||||
uint32_t read_domains, uint32_t write_domain,
|
||||
uint32_t delta, uint32_t offset, dri_bo *target);
|
||||
|
||||
/**
|
||||
* Processes the relocations, either in userland or by converting the list
|
||||
* for use in batchbuffer submission.
|
||||
*
|
||||
* Kernel-based implementations will return a pointer to the arguments
|
||||
* to be handed with batchbuffer submission to the kernel. The userland
|
||||
* implementation performs the buffer validation and emits relocations
|
||||
* into them the appopriate order.
|
||||
*
|
||||
* \param batch_buf buffer at the root of the tree of relocations
|
||||
* \return argument to be completed and passed to the execbuffers ioctl
|
||||
* (if any).
|
||||
*/
|
||||
void *(*process_relocs)(dri_bo *batch_buf);
|
||||
|
||||
void (*post_submit)(dri_bo *batch_buf);
|
||||
|
||||
int (*check_aperture_space)(dri_bo *bo);
|
||||
GLboolean debug; /**< Enables verbose debugging printouts */
|
||||
};
|
||||
|
||||
dri_bo *dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size,
|
||||
unsigned int alignment, uint64_t location_mask);
|
||||
dri_bo *dri_bo_alloc_static(dri_bufmgr *bufmgr, const char *name,
|
||||
unsigned long offset, unsigned long size,
|
||||
void *virtual, uint64_t location_mask);
|
||||
void dri_bo_reference(dri_bo *bo);
|
||||
void dri_bo_unreference(dri_bo *bo);
|
||||
int dri_bo_map(dri_bo *buf, GLboolean write_enable);
|
||||
int dri_bo_unmap(dri_bo *buf);
|
||||
|
||||
int dri_bo_subdata(dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, const void *data);
|
||||
int dri_bo_get_subdata(dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, void *data);
|
||||
void dri_bo_wait_rendering(dri_bo *bo);
|
||||
|
||||
void dri_bufmgr_set_debug(dri_bufmgr *bufmgr, GLboolean enable_debug);
|
||||
void dri_bufmgr_destroy(dri_bufmgr *bufmgr);
|
||||
|
||||
int dri_emit_reloc(dri_bo *reloc_buf,
|
||||
uint32_t read_domains, uint32_t write_domain,
|
||||
uint32_t delta, uint32_t offset, dri_bo *target_buf);
|
||||
void *dri_process_relocs(dri_bo *batch_buf);
|
||||
void dri_post_process_relocs(dri_bo *batch_buf);
|
||||
void dri_post_submit(dri_bo *batch_buf);
|
||||
int dri_bufmgr_check_aperture_space(dri_bo *bo);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright © 2007 Intel Corporation
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
* Keith Whitwell <keithw-at-tungstengraphics-dot-com>
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_BUFMGR_FAKE_H_
|
||||
#define _INTEL_BUFMGR_FAKE_H_
|
||||
|
||||
void dri_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr);
|
||||
dri_bufmgr *dri_bufmgr_fake_init(unsigned long low_offset, void *low_virtual,
|
||||
unsigned long size,
|
||||
unsigned int (*fence_emit)(void *private),
|
||||
int (*fence_wait)(void *private,
|
||||
unsigned int cookie),
|
||||
void *driver_priv);
|
||||
void dri_bo_fake_disable_backing_store(dri_bo *bo,
|
||||
void (*invalidate_cb)(dri_bo *bo,
|
||||
void *ptr),
|
||||
void *ptr);
|
||||
#endif /* _INTEL_BUFMGR_FAKE_H_ */
|
||||
|
|
@ -0,0 +1,847 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright © 2007 Red Hat Inc.
|
||||
* Copyright © 2007 Intel Corporation
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
* Keith Whitwell <keithw-at-tungstengraphics-dot-com>
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Dave Airlie <airlied@linux.ie>
|
||||
*/
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "errno.h"
|
||||
#include "mtypes.h"
|
||||
#include "dri_bufmgr.h"
|
||||
#include "string.h"
|
||||
#include "imports.h"
|
||||
|
||||
#include "i915_drm.h"
|
||||
|
||||
#include "intel_bufmgr_gem.h"
|
||||
|
||||
#define DBG(...) do { \
|
||||
if (bufmgr_gem->bufmgr.debug) \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct intel_validate_entry {
|
||||
dri_bo *bo;
|
||||
struct drm_i915_op_arg bo_arg;
|
||||
};
|
||||
|
||||
struct dri_gem_bo_bucket_entry {
|
||||
uint32_t gem_handle;
|
||||
uint32_t last_offset;
|
||||
struct dri_gem_bo_bucket_entry *next;
|
||||
};
|
||||
|
||||
struct dri_gem_bo_bucket {
|
||||
struct dri_gem_bo_bucket_entry *head;
|
||||
struct dri_gem_bo_bucket_entry **tail;
|
||||
/**
|
||||
* Limit on the number of entries in this bucket.
|
||||
*
|
||||
* 0 means that this caching at this bucket size is disabled.
|
||||
* -1 means that there is no limit to caching at this size.
|
||||
*/
|
||||
int max_entries;
|
||||
int num_entries;
|
||||
};
|
||||
|
||||
/* Arbitrarily chosen, 16 means that the maximum size we'll cache for reuse
|
||||
* is 1 << 16 pages, or 256MB.
|
||||
*/
|
||||
#define INTEL_GEM_BO_BUCKETS 16
|
||||
typedef struct _dri_bufmgr_gem {
|
||||
dri_bufmgr bufmgr;
|
||||
|
||||
int fd;
|
||||
|
||||
uint32_t max_relocs;
|
||||
|
||||
struct drm_i915_gem_exec_object *exec_objects;
|
||||
dri_bo **exec_bos;
|
||||
int exec_size;
|
||||
int exec_count;
|
||||
|
||||
/** Array of lists of cached gem objects of power-of-two sizes */
|
||||
struct dri_gem_bo_bucket cache_bucket[INTEL_GEM_BO_BUCKETS];
|
||||
|
||||
struct drm_i915_gem_execbuffer exec_arg;
|
||||
} dri_bufmgr_gem;
|
||||
|
||||
typedef struct _dri_bo_gem {
|
||||
dri_bo bo;
|
||||
|
||||
int refcount;
|
||||
GLboolean mapped;
|
||||
uint32_t gem_handle;
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Index of the buffer within the validation list while preparing a
|
||||
* batchbuffer execution.
|
||||
*/
|
||||
int validate_index;
|
||||
|
||||
/**
|
||||
* Tracks whether set_domain to CPU is current
|
||||
* Set when set_domain has been called
|
||||
* Cleared when a batch has been submitted
|
||||
*/
|
||||
GLboolean cpu_domain_set;
|
||||
|
||||
/** Array passed to the DRM containing relocation information. */
|
||||
struct drm_i915_gem_relocation_entry *relocs;
|
||||
/** Array of bos corresponding to relocs[i].target_handle */
|
||||
dri_bo **reloc_target_bo;
|
||||
/** Number of entries in relocs */
|
||||
int reloc_count;
|
||||
/** Mapped address for the buffer */
|
||||
void *virtual;
|
||||
} dri_bo_gem;
|
||||
|
||||
static int
|
||||
logbase2(int n)
|
||||
{
|
||||
GLint i = 1;
|
||||
GLint log2 = 0;
|
||||
|
||||
while (n > i) {
|
||||
i *= 2;
|
||||
log2++;
|
||||
}
|
||||
|
||||
return log2;
|
||||
}
|
||||
|
||||
static struct dri_gem_bo_bucket *
|
||||
dri_gem_bo_bucket_for_size(dri_bufmgr_gem *bufmgr_gem, unsigned long size)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We only do buckets in power of two increments */
|
||||
if ((size & (size - 1)) != 0)
|
||||
return NULL;
|
||||
|
||||
/* We should only see sizes rounded to pages. */
|
||||
assert((size % 4096) == 0);
|
||||
|
||||
/* We always allocate in units of pages */
|
||||
i = ffs(size / 4096) - 1;
|
||||
if (i >= INTEL_GEM_BO_BUCKETS)
|
||||
return NULL;
|
||||
|
||||
return &bufmgr_gem->cache_bucket[i];
|
||||
}
|
||||
|
||||
|
||||
static void dri_gem_dump_validation_list(dri_bufmgr_gem *bufmgr_gem)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < bufmgr_gem->exec_count; i++) {
|
||||
dri_bo *bo = bufmgr_gem->exec_bos[i];
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
if (bo_gem->relocs == NULL) {
|
||||
DBG("%2d: %d (%s)\n", i, bo_gem->gem_handle, bo_gem->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < bo_gem->reloc_count; j++) {
|
||||
dri_bo *target_bo = bo_gem->reloc_target_bo[j];
|
||||
dri_bo_gem *target_gem = (dri_bo_gem *)target_bo;
|
||||
|
||||
DBG("%2d: %d (%s)@0x%08llx -> %d (%s)@0x%08lx + 0x%08x\n",
|
||||
i,
|
||||
bo_gem->gem_handle, bo_gem->name, bo_gem->relocs[j].offset,
|
||||
target_gem->gem_handle, target_gem->name, target_bo->offset,
|
||||
bo_gem->relocs[j].delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given buffer to the list of buffers to be validated (moved into the
|
||||
* appropriate memory type) with the next batch submission.
|
||||
*
|
||||
* If a buffer is validated multiple times in a batch submission, it ends up
|
||||
* with the intersection of the memory type flags and the union of the
|
||||
* access flags.
|
||||
*/
|
||||
static void
|
||||
intel_add_validate_buffer(dri_bo *bo)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
int index;
|
||||
|
||||
if (bo_gem->validate_index != -1)
|
||||
return;
|
||||
|
||||
/* Extend the array of validation entries as necessary. */
|
||||
if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) {
|
||||
int new_size = bufmgr_gem->exec_size * 2;
|
||||
|
||||
if (new_size == 0)
|
||||
new_size = 5;
|
||||
|
||||
bufmgr_gem->exec_objects =
|
||||
realloc(bufmgr_gem->exec_objects,
|
||||
sizeof(*bufmgr_gem->exec_objects) * new_size);
|
||||
bufmgr_gem->exec_bos =
|
||||
realloc(bufmgr_gem->exec_bos,
|
||||
sizeof(*bufmgr_gem->exec_bos) * new_size);
|
||||
bufmgr_gem->exec_size = new_size;
|
||||
}
|
||||
|
||||
index = bufmgr_gem->exec_count;
|
||||
bo_gem->validate_index = index;
|
||||
/* Fill in array entry */
|
||||
bufmgr_gem->exec_objects[index].handle = bo_gem->gem_handle;
|
||||
bufmgr_gem->exec_objects[index].relocation_count = bo_gem->reloc_count;
|
||||
bufmgr_gem->exec_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs;
|
||||
bufmgr_gem->exec_objects[index].alignment = 0;
|
||||
bufmgr_gem->exec_objects[index].offset = 0;
|
||||
bufmgr_gem->exec_bos[index] = bo;
|
||||
dri_bo_reference(bo);
|
||||
bufmgr_gem->exec_count++;
|
||||
}
|
||||
|
||||
|
||||
#define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
|
||||
sizeof(uint32_t))
|
||||
|
||||
static int
|
||||
intel_setup_reloc_list(dri_bo *bo)
|
||||
{
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
|
||||
bo_gem->relocs = malloc(bufmgr_gem->max_relocs *
|
||||
sizeof(struct drm_i915_gem_relocation_entry));
|
||||
bo_gem->reloc_target_bo = malloc(bufmgr_gem->max_relocs * sizeof(dri_bo *));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dri_bo *
|
||||
dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name,
|
||||
unsigned long size, unsigned int alignment,
|
||||
uint64_t location_mask)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
|
||||
dri_bo_gem *bo_gem;
|
||||
unsigned int page_size = getpagesize();
|
||||
int ret;
|
||||
struct dri_gem_bo_bucket *bucket;
|
||||
GLboolean alloc_from_cache = GL_FALSE;
|
||||
|
||||
bo_gem = calloc(1, sizeof(*bo_gem));
|
||||
if (!bo_gem)
|
||||
return NULL;
|
||||
|
||||
/* Round the allocated size up to a power of two number of pages. */
|
||||
bo_gem->bo.size = 1 << logbase2(size);
|
||||
if (bo_gem->bo.size < page_size)
|
||||
bo_gem->bo.size = page_size;
|
||||
bucket = dri_gem_bo_bucket_for_size(bufmgr_gem, bo_gem->bo.size);
|
||||
|
||||
/* If we don't have caching at this size, don't actually round the
|
||||
* allocation up.
|
||||
*/
|
||||
if (bucket == NULL || bucket->max_entries == 0) {
|
||||
bo_gem->bo.size = size;
|
||||
if (bo_gem->bo.size < page_size)
|
||||
bo_gem->bo.size = page_size;
|
||||
}
|
||||
|
||||
/* Get a buffer out of the cache if available */
|
||||
if (bucket != NULL && bucket->num_entries > 0) {
|
||||
struct dri_gem_bo_bucket_entry *entry = bucket->head;
|
||||
struct drm_i915_gem_busy busy;
|
||||
|
||||
busy.handle = entry->gem_handle;
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
|
||||
alloc_from_cache = (ret == 0 && busy.busy == 0);
|
||||
|
||||
if (alloc_from_cache) {
|
||||
bucket->head = entry->next;
|
||||
if (entry->next == NULL)
|
||||
bucket->tail = &bucket->head;
|
||||
bucket->num_entries--;
|
||||
|
||||
bo_gem->gem_handle = entry->gem_handle;
|
||||
bo_gem->bo.offset = entry->last_offset;
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!alloc_from_cache) {
|
||||
struct drm_gem_create create;
|
||||
|
||||
memset(&create, 0, sizeof(create));
|
||||
create.size = bo_gem->bo.size;
|
||||
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CREATE, &create);
|
||||
bo_gem->gem_handle = create.handle;
|
||||
if (ret != 0) {
|
||||
free(bo_gem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bo_gem->bo.virtual = NULL;
|
||||
bo_gem->bo.bufmgr = bufmgr;
|
||||
bo_gem->name = name;
|
||||
bo_gem->refcount = 1;
|
||||
bo_gem->validate_index = -1;
|
||||
|
||||
DBG("bo_create: buf %d (%s) %ldb\n",
|
||||
bo_gem->gem_handle, bo_gem->name, size);
|
||||
|
||||
return &bo_gem->bo;
|
||||
}
|
||||
|
||||
/* Our GEM backend doesn't allow creation of static buffers, as that requires
|
||||
* privelege for the non-fake case, and the lock in the fake case where we were
|
||||
* working around the X Server not creating buffers and passing handles to us.
|
||||
*/
|
||||
static dri_bo *
|
||||
dri_gem_bo_alloc_static(dri_bufmgr *bufmgr, const char *name,
|
||||
unsigned long offset, unsigned long size, void *virtual,
|
||||
uint64_t location_mask)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a dri_bo wrapping the given buffer object handle.
|
||||
*
|
||||
* This can be used when one application needs to pass a buffer object
|
||||
* to another.
|
||||
*/
|
||||
dri_bo *
|
||||
intel_gem_bo_create_from_handle(dri_bufmgr *bufmgr, const char *name,
|
||||
unsigned int handle)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
|
||||
dri_bo_gem *bo_gem;
|
||||
int ret;
|
||||
struct drm_gem_open open_arg;
|
||||
|
||||
bo_gem = calloc(1, sizeof(*bo_gem));
|
||||
if (!bo_gem)
|
||||
return NULL;
|
||||
|
||||
memset(&open_arg, 0, sizeof(open_arg));
|
||||
open_arg.name = handle;
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Couldn't reference %s handle 0x%08x: %s\n",
|
||||
name, handle, strerror(-ret));
|
||||
free(bo_gem);
|
||||
return NULL;
|
||||
}
|
||||
bo_gem->bo.size = open_arg.size;
|
||||
bo_gem->bo.offset = 0;
|
||||
bo_gem->bo.virtual = NULL;
|
||||
bo_gem->bo.bufmgr = bufmgr;
|
||||
bo_gem->name = name;
|
||||
bo_gem->refcount = 1;
|
||||
bo_gem->validate_index = -1;
|
||||
bo_gem->gem_handle = open_arg.handle;
|
||||
|
||||
DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
|
||||
|
||||
return &bo_gem->bo;
|
||||
}
|
||||
|
||||
static void
|
||||
dri_gem_bo_reference(dri_bo *bo)
|
||||
{
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
bo_gem->refcount++;
|
||||
}
|
||||
|
||||
static void
|
||||
dri_gem_bo_unreference(dri_bo *bo)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
if (!bo)
|
||||
return;
|
||||
|
||||
if (--bo_gem->refcount == 0) {
|
||||
struct dri_gem_bo_bucket *bucket;
|
||||
int ret;
|
||||
|
||||
if (bo_gem->mapped)
|
||||
munmap (bo_gem->virtual, bo->size);
|
||||
|
||||
if (bo_gem->relocs != NULL) {
|
||||
int i;
|
||||
|
||||
/* Unreference all the target buffers */
|
||||
for (i = 0; i < bo_gem->reloc_count; i++)
|
||||
dri_bo_unreference(bo_gem->reloc_target_bo[i]);
|
||||
free(bo_gem->reloc_target_bo);
|
||||
free(bo_gem->relocs);
|
||||
}
|
||||
|
||||
bucket = dri_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
|
||||
/* Put the buffer into our internal cache for reuse if we can. */
|
||||
if (bucket != NULL &&
|
||||
(bucket->max_entries == -1 ||
|
||||
(bucket->max_entries > 0 &&
|
||||
bucket->num_entries < bucket->max_entries)))
|
||||
{
|
||||
struct dri_gem_bo_bucket_entry *entry;
|
||||
|
||||
entry = calloc(1, sizeof(*entry));
|
||||
entry->gem_handle = bo_gem->gem_handle;
|
||||
entry->last_offset = bo->offset;
|
||||
|
||||
entry->next = NULL;
|
||||
*bucket->tail = entry;
|
||||
bucket->tail = &entry->next;
|
||||
bucket->num_entries++;
|
||||
} else {
|
||||
struct drm_gem_close close;
|
||||
|
||||
/* Close this object */
|
||||
close.handle = bo_gem->gem_handle;
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr,
|
||||
"DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",
|
||||
bo_gem->gem_handle, bo_gem->name, strerror(-ret));
|
||||
}
|
||||
}
|
||||
|
||||
DBG("bo_unreference final: %d (%s)\n",
|
||||
bo_gem->gem_handle, bo_gem->name);
|
||||
|
||||
free(bo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dri_gem_bo_map(dri_bo *bo, GLboolean write_enable)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
struct drm_gem_set_domain set_domain;
|
||||
int ret;
|
||||
|
||||
bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
|
||||
/* Allow recursive mapping. Mesa may recursively map buffers with
|
||||
* nested display loops.
|
||||
*/
|
||||
if (!bo_gem->mapped) {
|
||||
|
||||
assert(bo->virtual == NULL);
|
||||
|
||||
DBG("bo_map: %d (%s)\n", bo_gem->gem_handle, bo_gem->name);
|
||||
|
||||
if (bo_gem->virtual == NULL) {
|
||||
struct drm_gem_mmap mmap_arg;
|
||||
|
||||
memset(&mmap_arg, 0, sizeof(mmap_arg));
|
||||
mmap_arg.handle = bo_gem->gem_handle;
|
||||
mmap_arg.offset = 0;
|
||||
mmap_arg.size = bo->size;
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_MMAP, &mmap_arg);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s:%d: Error mapping buffer %d (%s): %s .\n",
|
||||
__FILE__, __LINE__,
|
||||
bo_gem->gem_handle, bo_gem->name, strerror(errno));
|
||||
}
|
||||
bo_gem->virtual = (void *)(uintptr_t)mmap_arg.addr_ptr;
|
||||
}
|
||||
bo->virtual = bo_gem->virtual;
|
||||
bo_gem->mapped = GL_TRUE;
|
||||
DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, bo_gem->virtual);
|
||||
}
|
||||
|
||||
if (!bo_gem->cpu_domain_set) {
|
||||
set_domain.handle = bo_gem->gem_handle;
|
||||
set_domain.read_domains = DRM_GEM_DOMAIN_CPU;
|
||||
set_domain.write_domain = write_enable ? DRM_GEM_DOMAIN_CPU : 0;
|
||||
ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_SET_DOMAIN, &set_domain);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
|
||||
__FILE__, __LINE__,
|
||||
bo_gem->gem_handle, set_domain.read_domains, set_domain.write_domain,
|
||||
strerror (errno));
|
||||
}
|
||||
bo_gem->cpu_domain_set = GL_TRUE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dri_gem_bo_unmap(dri_bo *bo)
|
||||
{
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
if (bo == NULL)
|
||||
return 0;
|
||||
|
||||
assert(bo_gem->mapped);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dri_gem_bo_subdata (dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, const void *data)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
struct drm_gem_pwrite pwrite;
|
||||
int ret;
|
||||
|
||||
memset (&pwrite, 0, sizeof (pwrite));
|
||||
pwrite.handle = bo_gem->gem_handle;
|
||||
pwrite.offset = offset;
|
||||
pwrite.size = size;
|
||||
pwrite.data_ptr = (uint64_t) (uintptr_t) data;
|
||||
ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_PWRITE, &pwrite);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, "%s:%d: Error writing data to buffer %d: (%d %d) %s .\n",
|
||||
__FILE__, __LINE__,
|
||||
bo_gem->gem_handle, (int) offset, (int) size,
|
||||
strerror (errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dri_gem_bo_get_subdata (dri_bo *bo, unsigned long offset,
|
||||
unsigned long size, void *data)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
struct drm_gem_pread pread;
|
||||
int ret;
|
||||
|
||||
memset (&pread, 0, sizeof (pread));
|
||||
pread.handle = bo_gem->gem_handle;
|
||||
pread.offset = offset;
|
||||
pread.size = size;
|
||||
pread.data_ptr = (uint64_t) (uintptr_t) data;
|
||||
ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_PREAD, &pread);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, "%s:%d: Error reading data from buffer %d: (%d %d) %s .\n",
|
||||
__FILE__, __LINE__,
|
||||
bo_gem->gem_handle, (int) offset, (int) size,
|
||||
strerror (errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dri_gem_bo_wait_rendering(dri_bo *bo)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
struct drm_gem_set_domain set_domain;
|
||||
int ret;
|
||||
|
||||
set_domain.handle = bo_gem->gem_handle;
|
||||
set_domain.read_domains = DRM_GEM_DOMAIN_CPU;
|
||||
set_domain.write_domain = 0;
|
||||
ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_SET_DOMAIN, &set_domain);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
|
||||
__FILE__, __LINE__,
|
||||
bo_gem->gem_handle, set_domain.read_domains, set_domain.write_domain,
|
||||
strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dri_bufmgr_gem_destroy(dri_bufmgr *bufmgr)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
|
||||
int i;
|
||||
|
||||
free(bufmgr_gem->exec_objects);
|
||||
free(bufmgr_gem->exec_bos);
|
||||
|
||||
/* Free any cached buffer objects we were going to reuse */
|
||||
for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) {
|
||||
struct dri_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i];
|
||||
struct dri_gem_bo_bucket_entry *entry;
|
||||
|
||||
while ((entry = bucket->head) != NULL) {
|
||||
struct drm_gem_close close;
|
||||
int ret;
|
||||
|
||||
bucket->head = entry->next;
|
||||
if (entry->next == NULL)
|
||||
bucket->tail = &bucket->head;
|
||||
bucket->num_entries--;
|
||||
|
||||
/* Close this object */
|
||||
close.handle = entry->gem_handle;
|
||||
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %s\n",
|
||||
strerror(-ret));
|
||||
}
|
||||
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
free(bufmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the target buffer to the validation list and adds the relocation
|
||||
* to the reloc_buffer's relocation list.
|
||||
*
|
||||
* The relocation entry at the given offset must already contain the
|
||||
* precomputed relocation value, because the kernel will optimize out
|
||||
* the relocation entry write when the buffer hasn't moved from the
|
||||
* last known offset in target_bo.
|
||||
*/
|
||||
static int
|
||||
dri_gem_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain,
|
||||
uint32_t delta, uint32_t offset, dri_bo *target_bo)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
dri_bo_gem *target_bo_gem = (dri_bo_gem *)target_bo;
|
||||
|
||||
/* Create a new relocation list if needed */
|
||||
if (bo_gem->relocs == NULL)
|
||||
intel_setup_reloc_list(bo);
|
||||
|
||||
/* Check overflow */
|
||||
assert(bo_gem->reloc_count < bufmgr_gem->max_relocs);
|
||||
|
||||
/* Check args */
|
||||
assert (offset <= bo->size - 4);
|
||||
assert ((write_domain & (write_domain-1)) == 0);
|
||||
|
||||
bo_gem->relocs[bo_gem->reloc_count].offset = offset;
|
||||
bo_gem->relocs[bo_gem->reloc_count].delta = delta;
|
||||
bo_gem->relocs[bo_gem->reloc_count].target_handle =
|
||||
target_bo_gem->gem_handle;
|
||||
bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains;
|
||||
bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain;
|
||||
bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset;
|
||||
|
||||
bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo;
|
||||
dri_bo_reference(target_bo);
|
||||
|
||||
bo_gem->reloc_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the tree of relocations rooted at BO and accumulate the list of
|
||||
* validations to be performed and update the relocation buffers with
|
||||
* index values into the validation list.
|
||||
*/
|
||||
static void
|
||||
dri_gem_bo_process_reloc(dri_bo *bo)
|
||||
{
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
int i;
|
||||
|
||||
if (bo_gem->relocs == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < bo_gem->reloc_count; i++) {
|
||||
dri_bo *target_bo = bo_gem->reloc_target_bo[i];
|
||||
|
||||
/* Continue walking the tree depth-first. */
|
||||
dri_gem_bo_process_reloc(target_bo);
|
||||
|
||||
/* Add the target to the validate list */
|
||||
intel_add_validate_buffer(target_bo);
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
dri_gem_process_reloc(dri_bo *batch_buf)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *) batch_buf->bufmgr;
|
||||
|
||||
/* Update indices and set up the validate list. */
|
||||
dri_gem_bo_process_reloc(batch_buf);
|
||||
|
||||
/* Add the batch buffer to the validation list. There are no relocations
|
||||
* pointing to it.
|
||||
*/
|
||||
intel_add_validate_buffer(batch_buf);
|
||||
|
||||
bufmgr_gem->exec_arg.buffers_ptr = (uintptr_t)bufmgr_gem->exec_objects;
|
||||
bufmgr_gem->exec_arg.buffer_count = bufmgr_gem->exec_count;
|
||||
bufmgr_gem->exec_arg.batch_start_offset = 0;
|
||||
bufmgr_gem->exec_arg.batch_len = 0; /* written in intel_exec_ioctl */
|
||||
|
||||
return &bufmgr_gem->exec_arg;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_update_buffer_offsets (dri_bufmgr_gem *bufmgr_gem)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bufmgr_gem->exec_count; i++) {
|
||||
dri_bo *bo = bufmgr_gem->exec_bos[i];
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
/* Update the buffer offset */
|
||||
if (bufmgr_gem->exec_objects[i].offset != bo->offset) {
|
||||
DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n",
|
||||
bo_gem->gem_handle, bo_gem->name, bo->offset,
|
||||
bufmgr_gem->exec_objects[i].offset);
|
||||
bo->offset = bufmgr_gem->exec_objects[i].offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dri_gem_post_submit(dri_bo *batch_buf)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)batch_buf->bufmgr;
|
||||
int i;
|
||||
|
||||
intel_update_buffer_offsets (bufmgr_gem);
|
||||
|
||||
if (bufmgr_gem->bufmgr.debug)
|
||||
dri_gem_dump_validation_list(bufmgr_gem);
|
||||
|
||||
for (i = 0; i < bufmgr_gem->exec_count; i++) {
|
||||
dri_bo *bo = bufmgr_gem->exec_bos[i];
|
||||
dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
|
||||
|
||||
/* Need to call set_domain on next bo_map */
|
||||
bo_gem->cpu_domain_set = GL_FALSE;
|
||||
|
||||
/* Disconnect the buffer from the validate list */
|
||||
bo_gem->validate_index = -1;
|
||||
dri_bo_unreference(bo);
|
||||
bufmgr_gem->exec_bos[i] = NULL;
|
||||
}
|
||||
bufmgr_gem->exec_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables unlimited caching of buffer objects for reuse.
|
||||
*
|
||||
* This is potentially very memory expensive, as the cache at each bucket
|
||||
* size is only bounded by how many buffers of that size we've managed to have
|
||||
* in flight at once.
|
||||
*/
|
||||
void
|
||||
intel_gem_enable_bo_reuse(dri_bufmgr *bufmgr)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) {
|
||||
bufmgr_gem->cache_bucket[i].max_entries = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
dri_gem_check_aperture_space(dri_bo *bo)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the GEM buffer manager, which uses the kernel to allocate, map,
|
||||
* and manage map buffer objections.
|
||||
*
|
||||
* \param fd File descriptor of the opened DRM device.
|
||||
*/
|
||||
dri_bufmgr *
|
||||
intel_bufmgr_gem_init(int fd, int batch_size)
|
||||
{
|
||||
dri_bufmgr_gem *bufmgr_gem;
|
||||
int i;
|
||||
|
||||
bufmgr_gem = calloc(1, sizeof(*bufmgr_gem));
|
||||
bufmgr_gem->fd = fd;
|
||||
|
||||
/* Let's go with one relocation per every 2 dwords (but round down a bit
|
||||
* since a power of two will mean an extra page allocation for the reloc
|
||||
* buffer).
|
||||
*
|
||||
* Every 4 was too few for the blender benchmark.
|
||||
*/
|
||||
bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2;
|
||||
|
||||
bufmgr_gem->bufmgr.bo_alloc = dri_gem_bo_alloc;
|
||||
bufmgr_gem->bufmgr.bo_alloc_static = dri_gem_bo_alloc_static;
|
||||
bufmgr_gem->bufmgr.bo_reference = dri_gem_bo_reference;
|
||||
bufmgr_gem->bufmgr.bo_unreference = dri_gem_bo_unreference;
|
||||
bufmgr_gem->bufmgr.bo_map = dri_gem_bo_map;
|
||||
bufmgr_gem->bufmgr.bo_unmap = dri_gem_bo_unmap;
|
||||
bufmgr_gem->bufmgr.bo_subdata = dri_gem_bo_subdata;
|
||||
bufmgr_gem->bufmgr.bo_get_subdata = dri_gem_bo_get_subdata;
|
||||
bufmgr_gem->bufmgr.bo_wait_rendering = dri_gem_bo_wait_rendering;
|
||||
bufmgr_gem->bufmgr.destroy = dri_bufmgr_gem_destroy;
|
||||
bufmgr_gem->bufmgr.emit_reloc = dri_gem_emit_reloc;
|
||||
bufmgr_gem->bufmgr.process_relocs = dri_gem_process_reloc;
|
||||
bufmgr_gem->bufmgr.post_submit = dri_gem_post_submit;
|
||||
bufmgr_gem->bufmgr.debug = GL_FALSE;
|
||||
bufmgr_gem->bufmgr.check_aperture_space = dri_gem_check_aperture_space;
|
||||
/* Initialize the linked lists for BO reuse cache. */
|
||||
for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++)
|
||||
bufmgr_gem->cache_bucket[i].tail = &bufmgr_gem->cache_bucket[i].head;
|
||||
|
||||
return &bufmgr_gem->bufmgr;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#ifndef INTEL_BUFMGR_GEM_H
|
||||
#define INTEL_BUFMGR_GEM_H
|
||||
|
||||
#include "dri_bufmgr.h"
|
||||
|
||||
extern dri_bo *intel_gem_bo_create_from_handle(dri_bufmgr *bufmgr,
|
||||
const char *name,
|
||||
unsigned int handle);
|
||||
|
||||
dri_bufmgr *intel_bufmgr_gem_init(int fd, int batch_size);
|
||||
|
||||
void
|
||||
intel_gem_enable_bo_reuse(dri_bufmgr *bufmgr);
|
||||
|
||||
#endif /* INTEL_BUFMGR_GEM_H */
|
Loading…
Reference in New Issue