mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-01 14:00:16 +01:00
svga/winsys: implement GBS support
This is a squash commit of many commits by Thomas Hellstrom. Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Cc: "10.1" <mesa-stable@lists.freedesktop.org>
This commit is contained in:
parent
59e7c59621
commit
fe6a854477
19 changed files with 3084 additions and 343 deletions
|
|
@ -7,4 +7,6 @@ C_SOURCES := \
|
|||
vmw_screen_ioctl.c \
|
||||
vmw_screen_pools.c \
|
||||
vmw_screen_svga.c \
|
||||
vmw_surface.c
|
||||
vmw_surface.c \
|
||||
vmw_shader.c \
|
||||
pb_buffer_simple_fenced.c
|
||||
|
|
|
|||
844
src/gallium/winsys/svga/drm/pb_buffer_simple_fenced.c
Normal file
844
src/gallium/winsys/svga/drm/pb_buffer_simple_fenced.c
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2007-2010 VMware, Inc.
|
||||
* 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 VMWARE 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.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Implementation of fenced buffers.
|
||||
*
|
||||
* \author Jose Fonseca <jfonseca-at-vmware-dot-com>
|
||||
* \author Thomas Hellström <thellstrom-at-vmware-dot-com>
|
||||
*/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "pipe/p_defines.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "os/os_thread.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_double_list.h"
|
||||
|
||||
#include "pipebuffer/pb_buffer.h"
|
||||
#include "pipebuffer/pb_bufmgr.h"
|
||||
#include "pipebuffer/pb_buffer_fenced.h"
|
||||
#include "vmw_screen.h"
|
||||
|
||||
|
||||
/**
|
||||
* Convenience macro (type safe).
|
||||
*/
|
||||
#define SUPER(__derived) (&(__derived)->base)
|
||||
|
||||
|
||||
struct fenced_manager
|
||||
{
|
||||
struct pb_manager base;
|
||||
struct pb_manager *provider;
|
||||
struct pb_fence_ops *ops;
|
||||
|
||||
/**
|
||||
* Following members are mutable and protected by this mutex.
|
||||
*/
|
||||
pipe_mutex mutex;
|
||||
|
||||
/**
|
||||
* Fenced buffer list.
|
||||
*
|
||||
* All fenced buffers are placed in this listed, ordered from the oldest
|
||||
* fence to the newest fence.
|
||||
*/
|
||||
struct list_head fenced;
|
||||
pb_size num_fenced;
|
||||
|
||||
struct list_head unfenced;
|
||||
pb_size num_unfenced;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fenced buffer.
|
||||
*
|
||||
* Wrapper around a pipe buffer which adds fencing and reference counting.
|
||||
*/
|
||||
struct fenced_buffer
|
||||
{
|
||||
/*
|
||||
* Immutable members.
|
||||
*/
|
||||
|
||||
struct pb_buffer base;
|
||||
struct fenced_manager *mgr;
|
||||
|
||||
/*
|
||||
* Following members are mutable and protected by fenced_manager::mutex.
|
||||
*/
|
||||
|
||||
struct list_head head;
|
||||
|
||||
/**
|
||||
* Buffer with storage.
|
||||
*/
|
||||
struct pb_buffer *buffer;
|
||||
pb_size size;
|
||||
|
||||
/**
|
||||
* A bitmask of PB_USAGE_CPU/GPU_READ/WRITE describing the current
|
||||
* buffer usage.
|
||||
*/
|
||||
unsigned flags;
|
||||
|
||||
unsigned mapcount;
|
||||
|
||||
struct pb_validate *vl;
|
||||
unsigned validation_flags;
|
||||
|
||||
struct pipe_fence_handle *fence;
|
||||
};
|
||||
|
||||
|
||||
static INLINE struct fenced_manager *
|
||||
fenced_manager(struct pb_manager *mgr)
|
||||
{
|
||||
assert(mgr);
|
||||
return (struct fenced_manager *)mgr;
|
||||
}
|
||||
|
||||
|
||||
static INLINE struct fenced_buffer *
|
||||
fenced_buffer(struct pb_buffer *buf)
|
||||
{
|
||||
assert(buf);
|
||||
return (struct fenced_buffer *)buf;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf);
|
||||
|
||||
static enum pipe_error
|
||||
fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf,
|
||||
const struct pb_desc *desc,
|
||||
boolean wait);
|
||||
/**
|
||||
* Dump the fenced buffer list.
|
||||
*
|
||||
* Useful to understand failures to allocate buffers.
|
||||
*/
|
||||
static void
|
||||
fenced_manager_dump_locked(struct fenced_manager *fenced_mgr)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
struct list_head *curr, *next;
|
||||
struct fenced_buffer *fenced_buf;
|
||||
|
||||
debug_printf("%10s %7s %8s %7s %10s %s\n",
|
||||
"buffer", "size", "refcount", "storage", "fence", "signalled");
|
||||
|
||||
curr = fenced_mgr->unfenced.next;
|
||||
next = curr->next;
|
||||
while(curr != &fenced_mgr->unfenced) {
|
||||
fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
|
||||
assert(!fenced_buf->fence);
|
||||
debug_printf("%10p %7u %8u %7s\n",
|
||||
(void *) fenced_buf,
|
||||
fenced_buf->base.size,
|
||||
p_atomic_read(&fenced_buf->base.reference.count),
|
||||
fenced_buf->buffer ? "gpu" : "none");
|
||||
curr = next;
|
||||
next = curr->next;
|
||||
}
|
||||
|
||||
curr = fenced_mgr->fenced.next;
|
||||
next = curr->next;
|
||||
while(curr != &fenced_mgr->fenced) {
|
||||
int signaled;
|
||||
fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
|
||||
assert(fenced_buf->buffer);
|
||||
signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
|
||||
debug_printf("%10p %7u %8u %7s %10p %s\n",
|
||||
(void *) fenced_buf,
|
||||
fenced_buf->base.size,
|
||||
p_atomic_read(&fenced_buf->base.reference.count),
|
||||
"gpu",
|
||||
(void *) fenced_buf->fence,
|
||||
signaled == 0 ? "y" : "n");
|
||||
curr = next;
|
||||
next = curr->next;
|
||||
}
|
||||
#else
|
||||
(void)fenced_mgr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static INLINE void
|
||||
fenced_buffer_destroy_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf)
|
||||
{
|
||||
assert(!pipe_is_referenced(&fenced_buf->base.reference));
|
||||
|
||||
assert(!fenced_buf->fence);
|
||||
assert(fenced_buf->head.prev);
|
||||
assert(fenced_buf->head.next);
|
||||
LIST_DEL(&fenced_buf->head);
|
||||
assert(fenced_mgr->num_unfenced);
|
||||
--fenced_mgr->num_unfenced;
|
||||
|
||||
fenced_buffer_destroy_gpu_storage_locked(fenced_buf);
|
||||
|
||||
FREE(fenced_buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the buffer to the fenced list.
|
||||
*
|
||||
* Reference count should be incremented before calling this function.
|
||||
*/
|
||||
static INLINE void
|
||||
fenced_buffer_add_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf)
|
||||
{
|
||||
assert(pipe_is_referenced(&fenced_buf->base.reference));
|
||||
assert(fenced_buf->flags & PB_USAGE_GPU_READ_WRITE);
|
||||
assert(fenced_buf->fence);
|
||||
|
||||
p_atomic_inc(&fenced_buf->base.reference.count);
|
||||
|
||||
LIST_DEL(&fenced_buf->head);
|
||||
assert(fenced_mgr->num_unfenced);
|
||||
--fenced_mgr->num_unfenced;
|
||||
LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->fenced);
|
||||
++fenced_mgr->num_fenced;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the buffer from the fenced list, and potentially destroy the buffer
|
||||
* if the reference count reaches zero.
|
||||
*
|
||||
* Returns TRUE if the buffer was detroyed.
|
||||
*/
|
||||
static INLINE boolean
|
||||
fenced_buffer_remove_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf)
|
||||
{
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
|
||||
assert(fenced_buf->fence);
|
||||
assert(fenced_buf->mgr == fenced_mgr);
|
||||
|
||||
ops->fence_reference(ops, &fenced_buf->fence, NULL);
|
||||
fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
|
||||
|
||||
assert(fenced_buf->head.prev);
|
||||
assert(fenced_buf->head.next);
|
||||
|
||||
LIST_DEL(&fenced_buf->head);
|
||||
assert(fenced_mgr->num_fenced);
|
||||
--fenced_mgr->num_fenced;
|
||||
|
||||
LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
|
||||
++fenced_mgr->num_unfenced;
|
||||
|
||||
if (p_atomic_dec_zero(&fenced_buf->base.reference.count)) {
|
||||
fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait for the fence to expire, and remove it from the fenced list.
|
||||
*
|
||||
* This function will release and re-aquire the mutex, so any copy of mutable
|
||||
* state must be discarded after calling it.
|
||||
*/
|
||||
static INLINE enum pipe_error
|
||||
fenced_buffer_finish_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf)
|
||||
{
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
enum pipe_error ret = PIPE_ERROR;
|
||||
|
||||
#if 0
|
||||
debug_warning("waiting for GPU");
|
||||
#endif
|
||||
|
||||
assert(pipe_is_referenced(&fenced_buf->base.reference));
|
||||
assert(fenced_buf->fence);
|
||||
|
||||
if(fenced_buf->fence) {
|
||||
struct pipe_fence_handle *fence = NULL;
|
||||
int finished;
|
||||
boolean proceed;
|
||||
|
||||
ops->fence_reference(ops, &fence, fenced_buf->fence);
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
|
||||
finished = ops->fence_finish(ops, fenced_buf->fence, 0);
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
assert(pipe_is_referenced(&fenced_buf->base.reference));
|
||||
|
||||
/*
|
||||
* Only proceed if the fence object didn't change in the meanwhile.
|
||||
* Otherwise assume the work has been already carried out by another
|
||||
* thread that re-aquired the lock before us.
|
||||
*/
|
||||
proceed = fence == fenced_buf->fence ? TRUE : FALSE;
|
||||
|
||||
ops->fence_reference(ops, &fence, NULL);
|
||||
|
||||
if(proceed && finished == 0) {
|
||||
/*
|
||||
* Remove from the fenced list
|
||||
*/
|
||||
|
||||
boolean destroyed;
|
||||
|
||||
destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
|
||||
|
||||
/* TODO: remove consequents buffers with the same fence? */
|
||||
|
||||
assert(!destroyed);
|
||||
|
||||
fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
|
||||
|
||||
ret = PIPE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove as many fenced buffers from the fenced list as possible.
|
||||
*
|
||||
* Returns TRUE if at least one buffer was removed.
|
||||
*/
|
||||
static boolean
|
||||
fenced_manager_check_signalled_locked(struct fenced_manager *fenced_mgr,
|
||||
boolean wait)
|
||||
{
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
struct list_head *curr, *next;
|
||||
struct fenced_buffer *fenced_buf;
|
||||
struct pipe_fence_handle *prev_fence = NULL;
|
||||
boolean ret = FALSE;
|
||||
|
||||
curr = fenced_mgr->fenced.next;
|
||||
next = curr->next;
|
||||
while(curr != &fenced_mgr->fenced) {
|
||||
fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
|
||||
|
||||
if(fenced_buf->fence != prev_fence) {
|
||||
int signaled;
|
||||
|
||||
if (wait) {
|
||||
signaled = ops->fence_finish(ops, fenced_buf->fence, 0);
|
||||
|
||||
/*
|
||||
* Don't return just now. Instead preemptively check if the
|
||||
* following buffers' fences already expired,
|
||||
* without further waits.
|
||||
*/
|
||||
wait = FALSE;
|
||||
}
|
||||
else {
|
||||
signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
|
||||
}
|
||||
|
||||
if (signaled != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
prev_fence = fenced_buf->fence;
|
||||
}
|
||||
else {
|
||||
/* This buffer's fence object is identical to the previous buffer's
|
||||
* fence object, so no need to check the fence again.
|
||||
*/
|
||||
assert(ops->fence_signalled(ops, fenced_buf->fence, 0) == 0);
|
||||
}
|
||||
|
||||
fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
curr = next;
|
||||
next = curr->next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy the GPU storage.
|
||||
*/
|
||||
static void
|
||||
fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf)
|
||||
{
|
||||
if(fenced_buf->buffer) {
|
||||
pb_reference(&fenced_buf->buffer, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to create GPU storage for this buffer.
|
||||
*
|
||||
* This function is a shorthand around pb_manager::create_buffer for
|
||||
* fenced_buffer_create_gpu_storage_locked()'s benefit.
|
||||
*/
|
||||
static INLINE boolean
|
||||
fenced_buffer_try_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf,
|
||||
const struct pb_desc *desc)
|
||||
{
|
||||
struct pb_manager *provider = fenced_mgr->provider;
|
||||
|
||||
assert(!fenced_buf->buffer);
|
||||
|
||||
fenced_buf->buffer = provider->create_buffer(fenced_mgr->provider,
|
||||
fenced_buf->size, desc);
|
||||
return fenced_buf->buffer ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create GPU storage for this buffer.
|
||||
*/
|
||||
static enum pipe_error
|
||||
fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
|
||||
struct fenced_buffer *fenced_buf,
|
||||
const struct pb_desc *desc,
|
||||
boolean wait)
|
||||
{
|
||||
assert(!fenced_buf->buffer);
|
||||
|
||||
/*
|
||||
* Check for signaled buffers before trying to allocate.
|
||||
*/
|
||||
fenced_manager_check_signalled_locked(fenced_mgr, FALSE);
|
||||
|
||||
fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf, desc);
|
||||
|
||||
/*
|
||||
* Keep trying while there is some sort of progress:
|
||||
* - fences are expiring,
|
||||
* - or buffers are being being swapped out from GPU memory into CPU memory.
|
||||
*/
|
||||
while(!fenced_buf->buffer &&
|
||||
(fenced_manager_check_signalled_locked(fenced_mgr, FALSE))) {
|
||||
fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf,
|
||||
desc);
|
||||
}
|
||||
|
||||
if(!fenced_buf->buffer && wait) {
|
||||
/*
|
||||
* Same as before, but this time around, wait to free buffers if
|
||||
* necessary.
|
||||
*/
|
||||
while(!fenced_buf->buffer &&
|
||||
(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))) {
|
||||
fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf,
|
||||
desc);
|
||||
}
|
||||
}
|
||||
|
||||
if(!fenced_buf->buffer) {
|
||||
if(0)
|
||||
fenced_manager_dump_locked(fenced_mgr);
|
||||
|
||||
/* give up */
|
||||
return PIPE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return PIPE_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_buffer_destroy(struct pb_buffer *buf)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
|
||||
assert(!pipe_is_referenced(&fenced_buf->base.reference));
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
fenced_buffer_map(struct pb_buffer *buf,
|
||||
unsigned flags, void *flush_ctx)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
void *map = NULL;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
assert(!(flags & PB_USAGE_GPU_READ_WRITE));
|
||||
|
||||
/*
|
||||
* Serialize writes.
|
||||
*/
|
||||
while((fenced_buf->flags & PB_USAGE_GPU_WRITE) ||
|
||||
((fenced_buf->flags & PB_USAGE_GPU_READ) &&
|
||||
(flags & PB_USAGE_CPU_WRITE))) {
|
||||
|
||||
/*
|
||||
* Don't wait for the GPU to finish accessing it,
|
||||
* if blocking is forbidden.
|
||||
*/
|
||||
if((flags & PB_USAGE_DONTBLOCK) &&
|
||||
ops->fence_signalled(ops, fenced_buf->fence, 0) != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (flags & PB_USAGE_UNSYNCHRONIZED) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the GPU to finish accessing. This will release and re-acquire
|
||||
* the mutex, so all copies of mutable state must be discarded.
|
||||
*/
|
||||
fenced_buffer_finish_locked(fenced_mgr, fenced_buf);
|
||||
}
|
||||
|
||||
map = pb_map(fenced_buf->buffer, flags, flush_ctx);
|
||||
|
||||
if(map) {
|
||||
++fenced_buf->mapcount;
|
||||
fenced_buf->flags |= flags & PB_USAGE_CPU_READ_WRITE;
|
||||
}
|
||||
|
||||
done:
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_buffer_unmap(struct pb_buffer *buf)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
assert(fenced_buf->mapcount);
|
||||
if(fenced_buf->mapcount) {
|
||||
if (fenced_buf->buffer)
|
||||
pb_unmap(fenced_buf->buffer);
|
||||
--fenced_buf->mapcount;
|
||||
if(!fenced_buf->mapcount)
|
||||
fenced_buf->flags &= ~PB_USAGE_CPU_READ_WRITE;
|
||||
}
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
}
|
||||
|
||||
|
||||
static enum pipe_error
|
||||
fenced_buffer_validate(struct pb_buffer *buf,
|
||||
struct pb_validate *vl,
|
||||
unsigned flags)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
enum pipe_error ret;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
if(!vl) {
|
||||
/* invalidate */
|
||||
fenced_buf->vl = NULL;
|
||||
fenced_buf->validation_flags = 0;
|
||||
ret = PIPE_OK;
|
||||
goto done;
|
||||
}
|
||||
|
||||
assert(flags & PB_USAGE_GPU_READ_WRITE);
|
||||
assert(!(flags & ~PB_USAGE_GPU_READ_WRITE));
|
||||
flags &= PB_USAGE_GPU_READ_WRITE;
|
||||
|
||||
/* Buffer cannot be validated in two different lists */
|
||||
if(fenced_buf->vl && fenced_buf->vl != vl) {
|
||||
ret = PIPE_ERROR_RETRY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(fenced_buf->vl == vl &&
|
||||
(fenced_buf->validation_flags & flags) == flags) {
|
||||
/* Nothing to do -- buffer already validated */
|
||||
ret = PIPE_OK;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = pb_validate(fenced_buf->buffer, vl, flags);
|
||||
if (ret != PIPE_OK)
|
||||
goto done;
|
||||
|
||||
fenced_buf->vl = vl;
|
||||
fenced_buf->validation_flags |= flags;
|
||||
|
||||
done:
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_buffer_fence(struct pb_buffer *buf,
|
||||
struct pipe_fence_handle *fence)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
struct pb_fence_ops *ops = fenced_mgr->ops;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
assert(pipe_is_referenced(&fenced_buf->base.reference));
|
||||
assert(fenced_buf->buffer);
|
||||
|
||||
if(fence != fenced_buf->fence) {
|
||||
assert(fenced_buf->vl);
|
||||
assert(fenced_buf->validation_flags);
|
||||
|
||||
if (fenced_buf->fence) {
|
||||
boolean destroyed;
|
||||
destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
|
||||
assert(!destroyed);
|
||||
}
|
||||
if (fence) {
|
||||
ops->fence_reference(ops, &fenced_buf->fence, fence);
|
||||
fenced_buf->flags |= fenced_buf->validation_flags;
|
||||
fenced_buffer_add_locked(fenced_mgr, fenced_buf);
|
||||
}
|
||||
|
||||
pb_fence(fenced_buf->buffer, fence);
|
||||
|
||||
fenced_buf->vl = NULL;
|
||||
fenced_buf->validation_flags = 0;
|
||||
}
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_buffer_get_base_buffer(struct pb_buffer *buf,
|
||||
struct pb_buffer **base_buf,
|
||||
pb_size *offset)
|
||||
{
|
||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||
struct fenced_manager *fenced_mgr = fenced_buf->mgr;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
assert(fenced_buf->buffer);
|
||||
|
||||
if(fenced_buf->buffer)
|
||||
pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
|
||||
else {
|
||||
*base_buf = buf;
|
||||
*offset = 0;
|
||||
}
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
}
|
||||
|
||||
|
||||
static const struct pb_vtbl
|
||||
fenced_buffer_vtbl = {
|
||||
fenced_buffer_destroy,
|
||||
fenced_buffer_map,
|
||||
fenced_buffer_unmap,
|
||||
fenced_buffer_validate,
|
||||
fenced_buffer_fence,
|
||||
fenced_buffer_get_base_buffer
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a buffer in a fenced buffer.
|
||||
*/
|
||||
static struct pb_buffer *
|
||||
fenced_bufmgr_create_buffer(struct pb_manager *mgr,
|
||||
pb_size size,
|
||||
const struct pb_desc *desc)
|
||||
{
|
||||
struct fenced_manager *fenced_mgr = fenced_manager(mgr);
|
||||
struct fenced_buffer *fenced_buf;
|
||||
enum pipe_error ret;
|
||||
|
||||
fenced_buf = CALLOC_STRUCT(fenced_buffer);
|
||||
if(!fenced_buf)
|
||||
goto no_buffer;
|
||||
|
||||
pipe_reference_init(&fenced_buf->base.reference, 1);
|
||||
fenced_buf->base.alignment = desc->alignment;
|
||||
fenced_buf->base.usage = desc->usage;
|
||||
fenced_buf->base.size = size;
|
||||
fenced_buf->size = size;
|
||||
|
||||
fenced_buf->base.vtbl = &fenced_buffer_vtbl;
|
||||
fenced_buf->mgr = fenced_mgr;
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
/*
|
||||
* Try to create GPU storage without stalling,
|
||||
*/
|
||||
ret = fenced_buffer_create_gpu_storage_locked(fenced_mgr, fenced_buf,
|
||||
desc, TRUE);
|
||||
|
||||
/*
|
||||
* Give up.
|
||||
*/
|
||||
if(ret != PIPE_OK) {
|
||||
goto no_storage;
|
||||
}
|
||||
|
||||
assert(fenced_buf->buffer);
|
||||
|
||||
LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
|
||||
++fenced_mgr->num_unfenced;
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
|
||||
return &fenced_buf->base;
|
||||
|
||||
no_storage:
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
FREE(fenced_buf);
|
||||
no_buffer:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_bufmgr_flush(struct pb_manager *mgr)
|
||||
{
|
||||
struct fenced_manager *fenced_mgr = fenced_manager(mgr);
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
|
||||
;
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
|
||||
assert(fenced_mgr->provider->flush);
|
||||
if(fenced_mgr->provider->flush)
|
||||
fenced_mgr->provider->flush(fenced_mgr->provider);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fenced_bufmgr_destroy(struct pb_manager *mgr)
|
||||
{
|
||||
struct fenced_manager *fenced_mgr = fenced_manager(mgr);
|
||||
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
|
||||
/* Wait on outstanding fences */
|
||||
while (fenced_mgr->num_fenced) {
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)
|
||||
sched_yield();
|
||||
#endif
|
||||
pipe_mutex_lock(fenced_mgr->mutex);
|
||||
while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*assert(!fenced_mgr->num_unfenced);*/
|
||||
#endif
|
||||
|
||||
pipe_mutex_unlock(fenced_mgr->mutex);
|
||||
pipe_mutex_destroy(fenced_mgr->mutex);
|
||||
|
||||
FREE(fenced_mgr);
|
||||
}
|
||||
|
||||
|
||||
struct pb_manager *
|
||||
simple_fenced_bufmgr_create(struct pb_manager *provider,
|
||||
struct pb_fence_ops *ops)
|
||||
{
|
||||
struct fenced_manager *fenced_mgr;
|
||||
|
||||
if(!provider)
|
||||
return NULL;
|
||||
|
||||
fenced_mgr = CALLOC_STRUCT(fenced_manager);
|
||||
if (!fenced_mgr)
|
||||
return NULL;
|
||||
|
||||
fenced_mgr->base.destroy = fenced_bufmgr_destroy;
|
||||
fenced_mgr->base.create_buffer = fenced_bufmgr_create_buffer;
|
||||
fenced_mgr->base.flush = fenced_bufmgr_flush;
|
||||
|
||||
fenced_mgr->provider = provider;
|
||||
fenced_mgr->ops = ops;
|
||||
|
||||
LIST_INITHEAD(&fenced_mgr->fenced);
|
||||
fenced_mgr->num_fenced = 0;
|
||||
|
||||
LIST_INITHEAD(&fenced_mgr->unfenced);
|
||||
fenced_mgr->num_unfenced = 0;
|
||||
|
||||
pipe_mutex_init(fenced_mgr->mutex);
|
||||
|
||||
return &fenced_mgr->base;
|
||||
}
|
||||
|
|
@ -51,7 +51,6 @@
|
|||
#include "vmw_screen.h"
|
||||
#include "vmw_buffer.h"
|
||||
|
||||
|
||||
struct vmw_gmr_bufmgr;
|
||||
|
||||
|
||||
|
|
@ -63,6 +62,7 @@ struct vmw_gmr_buffer
|
|||
|
||||
struct vmw_region *region;
|
||||
void *map;
|
||||
unsigned map_flags;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -113,6 +113,25 @@ vmw_gmr_buffer_map(struct pb_buffer *_buf,
|
|||
void *flush_ctx)
|
||||
{
|
||||
struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf);
|
||||
int ret;
|
||||
|
||||
if (!buf->map)
|
||||
buf->map = vmw_ioctl_region_map(buf->region);
|
||||
|
||||
if (!buf->map)
|
||||
return NULL;
|
||||
|
||||
|
||||
if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) &&
|
||||
!(flags & PB_USAGE_UNSYNCHRONIZED)) {
|
||||
ret = vmw_ioctl_syncforcpu(buf->region,
|
||||
!!(flags & PB_USAGE_DONTBLOCK),
|
||||
!(flags & PB_USAGE_CPU_WRITE),
|
||||
FALSE);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf->map;
|
||||
}
|
||||
|
||||
|
|
@ -120,8 +139,15 @@ vmw_gmr_buffer_map(struct pb_buffer *_buf,
|
|||
static void
|
||||
vmw_gmr_buffer_unmap(struct pb_buffer *_buf)
|
||||
{
|
||||
/* Do nothing */
|
||||
(void)_buf;
|
||||
struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf);
|
||||
unsigned flags = buf->map_flags;
|
||||
|
||||
if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) &&
|
||||
!(flags & PB_USAGE_UNSYNCHRONIZED)) {
|
||||
vmw_ioctl_releasefromcpu(buf->region,
|
||||
!(flags & PB_USAGE_CPU_WRITE),
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -167,35 +193,33 @@ const struct pb_vtbl vmw_gmr_buffer_vtbl = {
|
|||
static struct pb_buffer *
|
||||
vmw_gmr_bufmgr_create_buffer(struct pb_manager *_mgr,
|
||||
pb_size size,
|
||||
const struct pb_desc *desc)
|
||||
const struct pb_desc *pb_desc)
|
||||
{
|
||||
struct vmw_gmr_bufmgr *mgr = vmw_gmr_bufmgr(_mgr);
|
||||
struct vmw_winsys_screen *vws = mgr->vws;
|
||||
struct vmw_gmr_buffer *buf;
|
||||
const struct vmw_buffer_desc *desc =
|
||||
(const struct vmw_buffer_desc *) pb_desc;
|
||||
|
||||
buf = CALLOC_STRUCT(vmw_gmr_buffer);
|
||||
if(!buf)
|
||||
goto error1;
|
||||
|
||||
pipe_reference_init(&buf->base.reference, 1);
|
||||
buf->base.alignment = desc->alignment;
|
||||
buf->base.usage = desc->usage;
|
||||
buf->base.size = size;
|
||||
buf->base.alignment = pb_desc->alignment;
|
||||
buf->base.usage = pb_desc->usage & ~VMW_BUFFER_USAGE_SHARED;
|
||||
buf->base.vtbl = &vmw_gmr_buffer_vtbl;
|
||||
buf->mgr = mgr;
|
||||
|
||||
buf->region = vmw_ioctl_region_create(vws, size);
|
||||
if(!buf->region)
|
||||
goto error2;
|
||||
buf->base.size = size;
|
||||
if ((pb_desc->usage & VMW_BUFFER_USAGE_SHARED) && desc->region) {
|
||||
buf->region = desc->region;
|
||||
} else {
|
||||
buf->region = vmw_ioctl_region_create(vws, size);
|
||||
if(!buf->region)
|
||||
goto error2;
|
||||
}
|
||||
|
||||
buf->map = vmw_ioctl_region_map(buf->region);
|
||||
if(!buf->map)
|
||||
goto error3;
|
||||
|
||||
return &buf->base;
|
||||
|
||||
error3:
|
||||
vmw_ioctl_region_destroy(buf->region);
|
||||
error2:
|
||||
FREE(buf);
|
||||
error1:
|
||||
|
|
@ -257,3 +281,91 @@ vmw_gmr_bufmgr_region_ptr(struct pb_buffer *buf,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
struct svga_winsys_buffer {
|
||||
struct pb_buffer *pb_buf;
|
||||
struct debug_flush_buf *fbuf;
|
||||
};
|
||||
|
||||
struct pb_buffer *
|
||||
vmw_pb_buffer(struct svga_winsys_buffer *buffer)
|
||||
{
|
||||
assert(buffer);
|
||||
return buffer->pb_buf;
|
||||
}
|
||||
|
||||
struct svga_winsys_buffer *
|
||||
vmw_svga_winsys_buffer_wrap(struct pb_buffer *buffer)
|
||||
{
|
||||
struct svga_winsys_buffer *buf;
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
buf = CALLOC_STRUCT(svga_winsys_buffer);
|
||||
if (!buf) {
|
||||
pb_reference(&buffer, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf->pb_buf = buffer;
|
||||
buf->fbuf = debug_flush_buf_create(TRUE, VMW_DEBUG_FLUSH_STACK);
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct debug_flush_buf *
|
||||
vmw_debug_flush_buf(struct svga_winsys_buffer *buffer)
|
||||
{
|
||||
return buffer->fbuf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
vmw_svga_winsys_buffer_destroy(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf)
|
||||
{
|
||||
struct pb_buffer *pbuf = vmw_pb_buffer(buf);
|
||||
(void)sws;
|
||||
pb_reference(&pbuf, NULL);
|
||||
#ifdef DEBUG
|
||||
debug_flush_buf_reference(&buf->fbuf, NULL);
|
||||
FREE(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *
|
||||
vmw_svga_winsys_buffer_map(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf,
|
||||
unsigned flags)
|
||||
{
|
||||
void *map;
|
||||
|
||||
(void)sws;
|
||||
if (flags & PIPE_TRANSFER_UNSYNCHRONIZED)
|
||||
flags &= ~PIPE_TRANSFER_DONTBLOCK;
|
||||
|
||||
map = pb_map(vmw_pb_buffer(buf), flags, NULL);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (map != NULL)
|
||||
debug_flush_map(buf->fbuf, flags);
|
||||
#endif
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vmw_svga_winsys_buffer_unmap(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf)
|
||||
{
|
||||
(void)sws;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug_flush_unmap(buf->fbuf);
|
||||
#endif
|
||||
|
||||
pb_unmap(vmw_pb_buffer(buf));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "pipebuffer/pb_bufmgr.h"
|
||||
#include "util/u_debug_flush.h"
|
||||
|
||||
|
||||
#define VMW_BUFFER_USAGE_SHARED (1 << 20)
|
||||
#define VMW_BUFFER_USAGE_SYNC (1 << 21)
|
||||
|
||||
struct SVGAGuestPtr;
|
||||
struct pb_buffer;
|
||||
|
|
@ -37,7 +43,22 @@ struct svga_winsys_buffer;
|
|||
struct svga_winsys_surface;
|
||||
struct vmw_winsys_screen;
|
||||
|
||||
struct vmw_buffer_desc {
|
||||
struct pb_desc pb_desc;
|
||||
struct vmw_region *region;
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
struct pb_buffer *
|
||||
vmw_pb_buffer(struct svga_winsys_buffer *buffer);
|
||||
struct svga_winsys_buffer *
|
||||
vmw_svga_winsys_buffer_wrap(struct pb_buffer *buffer);
|
||||
struct debug_flush_buf *
|
||||
vmw_debug_flush_buf(struct svga_winsys_buffer *buffer);
|
||||
|
||||
#else
|
||||
static INLINE struct pb_buffer *
|
||||
vmw_pb_buffer(struct svga_winsys_buffer *buffer)
|
||||
{
|
||||
|
|
@ -47,12 +68,23 @@ vmw_pb_buffer(struct svga_winsys_buffer *buffer)
|
|||
|
||||
|
||||
static INLINE struct svga_winsys_buffer *
|
||||
vmw_svga_winsys_buffer(struct pb_buffer *buffer)
|
||||
vmw_svga_winsys_buffer_wrap(struct pb_buffer *buffer)
|
||||
{
|
||||
assert(buffer);
|
||||
return (struct svga_winsys_buffer *)buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
vmw_svga_winsys_buffer_destroy(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf);
|
||||
void *
|
||||
vmw_svga_winsys_buffer_map(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf,
|
||||
unsigned flags);
|
||||
|
||||
void
|
||||
vmw_svga_winsys_buffer_unmap(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf);
|
||||
|
||||
struct pb_manager *
|
||||
vmw_gmr_bufmgr_create(struct vmw_winsys_screen *vws);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_debug_stack.h"
|
||||
#include "util/u_debug_flush.h"
|
||||
#include "util/u_hash_table.h"
|
||||
#include "pipebuffer/pb_buffer.h"
|
||||
#include "pipebuffer/pb_validate.h"
|
||||
|
||||
|
|
@ -38,19 +40,38 @@
|
|||
#include "vmw_buffer.h"
|
||||
#include "vmw_surface.h"
|
||||
#include "vmw_fence.h"
|
||||
#include "vmw_shader.h"
|
||||
|
||||
#define VMW_COMMAND_SIZE (64*1024)
|
||||
#define VMW_SURFACE_RELOCS (1024)
|
||||
#define VMW_SHADER_RELOCS (1024)
|
||||
#define VMW_REGION_RELOCS (512)
|
||||
|
||||
#define VMW_MUST_FLUSH_STACK 8
|
||||
|
||||
struct vmw_region_relocation
|
||||
struct vmw_buffer_relocation
|
||||
{
|
||||
struct SVGAGuestPtr *where;
|
||||
struct pb_buffer *buffer;
|
||||
/* TODO: put offset info inside where */
|
||||
boolean is_mob;
|
||||
uint32 offset;
|
||||
|
||||
union {
|
||||
struct {
|
||||
struct SVGAGuestPtr *where;
|
||||
} region;
|
||||
struct {
|
||||
SVGAMobId *id;
|
||||
uint32 *offset_into_mob;
|
||||
} mob;
|
||||
};
|
||||
};
|
||||
|
||||
struct vmw_ctx_validate_item {
|
||||
union {
|
||||
struct vmw_svga_winsys_surface *vsurf;
|
||||
struct vmw_svga_winsys_shader *vshader;
|
||||
};
|
||||
boolean referenced;
|
||||
};
|
||||
|
||||
struct vmw_svga_winsys_context
|
||||
|
|
@ -58,10 +79,12 @@ struct vmw_svga_winsys_context
|
|||
struct svga_winsys_context base;
|
||||
|
||||
struct vmw_winsys_screen *vws;
|
||||
struct util_hash_table *hash;
|
||||
|
||||
#ifdef DEBUG
|
||||
boolean must_flush;
|
||||
struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
|
||||
struct debug_flush_ctx *fctx;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
|
|
@ -72,7 +95,7 @@ struct vmw_svga_winsys_context
|
|||
} command;
|
||||
|
||||
struct {
|
||||
struct vmw_svga_winsys_surface *handles[VMW_SURFACE_RELOCS];
|
||||
struct vmw_ctx_validate_item items[VMW_SURFACE_RELOCS];
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
uint32_t staged;
|
||||
|
|
@ -80,20 +103,30 @@ struct vmw_svga_winsys_context
|
|||
} surface;
|
||||
|
||||
struct {
|
||||
struct vmw_region_relocation relocs[VMW_REGION_RELOCS];
|
||||
struct vmw_buffer_relocation relocs[VMW_REGION_RELOCS];
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
uint32_t staged;
|
||||
uint32_t reserved;
|
||||
} region;
|
||||
|
||||
struct {
|
||||
struct vmw_ctx_validate_item items[VMW_SHADER_RELOCS];
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
uint32_t staged;
|
||||
uint32_t reserved;
|
||||
} shader;
|
||||
|
||||
struct pb_validate *validate;
|
||||
|
||||
/**
|
||||
* The amount of GMR that is referred by the commands currently batched
|
||||
* in the context.
|
||||
* The amount of surface, GMR or MOB memory that is referred by the commands
|
||||
* currently batched in the context command buffer.
|
||||
*/
|
||||
uint32_t seen_regions;
|
||||
uint64_t seen_surfaces;
|
||||
uint64_t seen_regions;
|
||||
uint64_t seen_mobs;
|
||||
|
||||
/**
|
||||
* Whether this context should fail to reserve more commands, not because it
|
||||
|
|
@ -140,7 +173,7 @@ vmw_swc_flush(struct svga_winsys_context *swc,
|
|||
|
||||
/* Apply relocations */
|
||||
for(i = 0; i < vswc->region.used; ++i) {
|
||||
struct vmw_region_relocation *reloc = &vswc->region.relocs[i];
|
||||
struct vmw_buffer_relocation *reloc = &vswc->region.relocs[i];
|
||||
struct SVGAGuestPtr ptr;
|
||||
|
||||
if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr))
|
||||
|
|
@ -148,7 +181,16 @@ vmw_swc_flush(struct svga_winsys_context *swc,
|
|||
|
||||
ptr.offset += reloc->offset;
|
||||
|
||||
*reloc->where = ptr;
|
||||
if (reloc->is_mob) {
|
||||
if (reloc->mob.id)
|
||||
*reloc->mob.id = ptr.gmrId;
|
||||
if (reloc->mob.offset_into_mob)
|
||||
*reloc->mob.offset_into_mob = ptr.offset;
|
||||
else {
|
||||
assert(ptr.offset == 0);
|
||||
}
|
||||
} else
|
||||
*reloc->region.where = ptr;
|
||||
}
|
||||
|
||||
if (vswc->command.used || pfence != NULL)
|
||||
|
|
@ -166,27 +208,37 @@ vmw_swc_flush(struct svga_winsys_context *swc,
|
|||
vswc->command.reserved = 0;
|
||||
|
||||
for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
|
||||
struct vmw_svga_winsys_surface *vsurf =
|
||||
vswc->surface.handles[i];
|
||||
p_atomic_dec(&vsurf->validated);
|
||||
vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
|
||||
struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
|
||||
if (isurf->referenced)
|
||||
p_atomic_dec(&isurf->vsurf->validated);
|
||||
vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
|
||||
}
|
||||
|
||||
util_hash_table_clear(vswc->hash);
|
||||
vswc->surface.used = 0;
|
||||
vswc->surface.reserved = 0;
|
||||
|
||||
for(i = 0; i < vswc->region.used + vswc->region.staged; ++i) {
|
||||
pb_reference(&vswc->region.relocs[i].buffer, NULL);
|
||||
for(i = 0; i < vswc->shader.used + vswc->shader.staged; ++i) {
|
||||
struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
|
||||
if (ishader->referenced)
|
||||
p_atomic_dec(&ishader->vshader->validated);
|
||||
vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
|
||||
}
|
||||
|
||||
vswc->shader.used = 0;
|
||||
vswc->shader.reserved = 0;
|
||||
|
||||
vswc->region.used = 0;
|
||||
vswc->region.reserved = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
vswc->must_flush = FALSE;
|
||||
debug_flush_flush(vswc->fctx);
|
||||
#endif
|
||||
vswc->preemptive_flush = FALSE;
|
||||
vswc->seen_surfaces = 0;
|
||||
vswc->seen_regions = 0;
|
||||
vswc->seen_mobs = 0;
|
||||
|
||||
if(pfence)
|
||||
vmw_fence_reference(vswc->vws, pfence, fence);
|
||||
|
|
@ -210,6 +262,7 @@ vmw_swc_reserve(struct svga_winsys_context *swc,
|
|||
debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
|
||||
assert(!vswc->must_flush);
|
||||
}
|
||||
debug_flush_might_flush(vswc->fctx);
|
||||
#endif
|
||||
|
||||
assert(nr_bytes <= vswc->command.size);
|
||||
|
|
@ -219,6 +272,7 @@ vmw_swc_reserve(struct svga_winsys_context *swc,
|
|||
if(vswc->preemptive_flush ||
|
||||
vswc->command.used + nr_bytes > vswc->command.size ||
|
||||
vswc->surface.used + nr_relocs > vswc->surface.size ||
|
||||
vswc->shader.used + nr_relocs > vswc->shader.size ||
|
||||
vswc->region.used + nr_relocs > vswc->region.size) {
|
||||
#ifdef DEBUG
|
||||
vswc->must_flush = TRUE;
|
||||
|
|
@ -230,44 +284,51 @@ vmw_swc_reserve(struct svga_winsys_context *swc,
|
|||
|
||||
assert(vswc->command.used + nr_bytes <= vswc->command.size);
|
||||
assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
|
||||
assert(vswc->shader.used + nr_relocs <= vswc->shader.size);
|
||||
assert(vswc->region.used + nr_relocs <= vswc->region.size);
|
||||
|
||||
vswc->command.reserved = nr_bytes;
|
||||
vswc->surface.reserved = nr_relocs;
|
||||
vswc->surface.staged = 0;
|
||||
vswc->shader.reserved = nr_relocs;
|
||||
vswc->shader.staged = 0;
|
||||
vswc->region.reserved = nr_relocs;
|
||||
vswc->region.staged = 0;
|
||||
|
||||
return vswc->command.buffer + vswc->command.used;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vmw_swc_surface_relocation(struct svga_winsys_context *swc,
|
||||
uint32 *where,
|
||||
uint32 *mobid,
|
||||
struct svga_winsys_surface *surface,
|
||||
unsigned flags)
|
||||
vmw_swc_context_relocation(struct svga_winsys_context *swc,
|
||||
uint32 *cid)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_svga_winsys_surface *vsurf;
|
||||
|
||||
if(!surface) {
|
||||
*where = SVGA3D_INVALID_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vswc->surface.staged < vswc->surface.reserved);
|
||||
|
||||
vsurf = vmw_svga_winsys_surface(surface);
|
||||
|
||||
*where = vsurf->sid;
|
||||
|
||||
vmw_svga_winsys_surface_reference(&vswc->surface.handles[vswc->surface.used + vswc->surface.staged], vsurf);
|
||||
p_atomic_inc(&vsurf->validated);
|
||||
++vswc->surface.staged;
|
||||
*cid = swc->cid;
|
||||
}
|
||||
|
||||
static boolean
|
||||
vmw_swc_add_validate_buffer(struct vmw_svga_winsys_context *vswc,
|
||||
struct pb_buffer *pb_buf,
|
||||
unsigned flags)
|
||||
{
|
||||
enum pipe_error ret;
|
||||
unsigned translated_flags;
|
||||
|
||||
/*
|
||||
* TODO: Update pb_validate to provide a similar functionality
|
||||
* (Check buffer already present before adding)
|
||||
*/
|
||||
if (util_hash_table_get(vswc->hash, pb_buf) != pb_buf) {
|
||||
translated_flags = vmw_translate_to_pb_flags(flags);
|
||||
ret = pb_validate_add_buffer(vswc->validate, pb_buf, translated_flags);
|
||||
/* TODO: Update pipebuffer to reserve buffers and not fail here */
|
||||
assert(ret == PIPE_OK);
|
||||
(void)ret;
|
||||
(void)util_hash_table_set(vswc->hash, pb_buf, pb_buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_region_relocation(struct svga_winsys_context *swc,
|
||||
|
|
@ -277,46 +338,216 @@ vmw_swc_region_relocation(struct svga_winsys_context *swc,
|
|||
unsigned flags)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_region_relocation *reloc;
|
||||
unsigned translated_flags;
|
||||
enum pipe_error ret;
|
||||
|
||||
struct vmw_buffer_relocation *reloc;
|
||||
|
||||
assert(vswc->region.staged < vswc->region.reserved);
|
||||
|
||||
reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
|
||||
reloc->where = where;
|
||||
pb_reference(&reloc->buffer, vmw_pb_buffer(buffer));
|
||||
reloc->offset = offset;
|
||||
|
||||
++vswc->region.staged;
|
||||
|
||||
translated_flags = vmw_translate_to_pb_flags(flags);
|
||||
ret = pb_validate_add_buffer(vswc->validate, reloc->buffer, translated_flags);
|
||||
/* TODO: Update pipebuffer to reserve buffers and not fail here */
|
||||
assert(ret == PIPE_OK);
|
||||
(void)ret;
|
||||
reloc->region.where = where;
|
||||
|
||||
/*
|
||||
* Flush preemptively the FIFO commands to keep the GMR working set within
|
||||
* the GMR pool size.
|
||||
*
|
||||
* This is necessary for applications like SPECviewperf that generate huge
|
||||
* amounts of immediate vertex data, so that we don't pile up too much of
|
||||
* that vertex data neither in the guest nor in the host.
|
||||
*
|
||||
* Note that in the current implementation if a region is referred twice in
|
||||
* a command stream, it will be accounted twice. We could detect repeated
|
||||
* regions and count only once, but there is no incentive to do that, since
|
||||
* regions are typically short-lived; always referred in a single command;
|
||||
* and at the worst we just flush the commands a bit sooner, which for the
|
||||
* SVGA virtual device it's not a performance issue since flushing commands
|
||||
* to the FIFO won't cause flushing in the host.
|
||||
* pb_validate holds a refcount to the buffer, so no need to
|
||||
* refcount it again in the relocation.
|
||||
*/
|
||||
vswc->seen_regions += reloc->buffer->size;
|
||||
if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/3)
|
||||
vswc->preemptive_flush = TRUE;
|
||||
reloc->buffer = vmw_pb_buffer(buffer);
|
||||
reloc->offset = offset;
|
||||
reloc->is_mob = FALSE;
|
||||
++vswc->region.staged;
|
||||
|
||||
if (vmw_swc_add_validate_buffer(vswc, reloc->buffer, flags)) {
|
||||
vswc->seen_regions += reloc->buffer->size;
|
||||
if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/5)
|
||||
vswc->preemptive_flush = TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!(flags & SVGA_RELOC_INTERNAL))
|
||||
debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_mob_relocation(struct svga_winsys_context *swc,
|
||||
SVGAMobId *id,
|
||||
uint32 *offset_into_mob,
|
||||
struct svga_winsys_buffer *buffer,
|
||||
uint32 offset,
|
||||
unsigned flags)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_buffer_relocation *reloc;
|
||||
|
||||
assert(vswc->region.staged < vswc->region.reserved);
|
||||
|
||||
reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
|
||||
reloc->mob.id = id;
|
||||
reloc->mob.offset_into_mob = offset_into_mob;
|
||||
|
||||
/*
|
||||
* pb_validate holds a refcount to the buffer, so no need to
|
||||
* refcount it again in the relocation.
|
||||
*/
|
||||
reloc->buffer = vmw_pb_buffer(buffer);
|
||||
reloc->offset = offset;
|
||||
reloc->is_mob = TRUE;
|
||||
++vswc->region.staged;
|
||||
|
||||
if (vmw_swc_add_validate_buffer(vswc, reloc->buffer, flags)) {
|
||||
vswc->seen_mobs += reloc->buffer->size;
|
||||
/* divide by 5, tested for best performance */
|
||||
if (vswc->seen_mobs >= vswc->vws->ioctl.max_mob_memory / 5)
|
||||
vswc->preemptive_flush = TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!(flags & SVGA_RELOC_INTERNAL))
|
||||
debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_swc_surface_clear_reference - Clear referenced info for a surface
|
||||
*
|
||||
* @swc: Pointer to an svga_winsys_context
|
||||
* @vsurf: Pointer to a vmw_svga_winsys_surface, the referenced info of which
|
||||
* we want to clear
|
||||
*
|
||||
* This is primarily used by a discard surface map to indicate that the
|
||||
* surface data is no longer referenced by a draw call, and mapping it
|
||||
* should therefore no longer cause a flush.
|
||||
*/
|
||||
void
|
||||
vmw_swc_surface_clear_reference(struct svga_winsys_context *swc,
|
||||
struct vmw_svga_winsys_surface *vsurf)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_ctx_validate_item *isrf =
|
||||
util_hash_table_get(vswc->hash, vsurf);
|
||||
|
||||
if (isrf && isrf->referenced) {
|
||||
isrf->referenced = FALSE;
|
||||
p_atomic_dec(&vsurf->validated);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_surface_only_relocation(struct svga_winsys_context *swc,
|
||||
uint32 *where,
|
||||
struct vmw_svga_winsys_surface *vsurf,
|
||||
unsigned flags)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_ctx_validate_item *isrf;
|
||||
|
||||
assert(vswc->surface.staged < vswc->surface.reserved);
|
||||
isrf = util_hash_table_get(vswc->hash, vsurf);
|
||||
|
||||
if (isrf == NULL) {
|
||||
isrf = &vswc->surface.items[vswc->surface.used + vswc->surface.staged];
|
||||
vmw_svga_winsys_surface_reference(&isrf->vsurf, vsurf);
|
||||
isrf->referenced = FALSE;
|
||||
/*
|
||||
* Note that a failure here may just fall back to unhashed behavior
|
||||
* and potentially cause unnecessary flushing, so ignore the
|
||||
* return code.
|
||||
*/
|
||||
(void) util_hash_table_set(vswc->hash, vsurf, isrf);
|
||||
++vswc->surface.staged;
|
||||
|
||||
vswc->seen_surfaces += vsurf->size;
|
||||
/* divide by 5 not well tuned for performance */
|
||||
if (vswc->seen_surfaces >= vswc->vws->ioctl.max_surface_memory / 5)
|
||||
vswc->preemptive_flush = TRUE;
|
||||
}
|
||||
|
||||
if (!(flags & SVGA_RELOC_INTERNAL) && !isrf->referenced) {
|
||||
isrf->referenced = TRUE;
|
||||
p_atomic_inc(&vsurf->validated);
|
||||
}
|
||||
|
||||
*where = vsurf->sid;
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_surface_relocation(struct svga_winsys_context *swc,
|
||||
uint32 *where,
|
||||
uint32 *mobid,
|
||||
struct svga_winsys_surface *surface,
|
||||
unsigned flags)
|
||||
{
|
||||
struct vmw_svga_winsys_surface *vsurf;
|
||||
|
||||
assert(swc->have_gb_objects || mobid == NULL);
|
||||
|
||||
if(!surface) {
|
||||
*where = SVGA3D_INVALID_ID;
|
||||
if (mobid)
|
||||
*mobid = SVGA3D_INVALID_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
vsurf = vmw_svga_winsys_surface(surface);
|
||||
vmw_swc_surface_only_relocation(swc, where, vsurf, flags);
|
||||
|
||||
if (swc->have_gb_objects && vsurf->buf != NULL) {
|
||||
|
||||
/*
|
||||
* Make sure backup buffer ends up fenced.
|
||||
*/
|
||||
|
||||
pipe_mutex_lock(vsurf->mutex);
|
||||
assert(vsurf->buf != NULL);
|
||||
|
||||
vmw_swc_mob_relocation(swc, mobid, NULL, (struct svga_winsys_buffer *)
|
||||
vsurf->buf, 0, flags);
|
||||
pipe_mutex_unlock(vsurf->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_shader_relocation(struct svga_winsys_context *swc,
|
||||
uint32 *shid,
|
||||
uint32 *mobid,
|
||||
uint32 *offset,
|
||||
struct svga_winsys_gb_shader *shader)
|
||||
{
|
||||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
struct vmw_svga_winsys_shader *vshader;
|
||||
struct vmw_ctx_validate_item *ishader;
|
||||
if(!shader) {
|
||||
*shid = SVGA3D_INVALID_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vswc->shader.staged < vswc->shader.reserved);
|
||||
vshader = vmw_svga_winsys_shader(shader);
|
||||
ishader = util_hash_table_get(vswc->hash, vshader);
|
||||
|
||||
if (ishader == NULL) {
|
||||
ishader = &vswc->shader.items[vswc->shader.used + vswc->shader.staged];
|
||||
vmw_svga_winsys_shader_reference(&ishader->vshader, vshader);
|
||||
ishader->referenced = FALSE;
|
||||
/*
|
||||
* Note that a failure here may just fall back to unhashed behavior
|
||||
* and potentially cause unnecessary flushing, so ignore the
|
||||
* return code.
|
||||
*/
|
||||
(void) util_hash_table_set(vswc->hash, vshader, ishader);
|
||||
++vswc->shader.staged;
|
||||
}
|
||||
|
||||
if (!ishader->referenced) {
|
||||
ishader->referenced = TRUE;
|
||||
p_atomic_inc(&vshader->validated);
|
||||
}
|
||||
|
||||
*shid = vshader->shid;
|
||||
|
||||
if (mobid != NULL && vshader->buf)
|
||||
vmw_swc_mob_relocation(swc, mobid, offset, vshader->buf,
|
||||
0, SVGA_RELOC_READ);
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_swc_commit(struct svga_winsys_context *swc)
|
||||
|
|
@ -334,6 +565,12 @@ vmw_swc_commit(struct svga_winsys_context *swc)
|
|||
vswc->surface.staged = 0;
|
||||
vswc->surface.reserved = 0;
|
||||
|
||||
assert(vswc->shader.staged <= vswc->shader.reserved);
|
||||
assert(vswc->shader.used + vswc->shader.staged <= vswc->shader.size);
|
||||
vswc->shader.used += vswc->shader.staged;
|
||||
vswc->shader.staged = 0;
|
||||
vswc->shader.reserved = 0;
|
||||
|
||||
assert(vswc->region.staged <= vswc->region.reserved);
|
||||
assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
|
||||
vswc->region.used += vswc->region.staged;
|
||||
|
|
@ -348,19 +585,38 @@ vmw_swc_destroy(struct svga_winsys_context *swc)
|
|||
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
|
||||
unsigned i;
|
||||
|
||||
for(i = 0; i < vswc->region.used; ++i) {
|
||||
pb_reference(&vswc->region.relocs[i].buffer, NULL);
|
||||
for(i = 0; i < vswc->surface.used; ++i) {
|
||||
struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
|
||||
if (isurf->referenced)
|
||||
p_atomic_dec(&isurf->vsurf->validated);
|
||||
vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
|
||||
}
|
||||
|
||||
for(i = 0; i < vswc->surface.used; ++i) {
|
||||
p_atomic_dec(&vswc->surface.handles[i]->validated);
|
||||
vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
|
||||
for(i = 0; i < vswc->shader.used; ++i) {
|
||||
struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
|
||||
if (ishader->referenced)
|
||||
p_atomic_dec(&ishader->vshader->validated);
|
||||
vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
|
||||
}
|
||||
|
||||
util_hash_table_destroy(vswc->hash);
|
||||
pb_validate_destroy(vswc->validate);
|
||||
vmw_ioctl_context_destroy(vswc->vws, swc->cid);
|
||||
#ifdef DEBUG
|
||||
debug_flush_ctx_destroy(vswc->fctx);
|
||||
#endif
|
||||
FREE(vswc);
|
||||
}
|
||||
|
||||
static unsigned vmw_hash_ptr(void *p)
|
||||
{
|
||||
return (unsigned)(unsigned long)p;
|
||||
}
|
||||
|
||||
static int vmw_ptr_compare(void *key1, void *key2)
|
||||
{
|
||||
return (key1 == key2) ? 0 : 1;
|
||||
}
|
||||
|
||||
struct svga_winsys_context *
|
||||
vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
|
||||
|
|
@ -376,22 +632,41 @@ vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
|
|||
vswc->base.reserve = vmw_swc_reserve;
|
||||
vswc->base.surface_relocation = vmw_swc_surface_relocation;
|
||||
vswc->base.region_relocation = vmw_swc_region_relocation;
|
||||
vswc->base.mob_relocation = vmw_swc_mob_relocation;
|
||||
vswc->base.context_relocation = vmw_swc_context_relocation;
|
||||
vswc->base.shader_relocation = vmw_swc_shader_relocation;
|
||||
vswc->base.commit = vmw_swc_commit;
|
||||
vswc->base.flush = vmw_swc_flush;
|
||||
vswc->base.surface_map = vmw_svga_winsys_surface_map;
|
||||
vswc->base.surface_unmap = vmw_svga_winsys_surface_unmap;
|
||||
|
||||
vswc->base.cid = vmw_ioctl_context_create(vws);
|
||||
vswc->base.have_gb_objects = sws->have_gb_objects;
|
||||
|
||||
vswc->vws = vws;
|
||||
|
||||
vswc->command.size = VMW_COMMAND_SIZE;
|
||||
vswc->surface.size = VMW_SURFACE_RELOCS;
|
||||
vswc->shader.size = VMW_SHADER_RELOCS;
|
||||
vswc->region.size = VMW_REGION_RELOCS;
|
||||
|
||||
vswc->validate = pb_validate_create();
|
||||
if(!vswc->validate) {
|
||||
FREE(vswc);
|
||||
return NULL;
|
||||
}
|
||||
if(!vswc->validate)
|
||||
goto out_no_validate;
|
||||
|
||||
vswc->hash = util_hash_table_create(vmw_hash_ptr, vmw_ptr_compare);
|
||||
if (!vswc->hash)
|
||||
goto out_no_hash;
|
||||
|
||||
#ifdef DEBUG
|
||||
vswc->fctx = debug_flush_ctx_create(TRUE, VMW_DEBUG_FLUSH_STACK);
|
||||
#endif
|
||||
|
||||
return &vswc->base;
|
||||
|
||||
out_no_hash:
|
||||
pb_validate_destroy(vswc->validate);
|
||||
out_no_validate:
|
||||
FREE(vswc);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,4 +62,12 @@ struct pipe_screen;
|
|||
struct svga_winsys_context *
|
||||
vmw_svga_winsys_context_create(struct svga_winsys_screen *sws);
|
||||
|
||||
struct vmw_svga_winsys_surface;
|
||||
|
||||
|
||||
void
|
||||
vmw_swc_surface_clear_reference(struct svga_winsys_context *swc,
|
||||
struct vmw_svga_winsys_surface *vsurf);
|
||||
|
||||
|
||||
#endif /* VMW_CONTEXT_H_ */
|
||||
|
|
|
|||
|
|
@ -22,20 +22,10 @@
|
|||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************/
|
||||
/*
|
||||
* TODO:
|
||||
*
|
||||
* Fencing is currently a bit inefficient, since we need to call the
|
||||
* kernel do determine a fence object signaled status if the fence is not
|
||||
* signaled. This can be greatly improved upon by using the fact that the
|
||||
* execbuf ioctl returns the last signaled fence seqno, as does the
|
||||
* fence signaled ioctl. We should set up a ring of fence objects and
|
||||
* walk through them checking for signaled status each time we receive a
|
||||
* new passed fence seqno.
|
||||
*/
|
||||
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_atomic.h"
|
||||
#include "util/u_double_list.h"
|
||||
#include "os/os_thread.h"
|
||||
|
||||
#include "pipebuffer/pb_buffer_fenced.h"
|
||||
|
||||
|
|
@ -44,54 +34,45 @@
|
|||
|
||||
struct vmw_fence_ops
|
||||
{
|
||||
/*
|
||||
* Immutable members.
|
||||
*/
|
||||
struct pb_fence_ops base;
|
||||
|
||||
struct vmw_winsys_screen *vws;
|
||||
|
||||
pipe_mutex mutex;
|
||||
|
||||
/*
|
||||
* Protected by mutex;
|
||||
*/
|
||||
struct list_head not_signaled;
|
||||
uint32_t last_signaled;
|
||||
uint32_t last_emitted;
|
||||
};
|
||||
|
||||
struct vmw_fence
|
||||
{
|
||||
struct list_head ops_list;
|
||||
int32_t refcount;
|
||||
uint32_t handle;
|
||||
uint32_t mask;
|
||||
int32_t signalled;
|
||||
uint32_t seqno;
|
||||
};
|
||||
|
||||
/**
|
||||
* vmw_fence - return the vmw_fence object identified by a
|
||||
* struct pipe_fence_handle *
|
||||
* vmw_fence_seq_is_signaled - Check whether a fence seqno is
|
||||
* signaled.
|
||||
*
|
||||
* @ops: Pointer to a struct pb_fence_ops.
|
||||
*
|
||||
* @fence: The opaque pipe fence handle.
|
||||
*/
|
||||
static INLINE struct vmw_fence *
|
||||
vmw_fence(struct pipe_fence_handle *fence)
|
||||
static INLINE boolean
|
||||
vmw_fence_seq_is_signaled(uint32_t seq, uint32_t last, uint32_t cur)
|
||||
{
|
||||
return (struct vmw_fence *) fence;
|
||||
return (cur - last <= cur - seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_fence_create - Create a user-space fence object.
|
||||
*
|
||||
* @handle: Handle identifying the kernel fence object.
|
||||
* @mask: Mask of flags that this fence object may signal.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct pipe_fence_handle *
|
||||
vmw_fence_create(uint32_t handle, uint32_t mask)
|
||||
{
|
||||
struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence);
|
||||
|
||||
if (!fence)
|
||||
return NULL;
|
||||
|
||||
p_atomic_set(&fence->refcount, 1);
|
||||
fence->handle = handle;
|
||||
fence->mask = mask;
|
||||
p_atomic_set(&fence->signalled, 0);
|
||||
|
||||
return (struct pipe_fence_handle *) fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_fence_ops - Return the vmw_fence_ops structure backing a
|
||||
|
|
@ -108,6 +89,125 @@ vmw_fence_ops(struct pb_fence_ops *ops)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_fences_release - Release all fences from the not_signaled
|
||||
* list.
|
||||
*
|
||||
* @ops: Pointer to a struct vmw_fence_ops.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
vmw_fences_release(struct vmw_fence_ops *ops)
|
||||
{
|
||||
struct vmw_fence *fence, *n;
|
||||
|
||||
pipe_mutex_lock(ops->mutex);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(fence, n, &ops->not_signaled, ops_list)
|
||||
LIST_DELINIT(&fence->ops_list);
|
||||
pipe_mutex_unlock(ops->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_fences_signal - Traverse the not_signaled list and try to
|
||||
* signal unsignaled fences.
|
||||
*
|
||||
* @ops: Pointer to a struct pb_fence_ops.
|
||||
* @signaled: Seqno that has signaled.
|
||||
* @emitted: Last seqno emitted by the kernel.
|
||||
* @has_emitted: Whether we provide the emitted value.
|
||||
*
|
||||
*/
|
||||
void
|
||||
vmw_fences_signal(struct pb_fence_ops *fence_ops,
|
||||
uint32_t signaled,
|
||||
uint32_t emitted,
|
||||
boolean has_emitted)
|
||||
{
|
||||
struct vmw_fence_ops *ops = NULL;
|
||||
struct vmw_fence *fence, *n;
|
||||
|
||||
if (fence_ops == NULL)
|
||||
return;
|
||||
|
||||
ops = vmw_fence_ops(fence_ops);
|
||||
pipe_mutex_lock(ops->mutex);
|
||||
|
||||
if (!has_emitted) {
|
||||
emitted = ops->last_emitted;
|
||||
if (emitted - signaled > (1 << 30))
|
||||
emitted = signaled;
|
||||
}
|
||||
|
||||
if (signaled == ops->last_signaled && emitted == ops->last_emitted)
|
||||
goto out_unlock;
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(fence, n, &ops->not_signaled, ops_list) {
|
||||
if (!vmw_fence_seq_is_signaled(fence->seqno, signaled, emitted))
|
||||
break;
|
||||
|
||||
p_atomic_set(&fence->signalled, 1);
|
||||
LIST_DELINIT(&fence->ops_list);
|
||||
}
|
||||
ops->last_signaled = signaled;
|
||||
ops->last_emitted = emitted;
|
||||
|
||||
out_unlock:
|
||||
pipe_mutex_unlock(ops->mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_fence - return the vmw_fence object identified by a
|
||||
* struct pipe_fence_handle *
|
||||
*
|
||||
* @fence: The opaque pipe fence handle.
|
||||
*/
|
||||
static INLINE struct vmw_fence *
|
||||
vmw_fence(struct pipe_fence_handle *fence)
|
||||
{
|
||||
return (struct vmw_fence *) fence;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_fence_create - Create a user-space fence object.
|
||||
*
|
||||
* @fence_ops: The fence_ops manager to register with.
|
||||
* @handle: Handle identifying the kernel fence object.
|
||||
* @mask: Mask of flags that this fence object may signal.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct pipe_fence_handle *
|
||||
vmw_fence_create(struct pb_fence_ops *fence_ops, uint32_t handle,
|
||||
uint32_t seqno, uint32_t mask)
|
||||
{
|
||||
struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence);
|
||||
struct vmw_fence_ops *ops = vmw_fence_ops(fence_ops);
|
||||
|
||||
if (!fence)
|
||||
return NULL;
|
||||
|
||||
p_atomic_set(&fence->refcount, 1);
|
||||
fence->handle = handle;
|
||||
fence->mask = mask;
|
||||
fence->seqno = seqno;
|
||||
p_atomic_set(&fence->signalled, 0);
|
||||
pipe_mutex_lock(ops->mutex);
|
||||
|
||||
if (vmw_fence_seq_is_signaled(seqno, ops->last_signaled, seqno)) {
|
||||
p_atomic_set(&fence->signalled, 1);
|
||||
LIST_INITHEAD(&fence->ops_list);
|
||||
} else {
|
||||
p_atomic_set(&fence->signalled, 0);
|
||||
LIST_ADDTAIL(&fence->ops_list, &ops->not_signaled);
|
||||
}
|
||||
|
||||
pipe_mutex_unlock(ops->mutex);
|
||||
|
||||
return (struct pipe_fence_handle *) fence;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_fence_reference - Reference / unreference a vmw fence object.
|
||||
|
|
@ -125,7 +225,14 @@ vmw_fence_reference(struct vmw_winsys_screen *vws,
|
|||
struct vmw_fence *vfence = vmw_fence(*ptr);
|
||||
|
||||
if (p_atomic_dec_zero(&vfence->refcount)) {
|
||||
struct vmw_fence_ops *ops = vmw_fence_ops(vws->fence_ops);
|
||||
|
||||
vmw_ioctl_fence_unref(vws, vfence->handle);
|
||||
|
||||
pipe_mutex_lock(ops->mutex);
|
||||
LIST_DELINIT(&vfence->ops_list);
|
||||
pipe_mutex_unlock(ops->mutex);
|
||||
|
||||
FREE(vfence);
|
||||
}
|
||||
}
|
||||
|
|
@ -171,18 +278,21 @@ vmw_fence_signalled(struct vmw_winsys_screen *vws,
|
|||
if ((old & vflags) == vflags)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Currently we update signaled fences on each execbuf call.
|
||||
* That should really be sufficient, and we can avoid
|
||||
* a lot of kernel calls this way.
|
||||
*/
|
||||
#if 1
|
||||
ret = vmw_ioctl_fence_signalled(vws, vfence->handle, vflags);
|
||||
|
||||
if (ret == 0) {
|
||||
int32_t prev = old;
|
||||
|
||||
do {
|
||||
old = prev;
|
||||
prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags);
|
||||
} while (prev != old);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
p_atomic_set(&vfence->signalled, 1);
|
||||
return ret;
|
||||
#else
|
||||
(void) ret;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,6 +397,7 @@ vmw_fence_ops_fence_finish(struct pb_fence_ops *ops,
|
|||
static void
|
||||
vmw_fence_ops_destroy(struct pb_fence_ops *ops)
|
||||
{
|
||||
vmw_fences_release(vmw_fence_ops(ops));
|
||||
FREE(ops);
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +421,8 @@ vmw_fence_ops_create(struct vmw_winsys_screen *vws)
|
|||
if(!ops)
|
||||
return NULL;
|
||||
|
||||
pipe_mutex_init(ops->mutex);
|
||||
LIST_INITHEAD(&ops->not_signaled);
|
||||
ops->base.destroy = &vmw_fence_ops_destroy;
|
||||
ops->base.fence_reference = &vmw_fence_ops_fence_reference;
|
||||
ops->base.fence_signalled = &vmw_fence_ops_fence_signalled;
|
||||
|
|
@ -319,5 +432,3 @@ vmw_fence_ops_create(struct vmw_winsys_screen *vws)
|
|||
|
||||
return &ops->base;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
|
||||
#include "pipe/p_compiler.h"
|
||||
|
||||
#include "pipebuffer/pb_buffer_fenced.h"
|
||||
|
||||
struct pipe_fence_handle;
|
||||
struct pb_fence_ops;
|
||||
|
|
@ -37,7 +37,8 @@ struct vmw_winsys_screen;
|
|||
|
||||
|
||||
struct pipe_fence_handle *
|
||||
vmw_fence_create(uint32_t handle, uint32_t mask);
|
||||
vmw_fence_create(struct pb_fence_ops *fence_ops,
|
||||
uint32_t handle, uint32_t seqno, uint32_t mask);
|
||||
|
||||
int
|
||||
vmw_fence_finish(struct vmw_winsys_screen *vws,
|
||||
|
|
|
|||
|
|
@ -25,42 +25,94 @@
|
|||
|
||||
|
||||
#include "vmw_screen.h"
|
||||
|
||||
#include "vmw_fence.h"
|
||||
#include "vmw_context.h"
|
||||
|
||||
#include "util/u_memory.h"
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_hash_table.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static struct util_hash_table *dev_hash = NULL;
|
||||
|
||||
static int vmw_dev_compare(void *key1, void *key2)
|
||||
{
|
||||
return (major(*(dev_t *)key1) == major(*(dev_t *)key2) &&
|
||||
minor(*(dev_t *)key1) == minor(*(dev_t *)key2)) ? 0 : 1;
|
||||
}
|
||||
|
||||
static unsigned vmw_dev_hash(void *key)
|
||||
{
|
||||
return (major(*(dev_t *) key) << 16) | minor(*(dev_t *) key);
|
||||
}
|
||||
|
||||
/* Called from vmw_drm_create_screen(), creates and initializes the
|
||||
* vmw_winsys_screen structure, which is the main entity in this
|
||||
* module.
|
||||
* First, check whether a vmw_winsys_screen object already exists for
|
||||
* this device, and in that case return that one, making sure that we
|
||||
* have our own file descriptor open to DRM.
|
||||
*/
|
||||
|
||||
struct vmw_winsys_screen *
|
||||
vmw_winsys_create( int fd, boolean use_old_scanout_flag )
|
||||
{
|
||||
struct vmw_winsys_screen *vws = CALLOC_STRUCT(vmw_winsys_screen);
|
||||
struct vmw_winsys_screen *vws;
|
||||
struct stat stat_buf;
|
||||
|
||||
if (dev_hash == NULL) {
|
||||
dev_hash = util_hash_table_create(vmw_dev_hash, vmw_dev_compare);
|
||||
if (dev_hash == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(fd, &stat_buf))
|
||||
return NULL;
|
||||
|
||||
vws = util_hash_table_get(dev_hash, &stat_buf.st_rdev);
|
||||
if (vws) {
|
||||
vws->open_count++;
|
||||
return vws;
|
||||
}
|
||||
|
||||
vws = CALLOC_STRUCT(vmw_winsys_screen);
|
||||
if (!vws)
|
||||
goto out_no_vws;
|
||||
|
||||
vws->ioctl.drm_fd = fd;
|
||||
vws->device = stat_buf.st_rdev;
|
||||
vws->open_count = 1;
|
||||
vws->ioctl.drm_fd = dup(fd);
|
||||
vws->use_old_scanout_flag = use_old_scanout_flag;
|
||||
vws->base.have_gb_dma = TRUE;
|
||||
|
||||
if (!vmw_ioctl_init(vws))
|
||||
goto out_no_ioctl;
|
||||
|
||||
vws->fence_ops = vmw_fence_ops_create(vws);
|
||||
if (!vws->fence_ops)
|
||||
goto out_no_fence_ops;
|
||||
|
||||
if(!vmw_pools_init(vws))
|
||||
goto out_no_pools;
|
||||
|
||||
if (!vmw_winsys_screen_init_svga(vws))
|
||||
goto out_no_svga;
|
||||
|
||||
if (util_hash_table_set(dev_hash, &vws->device, vws) != PIPE_OK)
|
||||
goto out_no_hash_insert;
|
||||
|
||||
return vws;
|
||||
out_no_hash_insert:
|
||||
out_no_svga:
|
||||
vmw_pools_cleanup(vws);
|
||||
out_no_pools:
|
||||
vws->fence_ops->destroy(vws->fence_ops);
|
||||
out_no_fence_ops:
|
||||
vmw_ioctl_cleanup(vws);
|
||||
out_no_ioctl:
|
||||
close(vws->ioctl.drm_fd);
|
||||
FREE(vws);
|
||||
out_no_vws:
|
||||
return NULL;
|
||||
|
|
@ -69,7 +121,12 @@ out_no_vws:
|
|||
void
|
||||
vmw_winsys_destroy(struct vmw_winsys_screen *vws)
|
||||
{
|
||||
vmw_pools_cleanup(vws);
|
||||
vmw_ioctl_cleanup(vws);
|
||||
FREE(vws);
|
||||
if (--vws->open_count == 0) {
|
||||
util_hash_table_remove(dev_hash, &vws->device);
|
||||
vmw_pools_cleanup(vws);
|
||||
vws->fence_ops->destroy(vws->fence_ops);
|
||||
vmw_ioctl_cleanup(vws);
|
||||
close(vws->ioctl.drm_fd);
|
||||
FREE(vws);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,13 @@
|
|||
#include "pipe/p_state.h"
|
||||
|
||||
#include "svga_winsys.h"
|
||||
#include "pipebuffer/pb_buffer_fenced.h"
|
||||
|
||||
|
||||
#define VMW_GMR_POOL_SIZE (16*1024*1024)
|
||||
#define VMW_QUERY_POOL_SIZE (8192)
|
||||
#define VMW_DEBUG_FLUSH_STACK 10
|
||||
|
||||
/*
|
||||
* Something big, but arbitrary. The kernel reports an error if it can't
|
||||
* handle this, and the svga driver will resort to multiple partial
|
||||
|
|
@ -53,6 +56,10 @@
|
|||
struct pb_manager;
|
||||
struct vmw_region;
|
||||
|
||||
struct vmw_cap_3d {
|
||||
boolean has_cap;
|
||||
SVGA3dDevCapResult result;
|
||||
};
|
||||
|
||||
struct vmw_winsys_screen
|
||||
{
|
||||
|
|
@ -63,7 +70,10 @@ struct vmw_winsys_screen
|
|||
struct {
|
||||
int drm_fd;
|
||||
uint32_t hwversion;
|
||||
uint32_t *buffer;
|
||||
uint32_t num_cap_3d;
|
||||
struct vmw_cap_3d *cap_3d;
|
||||
uint64_t max_mob_memory;
|
||||
uint64_t max_surface_memory;
|
||||
} ioctl;
|
||||
|
||||
struct {
|
||||
|
|
@ -72,10 +82,21 @@ struct vmw_winsys_screen
|
|||
struct pb_manager *gmr_fenced;
|
||||
struct pb_manager *gmr_slab;
|
||||
struct pb_manager *gmr_slab_fenced;
|
||||
struct pb_manager *query;
|
||||
struct pb_manager *query_mm;
|
||||
struct pb_manager *query_fenced;
|
||||
struct pb_manager *mob_fenced;
|
||||
struct pb_manager *mob_cache;
|
||||
struct pb_manager *mob_shader_slab;
|
||||
struct pb_manager *mob_shader_slab_fenced;
|
||||
} pools;
|
||||
|
||||
struct pb_fence_ops *fence_ops;
|
||||
|
||||
/*
|
||||
* Screen instances
|
||||
*/
|
||||
dev_t device;
|
||||
int open_count;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -86,6 +107,9 @@ vmw_winsys_screen(struct svga_winsys_screen *base)
|
|||
}
|
||||
|
||||
/* */
|
||||
uint32_t
|
||||
vmw_region_size(struct vmw_region *region);
|
||||
|
||||
uint32
|
||||
vmw_ioctl_context_create(struct vmw_winsys_screen *vws);
|
||||
|
||||
|
|
@ -100,6 +124,23 @@ vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
|
|||
SVGA3dSize size,
|
||||
uint32 numFaces,
|
||||
uint32 numMipLevels);
|
||||
uint32
|
||||
vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
|
||||
SVGA3dSurfaceFlags flags,
|
||||
SVGA3dSurfaceFormat format,
|
||||
SVGA3dSize size,
|
||||
uint32 numFaces,
|
||||
uint32 numMipLevels,
|
||||
uint32 buffer_handle,
|
||||
struct vmw_region **p_region);
|
||||
|
||||
int
|
||||
vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
|
||||
uint32_t handle,
|
||||
SVGA3dSurfaceFlags *flags,
|
||||
SVGA3dSurfaceFormat *format,
|
||||
uint32_t *numMipLevels,
|
||||
struct vmw_region **p_region);
|
||||
|
||||
void
|
||||
vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws,
|
||||
|
|
@ -140,12 +181,28 @@ void
|
|||
vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
|
||||
uint32_t handle);
|
||||
|
||||
uint32
|
||||
vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,
|
||||
SVGA3dShaderType type,
|
||||
uint32 code_len);
|
||||
void
|
||||
vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid);
|
||||
|
||||
int
|
||||
vmw_ioctl_syncforcpu(struct vmw_region *region,
|
||||
boolean dont_block,
|
||||
boolean readonly,
|
||||
boolean allow_cs);
|
||||
void
|
||||
vmw_ioctl_releasefromcpu(struct vmw_region *region,
|
||||
boolean readonly,
|
||||
boolean allow_cs);
|
||||
/* Initialize parts of vmw_winsys_screen at startup:
|
||||
*/
|
||||
boolean vmw_ioctl_init(struct vmw_winsys_screen *vws);
|
||||
boolean vmw_pools_init(struct vmw_winsys_screen *vws);
|
||||
boolean vmw_query_pools_init(struct vmw_winsys_screen *vws);
|
||||
boolean vmw_mob_pools_init(struct vmw_winsys_screen *vws);
|
||||
boolean vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws);
|
||||
|
||||
void vmw_ioctl_cleanup(struct vmw_winsys_screen *vws);
|
||||
|
|
@ -156,4 +213,13 @@ void vmw_winsys_destroy(struct vmw_winsys_screen *sws);
|
|||
void vmw_winsys_screen_set_throttling(struct pipe_screen *screen,
|
||||
uint32_t throttle_us);
|
||||
|
||||
struct pb_manager *
|
||||
simple_fenced_bufmgr_create(struct pb_manager *provider,
|
||||
struct pb_fence_ops *ops);
|
||||
void
|
||||
vmw_fences_signal(struct pb_fence_ops *fence_ops,
|
||||
uint32_t signaled,
|
||||
uint32_t emitted,
|
||||
boolean has_emitted);
|
||||
|
||||
#endif /* VMW_SCREEN_H_ */
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@
|
|||
#include "vmw_context.h"
|
||||
#include "vmw_screen.h"
|
||||
#include "vmw_surface.h"
|
||||
#include "vmw_buffer.h"
|
||||
#include "svga_drm_public.h"
|
||||
#include "svga3d_surfacedefs.h"
|
||||
|
||||
#include "state_tracker/drm_driver.h"
|
||||
|
||||
|
|
@ -52,6 +54,11 @@ static struct svga_winsys_surface *
|
|||
vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
|
||||
struct winsys_handle *whandle,
|
||||
SVGA3dSurfaceFormat *format);
|
||||
|
||||
static struct svga_winsys_surface *
|
||||
vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
|
||||
struct winsys_handle *whandle,
|
||||
SVGA3dSurfaceFormat *format);
|
||||
static boolean
|
||||
vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_surface *surface,
|
||||
|
|
@ -109,7 +116,8 @@ svga_drm_winsys_screen_create(int fd)
|
|||
goto out_no_vws;
|
||||
|
||||
/* XXX do this properly */
|
||||
vws->base.surface_from_handle = vmw_drm_surface_from_handle;
|
||||
vws->base.surface_from_handle = vws->base.have_gb_objects ?
|
||||
vmw_drm_gb_surface_from_handle : vmw_drm_surface_from_handle;
|
||||
vws->base.surface_get_handle = vmw_drm_surface_get_handle;
|
||||
|
||||
return &vws->base;
|
||||
|
|
@ -150,6 +158,83 @@ vmw_dri1_intersect_src_bbox(struct drm_clip_rect *dst,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_drm_gb_surface_from_handle - Create a shared surface
|
||||
*
|
||||
* @sws: Screen to register the surface with.
|
||||
* @whandle: struct winsys_handle identifying the kernel surface object
|
||||
* @format: On successful return points to a value describing the
|
||||
* surface format.
|
||||
*
|
||||
* Returns a refcounted pointer to a struct svga_winsys_surface
|
||||
* embedded in a struct vmw_svga_winsys_surface on success or NULL
|
||||
* on failure.
|
||||
*/
|
||||
static struct svga_winsys_surface *
|
||||
vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
|
||||
struct winsys_handle *whandle,
|
||||
SVGA3dSurfaceFormat *format)
|
||||
{
|
||||
struct vmw_svga_winsys_surface *vsrf;
|
||||
struct svga_winsys_surface *ssrf;
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
SVGA3dSurfaceFlags flags;
|
||||
uint32_t mip_levels;
|
||||
struct vmw_buffer_desc desc;
|
||||
struct pb_manager *provider = vws->pools.gmr;
|
||||
struct pb_buffer *pb_buf;
|
||||
int ret;
|
||||
|
||||
ret = vmw_ioctl_gb_surface_ref(vws, whandle->handle, &flags, format,
|
||||
&mip_levels, &desc.region);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
|
||||
"Error %d (%s).\n",
|
||||
whandle->handle, ret, strerror(-ret));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mip_levels != 1) {
|
||||
fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
|
||||
" SID %d, levels %d\n",
|
||||
whandle->handle, mip_levels);
|
||||
goto out_mip;
|
||||
}
|
||||
|
||||
vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
|
||||
if (!vsrf)
|
||||
goto out_mip;
|
||||
|
||||
pipe_reference_init(&vsrf->refcnt, 1);
|
||||
p_atomic_set(&vsrf->validated, 0);
|
||||
vsrf->screen = vws;
|
||||
vsrf->sid = whandle->handle;
|
||||
vsrf->size = vmw_region_size(desc.region);
|
||||
|
||||
/*
|
||||
* Synchronize backing buffers of shared surfaces using the
|
||||
* kernel, since we don't pass fence objects around between
|
||||
* processes.
|
||||
*/
|
||||
desc.pb_desc.alignment = 4096;
|
||||
desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED | VMW_BUFFER_USAGE_SYNC;
|
||||
pb_buf = provider->create_buffer(provider, vsrf->size, &desc.pb_desc);
|
||||
vsrf->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
|
||||
if (!vsrf->buf)
|
||||
goto out_no_buf;
|
||||
ssrf = svga_winsys_surface(vsrf);
|
||||
|
||||
return ssrf;
|
||||
|
||||
out_no_buf:
|
||||
FREE(vsrf);
|
||||
out_mip:
|
||||
vmw_ioctl_region_destroy(desc.region);
|
||||
vmw_ioctl_surface_destroy(vws, whandle->handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct svga_winsys_surface *
|
||||
vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
|
||||
struct winsys_handle *whandle,
|
||||
|
|
@ -162,6 +247,7 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
|
|||
struct drm_vmw_surface_arg *req = &arg.req;
|
||||
struct drm_vmw_surface_create_req *rep = &arg.rep;
|
||||
uint32_t handle = 0;
|
||||
SVGA3dSize size;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
|
|
@ -187,6 +273,7 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
|
|||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
req->sid = handle;
|
||||
rep->size_addr = (size_t)&size;
|
||||
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
|
||||
&arg, sizeof(arg));
|
||||
|
|
@ -235,6 +322,11 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
|
|||
ssrf = svga_winsys_surface(vsrf);
|
||||
*format = rep->format;
|
||||
|
||||
/* Estimate usage, for early flushing. */
|
||||
vsrf->size = svga3dsurface_get_serialized_size(rep->format, size,
|
||||
rep->mip_levels[0],
|
||||
FALSE);
|
||||
|
||||
return ssrf;
|
||||
|
||||
out_mip:
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "xf86drm.h"
|
||||
#include "vmwgfx_drm.h"
|
||||
#include "svga3d_caps.h"
|
||||
#include "svga3d_reg.h"
|
||||
|
||||
#include "os/os_mman.h"
|
||||
|
||||
|
|
@ -51,7 +52,6 @@
|
|||
|
||||
struct vmw_region
|
||||
{
|
||||
SVGAGuestPtr ptr;
|
||||
uint32_t handle;
|
||||
uint64_t map_handle;
|
||||
void *data;
|
||||
|
|
@ -66,6 +66,13 @@ struct vmw_region
|
|||
*/
|
||||
#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
|
||||
|
||||
|
||||
uint32_t
|
||||
vmw_region_size(struct vmw_region *region)
|
||||
{
|
||||
return region->size;
|
||||
}
|
||||
|
||||
uint32
|
||||
vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
|
||||
{
|
||||
|
|
@ -168,6 +175,139 @@ vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
|
|||
return rep->sid;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
|
||||
SVGA3dSurfaceFlags flags,
|
||||
SVGA3dSurfaceFormat format,
|
||||
SVGA3dSize size,
|
||||
uint32_t numFaces,
|
||||
uint32_t numMipLevels,
|
||||
uint32_t buffer_handle,
|
||||
struct vmw_region **p_region)
|
||||
{
|
||||
union drm_vmw_gb_surface_create_arg s_arg;
|
||||
struct drm_vmw_gb_surface_create_req *req = &s_arg.req;
|
||||
struct drm_vmw_gb_surface_create_rep *rep = &s_arg.rep;
|
||||
struct vmw_region *region = NULL;
|
||||
int ret;
|
||||
|
||||
vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
|
||||
|
||||
if (p_region) {
|
||||
region = CALLOC_STRUCT(vmw_region);
|
||||
if (!region)
|
||||
return SVGA3D_INVALID_ID;
|
||||
}
|
||||
|
||||
memset(&s_arg, 0, sizeof(s_arg));
|
||||
if (flags & SVGA3D_SURFACE_HINT_SCANOUT) {
|
||||
req->svga3d_flags = (uint32_t) (flags & ~SVGA3D_SURFACE_HINT_SCANOUT);
|
||||
req->drm_surface_flags = drm_vmw_surface_flag_scanout;
|
||||
} else {
|
||||
req->svga3d_flags = (uint32_t) flags;
|
||||
}
|
||||
req->format = (uint32_t) format;
|
||||
req->drm_surface_flags |= drm_vmw_surface_flag_shareable;
|
||||
req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
|
||||
|
||||
assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
|
||||
DRM_VMW_MAX_MIP_LEVELS);
|
||||
req->base_size.width = size.width;
|
||||
req->base_size.height = size.height;
|
||||
req->base_size.depth = size.depth;
|
||||
req->mip_levels = numMipLevels;
|
||||
req->multisample_count = 0;
|
||||
req->autogen_filter = SVGA3D_TEX_FILTER_NONE;
|
||||
if (buffer_handle)
|
||||
req->buffer_handle = buffer_handle;
|
||||
else
|
||||
req->buffer_handle = SVGA3D_INVALID_ID;
|
||||
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,
|
||||
&s_arg, sizeof(s_arg));
|
||||
|
||||
if (ret)
|
||||
goto out_fail_create;
|
||||
|
||||
if (p_region) {
|
||||
region->handle = rep->buffer_handle;
|
||||
region->map_handle = rep->buffer_map_handle;
|
||||
region->drm_fd = vws->ioctl.drm_fd;
|
||||
region->size = rep->backup_size;
|
||||
*p_region = region;
|
||||
}
|
||||
|
||||
vmw_printf("Surface id is %d\n", rep->sid);
|
||||
return rep->handle;
|
||||
|
||||
out_fail_create:
|
||||
if (region)
|
||||
FREE(region);
|
||||
return SVGA3D_INVALID_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
|
||||
* get surface information
|
||||
*
|
||||
* @vws: Screen to register the reference on
|
||||
* @handle: Kernel handle of the guest-backed surface
|
||||
* @flags: flags used when the surface was created
|
||||
* @format: Format used when the surface was created
|
||||
* @numMipLevels: Number of mipmap levels of the surface
|
||||
* @p_region: On successful return points to a newly allocated
|
||||
* struct vmw_region holding a reference to the surface backup buffer.
|
||||
*
|
||||
* Returns 0 on success, a system error on failure.
|
||||
*/
|
||||
int
|
||||
vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
|
||||
uint32_t handle,
|
||||
SVGA3dSurfaceFlags *flags,
|
||||
SVGA3dSurfaceFormat *format,
|
||||
uint32_t *numMipLevels,
|
||||
struct vmw_region **p_region)
|
||||
{
|
||||
union drm_vmw_gb_surface_reference_arg s_arg;
|
||||
struct drm_vmw_surface_arg *req = &s_arg.req;
|
||||
struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
|
||||
struct vmw_region *region = NULL;
|
||||
int ret;
|
||||
|
||||
vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
|
||||
|
||||
assert(p_region != NULL);
|
||||
region = CALLOC_STRUCT(vmw_region);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&s_arg, 0, sizeof(s_arg));
|
||||
req->sid = handle;
|
||||
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
|
||||
&s_arg, sizeof(s_arg));
|
||||
|
||||
if (ret)
|
||||
goto out_fail_ref;
|
||||
|
||||
region->handle = rep->crep.buffer_handle;
|
||||
region->map_handle = rep->crep.buffer_map_handle;
|
||||
region->drm_fd = vws->ioctl.drm_fd;
|
||||
region->size = rep->crep.backup_size;
|
||||
*p_region = region;
|
||||
|
||||
*flags = rep->creq.svga3d_flags;
|
||||
*format = rep->creq.format;
|
||||
*numMipLevels = rep->creq.mip_levels;
|
||||
|
||||
return 0;
|
||||
out_fail_ref:
|
||||
if (region)
|
||||
FREE(region);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
|
||||
{
|
||||
|
|
@ -238,8 +378,11 @@ vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
|
|||
*pfence = NULL;
|
||||
} else {
|
||||
if (pfence) {
|
||||
*pfence = vmw_fence_create(rep.handle, rep.mask);
|
||||
vmw_fences_signal(vws->fence_ops, rep.passed_seqno, rep.seqno,
|
||||
TRUE);
|
||||
|
||||
*pfence = vmw_fence_create(vws->fence_ops, rep.handle,
|
||||
rep.seqno, rep.mask);
|
||||
if (*pfence == NULL) {
|
||||
/*
|
||||
* Fence creation failed. Need to sync.
|
||||
|
|
@ -279,8 +422,6 @@ vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
|
|||
goto out_err1;
|
||||
}
|
||||
|
||||
region->ptr.gmrId = rep->cur_gmr_id;
|
||||
region->ptr.offset = rep->cur_gmr_offset;
|
||||
region->data = NULL;
|
||||
region->handle = rep->handle;
|
||||
region->map_handle = rep->map_handle;
|
||||
|
|
@ -321,7 +462,8 @@ vmw_ioctl_region_destroy(struct vmw_region *region)
|
|||
SVGAGuestPtr
|
||||
vmw_ioctl_region_ptr(struct vmw_region *region)
|
||||
{
|
||||
return region->ptr;
|
||||
SVGAGuestPtr ptr = {region->handle, 0};
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
|
|
@ -356,6 +498,69 @@ vmw_ioctl_region_unmap(struct vmw_region *region)
|
|||
--region->map_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage
|
||||
*
|
||||
* @region: Pointer to a struct vmw_region representing the buffer object.
|
||||
* @dont_block: Dont wait for GPU idle, but rather return -EBUSY if the
|
||||
* GPU is busy with the buffer object.
|
||||
* @readonly: Hint that the CPU access is read-only.
|
||||
* @allow_cs: Allow concurrent command submission while the buffer is
|
||||
* synchronized for CPU. If FALSE command submissions referencing the
|
||||
* buffer will block until a corresponding call to vmw_ioctl_releasefromcpu.
|
||||
*
|
||||
* This function idles any GPU activities touching the buffer and blocks
|
||||
* command submission of commands referencing the buffer, even from
|
||||
* other processes.
|
||||
*/
|
||||
int
|
||||
vmw_ioctl_syncforcpu(struct vmw_region *region,
|
||||
boolean dont_block,
|
||||
boolean readonly,
|
||||
boolean allow_cs)
|
||||
{
|
||||
struct drm_vmw_synccpu_arg arg;
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.op = drm_vmw_synccpu_grab;
|
||||
arg.handle = region->handle;
|
||||
arg.flags = drm_vmw_synccpu_read;
|
||||
if (!readonly)
|
||||
arg.flags |= drm_vmw_synccpu_write;
|
||||
if (dont_block)
|
||||
arg.flags |= drm_vmw_synccpu_dontblock;
|
||||
if (allow_cs)
|
||||
arg.flags |= drm_vmw_synccpu_allow_cs;
|
||||
|
||||
return drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.
|
||||
*
|
||||
* @region: Pointer to a struct vmw_region representing the buffer object.
|
||||
* @readonly: Should hold the same value as the matching syncforcpu call.
|
||||
* @allow_cs: Should hold the same value as the matching syncforcpu call.
|
||||
*/
|
||||
void
|
||||
vmw_ioctl_releasefromcpu(struct vmw_region *region,
|
||||
boolean readonly,
|
||||
boolean allow_cs)
|
||||
{
|
||||
struct drm_vmw_synccpu_arg arg;
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.op = drm_vmw_synccpu_release;
|
||||
arg.handle = region->handle;
|
||||
arg.flags = drm_vmw_synccpu_read;
|
||||
if (!readonly)
|
||||
arg.flags |= drm_vmw_synccpu_write;
|
||||
if (allow_cs)
|
||||
arg.flags |= drm_vmw_synccpu_allow_cs;
|
||||
|
||||
(void) drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
void
|
||||
vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
|
||||
uint32_t handle)
|
||||
|
|
@ -405,6 +610,8 @@ vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
|
|||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
vmw_fences_signal(vws->fence_ops, arg.passed_seqno, 0, FALSE);
|
||||
|
||||
return (arg.signaled) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
|
@ -435,6 +642,113 @@ vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32
|
||||
vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,
|
||||
SVGA3dShaderType type,
|
||||
uint32 code_len)
|
||||
{
|
||||
struct drm_vmw_shader_create_arg sh_arg;
|
||||
int ret;
|
||||
|
||||
VMW_FUNC;
|
||||
|
||||
memset(&sh_arg, 0, sizeof(sh_arg));
|
||||
|
||||
sh_arg.size = code_len;
|
||||
sh_arg.buffer_handle = SVGA3D_INVALID_ID;
|
||||
sh_arg.shader_handle = SVGA3D_INVALID_ID;
|
||||
switch (type) {
|
||||
case SVGA3D_SHADERTYPE_VS:
|
||||
sh_arg.shader_type = drm_vmw_shader_type_vs;
|
||||
break;
|
||||
case SVGA3D_SHADERTYPE_PS:
|
||||
sh_arg.shader_type = drm_vmw_shader_type_ps;
|
||||
break;
|
||||
default:
|
||||
assert(!"Invalid shader type.");
|
||||
break;
|
||||
}
|
||||
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SHADER,
|
||||
&sh_arg, sizeof(sh_arg));
|
||||
|
||||
if (ret)
|
||||
return SVGA3D_INVALID_ID;
|
||||
|
||||
return sh_arg.shader_handle;
|
||||
}
|
||||
|
||||
void
|
||||
vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid)
|
||||
{
|
||||
struct drm_vmw_shader_arg sh_arg;
|
||||
|
||||
VMW_FUNC;
|
||||
|
||||
memset(&sh_arg, 0, sizeof(sh_arg));
|
||||
sh_arg.handle = shid;
|
||||
|
||||
(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER,
|
||||
&sh_arg, sizeof(sh_arg));
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
vmw_ioctl_parse_caps(struct vmw_winsys_screen *vws,
|
||||
const uint32_t *cap_buffer)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (vws->base.have_gb_objects) {
|
||||
for (i = 0; i < vws->ioctl.num_cap_3d; ++i) {
|
||||
vws->ioctl.cap_3d[i].has_cap = TRUE;
|
||||
vws->ioctl.cap_3d[i].result.u = cap_buffer[i];
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
const uint32 *capsBlock;
|
||||
const SVGA3dCapsRecord *capsRecord = NULL;
|
||||
uint32 offset;
|
||||
const SVGA3dCapPair *capArray;
|
||||
int numCaps, index;
|
||||
|
||||
/*
|
||||
* Search linearly through the caps block records for the specified type.
|
||||
*/
|
||||
capsBlock = cap_buffer;
|
||||
for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
|
||||
const SVGA3dCapsRecord *record;
|
||||
assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
|
||||
record = (const SVGA3dCapsRecord *) (capsBlock + offset);
|
||||
if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
|
||||
(record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
|
||||
(!capsRecord || (record->header.type > capsRecord->header.type))) {
|
||||
capsRecord = record;
|
||||
}
|
||||
}
|
||||
|
||||
if(!capsRecord)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Calculate the number of caps from the size of the record.
|
||||
*/
|
||||
capArray = (const SVGA3dCapPair *) capsRecord->data;
|
||||
numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
|
||||
sizeof capsRecord->header) / (2 * sizeof(uint32)));
|
||||
|
||||
for (i = 0; i < numCaps; i++) {
|
||||
index = capArray[i][0];
|
||||
if (index < vws->ioctl.num_cap_3d) {
|
||||
vws->ioctl.cap_3d[index].has_cap = TRUE;
|
||||
vws->ioctl.cap_3d[index].result.u = capArray[i][1];
|
||||
} else {
|
||||
debug_printf("Unknown devcaps seen: %d\n", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean
|
||||
vmw_ioctl_init(struct vmw_winsys_screen *vws)
|
||||
|
|
@ -443,9 +757,19 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
|
|||
struct drm_vmw_get_3d_cap_arg cap_arg;
|
||||
unsigned int size;
|
||||
int ret;
|
||||
uint32_t *cap_buffer;
|
||||
drmVersionPtr version;
|
||||
boolean drm_gb_capable;
|
||||
|
||||
VMW_FUNC;
|
||||
|
||||
version = drmGetVersion(vws->ioctl.drm_fd);
|
||||
if (!version)
|
||||
goto out_no_version;
|
||||
|
||||
drm_gb_capable = version->version_major > 2 ||
|
||||
(version->version_major == 2 && version->version_minor > 4);
|
||||
|
||||
memset(&gp_arg, 0, sizeof(gp_arg));
|
||||
gp_arg.param = DRM_VMW_PARAM_3D;
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
|
||||
|
|
@ -466,15 +790,78 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
|
|||
}
|
||||
vws->ioctl.hwversion = gp_arg.value;
|
||||
|
||||
size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
|
||||
vws->ioctl.buffer = calloc(1, size);
|
||||
if (!vws->ioctl.buffer) {
|
||||
memset(&gp_arg, 0, sizeof(gp_arg));
|
||||
gp_arg.param = DRM_VMW_PARAM_HW_CAPS;
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
|
||||
&gp_arg, sizeof(gp_arg));
|
||||
if (ret)
|
||||
vws->base.have_gb_objects = FALSE;
|
||||
else
|
||||
vws->base.have_gb_objects =
|
||||
!!(gp_arg.value & (uint64_t) SVGA_CAP_GBOBJECTS);
|
||||
|
||||
if (vws->base.have_gb_objects && !drm_gb_capable)
|
||||
goto out_no_3d;
|
||||
|
||||
if (vws->base.have_gb_objects) {
|
||||
memset(&gp_arg, 0, sizeof(gp_arg));
|
||||
gp_arg.param = DRM_VMW_PARAM_3D_CAPS_SIZE;
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
|
||||
&gp_arg, sizeof(gp_arg));
|
||||
if (ret)
|
||||
size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
|
||||
else
|
||||
size = gp_arg.value;
|
||||
|
||||
if (vws->base.have_gb_objects)
|
||||
vws->ioctl.num_cap_3d = size / sizeof(uint32_t);
|
||||
else
|
||||
vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
|
||||
|
||||
|
||||
memset(&gp_arg, 0, sizeof(gp_arg));
|
||||
gp_arg.param = DRM_VMW_PARAM_MAX_MOB_MEMORY;
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
|
||||
&gp_arg, sizeof(gp_arg));
|
||||
if (ret) {
|
||||
/* Just guess a large enough value. */
|
||||
vws->ioctl.max_mob_memory = 256*1024*1024;
|
||||
} else {
|
||||
vws->ioctl.max_mob_memory = gp_arg.value;
|
||||
}
|
||||
/* Never early flush surfaces, mobs do accounting. */
|
||||
vws->ioctl.max_surface_memory = -1;
|
||||
} else {
|
||||
vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
|
||||
|
||||
memset(&gp_arg, 0, sizeof(gp_arg));
|
||||
gp_arg.param = DRM_VMW_PARAM_MAX_SURF_MEMORY;
|
||||
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
|
||||
&gp_arg, sizeof(gp_arg));
|
||||
if (ret) {
|
||||
/* Just guess a large enough value, around 800mb. */
|
||||
vws->ioctl.max_surface_memory = 0x300000000;
|
||||
} else {
|
||||
vws->ioctl.max_surface_memory = gp_arg.value;
|
||||
}
|
||||
size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
cap_buffer = calloc(1, size);
|
||||
if (!cap_buffer) {
|
||||
debug_printf("Failed alloc fifo 3D caps buffer.\n");
|
||||
goto out_no_3d;
|
||||
}
|
||||
|
||||
vws->ioctl.cap_3d = calloc(vws->ioctl.num_cap_3d,
|
||||
sizeof(*vws->ioctl.cap_3d));
|
||||
if (!vws->ioctl.cap_3d) {
|
||||
debug_printf("Failed alloc fifo 3D caps buffer.\n");
|
||||
goto out_no_caparray;
|
||||
}
|
||||
|
||||
memset(&cap_arg, 0, sizeof(cap_arg));
|
||||
cap_arg.buffer = (uint64_t) (unsigned long) (vws->ioctl.buffer);
|
||||
cap_arg.buffer = (uint64_t) (unsigned long) (cap_buffer);
|
||||
cap_arg.max_size = size;
|
||||
|
||||
ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,
|
||||
|
|
@ -486,11 +873,24 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
|
|||
goto out_no_caps;
|
||||
}
|
||||
|
||||
ret = vmw_ioctl_parse_caps(vws, cap_buffer);
|
||||
if (ret) {
|
||||
debug_printf("Failed to parse 3D capabilities"
|
||||
" (%i, %s).\n", ret, strerror(-ret));
|
||||
goto out_no_caps;
|
||||
}
|
||||
free(cap_buffer);
|
||||
drmFreeVersion(version);
|
||||
vmw_printf("%s OK\n", __FUNCTION__);
|
||||
return TRUE;
|
||||
out_no_caps:
|
||||
free(vws->ioctl.buffer);
|
||||
free(vws->ioctl.cap_3d);
|
||||
out_no_caparray:
|
||||
free(cap_buffer);
|
||||
out_no_3d:
|
||||
drmFreeVersion(version);
|
||||
out_no_version:
|
||||
vws->ioctl.num_cap_3d = 0;
|
||||
debug_printf("%s Failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,13 +32,6 @@
|
|||
#include "pipebuffer/pb_buffer.h"
|
||||
#include "pipebuffer/pb_bufmgr.h"
|
||||
|
||||
/*
|
||||
* TODO: Have the query pool always ask the fence manager for
|
||||
* SVGA_FENCE_FLAG_QUERY signaled. Unfortunately, pb_fenced doesn't
|
||||
* support that currently, so we'd have to create a separate
|
||||
* pb_fence_ops wrapper that does this implicitly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* vmw_pools_cleanup - Destroy the buffer pools.
|
||||
*
|
||||
|
|
@ -47,20 +40,32 @@
|
|||
void
|
||||
vmw_pools_cleanup(struct vmw_winsys_screen *vws)
|
||||
{
|
||||
if(vws->pools.gmr_fenced)
|
||||
vws->pools.gmr_fenced->destroy(vws->pools.gmr_fenced);
|
||||
if (vws->pools.mob_shader_slab_fenced)
|
||||
vws->pools.mob_shader_slab_fenced->destroy
|
||||
(vws->pools.mob_shader_slab_fenced);
|
||||
if (vws->pools.mob_shader_slab)
|
||||
vws->pools.mob_shader_slab->destroy(vws->pools.mob_shader_slab);
|
||||
if (vws->pools.mob_fenced)
|
||||
vws->pools.mob_fenced->destroy(vws->pools.mob_fenced);
|
||||
if (vws->pools.mob_cache)
|
||||
vws->pools.mob_cache->destroy(vws->pools.mob_cache);
|
||||
|
||||
if (vws->pools.query_fenced)
|
||||
vws->pools.query_fenced->destroy(vws->pools.query_fenced);
|
||||
if (vws->pools.query_mm)
|
||||
vws->pools.query_mm->destroy(vws->pools.query_mm);
|
||||
|
||||
/* gmr_mm pool is already destroyed above */
|
||||
|
||||
if(vws->pools.gmr_fenced)
|
||||
vws->pools.gmr_fenced->destroy(vws->pools.gmr_fenced);
|
||||
if (vws->pools.gmr_mm)
|
||||
vws->pools.gmr_mm->destroy(vws->pools.gmr_mm);
|
||||
if (vws->pools.gmr_slab_fenced)
|
||||
vws->pools.gmr_slab_fenced->destroy(vws->pools.gmr_slab_fenced);
|
||||
if (vws->pools.gmr_slab)
|
||||
vws->pools.gmr_slab->destroy(vws->pools.gmr_slab);
|
||||
|
||||
if(vws->pools.gmr)
|
||||
vws->pools.gmr->destroy(vws->pools.gmr);
|
||||
if(vws->pools.query)
|
||||
vws->pools.query->destroy(vws->pools.query);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -77,21 +82,14 @@ vmw_pools_cleanup(struct vmw_winsys_screen *vws)
|
|||
boolean
|
||||
vmw_query_pools_init(struct vmw_winsys_screen *vws)
|
||||
{
|
||||
vws->pools.query = vmw_gmr_bufmgr_create(vws);
|
||||
if(!vws->pools.query)
|
||||
return FALSE;
|
||||
|
||||
vws->pools.query_mm = mm_bufmgr_create(vws->pools.query,
|
||||
vws->pools.query_mm = mm_bufmgr_create(vws->pools.gmr,
|
||||
VMW_QUERY_POOL_SIZE,
|
||||
3 /* 8 alignment */);
|
||||
if(!vws->pools.query_mm)
|
||||
goto out_no_query_mm;
|
||||
if (!vws->pools.query_mm)
|
||||
return FALSE;
|
||||
|
||||
vws->pools.query_fenced = fenced_bufmgr_create(
|
||||
vws->pools.query_mm,
|
||||
vmw_fence_ops_create(vws),
|
||||
VMW_QUERY_POOL_SIZE,
|
||||
~0);
|
||||
vws->pools.query_fenced = simple_fenced_bufmgr_create(
|
||||
vws->pools.query_mm, vws->fence_ops);
|
||||
|
||||
if(!vws->pools.query_fenced)
|
||||
goto out_no_query_fenced;
|
||||
|
|
@ -100,8 +98,60 @@ vmw_query_pools_init(struct vmw_winsys_screen *vws)
|
|||
|
||||
out_no_query_fenced:
|
||||
vws->pools.query_mm->destroy(vws->pools.query_mm);
|
||||
out_no_query_mm:
|
||||
vws->pools.query->destroy(vws->pools.query);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_mob_pool_init - Create a pool of fenced kernel buffers.
|
||||
*
|
||||
* @vws: Pointer to a struct vmw_winsys_screen.
|
||||
*
|
||||
* Typically this pool should be created on demand when we
|
||||
* detect that the app will be using MOB buffers.
|
||||
*/
|
||||
boolean
|
||||
vmw_mob_pools_init(struct vmw_winsys_screen *vws)
|
||||
{
|
||||
struct pb_desc desc;
|
||||
|
||||
vws->pools.mob_cache =
|
||||
pb_cache_manager_create(vws->pools.gmr, 100000, 2,
|
||||
VMW_BUFFER_USAGE_SHARED);
|
||||
if (!vws->pools.mob_cache)
|
||||
return FALSE;
|
||||
|
||||
vws->pools.mob_fenced =
|
||||
simple_fenced_bufmgr_create(vws->pools.mob_cache,
|
||||
vws->fence_ops);
|
||||
if(!vws->pools.mob_fenced)
|
||||
goto out_no_mob_fenced;
|
||||
|
||||
desc.alignment = 64;
|
||||
desc.usage = ~(SVGA_BUFFER_USAGE_PINNED | VMW_BUFFER_USAGE_SHARED |
|
||||
VMW_BUFFER_USAGE_SYNC);
|
||||
vws->pools.mob_shader_slab =
|
||||
pb_slab_range_manager_create(vws->pools.mob_cache,
|
||||
64,
|
||||
8192,
|
||||
16384,
|
||||
&desc);
|
||||
if(!vws->pools.mob_shader_slab)
|
||||
goto out_no_mob_shader_slab;
|
||||
|
||||
vws->pools.mob_shader_slab_fenced =
|
||||
simple_fenced_bufmgr_create(vws->pools.mob_shader_slab,
|
||||
vws->fence_ops);
|
||||
if(!vws->pools.mob_fenced)
|
||||
goto out_no_mob_shader_slab_fenced;
|
||||
|
||||
return TRUE;
|
||||
|
||||
out_no_mob_shader_slab_fenced:
|
||||
vws->pools.mob_shader_slab->destroy(vws->pools.mob_shader_slab);
|
||||
out_no_mob_shader_slab:
|
||||
vws->pools.mob_fenced->destroy(vws->pools.mob_fenced);
|
||||
out_no_mob_fenced:
|
||||
vws->pools.mob_cache->destroy(vws->pools.mob_cache);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -119,33 +169,27 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
|
|||
if(!vws->pools.gmr)
|
||||
goto error;
|
||||
|
||||
vws->pools.gmr_mm = mm_bufmgr_create(vws->pools.gmr,
|
||||
VMW_GMR_POOL_SIZE,
|
||||
12 /* 4096 alignment */);
|
||||
if(!vws->pools.gmr_mm)
|
||||
goto error;
|
||||
if ((vws->base.have_gb_objects && vws->base.have_gb_dma) ||
|
||||
!vws->base.have_gb_objects) {
|
||||
/*
|
||||
* A managed pool for DMA buffers.
|
||||
*/
|
||||
vws->pools.gmr_mm = mm_bufmgr_create(vws->pools.gmr,
|
||||
VMW_GMR_POOL_SIZE,
|
||||
12 /* 4096 alignment */);
|
||||
if(!vws->pools.gmr_mm)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* We disallow "CPU" buffers to be created by the fenced_bufmgr_create,
|
||||
* because that defers "GPU" buffer creation to buffer validation,
|
||||
* and at buffer validation we have no means of handling failures
|
||||
* due to pools space shortage or fragmentation. Effectively this
|
||||
* makes sure all failures are reported immediately on buffer allocation,
|
||||
* and we can revert to allocating directly from the kernel.
|
||||
*/
|
||||
vws->pools.gmr_fenced = fenced_bufmgr_create(
|
||||
vws->pools.gmr_mm,
|
||||
vmw_fence_ops_create(vws),
|
||||
VMW_GMR_POOL_SIZE,
|
||||
0);
|
||||
vws->pools.gmr_fenced = simple_fenced_bufmgr_create
|
||||
(vws->pools.gmr_mm, vws->fence_ops);
|
||||
|
||||
#ifdef DEBUG
|
||||
vws->pools.gmr_fenced = pb_debug_manager_create(vws->pools.gmr_fenced,
|
||||
4096,
|
||||
4096);
|
||||
vws->pools.gmr_fenced = pb_debug_manager_create(vws->pools.gmr_fenced,
|
||||
4096,
|
||||
4096);
|
||||
#endif
|
||||
if(!vws->pools.gmr_fenced)
|
||||
goto error;
|
||||
if(!vws->pools.gmr_fenced)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* The slab pool allocates buffers directly from the kernel except
|
||||
|
|
@ -153,30 +197,33 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
|
|||
* not to waste memory, since a kernel buffer is a minimum 4096 bytes.
|
||||
*
|
||||
* Here we use it only for emergency in the case our pre-allocated
|
||||
* buffer pool runs out of memory.
|
||||
* managed buffer pool runs out of memory.
|
||||
*/
|
||||
desc.alignment = 64;
|
||||
desc.usage = ~0;
|
||||
vws->pools.gmr_slab = pb_slab_range_manager_create(vws->pools.gmr,
|
||||
64,
|
||||
8192,
|
||||
16384,
|
||||
&desc);
|
||||
if (!vws->pools.gmr_slab)
|
||||
goto error;
|
||||
|
||||
vws->pools.gmr_slab_fenced =
|
||||
fenced_bufmgr_create(vws->pools.gmr_slab,
|
||||
vmw_fence_ops_create(vws),
|
||||
VMW_MAX_BUFFER_SIZE,
|
||||
0);
|
||||
desc.alignment = 64;
|
||||
desc.usage = ~(SVGA_BUFFER_USAGE_PINNED | SVGA_BUFFER_USAGE_SHADER |
|
||||
VMW_BUFFER_USAGE_SHARED | VMW_BUFFER_USAGE_SYNC);
|
||||
vws->pools.gmr_slab = pb_slab_range_manager_create(vws->pools.gmr,
|
||||
64,
|
||||
8192,
|
||||
16384,
|
||||
&desc);
|
||||
if (!vws->pools.gmr_slab)
|
||||
goto error;
|
||||
|
||||
if (!vws->pools.gmr_slab_fenced)
|
||||
goto error;
|
||||
vws->pools.gmr_slab_fenced =
|
||||
simple_fenced_bufmgr_create(vws->pools.gmr_slab, vws->fence_ops);
|
||||
|
||||
if (!vws->pools.gmr_slab_fenced)
|
||||
goto error;
|
||||
}
|
||||
|
||||
vws->pools.query_fenced = NULL;
|
||||
vws->pools.query_mm = NULL;
|
||||
vws->pools.query = NULL;
|
||||
vws->pools.mob_cache = NULL;
|
||||
|
||||
if (vws->base.have_gb_objects && !vmw_mob_pools_init(vws))
|
||||
goto error;
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -184,4 +231,3 @@ error:
|
|||
vmw_pools_cleanup(vws);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,14 @@
|
|||
#include "vmw_surface.h"
|
||||
#include "vmw_buffer.h"
|
||||
#include "vmw_fence.h"
|
||||
#include "vmw_shader.h"
|
||||
#include "svga3d_surfacedefs.h"
|
||||
|
||||
/**
|
||||
* Try to get a surface backing buffer from the cache
|
||||
* if it's this size or smaller.
|
||||
*/
|
||||
#define VMW_TRY_CACHED_SIZE (2*1024*1024)
|
||||
|
||||
static struct svga_winsys_buffer *
|
||||
vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
|
||||
|
|
@ -56,64 +63,37 @@ vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
|
|||
unsigned size)
|
||||
{
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
struct pb_desc desc;
|
||||
struct vmw_buffer_desc desc;
|
||||
struct pb_manager *provider;
|
||||
struct pb_buffer *buffer;
|
||||
|
||||
memset(&desc, 0, sizeof desc);
|
||||
desc.alignment = alignment;
|
||||
desc.usage = usage;
|
||||
desc.pb_desc.alignment = alignment;
|
||||
desc.pb_desc.usage = usage;
|
||||
|
||||
if (usage == SVGA_BUFFER_USAGE_PINNED) {
|
||||
if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
|
||||
return NULL;
|
||||
provider = vws->pools.query_fenced;
|
||||
} else if (usage == SVGA_BUFFER_USAGE_SHADER) {
|
||||
provider = vws->pools.mob_shader_slab_fenced;
|
||||
} else
|
||||
provider = vws->pools.gmr_fenced;
|
||||
|
||||
assert(provider);
|
||||
buffer = provider->create_buffer(provider, size, &desc);
|
||||
buffer = provider->create_buffer(provider, size, &desc.pb_desc);
|
||||
|
||||
if(!buffer && provider == vws->pools.gmr_fenced) {
|
||||
|
||||
assert(provider);
|
||||
provider = vws->pools.gmr_slab_fenced;
|
||||
buffer = provider->create_buffer(provider, size, &desc);
|
||||
buffer = provider->create_buffer(provider, size, &desc.pb_desc);
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
return vmw_svga_winsys_buffer(buffer);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
vmw_svga_winsys_buffer_map(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf,
|
||||
unsigned flags)
|
||||
{
|
||||
(void)sws;
|
||||
return pb_map(vmw_pb_buffer(buf), flags, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vmw_svga_winsys_buffer_unmap(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf)
|
||||
{
|
||||
(void)sws;
|
||||
pb_unmap(vmw_pb_buffer(buf));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vmw_svga_winsys_buffer_destroy(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_buffer *buf)
|
||||
{
|
||||
struct pb_buffer *pbuf = vmw_pb_buffer(buf);
|
||||
(void)sws;
|
||||
pb_reference(&pbuf, NULL);
|
||||
return vmw_svga_winsys_buffer_wrap(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -161,7 +141,12 @@ vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
|
|||
{
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
struct vmw_svga_winsys_surface *surface;
|
||||
struct vmw_buffer_desc desc;
|
||||
struct pb_manager *provider = vws->pools.mob_fenced;
|
||||
uint32_t buffer_size;
|
||||
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
|
||||
if(!surface)
|
||||
goto no_surface;
|
||||
|
|
@ -169,15 +154,96 @@ vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
|
|||
pipe_reference_init(&surface->refcnt, 1);
|
||||
p_atomic_set(&surface->validated, 0);
|
||||
surface->screen = vws;
|
||||
surface->sid = vmw_ioctl_surface_create(vws,
|
||||
flags, format, size,
|
||||
numFaces, numMipLevels);
|
||||
if(surface->sid == SVGA3D_INVALID_ID)
|
||||
goto no_sid;
|
||||
pipe_mutex_init(surface->mutex);
|
||||
|
||||
/*
|
||||
* Used for the backing buffer GB surfaces, and to approximate
|
||||
* when to flush on non-GB hosts.
|
||||
*/
|
||||
buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels, (numFaces == 6));
|
||||
if (sws->have_gb_objects) {
|
||||
SVGAGuestPtr ptr = {0,0};
|
||||
|
||||
/*
|
||||
* If the backing buffer size is small enough, try to allocate a
|
||||
* buffer out of the buffer cache. Otherwise, let the kernel allocate
|
||||
* a suitable buffer for us.
|
||||
*/
|
||||
if (buffer_size < VMW_TRY_CACHED_SIZE) {
|
||||
struct pb_buffer *pb_buf;
|
||||
|
||||
surface->size = buffer_size;
|
||||
desc.pb_desc.alignment = 4096;
|
||||
desc.pb_desc.usage = 0;
|
||||
pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
|
||||
surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
|
||||
if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
|
||||
assert(0);
|
||||
}
|
||||
|
||||
surface->sid = vmw_ioctl_gb_surface_create(vws,
|
||||
flags, format, size,
|
||||
numFaces, numMipLevels,
|
||||
ptr.gmrId,
|
||||
surface->buf ? NULL :
|
||||
&desc.region);
|
||||
|
||||
if (surface->sid == SVGA3D_INVALID_ID && surface->buf) {
|
||||
|
||||
/*
|
||||
* Kernel refused to allocate a surface for us.
|
||||
* Perhaps something was wrong with our buffer?
|
||||
* This is really a guard against future new size requirements
|
||||
* on the backing buffers.
|
||||
*/
|
||||
vmw_svga_winsys_buffer_destroy(sws, surface->buf);
|
||||
surface->buf = NULL;
|
||||
surface->sid = vmw_ioctl_gb_surface_create(vws,
|
||||
flags, format, size,
|
||||
numFaces, numMipLevels,
|
||||
0,
|
||||
&desc.region);
|
||||
if (surface->sid == SVGA3D_INVALID_ID)
|
||||
goto no_sid;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the kernel created the buffer for us, wrap it into a
|
||||
* vmw_svga_winsys_buffer.
|
||||
*/
|
||||
if (surface->buf == NULL) {
|
||||
struct pb_buffer *pb_buf;
|
||||
|
||||
surface->size = vmw_region_size(desc.region);
|
||||
desc.pb_desc.alignment = 4096;
|
||||
desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
|
||||
pb_buf = provider->create_buffer(provider, surface->size,
|
||||
&desc.pb_desc);
|
||||
surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
|
||||
if (surface->buf == NULL) {
|
||||
vmw_ioctl_region_destroy(desc.region);
|
||||
vmw_ioctl_surface_destroy(vws, surface->sid);
|
||||
goto no_sid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
surface->sid = vmw_ioctl_surface_create(vws,
|
||||
flags, format, size,
|
||||
numFaces, numMipLevels);
|
||||
if(surface->sid == SVGA3D_INVALID_ID)
|
||||
goto no_sid;
|
||||
|
||||
/* Best estimate for surface size, used for early flushing. */
|
||||
surface->size = buffer_size;
|
||||
surface->buf = NULL;
|
||||
}
|
||||
|
||||
return svga_winsys_surface(surface);
|
||||
|
||||
no_sid:
|
||||
if (surface->buf)
|
||||
vmw_svga_winsys_buffer_destroy(sws, surface->buf);
|
||||
|
||||
FREE(surface);
|
||||
no_surface:
|
||||
return NULL;
|
||||
|
|
@ -220,6 +286,9 @@ vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
|
|||
{
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
|
||||
if (sws->have_gb_objects)
|
||||
return SVGA3D_HWVERSION_WS8_B1;
|
||||
|
||||
return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
|
||||
}
|
||||
|
||||
|
|
@ -228,69 +297,69 @@ static boolean
|
|||
vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
|
||||
SVGA3dDevCapIndex index,
|
||||
SVGA3dDevCapResult *result)
|
||||
{
|
||||
{
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
const uint32 *capsBlock;
|
||||
const SVGA3dCapsRecord *capsRecord = NULL;
|
||||
uint32 offset;
|
||||
const SVGA3dCapPair *capArray;
|
||||
int numCaps, first, last;
|
||||
|
||||
if(vws->ioctl.hwversion < SVGA3D_HWVERSION_WS6_B1)
|
||||
if (index > vws->ioctl.num_cap_3d || !vws->ioctl.cap_3d[index].has_cap)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Search linearly through the caps block records for the specified type.
|
||||
*/
|
||||
capsBlock = (const uint32 *)vws->ioctl.buffer;
|
||||
for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
|
||||
const SVGA3dCapsRecord *record;
|
||||
assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
|
||||
record = (const SVGA3dCapsRecord *) (capsBlock + offset);
|
||||
if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
|
||||
(record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
|
||||
(!capsRecord || (record->header.type > capsRecord->header.type))) {
|
||||
capsRecord = record;
|
||||
}
|
||||
}
|
||||
|
||||
if(!capsRecord)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Calculate the number of caps from the size of the record.
|
||||
*/
|
||||
capArray = (const SVGA3dCapPair *) capsRecord->data;
|
||||
numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
|
||||
sizeof capsRecord->header) / (2 * sizeof(uint32)));
|
||||
|
||||
/*
|
||||
* Binary-search for the cap with the specified index.
|
||||
*/
|
||||
for (first = 0, last = numCaps - 1; first <= last; ) {
|
||||
int mid = (first + last) / 2;
|
||||
|
||||
if ((SVGA3dDevCapIndex) capArray[mid][0] == index) {
|
||||
/*
|
||||
* Found it.
|
||||
*/
|
||||
result->u = capArray[mid][1];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Divide and conquer.
|
||||
*/
|
||||
if ((SVGA3dDevCapIndex) capArray[mid][0] > index) {
|
||||
last = mid - 1;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
*result = vws->ioctl.cap_3d[index].result;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct svga_winsys_gb_shader *
|
||||
vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
|
||||
SVGA3dShaderType type,
|
||||
const uint32 *bytecode,
|
||||
uint32 bytecodeLen)
|
||||
{
|
||||
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
|
||||
struct vmw_svga_winsys_shader *shader;
|
||||
void *code;
|
||||
|
||||
shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
|
||||
if(!shader)
|
||||
goto out_no_shader;
|
||||
|
||||
pipe_reference_init(&shader->refcnt, 1);
|
||||
p_atomic_set(&shader->validated, 0);
|
||||
shader->screen = vws;
|
||||
shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
|
||||
SVGA_BUFFER_USAGE_SHADER,
|
||||
bytecodeLen);
|
||||
if (!shader->buf)
|
||||
goto out_no_buf;
|
||||
|
||||
code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
|
||||
if (!code)
|
||||
goto out_no_buf;
|
||||
|
||||
memcpy(code, bytecode, bytecodeLen);
|
||||
vmw_svga_winsys_buffer_unmap(sws, shader->buf);
|
||||
|
||||
shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
|
||||
if(shader->shid == SVGA3D_INVALID_ID)
|
||||
goto out_no_shid;
|
||||
|
||||
return svga_winsys_shader(shader);
|
||||
|
||||
out_no_shid:
|
||||
vmw_svga_winsys_buffer_destroy(sws, shader->buf);
|
||||
out_no_buf:
|
||||
FREE(shader);
|
||||
out_no_shader:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
|
||||
struct svga_winsys_gb_shader *shader)
|
||||
{
|
||||
struct vmw_svga_winsys_shader *d_shader =
|
||||
vmw_svga_winsys_shader(shader);
|
||||
|
||||
vmw_svga_winsys_shader_reference(&d_shader, NULL);
|
||||
}
|
||||
|
||||
boolean
|
||||
vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
|
||||
|
|
@ -308,6 +377,8 @@ vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
|
|||
vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
|
||||
vws->base.fence_reference = vmw_svga_winsys_fence_reference;
|
||||
vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
|
||||
vws->base.shader_create = vmw_svga_winsys_shader_create;
|
||||
vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
|
||||
vws->base.fence_finish = vmw_svga_winsys_fence_finish;
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
64
src/gallium/winsys/svga/drm/vmw_shader.c
Normal file
64
src/gallium/winsys/svga/drm/vmw_shader.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/**********************************************************
|
||||
* Copyright 2009-2012 VMware, Inc. 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, 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 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.
|
||||
*
|
||||
**********************************************************/
|
||||
|
||||
|
||||
#include "svga_cmd.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
#include "vmw_shader.h"
|
||||
#include "vmw_screen.h"
|
||||
|
||||
void
|
||||
vmw_svga_winsys_shader_reference(struct vmw_svga_winsys_shader **pdst,
|
||||
struct vmw_svga_winsys_shader *src)
|
||||
{
|
||||
struct pipe_reference *src_ref;
|
||||
struct pipe_reference *dst_ref;
|
||||
struct vmw_svga_winsys_shader *dst;
|
||||
|
||||
if(pdst == NULL || *pdst == src)
|
||||
return;
|
||||
|
||||
dst = *pdst;
|
||||
|
||||
src_ref = src ? &src->refcnt : NULL;
|
||||
dst_ref = dst ? &dst->refcnt : NULL;
|
||||
|
||||
if (pipe_reference(dst_ref, src_ref)) {
|
||||
struct svga_winsys_screen *sws = &dst->screen->base;
|
||||
|
||||
vmw_ioctl_shader_destroy(dst->screen, dst->shid);
|
||||
#ifdef DEBUG
|
||||
/* to detect dangling pointers */
|
||||
assert(p_atomic_read(&dst->validated) == 0);
|
||||
dst->shid = SVGA3D_INVALID_ID;
|
||||
#endif
|
||||
sws->buffer_destroy(sws, dst->buf);
|
||||
FREE(dst);
|
||||
}
|
||||
|
||||
*pdst = src;
|
||||
}
|
||||
67
src/gallium/winsys/svga/drm/vmw_shader.h
Normal file
67
src/gallium/winsys/svga/drm/vmw_shader.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**********************************************************
|
||||
* Copyright 2009-2012 VMware, Inc. 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, 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 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.
|
||||
*
|
||||
**********************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Shaders for VMware SVGA winsys.
|
||||
*
|
||||
* @author Jose Fonseca <jfonseca@vmware.com>
|
||||
* @author Thomas Hellstrom <thellstrom@vmware.com>
|
||||
*/
|
||||
|
||||
#ifndef VMW_SHADER_H_
|
||||
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_atomic.h"
|
||||
#include "util/u_inlines.h"
|
||||
|
||||
struct vmw_svga_winsys_shader
|
||||
{
|
||||
int32_t validated;
|
||||
struct pipe_reference refcnt;
|
||||
|
||||
struct vmw_winsys_screen *screen;
|
||||
struct svga_winsys_buffer *buf;
|
||||
uint32_t shid;
|
||||
};
|
||||
|
||||
static INLINE struct svga_winsys_gb_shader *
|
||||
svga_winsys_shader(struct vmw_svga_winsys_shader *shader)
|
||||
{
|
||||
assert(!shader || shader->shid != SVGA3D_INVALID_ID);
|
||||
return (struct svga_winsys_gb_shader *)shader;
|
||||
}
|
||||
|
||||
static INLINE struct vmw_svga_winsys_shader *
|
||||
vmw_svga_winsys_shader(struct svga_winsys_gb_shader *shader)
|
||||
{
|
||||
return (struct vmw_svga_winsys_shader *)shader;
|
||||
}
|
||||
|
||||
void
|
||||
vmw_svga_winsys_shader_reference(struct vmw_svga_winsys_shader **pdst,
|
||||
struct vmw_svga_winsys_shader *src);
|
||||
|
||||
#endif /* VMW_SHADER_H_ */
|
||||
|
|
@ -27,9 +27,152 @@
|
|||
#include "svga_cmd.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
#include "pipe/p_defines.h"
|
||||
#include "vmw_surface.h"
|
||||
#include "vmw_screen.h"
|
||||
#include "vmw_buffer.h"
|
||||
#include "vmw_context.h"
|
||||
#include "pipebuffer/pb_bufmgr.h"
|
||||
|
||||
|
||||
void *
|
||||
vmw_svga_winsys_surface_map(struct svga_winsys_context *swc,
|
||||
struct svga_winsys_surface *srf,
|
||||
unsigned flags, boolean *retry)
|
||||
{
|
||||
struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
|
||||
void *data = NULL;
|
||||
struct pb_buffer *pb_buf;
|
||||
uint32_t pb_flags;
|
||||
struct vmw_winsys_screen *vws = vsrf->screen;
|
||||
|
||||
*retry = FALSE;
|
||||
assert((flags & (PIPE_TRANSFER_READ | PIPE_TRANSFER_WRITE)) != 0);
|
||||
pipe_mutex_lock(vsrf->mutex);
|
||||
|
||||
if (vsrf->mapcount) {
|
||||
/*
|
||||
* Only allow multiple readers to map.
|
||||
*/
|
||||
if ((flags & PIPE_TRANSFER_WRITE) ||
|
||||
(vsrf->map_mode & PIPE_TRANSFER_WRITE))
|
||||
goto out_unlock;
|
||||
|
||||
data = vsrf->data;
|
||||
goto out_mapped;
|
||||
}
|
||||
|
||||
vsrf->rebind = FALSE;
|
||||
|
||||
/*
|
||||
* If we intend to read, there's no point discarding the
|
||||
* data if busy.
|
||||
*/
|
||||
if (flags & PIPE_TRANSFER_READ || vsrf->shared)
|
||||
flags &= ~PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
|
||||
|
||||
/*
|
||||
* Discard is a hint to a synchronized map.
|
||||
*/
|
||||
if (flags & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)
|
||||
flags &= ~PIPE_TRANSFER_UNSYNCHRONIZED;
|
||||
|
||||
/*
|
||||
* The surface is allowed to be referenced on the command stream iff
|
||||
* we're mapping unsynchronized or discard. This is an early check.
|
||||
* We need to recheck after a failing discard map.
|
||||
*/
|
||||
if (!(flags & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
|
||||
PIPE_TRANSFER_UNSYNCHRONIZED)) &&
|
||||
p_atomic_read(&vsrf->validated)) {
|
||||
*retry = TRUE;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
pb_flags = flags & (PIPE_TRANSFER_READ_WRITE | PIPE_TRANSFER_UNSYNCHRONIZED);
|
||||
|
||||
if (flags & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
|
||||
struct pb_manager *provider;
|
||||
struct pb_desc desc;
|
||||
|
||||
/*
|
||||
* First, if possible, try to map existing storage with DONTBLOCK.
|
||||
*/
|
||||
if (!p_atomic_read(&vsrf->validated)) {
|
||||
data = vmw_svga_winsys_buffer_map(&vws->base, vsrf->buf,
|
||||
PIPE_TRANSFER_DONTBLOCK | pb_flags);
|
||||
if (data)
|
||||
goto out_mapped;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to get a new buffer.
|
||||
*/
|
||||
provider = vws->pools.mob_fenced;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.alignment = 4096;
|
||||
pb_buf = provider->create_buffer(provider, vsrf->size, &desc);
|
||||
if (pb_buf != NULL) {
|
||||
struct svga_winsys_buffer *vbuf =
|
||||
vmw_svga_winsys_buffer_wrap(pb_buf);
|
||||
|
||||
data = vmw_svga_winsys_buffer_map(&vws->base, vbuf, pb_flags);
|
||||
if (data) {
|
||||
vsrf->rebind = TRUE;
|
||||
/*
|
||||
* We've discarded data on this surface and thus
|
||||
* it's data is no longer consider referenced.
|
||||
*/
|
||||
vmw_swc_surface_clear_reference(swc, vsrf);
|
||||
if (vsrf->buf)
|
||||
vmw_svga_winsys_buffer_destroy(&vws->base, vsrf->buf);
|
||||
vsrf->buf = vbuf;
|
||||
goto out_mapped;
|
||||
} else
|
||||
vmw_svga_winsys_buffer_destroy(&vws->base, vbuf);
|
||||
}
|
||||
/*
|
||||
* We couldn't get and map a new buffer for some reason.
|
||||
* Fall through to an ordinary map.
|
||||
* But tell pipe driver to flush now if already on validate list,
|
||||
* Otherwise we'll overwrite previous contents.
|
||||
*/
|
||||
if (!(flags & PIPE_TRANSFER_UNSYNCHRONIZED) &&
|
||||
p_atomic_read(&vsrf->validated)) {
|
||||
*retry = TRUE;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
pb_flags |= (flags & PIPE_TRANSFER_DONTBLOCK);
|
||||
data = vmw_svga_winsys_buffer_map(&vws->base, vsrf->buf, pb_flags);
|
||||
if (data == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
out_mapped:
|
||||
++vsrf->mapcount;
|
||||
vsrf->data = data;
|
||||
vsrf->map_mode = flags & (PIPE_TRANSFER_READ | PIPE_TRANSFER_WRITE);
|
||||
out_unlock:
|
||||
pipe_mutex_unlock(vsrf->mutex);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vmw_svga_winsys_surface_unmap(struct svga_winsys_context *swc,
|
||||
struct svga_winsys_surface *srf,
|
||||
boolean *rebind)
|
||||
{
|
||||
struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
|
||||
pipe_mutex_lock(vsrf->mutex);
|
||||
if (--vsrf->mapcount == 0) {
|
||||
*rebind = vsrf->rebind;
|
||||
vsrf->rebind = FALSE;
|
||||
vmw_svga_winsys_buffer_unmap(&vsrf->screen->base, vsrf->buf);
|
||||
}
|
||||
pipe_mutex_unlock(vsrf->mutex);
|
||||
}
|
||||
|
||||
void
|
||||
vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
|
||||
|
|
@ -48,12 +191,15 @@ vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
|
|||
dst_ref = dst ? &dst->refcnt : NULL;
|
||||
|
||||
if (pipe_reference(dst_ref, src_ref)) {
|
||||
if (dst->buf)
|
||||
vmw_svga_winsys_buffer_destroy(&dst->screen->base, dst->buf);
|
||||
vmw_ioctl_surface_destroy(dst->screen, dst->sid);
|
||||
#ifdef DEBUG
|
||||
/* to detect dangling pointers */
|
||||
assert(p_atomic_read(&dst->validated) == 0);
|
||||
dst->sid = SVGA3D_INVALID_ID;
|
||||
#endif
|
||||
pipe_mutex_destroy(dst->mutex);
|
||||
FREE(dst);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_atomic.h"
|
||||
#include "util/u_inlines.h"
|
||||
#include "os/os_thread.h"
|
||||
#include "pipebuffer/pb_buffer.h"
|
||||
|
||||
#define VMW_MAX_PRESENTS 3
|
||||
|
||||
|
|
@ -54,6 +56,15 @@ struct vmw_svga_winsys_surface
|
|||
/* FIXME: make this thread safe */
|
||||
unsigned next_present_no;
|
||||
uint32_t present_fences[VMW_MAX_PRESENTS];
|
||||
|
||||
pipe_mutex mutex;
|
||||
struct svga_winsys_buffer *buf; /* Current backing guest buffer */
|
||||
uint32_t mapcount; /* Number of mappers */
|
||||
uint32_t map_mode; /* PIPE_TRANSFER_[READ|WRITE] */
|
||||
void *data; /* Pointer to data if mapcount != 0*/
|
||||
boolean shared; /* Shared surface. Never discard */
|
||||
uint32_t size; /* Size of backing buffer */
|
||||
boolean rebind; /* Surface needs a rebind after next unmap */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -75,5 +86,13 @@ vmw_svga_winsys_surface(struct svga_winsys_surface *surf)
|
|||
void
|
||||
vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
|
||||
struct vmw_svga_winsys_surface *src);
|
||||
void *
|
||||
vmw_svga_winsys_surface_map(struct svga_winsys_context *swc,
|
||||
struct svga_winsys_surface *srf,
|
||||
unsigned flags, boolean *retry);
|
||||
void
|
||||
vmw_svga_winsys_surface_unmap(struct svga_winsys_context *swc,
|
||||
struct svga_winsys_surface *srf,
|
||||
boolean *rebind);
|
||||
|
||||
#endif /* VMW_SURFACE_H_ */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
#ifndef __VMWGFX_DRM_H__
|
||||
#define __VMWGFX_DRM_H__
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#include <drm.h>
|
||||
#endif
|
||||
|
||||
#define DRM_VMW_MAX_SURFACE_FACES 6
|
||||
#define DRM_VMW_MAX_MIP_LEVELS 24
|
||||
|
||||
|
|
@ -54,7 +58,12 @@
|
|||
#define DRM_VMW_FENCE_EVENT 17
|
||||
#define DRM_VMW_PRESENT 18
|
||||
#define DRM_VMW_PRESENT_READBACK 19
|
||||
|
||||
#define DRM_VMW_UPDATE_LAYOUT 20
|
||||
#define DRM_VMW_CREATE_SHADER 21
|
||||
#define DRM_VMW_UNREF_SHADER 22
|
||||
#define DRM_VMW_GB_SURFACE_CREATE 23
|
||||
#define DRM_VMW_GB_SURFACE_REF 24
|
||||
#define DRM_VMW_SYNCCPU 25
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
|
|
@ -75,6 +84,9 @@
|
|||
#define DRM_VMW_PARAM_FIFO_CAPS 4
|
||||
#define DRM_VMW_PARAM_MAX_FB_SIZE 5
|
||||
#define DRM_VMW_PARAM_FIFO_HW_VERSION 6
|
||||
#define DRM_VMW_PARAM_MAX_SURF_MEMORY 7
|
||||
#define DRM_VMW_PARAM_3D_CAPS_SIZE 8
|
||||
#define DRM_VMW_PARAM_MAX_MOB_MEMORY 9
|
||||
|
||||
/**
|
||||
* struct drm_vmw_getparam_arg
|
||||
|
|
@ -659,6 +671,51 @@ struct drm_vmw_fence_arg {
|
|||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_FENCE_EVENT
|
||||
*
|
||||
* Queues an event on a fence to be delivered on the drm character device
|
||||
* when the fence has signaled the DRM_VMW_FENCE_FLAG_EXEC flag.
|
||||
* Optionally the approximate time when the fence signaled is
|
||||
* given by the event.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The event type
|
||||
*/
|
||||
#define DRM_VMW_EVENT_FENCE_SIGNALED 0x80000000
|
||||
|
||||
struct drm_vmw_event_fence {
|
||||
struct drm_event base;
|
||||
uint64_t user_data;
|
||||
uint32_t tv_sec;
|
||||
uint32_t tv_usec;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags that may be given to the command.
|
||||
*/
|
||||
/* Request fence signaled time on the event. */
|
||||
#define DRM_VMW_FE_FLAG_REQ_TIME (1 << 0)
|
||||
|
||||
/**
|
||||
* struct drm_vmw_fence_event_arg
|
||||
*
|
||||
* @fence_rep: Pointer to fence_rep structure cast to uint64_t or 0 if
|
||||
* the fence is not supposed to be referenced by user-space.
|
||||
* @user_info: Info to be delivered with the event.
|
||||
* @handle: Attach the event to this fence only.
|
||||
* @flags: A set of flags as defined above.
|
||||
*/
|
||||
struct drm_vmw_fence_event_arg {
|
||||
uint64_t fence_rep;
|
||||
uint64_t user_data;
|
||||
uint32_t handle;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_PRESENT
|
||||
|
|
@ -720,5 +777,276 @@ struct drm_vmw_present_readback_arg {
|
|||
uint64_t fence_rep;
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_UPDATE_LAYOUT - Update layout
|
||||
*
|
||||
* Updates the preferred modes and connection status for connectors. The
|
||||
* command consists of one drm_vmw_update_layout_arg pointing to an array
|
||||
* of num_outputs drm_vmw_rect's.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct drm_vmw_update_layout_arg
|
||||
*
|
||||
* @num_outputs: number of active connectors
|
||||
* @rects: pointer to array of drm_vmw_rect cast to an uint64_t
|
||||
*
|
||||
* Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
|
||||
*/
|
||||
struct drm_vmw_update_layout_arg {
|
||||
uint32_t num_outputs;
|
||||
uint32_t pad64;
|
||||
uint64_t rects;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_CREATE_SHADER - Create shader
|
||||
*
|
||||
* Creates a shader and optionally binds it to a dma buffer containing
|
||||
* the shader byte-code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum drm_vmw_shader_type - Shader types
|
||||
*/
|
||||
enum drm_vmw_shader_type {
|
||||
drm_vmw_shader_type_vs = 0,
|
||||
drm_vmw_shader_type_ps,
|
||||
drm_vmw_shader_type_gs
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct drm_vmw_shader_create_arg
|
||||
*
|
||||
* @shader_type: Shader type of the shader to create.
|
||||
* @size: Size of the byte-code in bytes.
|
||||
* where the shader byte-code starts
|
||||
* @buffer_handle: Buffer handle identifying the buffer containing the
|
||||
* shader byte-code
|
||||
* @shader_handle: On successful completion contains a handle that
|
||||
* can be used to subsequently identify the shader.
|
||||
* @offset: Offset in bytes into the buffer given by @buffer_handle,
|
||||
*
|
||||
* Input / Output argument to the DRM_VMW_CREATE_SHADER Ioctl.
|
||||
*/
|
||||
struct drm_vmw_shader_create_arg {
|
||||
enum drm_vmw_shader_type shader_type;
|
||||
uint32_t size;
|
||||
uint32_t buffer_handle;
|
||||
uint32_t shader_handle;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_UNREF_SHADER - Unreferences a shader
|
||||
*
|
||||
* Destroys a user-space reference to a shader, optionally destroying
|
||||
* it.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct drm_vmw_shader_arg
|
||||
*
|
||||
* @handle: Handle identifying the shader to destroy.
|
||||
*
|
||||
* Input argument to the DRM_VMW_UNREF_SHADER ioctl.
|
||||
*/
|
||||
struct drm_vmw_shader_arg {
|
||||
uint32_t handle;
|
||||
uint32_t pad64;
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_GB_SURFACE_CREATE - Create a host guest-backed surface.
|
||||
*
|
||||
* Allocates a surface handle and queues a create surface command
|
||||
* for the host on the first use of the surface. The surface ID can
|
||||
* be used as the surface ID in commands referencing the surface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum drm_vmw_surface_flags
|
||||
*
|
||||
* @drm_vmw_surface_flag_shareable: Whether the surface is shareable
|
||||
* @drm_vmw_surface_flag_scanout: Whether the surface is a scanout
|
||||
* surface.
|
||||
* @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is
|
||||
* given.
|
||||
*/
|
||||
enum drm_vmw_surface_flags {
|
||||
drm_vmw_surface_flag_shareable = (1 << 0),
|
||||
drm_vmw_surface_flag_scanout = (1 << 1),
|
||||
drm_vmw_surface_flag_create_buffer = (1 << 2)
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_vmw_gb_surface_create_req
|
||||
*
|
||||
* @svga3d_flags: SVGA3d surface flags for the device.
|
||||
* @format: SVGA3d format.
|
||||
* @mip_level: Number of mip levels for all faces.
|
||||
* @drm_surface_flags Flags as described above.
|
||||
* @multisample_count Future use. Set to 0.
|
||||
* @autogen_filter Future use. Set to 0.
|
||||
* @buffer_handle Buffer handle of backup buffer. SVGA3D_INVALID_ID
|
||||
* if none.
|
||||
* @base_size Size of the base mip level for all faces.
|
||||
*
|
||||
* Input argument to the DRM_VMW_GB_SURFACE_CREATE Ioctl.
|
||||
* Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.
|
||||
*/
|
||||
struct drm_vmw_gb_surface_create_req {
|
||||
uint32_t svga3d_flags;
|
||||
uint32_t format;
|
||||
uint32_t mip_levels;
|
||||
enum drm_vmw_surface_flags drm_surface_flags;
|
||||
uint32_t multisample_count;
|
||||
uint32_t autogen_filter;
|
||||
uint32_t buffer_handle;
|
||||
uint32_t pad64;
|
||||
struct drm_vmw_size base_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_vmw_gb_surface_create_rep
|
||||
*
|
||||
* @handle: Surface handle.
|
||||
* @backup_size: Size of backup buffers for this surface.
|
||||
* @buffer_handle: Handle of backup buffer. SVGA3D_INVALID_ID if none.
|
||||
* @buffer_size: Actual size of the buffer identified by
|
||||
* @buffer_handle
|
||||
* @buffer_map_handle: Offset into device address space for the buffer
|
||||
* identified by @buffer_handle.
|
||||
*
|
||||
* Part of output argument for the DRM_VMW_GB_SURFACE_REF ioctl.
|
||||
* Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl.
|
||||
*/
|
||||
struct drm_vmw_gb_surface_create_rep {
|
||||
uint32_t handle;
|
||||
uint32_t backup_size;
|
||||
uint32_t buffer_handle;
|
||||
uint32_t buffer_size;
|
||||
uint64_t buffer_map_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* union drm_vmw_gb_surface_create_arg
|
||||
*
|
||||
* @req: Input argument as described above.
|
||||
* @rep: Output argument as described above.
|
||||
*
|
||||
* Argument to the DRM_VMW_GB_SURFACE_CREATE ioctl.
|
||||
*/
|
||||
union drm_vmw_gb_surface_create_arg {
|
||||
struct drm_vmw_gb_surface_create_rep rep;
|
||||
struct drm_vmw_gb_surface_create_req req;
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_GB_SURFACE_REF - Reference a host surface.
|
||||
*
|
||||
* Puts a reference on a host surface with a given handle, as previously
|
||||
* returned by the DRM_VMW_GB_SURFACE_CREATE ioctl.
|
||||
* A reference will make sure the surface isn't destroyed while we hold
|
||||
* it and will allow the calling client to use the surface handle in
|
||||
* the command stream.
|
||||
*
|
||||
* On successful return, the Ioctl returns the surface information given
|
||||
* to and returned from the DRM_VMW_GB_SURFACE_CREATE ioctl.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct drm_vmw_gb_surface_reference_arg
|
||||
*
|
||||
* @creq: The data used as input when the surface was created, as described
|
||||
* above at "struct drm_vmw_gb_surface_create_req"
|
||||
* @crep: Additional data output when the surface was created, as described
|
||||
* above at "struct drm_vmw_gb_surface_create_rep"
|
||||
*
|
||||
* Output Argument to the DRM_VMW_GB_SURFACE_REF ioctl.
|
||||
*/
|
||||
struct drm_vmw_gb_surface_ref_rep {
|
||||
struct drm_vmw_gb_surface_create_req creq;
|
||||
struct drm_vmw_gb_surface_create_rep crep;
|
||||
};
|
||||
|
||||
/**
|
||||
* union drm_vmw_gb_surface_reference_arg
|
||||
*
|
||||
* @req: Input data as described above at "struct drm_vmw_surface_arg"
|
||||
* @rep: Output data as described above at "struct drm_vmw_gb_surface_ref_rep"
|
||||
*
|
||||
* Argument to the DRM_VMW_GB_SURFACE_REF Ioctl.
|
||||
*/
|
||||
union drm_vmw_gb_surface_reference_arg {
|
||||
struct drm_vmw_gb_surface_ref_rep rep;
|
||||
struct drm_vmw_surface_arg req;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* DRM_VMW_SYNCCPU - Sync a DMA buffer / MOB for CPU access.
|
||||
*
|
||||
* Idles any previously submitted GPU operations on the buffer and
|
||||
* by default blocks command submissions that reference the buffer.
|
||||
* If the file descriptor used to grab a blocking CPU sync is closed, the
|
||||
* cpu sync is released.
|
||||
* The flags argument indicates how the grab / release operation should be
|
||||
* performed:
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum drm_vmw_synccpu_flags - Synccpu flags:
|
||||
*
|
||||
* @drm_vmw_synccpu_read: Sync for read. If sync is done for read only, it's a
|
||||
* hint to the kernel to allow command submissions that references the buffer
|
||||
* for read-only.
|
||||
* @drm_vmw_synccpu_write: Sync for write. Block all command submissions
|
||||
* referencing this buffer.
|
||||
* @drm_vmw_synccpu_dontblock: Dont wait for GPU idle, but rather return
|
||||
* -EBUSY should the buffer be busy.
|
||||
* @drm_vmw_synccpu_allow_cs: Allow command submission that touches the buffer
|
||||
* while the buffer is synced for CPU. This is similar to the GEM bo idle
|
||||
* behavior.
|
||||
*/
|
||||
enum drm_vmw_synccpu_flags {
|
||||
drm_vmw_synccpu_read = (1 << 0),
|
||||
drm_vmw_synccpu_write = (1 << 1),
|
||||
drm_vmw_synccpu_dontblock = (1 << 2),
|
||||
drm_vmw_synccpu_allow_cs = (1 << 3)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum drm_vmw_synccpu_op - Synccpu operations:
|
||||
*
|
||||
* @drm_vmw_synccpu_grab: Grab the buffer for CPU operations
|
||||
* @drm_vmw_synccpu_release: Release a previous grab.
|
||||
*/
|
||||
enum drm_vmw_synccpu_op {
|
||||
drm_vmw_synccpu_grab,
|
||||
drm_vmw_synccpu_release
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_vmw_synccpu_arg
|
||||
*
|
||||
* @op: The synccpu operation as described above.
|
||||
* @handle: Handle identifying the buffer object.
|
||||
* @flags: Flags as described above.
|
||||
*/
|
||||
struct drm_vmw_synccpu_arg {
|
||||
enum drm_vmw_synccpu_op op;
|
||||
enum drm_vmw_synccpu_flags flags;
|
||||
uint32_t handle;
|
||||
uint32_t pad64;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue