svga: Introduce userspace managed surfaces

Surfaces are currently managed by the vmwgfx kernel driver, and userspace
interacts with surfaces through DRM_VMW_*_SURFACE ioctls.
We would like to move to userspace managed surfaces to simplify surface
and buffer management across mesa and kernel driver.

This change introduces such surfaces, in which the userspace manages surface
id's and submits the create and destroy commands.

Userspace managed surfaces can be enabled with VMW_SVGA_USERSPACE_SURFACE
environment variable.

This change is tested with all piglit tests under spec@arb_copy_buffer@*
with userspace surfaces turned on.

Signed-off-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31744>
This commit is contained in:
Maaz Mombasawala 2024-04-15 19:07:05 -07:00 committed by Marge Bot
parent 40e6761262
commit 88804b8265
10 changed files with 200 additions and 3 deletions

View file

@ -239,6 +239,20 @@ SVGA3D_SetGBShader(struct svga_winsys_context *swc,
SVGA3dShaderType type,
struct svga_winsys_gb_shader *gbshader);
enum pipe_error
SVGA3D_DefineGBSurface_v4(struct svga_winsys_context *swc,
uint32 sid,
SVGA3dSurfaceAllFlags surfaceFlags,
SVGA3dSurfaceFormat format,
uint32 numMipLevels,
uint32 multisampleCount,
SVGA3dMSPattern multisamplePattern,
SVGA3dMSQualityLevel qualityLevel,
SVGA3dTextureFilter autogenFilter,
SVGA3dSize size,
uint32 arraySize,
uint32 bufferByteStride);
enum pipe_error
SVGA3D_BindGBSurface(struct svga_winsys_context *swc,
struct svga_winsys_surface *surface);
@ -293,6 +307,10 @@ SVGA3D_SetGBShaderConstsInline(struct svga_winsys_context *swc,
SVGA3dShaderConstType constType,
const void *values);
enum pipe_error
SVGA3D_DestroyGBSurface(struct svga_winsys_context *swc,
uint32 sid);
/*
* Queries
*/

View file

@ -1813,3 +1813,63 @@ SVGA3D_sm5_DefineRasterizerState_v2(struct svga_winsys_context *swc,
swc->commit(swc);
return PIPE_OK;
}
enum pipe_error
SVGA3D_DefineGBSurface_v4(struct svga_winsys_context *swc,
uint32 sid,
SVGA3dSurfaceAllFlags surfaceFlags,
SVGA3dSurfaceFormat format,
uint32 numMipLevels,
uint32 multisampleCount,
SVGA3dMSPattern multisamplePattern,
SVGA3dMSQualityLevel qualityLevel,
SVGA3dTextureFilter autogenFilter,
SVGA3dSize size,
uint32 arraySize,
uint32 bufferByteStride)
{
SVGA3dCmdDefineGBSurface_v4 *cmd =
SVGA3D_FIFOReserve(swc,
SVGA_3D_CMD_DEFINE_GB_SURFACE_V4,
sizeof(*cmd),
0);
if(!cmd)
return PIPE_ERROR_OUT_OF_MEMORY;
cmd->sid = sid;
cmd->surfaceFlags = surfaceFlags;
cmd->format = format;
cmd->numMipLevels = numMipLevels;
cmd->multisampleCount = multisampleCount;
cmd->multisamplePattern = multisamplePattern;
cmd->qualityLevel = qualityLevel;
cmd->autogenFilter = autogenFilter;
cmd->size = size;
cmd->arraySize = arraySize;
cmd->bufferByteStride = bufferByteStride;
swc->commit(swc);
return PIPE_OK;
}
enum pipe_error
SVGA3D_DestroyGBSurface(struct svga_winsys_context *swc,
uint32 sid)
{
SVGA3dCmdDestroyGBSurface *cmd =
SVGA3D_FIFOReserve(swc,
SVGA_3D_CMD_DESTROY_GB_SURFACE,
sizeof(*cmd),
0);
if(!cmd)
return PIPE_ERROR_OUT_OF_MEMORY;
cmd->sid = sid;
swc->commit(swc);
return PIPE_OK;
}

