xf86drm API exported to the X server
and client-side X applications. The low-level ioctl API
exported by the kernel to the xf86drm library is not
discussed here. Familiarity with the DRI design documents is
assumed [OM1998, MFOA1999].
Copyright © 1999 by Precision Insight, Inc., Cedar Park, Texas. All Rights Reserved.
Permission is granted to make and distribute verbatim copies of this document provided the copyright notice and this permission notice are preserved on all copies.
OpenGL is a registered trademark of Silicon Graphics, Inc. Unix is a registered trademark of The Open Group. The `X' device and X Window System are trademarks of The Open Group. XFree86 is a trademark of The XFree86 Project. Linux is a registered trademark of Linus Torvalds. Intel is a registered trademark of Intel Corporation. All other trademarks mentioned are the property of their respective owners.
The Direct Rendering Manager (DRM) is a kernel-level device driver that loads into the Linux kernel via the standard module interface. The functionality of the DRM can be implemented for other operating systems at a later date. There are a few issues that may require kernel changes outside the module interface -- these issues will be discussed in the future work section.
The DRM supports the Direct Rendering Infrastructure (DRI) in three major ways:
The direct rendering system has multiple entities (i.e., the X server, multiple direct-rendering clients, and the kernel) competing for direct access to the graphics hardware. Hardware that is currently available for PC-class machines will lock up if more than one entity is accessing the hardware (e.g., if two clients intermingle requests in the command FIFO or (on some hardware) if one client reads the framebuffer while another writes the command FIFO).
The DRM provides a single per-device hardware lock to synchronize access to the hardware. The hardware lock may be required when the X server performs 2D rendering, when a direct-rendering client is performing a software fallback that must read or write the frame buffer, or when the kernel is dispatching DMA buffers.
This hardware lock may not be required for all hardware (e.g., high-end hardware may be able to intermingle command requests from multiple clients) or for all implementations (e.g., one that uses a page fault mechanism instead of an explicit lock). In the later case, the DRM would be extended to provide support for this mechanism.
For more details on the hardware lock requirements and a discussion of the performance implications and implementation details, please see [FOM99].
The X server, running as root, usually obtains access
to the frame buffer and MMIO regions on the graphics
hardware by mapping these regions using /dev/mem.
The direct-rendering clients, however, do not run as
root, but still require similar mappings. Like
/dev/mem, the DRM device interface allows clients
to create these mappings, but with the following
restrictions:
xauth)./dev/drm?, which is only accessible by
root and by a group specified in the
XF86Config file (a file that only root can
edit). This allows the system administrator to
restrict direct rendering access to a group of trusted
users.Most modern PC-class graphics hardware provides for DMA access to the command FIFO. Often, DMA access has been optimized so that it provides significantly better throughput than does MMIO access. For these cards, the DRM provides a DMA engine with the following features:
The DMA engine is extensible via the use of a device-specific kernel module that can hook-out some or all of the generic functionality. Because DRM exports a well-known API with well-known entry points, the author of the device-specific driver can use as much of the existing DRM functionality as is applicable, and only hook out one or two pieces of functionality that is required by the hardware.
For example, the device-specific driver can use all of the
existing security, memory mapping, and DMA buffer
management features of the DRM and hook out only the
ioctl that performs the DMA. This is important for
graphics hardware that permits multiple-outstanding DMA
requests or that provides for ``nested DMA'' (i.e., a DMA
request that is initiated within another DMA request).
The next section documents the library-level API that provides
wrappers for the kernel-level ioctl API. Currently, there
is nearly a one-to-one mapping between the library API and the
ioctl API, with the library providing convenience and
abstraction.
The library API is available for use within the X server and the
direct-rendering clients. This API wraps the low-level ioctl
calls that are made to the kernel.
int drmAvailable(void)
drmAvailable is used to determine if the DRM kernel
driver has been loaded.
Returns 1 if the DRM driver is loaded, 0 otherwise.
int drmOpenDRM(void)
drmOpenDRM is used to open the main /dev/drm
control device. If running as root, this device is
automatically created in /dev with the appropriate
mode.
Returns a file descriptor for the main /dev/drm
control device, or a negative value on error.
int drmCloseDRM(int fd)
drmCloseDRM closes the file descriptor returned by
drmOpenDRM.
drmVersionPtr drmGetVersion(int fd)
drmGetVersion queries the driver specified by the file
descriptor and returns version information about that
specific driver. The drmVersion structure, shown
below, is automatically created and should be freed with
drmFreeVersion.
Returns a new drmVersion structure, or NULL on
error.
typedef struct _drmVersion {
int version_major; // Major version of driver
int version_minor; // Minor version of driver
int version_patchlevel; // Patch level of driver
char *name; // Driver name
char *date; // Driver date
char *desc; // Driver description
} drmVersion, *drmVersionPtr;
Similar information is available from
/proc/drm/drivers.
void drmFreeVersion(drmVersionPtr)
drmFreeVersion frees the drmVersion structure
returned by drmGetVersion.
drmListPtr drmGetVersionList(int fd)
drmGetVersionList returns information about all DRM
drivers currently loaded on the system. The drmList
structure, shown below, is automatically created and should
be freed with drmFreeVersionList.
Returns a new drmList strucutre, or NULL on error.
typedef struct _drmList {
int count; // Length of version
drmVersionPtr version; // List of versions
} drmList, *drmListPtr;
Similar information is available from
/proc/drm/drivers.
void drmFreeVersionList(drmListPtr)
drmFreeVersionList frees the drmList structure
returned by drmGetVersionList.
int drmGetInterruptFromBusID(int fd, int busnum,
int devnum, int funcnum)
The X server is responsible for determining the IRQ that the graphics hardware will use for DMA operations. XFree86 provides complete user-space support for querying PCI devices, and this support is used for determining graphics hardware capabilities, including which regions of memory should be mapped as the frame buffer and the MMIO regions. This user-space support can also be used to query the IRQ for the PCI device. However, the OS is free to remap the IRQ, and Linux will remap the IRQ whenever IO-APIC support is compiled into the kernel, making it impossible for the user-space routines to determine which IRQ should be used for the device.
The drmGetInterruptFromBusID call uses the bus, device,
and function description of the hardware to determine the
IRQ mapping.
Returns the IRQ being used by the hardware, or a negative value on error.
The /dev/drm device is the main control device for
the DRM. This device can be used to query the availability of
sub-drivers and to install these sub-drivers. The X server
will query the hardware and determine which sub-driver should
be used for that particular hardware. Then the X server will
install and configure that sub-driver. For hardware without a
device-specific sub-driver, the ``generic'' sub-driver will be
used.
int drmCreateSub(int fd, const char *name, const char *busid)
drmCreateSub will create an instance of the sub-driver
called name. To support multi-head X servers (or more
than one X server running simultaneously on different
hardware), each sub-driver may be instantiated more than
once. However, the busid must be unique across all
sub-driver. Usually the busid will be a string
describing the unique PCI bus identifier (e.g., a bus,
device, function tuple). For OSs that do not support this
notion of bus identifier, any unique string may be used.
A device of the appropriate ownership and mode will be
created in /dev. Sub-driver instantiations will
use /dev/drm0, /dev/drm1,
/dev/drm2, etc., and will be referred to in this
document at /dev/drm?.
NOTE/FIXME: For the Linux Expo demo, the ability to instantiate more than one sub-driver is not supported. This functionality will be supported for the SI.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmDestroySub(int fd, const char *busid)
drmDestroySub is used to destroy the sub-driver with
the specified busid. If the sub-driver is currently in
use by other processes, it will be marked as destroyed, and
will return errors for all subsequent uses. When the last
process disconnects from the sub-driver, then all of its
resources will be reclaimed.
NOTE/FIXME: For the Linux Expo demo, this call will fail unless all processes have disconnected from the sub-driver. The ability to mark a pending destruction will be supported for the SI.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmAddMap(int fd, drmHandle offset, drmSize size,
drmMapType type, drmMapFlags flags,
drmHandlePtr handle)
drmAddMap specifies a range of memory that is available
for mapping by a non-root process using mmap(2) on
/dev/drm?.
Returns 0 on success and a negative value on error. The
handle will be set to a value that may be used as the
offset parameter for mmap(2). May only be called
by root.
For the frame buffer,
offset will be the physical
address of the start of the frame buffer,size will be the size of the frame buffer in
bytes, and type will be DRM_FRAME_BUFFER.The area mapped will be uncached. If MTRR support is available in the kernel, the frame buffer area will be set to write combining.
For the MMIO register area,
offset will be the physical
address of the start of the register area,size will be the size of the register area
bytes, and type will be DRM_REGISTERS.The area mapped will be uncached.
The SAREA is a shared memory segment that is used for
communication between the X server, the direct-rendering
clients, and the kernel. Standard shm* calls provide
only uid/gid-based access restrictions and do not provide
the ability to enforce the DRI's security policy, so this
area is created and mapped via the DRM interface.
For the SAREA,
offset will be ignored and should be set to
zero, size will be the desired size of the SAREA
in bytes,type will be DRM_SHM.A shared memory area of the requested size will be created
and locked in kernel memory. This area may be mapped into
client-space by using the handle returned.
Several flags are provided to modify the actions of
drmAddMap:
DRM_RESTRICT will prevent the area from being
mapped into client space by a non-root user. The
area will still be mapped into kernel-space, so this
is useful to allow the kernel to have access to
registers that control DMA while preventing the client
from having such access.DRM_READ_ONLY will force the area to be mapped as
a read-only region in client space. This is useful if
the client requires read access to registers that are
in an area that also contains, for example, DMA
control registers. (The client must not be allowed to
initiate DMA to arbitrary locations in memory, since
this opens up a significant security risk
[FM99]).DRM_LOCKED will force SAREA pages (of type
DRM_SHM) to be locked into kernel memory. This
flag will be ignored for the SI, since all shared
memory will be locked.DRM_KERNEL will require that the kernel has
access to the mapped region. This flag will be
ignored in the SI and the kernel will have read/write
access to all mapped regions.DRM_WRITE_COMBINING will specify that, if
possible, the mapped region will be set to
write-combining. (This is the default for
DRM_FRAME_BUFFER but may be useful on some
(non-PC-class) hardware for DRM_REGISTERS.)DRM_CONTAINS_LOCK will specify that this SAREA
region (of type DRM_SHM) contains the
hardware lock at the beginning of the region. This
flag must be specified for one of the SAREA regions.
drmAddBufs(int fd, int count, int size)
drmAddBufs is used to request that count buffers
of size bytes be allocated for DMA transfers. More
than one size of buffer can be allocated by using
drmAddBufs multiple times.
Returns the number of buffers actually allocated, or a
negative value on error. May only be called by root.
int drmMarkBufs(int fd, double low, double high)
drmMarkBufs specifies a low and high water mark for
buffer allocation. low and high should be values
between 0 and 1.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmCreateContext(int fd, drmContextPtr handle)
drmCreateContext is used by the X server during
GLXContext initialization. The handle returned is used
by the client when requesting DMA dispatch with drmDMA.
This call causes kernel-level resources to be allocated for the kernel-level DMA queue associated with the context.
Returns 0 on success and a negative value on error. On
success, the handle parameter is set. May only be
called by root.
int drmDestroyContext(int fd, drmContext handle)
drmDestroyContext frees any kernel-level resources
allocated using drmCreateContext. Any DMA buffers that
are waiting on the kernel-level DMA queue that have not yet
been dispatched to the hardware are removed.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmSetContextFlags(int fd, drmContext context,
drmContextFlags flags)
drmSetContextFlags sets kernel-level flags on a
particular context. Currently, two flags are available:
DRM_CONTEXT_PRESERVED means that this context
guarantees that it will preserve the hardware state
(i.e., the GLXContext stored in the hardware) whenever
it is used. The kernel will never perform a hardware
context switch to or away from this context. This flag
is useful in the X server and in some portions of the
direct-rendering client library.DRM_CONTEXT_2DONLY means that this context is a 2D
rendering context. When the hardware context switches
are performed in the kernel device driver, this flag
will alert the kernel that only a portion of the full 3D
rendering context needs to be saved. In the SI, this
flag is ignored by the kernel implementation since it
does not perform hardware context switches (the X server
performs these switches as a proxy for the kernel, and
tracks 2D contexts in user space).Returns 0 on success and a negative value on error. May
only be called by root.
int drmGetContextFlags(int fd, drmContext context,
drmContextFlagsPtr flags)
drmGetContextFlags obtains the flags that were set with
drmSetContextFlags.
Returns 0 on success and a negative value on error.
int drmAddContextTag(int fd, drmContext context, void *tag)
The X server or the direct-rendering client library may want
to associate a private data structure with the
drmContext. Because the drmContext is opaque, the
drmAddContextTag function is provided as a
library-level helper-function to associate a context
with a tag. The tag can be retrieved with
drmGetContextTag.
This function is implemented in user-space, does not depend on kernel-level support, and is not required for proper kernel-level functionality.
Returns 0 on success.
void *drmGetContextTag(int fd, drmContext context)
drmGetContextTag returns the tag associated with the
context using drmSetContextTag.
Returns the tag on success, and NULL on failure.
drmContextPtr drmGetReservedContextList(int fd, int *count)
The X server may want to tag contexts that the kernel
reserves for itself. In order to do this,
drmGetReservedContextList is provided to get a list of
reserved contexts from the kernel. These contexts will
never be returned from a drmCreateContext call, but may
appear in a context switch request.
Returns a list of length count on success, and
NULL on error.
void drmFreeReservedContextList(drmContextPtr)
This call frees the pointer returned by
drmGetReservedContextList.
int drmCreateDrawable(int fd, drmDrawablePtr handle)
drmCreateDrawable creates a handle for each drawable.
This is a hook for future expansion and is not currently
used.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmDestroyDrawable(int fd, drmDrawable handle)
drmDestroyDrawable destroys a drawable handle created
with drmCreateDrawable. This is a hook for future
expansion and is not currently used.
Returns 0 on success and a negative value on error. May
only be called by root.
int drmCtlAddCommand(int fd, drmCtlDesc desc, int count, int *inst)
The generic version of the DRM contains no device-specific
code. However, the DRM must dispatch DMA, which is a
device-specific process. drmCtlAddCommand is used by
the X server to specify how to perform common
device-specific functions using a generic device-independent
byte code. For more efficient execution of these functions,
a device-specific driver can hook out all of the commands.
Returns 0 on success and a negative value on failure. May
only be called by root.
Several commands can be specified:
DRM_IH_PRE_INST will be executed before the
interrupt handler is installed.DRM_IH_POST_INST will be executed after the
interrupt handler is installed.DRM_IH_SERVICE is the body of the interrupt
handler, and will be executed whenever an interruption
occurs.DRM_IH_PRE_UNINST will be executed before the
interrupt handler is uninstalled.DRM_IH_POST_UNINST will be executed after the
interrupt handler is uninstalled.DRM_DMA_DISPATCH will wait until the hardware is
ready for a DMA dispatch, and will dispatch a DMA
buffer using a specified physical address and size.DRM_DMA_READY will wait until the hardware is
ready for a DMA dispatch.DRM_DMA_IS_READY will look at the hardware and
return a value indicating that the hardware is or is
not ready for another DMA dispatch.DRM_DMA_QUIESCENT will wait until the hardware is
no longer processing DMA or graphics commands.
Instructions are 5 integers long and can be constructed in
an array using macros. Instructions are fully documented
in the ioctl section of this paper, and are outlined
here:
DRM_M_WRITE will write to a specified mapped
region and offset.DRM_M_WHILE will read from a specified mapped
region and offset while a condition is met.DRM_M_IF will read from a specified mapped region
and offset and will jump to another instruction if a
condition is met.DRM_M_GOTO will unconditionally jump to another
instruction.DRM_M_NOOP will no nothing.DRM_M_RETURN will halt byte-code interpretation
before the end of the command stream, and can be used
to specify a return value for DRM_DMA_IS_READY.DRM_M_DO will execute special functions, such
returning the previously sent buffer to the free list
and dispatching a new buffer.DRM_M_READ will read from a specified mapped
region and offset and will store the value in the
byte-code accumulator.DRM_M_TEST will test the accumulator and will
jump to another instruction if a condition is met.
int drmCtlRemoveCommands(int fd)
drmCtlRemoveCommands will remove all of the commands
added with drmCtlAddCommand.
Returns 0 on success and a negative value on failure. May
only be called by root.
int drmCtlInstHandler(int fd, int irq)
drmCtlInstHandler installs an interrupt handler for the
specified irq.
Returns 0 on success and a negative value on failure. May
only be called by root.
int drmCtlUninstHandler(int fd)
drmCtlUninstHandler uninstalls the interrupt handler
installed with drmCtlInstHandler.
Returns 0 on success and a negative value on failure. May
only be called by root.
int drmInstallSIGIOHandler(int fd,
void (*f)(int fd, void *oldctx, void *newctx))
drmInstallSIGIOHandler sets up a signal handler for the
X server to be notified when drmContext swaps are
required. This function sets up the specified file
descriptor for non-blocking reads and installs a handler for
the SIGIO signal. When a SIGIO is received, the file
descriptor will be read. If commands are read from the file
descriptor they are parsed into a pair of drmContext
handles. These handles are translated to tags with
drmGetContextTag and the specified function is called.
When the function returns, the kernel will be notified using
the DRM_IOCTL_NEW_CTX ioctl.
Returns 0 on success and a negative value on failure. May
only be called by root.
int drmRemoveSIGIOHandler(int fd)
drmRemoveSIGIOHandler will remove the SIGIO handler
installed using drmInstallSIGIOHandler.
Returns 0 on success and a negative value on failure. May
only be called by root.
After the DRM sub-driver is installed and configured by the X server, both the X server and the 3D direct-rendering clients may use the facilities provided.
NOTE/FIXME: The client-size authentication API is not documented here. For the Linux Expo demo, we will use the current magic-cookie algorithm. However, for the SI, we will move to a different algorithm, suggested by Colin Plumb [Plumb99]:
/dev/drm?.ioctl that obtains a magic number from the kernel.ioctl telling the kernel to authenticate the
currently open-but-unauthenticated connection associated
with that magic number.
int drmOpenSub(const char *busid)
drmOpenSub returns a file descriptor for the sub-driver
specified by the busid. The busid is send from
the X server to the direct-rending client via the
XFree86-DRI protocol.
Returns a file descriptor on success, and a negative value on failure.
int drmCloseSub(int fd)
drmCloseSub closes the file descriptor obtained from
drmOpenSub.
Returns 0 on success, and a negative value on failure.
int drmMap(int fd, drmHandle handle, drmSize size,
drmAddressPtr address)
drmMap (implemented as a wrapper for mmap(2)) maps
a region of memory previously made mappable by the X server
via the drmAddMap call. The handle for
drmMap is the handle returned by the drmAddMap.
The size must match that used by drmAddMap.
Returns 0 on success, and a negative value on failure. On
success, address contains the user-space virtual
address where the mapping begins.
int drmUnmap(drmAddress address, drmSize size)
drmUnmap (implemented as a wrapper for munmap(2))
is used to unmap mappings obtained with drmMap.
Returns 0 on success, and a negative value on failure.
drmBufInfoPtr drmGetBufInfo(int fd)
drmGetBufInfo is used to get information about the
buffer mapping. This can be used for debugging purposes, or
by a sophisticated client library to determine how best to
use the available buffers (e.g., large buffers can be used
for image transfer).
typedef struct _drmBufDesc {
int count; // Number of buffers of this size
int size; // Size in bytes
int low_mark; // Low water mark
int high_mark; // High water mark
} drmBufDesc, *drmBufDescPtr;
typedef struct _drmBufInfo {
int count; // Number of buffers described in list
drmBufDescPtr list; // List of buffer descriptions
} drmBufInfo, *drmBufInfoPtr;
Returns a pointer to a newly allocated drmBufInfo
structure on success, and NULL on error.
void drmFreeBufInfo(drmBufInfoPtr)
Frees a structure allocated by drmGetBufInfo.
NOTE/FIXME: This function is not yet implemented.
drmBufMapPtr drmMapBufs(int fd)
Maps all of the the DMA buffers into client-virtual space,
creating and returning a drmBufMap structure. This
structure and the associated mappings, can be freed using
drmUnmapBufs.
Note that the client may not use these buffers until
obtaining buffer indices with drmDMA.
typedef struct _drmBuf {
int idx; // Index into master buflist
int total; // Buffer size
int used; // Amount of buffer in use (for DMA)
drmAddress address; // Address
} drmBuf, *drmBufPtr;
typedef struct _drmBufMap {
int count; // Number of buffers mapped
drmBufPtr list; // Buffers
} drmBufMap, *drmBufMapPtr;
Returns a pointer to the newly allocated drmBufMap on
success, and NULL on error.
int drmUnmapBufs(drmBufMapPtr bufs)
Unmaps buffers allocated with drmMapBufs.
Returns 0 on success, and a negative value on failure.
int drmDMA(int fd, drmDMAReqPtr request)
drmDMA can be used to reserve DMA buffers and to
dispatch previously reserved DMA buffers.
Returns 0 on success, and a negative value on failure.
typedef struct _drmDMAReq {
// Indices here refer to the offset into
// list in drmBufInfo
drmContext context; // Context handle
int send_count; // Number of buffers to send
int *send_list; // List of handles to buffers
int *send_sizes; // Lengths of data to send, in bytes
drmDMAFlags flags; // Flags
int request_count; // Number of buffers requested
int request_size; // Desired size of buffers requested
int *request_list; // Buffer information
int *request_sizes; // Minimum acceptable sizes
int granted_count; // Number of buffers granted at this size
} drmDMAReq, *drmDMAReqPtr;
The fields must be filled in before the call as follows:
context is the handle for the kernel-level DMA
queue to use for the request. It was obtained from
drmCreateContext by the X server and transmitted to
the client via the XFree86-DRI protocol stream.send_count is the number of buffers to send.send_list is a vector of integers at least
send_count long containing indices into the
list field of the drmBufInfo structure. These
are identical to the idx field of the drmBuf
structure.send_sizes is a vector of integers at least
send_count long containing the size, in bytes, of
each partially filled buffer. This value must be equal
to or less than the total field in the drmBuf
structure.request_count is the number of buffers requested.request_size is the desired size of the buffers.request_list is a vector of integers at least
request_count long. This vector will be filled
with the index values of the buffer that are being
reserved by this request.request_sizes is a vector of integers at least
request_count long. This vectore will be filled
with the actual maximum size of the buffers returned.
This value is identical to the total field in the
drmBuf structure and is provided here for
convenience only.granted_count is the number of buffers actually
reserved. This number is less than or equal to
request_count.flags specifies flags that modify the behavior of
the drmDMA call:
DRM_DMA_BLOCK will cause the drmDMA call
to wait until all of the DMA buffers have been
dispatched and completely copied to the graphics
hardware (although the commands in the DMA buffers
may not yet have been processed by the graphics
hardware). Without DRM_DMA_BLOCK or
DRM_DMA_PRIORITY, drmDMA will not wait for
DMA dispatch to occur.DRM_DMA_PRIORITY an experimental high-priority
blocking dispatch mode. NOTE/FIXME: This
may not be supported in the final SI.DRM_DMA_WHILE_LOCKED places the request on a
special high-priority kernel-level DMA queue and
dispatches the buffers ahead of all other buffers.
This may be used, for example, when the
direct-rendering client holds the hardware lock
while processing a software fallback and requires
that a DMA buffer be processed while the lock is
being held. This may also be used when the X server
is switching hardware contexts. This probably
doesn't make sense without DRM_DMA_BLOCK.DRM_DMA_WAIT will cause the drmDMA call to
wait until request_count buffers are available.
Otherwise, only buffers immediately available will
be returned.DRM_DMA_SMALLER_OK will allow buffers smaller
than request_size to be returned.DRM_DMA_LARGER_OK will allow buffers larger
then request_size to be returned.
int drmFreeBufs(int fd, int count, int *list)
drmFreeBufs will unreserve the buffers in list,
previously reserved using drmDMA. This function is
primarily used for debugging.
Returns 0 on success, and a negative value on failure.
int drmGetLock(int fd, drmContext context, drmLockFlags flags)
drmGetLock will obtain the heavyweight hardware lock
and will return 0. The hardware lock is obtained whenever
the hardware is touched, and holding the lock implies that
no other entity in the system will touch the hardware. For
a complete discussion of the locking algorithms, please see
[FOM99].
Several flags are available that determine the state of the
hardware when drmGetLock returns:
NOTE/FIXME None of these flags are currently implemented, but they will be before the Linux Expo demo.
DRM_LOCK_READY means that the hardware has
completed all DMA dispatches and is ready to receive
another DMA buffer (although the hardware may still be
processing queued commands from the previous dispatch).DRM_LOCK_QUIESCENT means that the hardware has
completed all DMA dispatches and has completely finished
processing the commands in those DMA buffers.DRM_LOCK_FLUSH means that all of the pending DMA
buffers for this context have been dispatched
(combine with the DRM_LOCK_QUIESCENT to dispatch
the buffers and wait for them to be processed).DRM_LOCK_FLUSH_ALL means that all of the pending
DMA buffers for all contexts have been dispatched.
int drmUnlock(int fd, drmContext context)
drmUnlock will release the hardware lock.
Returns 0 on success, and a negative value on failure.
int drmFinish(int fd, drmContext context, drmLockFlags flags)
drmFinish takes the same flags as drmGetLock and
does the same processing, but returns without the lock held.
NOTE/FIXME drmFinish is not currently
implemented, but they will be before the Linux Expo demo.
Returns 0 on success, and a negative value on failure.
Several helper functions are provided for use by the X server
and the direct-rendering client. These functions are
implemented purely in user-space and do not use the
kernel-level ioctl interface.
Simple hash tables are provided that map an unsigned
long key to an unsigned long value. The hash table is
currently not dynamically extensible, but should be
sufficient to store approximately 100-200 object. The hash
function uses a table of random integers, as described by
[Hanson97], and collisions are resolved using a
self-modifying linked list [Knuth73]. Suggestions
for future enhancements and references are included in the
source code.
The interface is described briefly:
void *drmHashCreate(void);
int drmHashDestroy(void *t);
int drmHashLookup(void *t, unsigned long key, unsigned long *value);
int drmHashInsert(void *t, unsigned long key, unsigned long value);
int drmHashDelete(void *t, unsigned long key);
int drmHashFirst(void *t, unsigned long *key, unsigned long *value);
int drmHashNext(void *t, unsigned long *key, unsigned long *value);
A simple, straightforward implementation of the Park and Miller ``Minimal Standard'' PRNG [PM88, PMS93], which is a Lehmer multiplicative linear congruential generator (MLCG) with a period of 2^31-1. This implementation is intended to provide a reliable, portable PRNG that is suitable for testing a hash table implementation and for implementing skip lists (see below). Suggestions for future enhancements and references are included in the source code.
The interface is described briefly:
void *drmRandomCreate(unsigned long seed);
int drmRandomDestroy(void *state);
unsigned long drmRandom(void *state);
double drmRandomDouble(void *state);
Skip lists [Pugh90] are a probabilistic alternative to balanced trees. An implementation is included to support maintenance of ordered lists for texture memory management. Suggestions for future enhancements and references are included in the source code.
The interface is described briefly:
void *drmSLCreate(void);
int drmSLDestroy(void *l);
int drmSLLookup(void *l, unsigned long key, void **value);
int drmSLInsert(void *l, unsigned long key, void *value);
int drmSLDelete(void *l, unsigned long key);
int drmSLNext(void *l, unsigned long *key, void **value);
int drmSLFirst(void *l, unsigned long *key, void **value);
void drmSLDump(void *l);
If the direct-rendering client holds the hardware lock and
receives a SIGKILL signal, deadlock may result. If the
SIGKILL is detected and the hardware lock is immediately
taken from the client, the typical PC-class graphics hardware
may be left in an unknown state and may lock up (this kind of
hardware usually does not deal well with intermingling of
command streams).
Similarly, if the direct-rendering client holds the hardware
lock and receives a SIGSTOP, the X server and all other
direct-rendering clients will block until the process releases
the lock.
Ideally, the client should be permitted to complete the
rendering operation that is currently in progress and have the
SIGKILL or SIGSTOP signals delivered as soon as the
hardware lock is released (or, after some reasonable timeout,
so that buggy clients can be halted). This delay of signal
delivery appears to require kernel-level changes that cannot
be performed by a loadable module using the standard module
interface.
Currently, the /proc/drm interface exports some
performance counters that can be used for debugging and for
gathering performance metrics. The counters currently
available were selected on an ad hoc basis as needed for
debugging the initial SI. Counter selection and presentation
needs to be revisited so that counter that are useful to both
the driver implementor and to the OpenGL application author
are available, together with a user-space application that
computes useful statistics from the counters (e.g., computing
rate from two counter snapshots).
[FM99] Rickard E. Faith and Kevin E. Martin. A Security Analysis of the Direct Rendering Infrastructure. Cedar Park, Texas: Precision Insight, Inc., 1999.
[FOM99] Rickard E. Faith, Jens Owen, and Kevin E. Martin. Hardware Locking for the Direct Rendering Infrastructure. Cedar Park, Texas: Precision Insight, Inc., 1999.
[Hanson97] David R. Hanson. C Interfaces and Implementations: Techniques for Creating Reusable Software. Reading, Massachusetts: Addison-Wesley, 1997.
[Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973.
[MFOA99] Kevin E. Martin, Rickard E. Faith, Jens Owen, Allen Akin. Direct Rendering Infrastructure, Low-Level Design Document. Cedar Park, Texas: Precision Insight, Inc., 1999.
[OM98] Jens Owen and Kevin E. Martin. A Multipipe Direct Rendering Architecture for 3D. Cedar Park, Texas: Precision Insight, Inc., 15 September 1998. Available from http://www.precisioninsight.com/dr/dr.html.
[Plumb99] Colin Plumb, personal communication, 20 March 1999.
[PM88] Stephen K. Park and Keith W. Miller. ``Random Number Generators: Good Ones are Hard to Find.'' CACM 31(10), October 1988, pp. 1192-1201.
[PMS93] Stephen K. Park, Keith W. Miller, and Paul K. Stockmeyer. In ``Technical Correspondence: Remarks on Choosing and Implementing Random Number Generators.'' CACM 36(7), July 1993, pp. 105-110.
[Pugh90] William Pugh. ``Skip Lists: A Probabilistic Alternative to Balanced Trees.'' CACM 33(6), June 1990, pp. 668-676.