View file

@ -13,6 +13,7 @@
#include "util/u_debug_stack.h"
#include "util/u_debug_flush.h"
#include "util/u_hash_table.h"
#include "util/u_bitmask.h"
#include "util/u_atomic.h"
#include "pipebuffer/pb_buffer.h"
#include "pipebuffer/pb_validate.h"
@ -130,6 +131,9 @@ struct vmw_svga_winsys_context
int32_t refcount;
/* Bitmask of userspace managed surfaces */
struct util_bitmask *surface_id_bm;
/**
* Whether this context should fail to reserve more commands, not because it
* ran out of command space, but because a substantial ammount of GMR was
@ -660,6 +664,8 @@ vmw_swc_destroy(struct svga_winsys_context *swc)
vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
}
if (vmw_has_userspace_surface(vswc->vws))
util_bitmask_destroy(vswc->surface_id_bm);
_mesa_hash_table_destroy(vswc->hash, NULL);
pb_validate_destroy(vswc->validate);
vmw_ioctl_context_destroy(vswc->vws, swc->cid);
@ -825,6 +831,16 @@ vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
if (!vswc->hash)
goto out_no_hash;
if (vmw_has_userspace_surface(vws)) {
if(!(vswc->surface_id_bm = util_bitmask_create()))
goto out_no_user_srf;
/**
* First id assigned is 0 which is invalid for surface id. Consume the
* first id.
*/
vmw_swc_surface_add_userspace_id(&vswc->base);
}
/**
* The context refcount is initialized to 2, one reference is for the context
* itself and the other is for vws screen. One unref is done when context
@ -847,6 +863,8 @@ vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
vswc->base.force_coherent = vws->force_coherent;
return &vswc->base;
out_no_user_srf:
_mesa_hash_table_destroy(vswc->hash, NULL);
out_no_hash:
pb_validate_destroy(vswc->validate);
out_no_validate:
@ -855,3 +873,18 @@ out_no_context:
FREE(vswc);
return NULL;
}
void
vmw_swc_surface_clear_userspace_id(struct svga_winsys_context *swc,
uint32 sid)
{
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
util_bitmask_clear(vswc->surface_id_bm, sid);
}
uint32_t
vmw_swc_surface_add_userspace_id(struct svga_winsys_context *swc)
{
struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
return util_bitmask_add(vswc->surface_id_bm);
}

View file

@ -54,5 +54,11 @@ vmw_swc_surface_clear_reference(struct svga_winsys_context *swc,
void
vmw_swc_unref(struct svga_winsys_context *swc);
void
vmw_swc_surface_clear_userspace_id(struct svga_winsys_context *swc,
uint32_t sid);
uint32_t
vmw_swc_surface_add_userspace_id(struct svga_winsys_context *swc);
#endif /* VMW_CONTEXT_H_ */

View file

@ -105,6 +105,7 @@ struct vmw_winsys_screen
bool force_coherent;
bool cache_maps;
bool userspace_surface;
};
@ -114,6 +115,14 @@ vmw_winsys_screen(struct svga_winsys_screen *base)
return (struct vmw_winsys_screen *)base;
}
static inline bool
vmw_has_userspace_surface(struct vmw_winsys_screen *vws)
{
if (!vws->base.have_gb_objects || !vws->base.have_vgpu10)
return false;
return vws->userspace_surface;
}
/* */
uint32_t
vmw_region_size(struct vmw_region *region);

View file

@ -1181,6 +1181,22 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
}
/* Userspace surfaces are only supported on guest-backed hardware */
vws->userspace_surface = false;
getenv_val = getenv("VMW_SVGA_USERSPACE_SURFACE");
if (getenv_val && atoi(getenv_val)) {
assert(vws->base.have_gb_objects);
assert(vws->base.have_vgpu10);
memset(&gp_arg, 0, sizeof(gp_arg));
gp_arg.param = DRM_VMW_PARAM_USER_SRF;
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM, &gp_arg,
sizeof(gp_arg));
if (!ret && gp_arg.value == true) {
vws->userspace_surface = true;
debug_printf("Using userspace managed surfaces\n");
}
}
debug_printf("VGPU10 interface is %s.\n",
vws->base.have_vgpu10 ? "on" : "off");

View file

@ -28,6 +28,7 @@
#include "util/u_inlines.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_bitmask.h"
#include "pipebuffer/pb_buffer.h"
#include "pipebuffer/pb_bufmgr.h"
#include "svga_winsys.h"
@ -516,7 +517,41 @@ vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
goto no_sid;
}
if (sws->have_gb_objects) {
if (vmw_has_userspace_surface(vws)) {
struct svga_winsys_context *swc = vws->swc;
struct pb_buffer *pb_buf;
surface->sid = vmw_swc_surface_add_userspace_id(swc);
if (surface->sid == UTIL_BITMASK_INVALID_INDEX)
goto no_sid;
if (SVGA3D_DefineGBSurface_v4(swc, surface->sid, flags, format,
numMipLevels, sampleCount, multisample_pattern, quality_level,
SVGA3D_TEX_FILTER_NONE, size, numLayers, 0) != PIPE_OK) {
vmw_swc_surface_clear_userspace_id(swc, surface->sid);
goto no_sid;
}
desc.pb_desc.alignment = 4096;
desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
surface->size = buffer_size;
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_svga_winsys_userspace_surface_destroy(swc, surface->sid);
goto no_sid;
}
if (SVGA3D_BindGBSurface(swc, svga_winsys_surface(surface)) != PIPE_OK) {
vmw_svga_winsys_buffer_destroy(sws, surface->buf);
vmw_svga_winsys_userspace_surface_destroy(swc, surface->sid);
goto no_sid;
}
swc->flush(swc, NULL);
} else if (sws->have_gb_objects) {
struct pb_buffer *pb_buf;
surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,

View file

@ -223,6 +223,15 @@ vmw_svga_winsys_surface_unmap(struct svga_winsys_context *swc,
mtx_unlock(&vsrf->mutex);
}
void
vmw_svga_winsys_userspace_surface_destroy(struct svga_winsys_context *swc,
uint32 sid)
{
SVGA3D_DestroyGBSurface(swc, sid);
swc->flush(swc, NULL);
vmw_swc_surface_clear_userspace_id(swc, sid);
}
void
vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
struct vmw_svga_winsys_surface *src)
@ -242,7 +251,10 @@ vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
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);
if (vmw_has_userspace_surface(dst->screen))
vmw_svga_winsys_userspace_surface_destroy(dst->screen->swc, dst->sid);
else
vmw_ioctl_surface_destroy(dst->screen, dst->sid);
#if MESA_DEBUG
/* to detect dangling pointers */
assert(p_atomic_read(&dst->validated) == 0);

View file

@ -82,5 +82,9 @@ void
vmw_svga_winsys_surface_init(struct svga_winsys_screen *sws,
struct svga_winsys_surface *surface,
unsigned surf_size, SVGA3dSurfaceAllFlags flags);
void
vmw_svga_winsys_userspace_surface_destroy(struct svga_winsys_context *swc,
uint32 sid);
#endif /* VMW_SURFACE_H_ */

View file

@ -78,6 +78,9 @@ extern "C" {
*
* DRM_VMW_PARAM_DEVICE_ID
* PCI ID of the underlying SVGA device.
*
* DRM_VMW_PARAM_USER_SRF
* Userspace managed surface support is enabled.
*/
#define DRM_VMW_PARAM_NUM_STREAMS 0
@ -98,6 +101,7 @@ extern "C" {
#define DRM_VMW_PARAM_SM5 15
#define DRM_VMW_PARAM_GL43 16
#define DRM_VMW_PARAM_DEVICE_ID 17
#define DRM_VMW_PARAM_USER_SRF 18
/**
* enum drm_vmw_handle_type - handle type for ref ioctls