Path: blob/21.2-virgl/src/virtio/vulkan/vn_renderer_vtest.c
4560 views
/*1* Copyright 2019 Google LLC2* SPDX-License-Identifier: MIT3*4* based in part on virgl which is:5* Copyright 2014, 2015 Red Hat.6*/78#include <errno.h>9#include <netinet/in.h>10#include <poll.h>11#include <sys/mman.h>12#include <sys/socket.h>13#include <sys/types.h>14#include <sys/un.h>15#include <unistd.h>1617#include "util/os_file.h"18#include "util/sparse_array.h"19#include "util/u_process.h"20#define VIRGL_RENDERER_UNSTABLE_APIS21#include "virtio-gpu/virglrenderer_hw.h"22#include "vtest/vtest_protocol.h"2324#include "vn_renderer.h"2526#define VTEST_PCI_VENDOR_ID 0x1af427#define VTEST_PCI_DEVICE_ID 0x10502829struct vtest;3031struct vtest_shmem {32struct vn_renderer_shmem base;33};3435struct vtest_bo {36struct vn_renderer_bo base;3738uint32_t blob_flags;39/* might be closed after mmap */40int res_fd;41};4243struct vtest_sync {44struct vn_renderer_sync base;45};4647struct vtest {48struct vn_renderer base;4950struct vn_instance *instance;5152mtx_t sock_mutex;53int sock_fd;5455uint32_t protocol_version;56uint32_t max_sync_queue_count;5758struct {59enum virgl_renderer_capset id;60uint32_t version;61struct virgl_renderer_capset_venus data;62} capset;6364struct util_sparse_array shmem_array;65struct util_sparse_array bo_array;66};6768static int69vtest_connect_socket(struct vn_instance *instance, const char *path)70{71struct sockaddr_un un;72int sock;7374sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);75if (sock < 0) {76vn_log(instance, "failed to create a socket");77return -1;78}7980memset(&un, 0, sizeof(un));81un.sun_family = AF_UNIX;82memcpy(un.sun_path, path, strlen(path));8384if (connect(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {85vn_log(instance, "failed to connect to %s: %s", path, strerror(errno));86close(sock);87return -1;88}8990return sock;91}9293static void94vtest_read(struct vtest *vtest, void *buf, size_t size)95{96do {97const ssize_t ret = read(vtest->sock_fd, buf, size);98if (unlikely(ret < 0)) {99vn_log(vtest->instance,100"lost connection to rendering server on %zu read %zi %d",101size, ret, errno);102abort();103}104105buf += ret;106size -= ret;107} while (size);108}109110static int111vtest_receive_fd(struct vtest *vtest)112{113char cmsg_buf[CMSG_SPACE(sizeof(int))];114char dummy;115struct msghdr msg = {116.msg_iov =117&(struct iovec){118.iov_base = &dummy,119.iov_len = sizeof(dummy),120},121.msg_iovlen = 1,122.msg_control = cmsg_buf,123.msg_controllen = sizeof(cmsg_buf),124};125126if (recvmsg(vtest->sock_fd, &msg, 0) < 0) {127vn_log(vtest->instance, "recvmsg failed: %s", strerror(errno));128abort();129}130131struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);132if (!cmsg || cmsg->cmsg_level != SOL_SOCKET ||133cmsg->cmsg_type != SCM_RIGHTS) {134vn_log(vtest->instance, "invalid cmsghdr");135abort();136}137138return *((int *)CMSG_DATA(cmsg));139}140141static void142vtest_write(struct vtest *vtest, const void *buf, size_t size)143{144do {145const ssize_t ret = write(vtest->sock_fd, buf, size);146if (unlikely(ret < 0)) {147vn_log(vtest->instance,148"lost connection to rendering server on %zu write %zi %d",149size, ret, errno);150abort();151}152153buf += ret;154size -= ret;155} while (size);156}157158static void159vtest_vcmd_create_renderer(struct vtest *vtest, const char *name)160{161const size_t size = strlen(name) + 1;162163uint32_t vtest_hdr[VTEST_HDR_SIZE];164vtest_hdr[VTEST_CMD_LEN] = size;165vtest_hdr[VTEST_CMD_ID] = VCMD_CREATE_RENDERER;166167vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));168vtest_write(vtest, name, size);169}170171static bool172vtest_vcmd_ping_protocol_version(struct vtest *vtest)173{174uint32_t vtest_hdr[VTEST_HDR_SIZE];175vtest_hdr[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;176vtest_hdr[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;177178vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));179180/* send a dummy busy wait to avoid blocking in vtest_read in case ping181* protocol version is not supported182*/183uint32_t vcmd_busy_wait[VCMD_BUSY_WAIT_SIZE];184vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;185vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;186vcmd_busy_wait[VCMD_BUSY_WAIT_HANDLE] = 0;187vcmd_busy_wait[VCMD_BUSY_WAIT_FLAGS] = 0;188189vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));190vtest_write(vtest, vcmd_busy_wait, sizeof(vcmd_busy_wait));191192uint32_t dummy;193vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));194if (vtest_hdr[VTEST_CMD_ID] == VCMD_PING_PROTOCOL_VERSION) {195/* consume the dummy busy wait result */196vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));197assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_BUSY_WAIT);198vtest_read(vtest, &dummy, sizeof(dummy));199return true;200} else {201/* no ping protocol version support */202assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_BUSY_WAIT);203vtest_read(vtest, &dummy, sizeof(dummy));204return false;205}206}207208static uint32_t209vtest_vcmd_protocol_version(struct vtest *vtest)210{211uint32_t vtest_hdr[VTEST_HDR_SIZE];212uint32_t vcmd_protocol_version[VCMD_PROTOCOL_VERSION_SIZE];213vtest_hdr[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;214vtest_hdr[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;215vcmd_protocol_version[VCMD_PROTOCOL_VERSION_VERSION] =216VTEST_PROTOCOL_VERSION;217218vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));219vtest_write(vtest, vcmd_protocol_version, sizeof(vcmd_protocol_version));220221vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));222assert(vtest_hdr[VTEST_CMD_LEN] == VCMD_PROTOCOL_VERSION_SIZE);223assert(vtest_hdr[VTEST_CMD_ID] == VCMD_PROTOCOL_VERSION);224vtest_read(vtest, vcmd_protocol_version, sizeof(vcmd_protocol_version));225226return vcmd_protocol_version[VCMD_PROTOCOL_VERSION_VERSION];227}228229static uint32_t230vtest_vcmd_get_param(struct vtest *vtest, enum vcmd_param param)231{232uint32_t vtest_hdr[VTEST_HDR_SIZE];233uint32_t vcmd_get_param[VCMD_GET_PARAM_SIZE];234vtest_hdr[VTEST_CMD_LEN] = VCMD_GET_PARAM_SIZE;235vtest_hdr[VTEST_CMD_ID] = VCMD_GET_PARAM;236vcmd_get_param[VCMD_GET_PARAM_PARAM] = param;237238vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));239vtest_write(vtest, vcmd_get_param, sizeof(vcmd_get_param));240241vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));242assert(vtest_hdr[VTEST_CMD_LEN] == 2);243assert(vtest_hdr[VTEST_CMD_ID] == VCMD_GET_PARAM);244245uint32_t resp[2];246vtest_read(vtest, resp, sizeof(resp));247248return resp[0] ? resp[1] : 0;249}250251static bool252vtest_vcmd_get_capset(struct vtest *vtest,253enum virgl_renderer_capset id,254uint32_t version,255void *capset,256size_t capset_size)257{258uint32_t vtest_hdr[VTEST_HDR_SIZE];259uint32_t vcmd_get_capset[VCMD_GET_CAPSET_SIZE];260vtest_hdr[VTEST_CMD_LEN] = VCMD_GET_CAPSET_SIZE;261vtest_hdr[VTEST_CMD_ID] = VCMD_GET_CAPSET;262vcmd_get_capset[VCMD_GET_CAPSET_ID] = id;263vcmd_get_capset[VCMD_GET_CAPSET_VERSION] = version;264265vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));266vtest_write(vtest, vcmd_get_capset, sizeof(vcmd_get_capset));267268vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));269assert(vtest_hdr[VTEST_CMD_ID] == VCMD_GET_CAPSET);270271uint32_t valid;272vtest_read(vtest, &valid, sizeof(valid));273if (!valid)274return false;275276size_t read_size = (vtest_hdr[VTEST_CMD_LEN] - 1) * 4;277if (capset_size >= read_size) {278vtest_read(vtest, capset, read_size);279memset(capset + read_size, 0, capset_size - read_size);280} else {281vtest_read(vtest, capset, capset_size);282283char temp[256];284read_size -= capset_size;285while (read_size) {286const size_t temp_size = MIN2(read_size, ARRAY_SIZE(temp));287vtest_read(vtest, temp, temp_size);288read_size -= temp_size;289}290}291292return true;293}294295static void296vtest_vcmd_context_init(struct vtest *vtest,297enum virgl_renderer_capset capset_id)298{299uint32_t vtest_hdr[VTEST_HDR_SIZE];300uint32_t vcmd_context_init[VCMD_CONTEXT_INIT_SIZE];301vtest_hdr[VTEST_CMD_LEN] = VCMD_CONTEXT_INIT_SIZE;302vtest_hdr[VTEST_CMD_ID] = VCMD_CONTEXT_INIT;303vcmd_context_init[VCMD_CONTEXT_INIT_CAPSET_ID] = capset_id;304305vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));306vtest_write(vtest, vcmd_context_init, sizeof(vcmd_context_init));307}308309static uint32_t310vtest_vcmd_resource_create_blob(struct vtest *vtest,311enum vcmd_blob_type type,312uint32_t flags,313VkDeviceSize size,314vn_object_id blob_id,315int *res_fd)316{317uint32_t vtest_hdr[VTEST_HDR_SIZE];318uint32_t vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE];319320vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_BLOB_SIZE;321vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE_BLOB;322323vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_TYPE] = type;324vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_FLAGS] = flags;325vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE_LO] = (uint32_t)size;326vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE_HI] =327(uint32_t)(size >> 32);328vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_ID_LO] = (uint32_t)blob_id;329vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_ID_HI] =330(uint32_t)(blob_id >> 32);331332vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));333vtest_write(vtest, vcmd_res_create_blob, sizeof(vcmd_res_create_blob));334335vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));336assert(vtest_hdr[VTEST_CMD_LEN] == 1);337assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_CREATE_BLOB);338339uint32_t res_id;340vtest_read(vtest, &res_id, sizeof(res_id));341342*res_fd = vtest_receive_fd(vtest);343344return res_id;345}346347static void348vtest_vcmd_resource_unref(struct vtest *vtest, uint32_t res_id)349{350uint32_t vtest_hdr[VTEST_HDR_SIZE];351uint32_t vcmd_res_unref[VCMD_RES_UNREF_SIZE];352353vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_UNREF_SIZE;354vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_UNREF;355vcmd_res_unref[VCMD_RES_UNREF_RES_HANDLE] = res_id;356357vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));358vtest_write(vtest, vcmd_res_unref, sizeof(vcmd_res_unref));359}360361static uint32_t362vtest_vcmd_sync_create(struct vtest *vtest, uint64_t initial_val)363{364uint32_t vtest_hdr[VTEST_HDR_SIZE];365uint32_t vcmd_sync_create[VCMD_SYNC_CREATE_SIZE];366367vtest_hdr[VTEST_CMD_LEN] = VCMD_SYNC_CREATE_SIZE;368vtest_hdr[VTEST_CMD_ID] = VCMD_SYNC_CREATE;369370vcmd_sync_create[VCMD_SYNC_CREATE_VALUE_LO] = (uint32_t)initial_val;371vcmd_sync_create[VCMD_SYNC_CREATE_VALUE_HI] =372(uint32_t)(initial_val >> 32);373374vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));375vtest_write(vtest, vcmd_sync_create, sizeof(vcmd_sync_create));376377vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));378assert(vtest_hdr[VTEST_CMD_LEN] == 1);379assert(vtest_hdr[VTEST_CMD_ID] == VCMD_SYNC_CREATE);380381uint32_t sync_id;382vtest_read(vtest, &sync_id, sizeof(sync_id));383384return sync_id;385}386387static void388vtest_vcmd_sync_unref(struct vtest *vtest, uint32_t sync_id)389{390uint32_t vtest_hdr[VTEST_HDR_SIZE];391uint32_t vcmd_sync_unref[VCMD_SYNC_UNREF_SIZE];392393vtest_hdr[VTEST_CMD_LEN] = VCMD_SYNC_UNREF_SIZE;394vtest_hdr[VTEST_CMD_ID] = VCMD_SYNC_UNREF;395vcmd_sync_unref[VCMD_SYNC_UNREF_ID] = sync_id;396397vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));398vtest_write(vtest, vcmd_sync_unref, sizeof(vcmd_sync_unref));399}400401static uint64_t402vtest_vcmd_sync_read(struct vtest *vtest, uint32_t sync_id)403{404uint32_t vtest_hdr[VTEST_HDR_SIZE];405uint32_t vcmd_sync_read[VCMD_SYNC_READ_SIZE];406407vtest_hdr[VTEST_CMD_LEN] = VCMD_SYNC_READ_SIZE;408vtest_hdr[VTEST_CMD_ID] = VCMD_SYNC_READ;409410vcmd_sync_read[VCMD_SYNC_READ_ID] = sync_id;411412vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));413vtest_write(vtest, vcmd_sync_read, sizeof(vcmd_sync_read));414415vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));416assert(vtest_hdr[VTEST_CMD_LEN] == 2);417assert(vtest_hdr[VTEST_CMD_ID] == VCMD_SYNC_READ);418419uint64_t val;420vtest_read(vtest, &val, sizeof(val));421422return val;423}424425static void426vtest_vcmd_sync_write(struct vtest *vtest, uint32_t sync_id, uint64_t val)427{428uint32_t vtest_hdr[VTEST_HDR_SIZE];429uint32_t vcmd_sync_write[VCMD_SYNC_WRITE_SIZE];430431vtest_hdr[VTEST_CMD_LEN] = VCMD_SYNC_WRITE_SIZE;432vtest_hdr[VTEST_CMD_ID] = VCMD_SYNC_WRITE;433434vcmd_sync_write[VCMD_SYNC_WRITE_ID] = sync_id;435vcmd_sync_write[VCMD_SYNC_WRITE_VALUE_LO] = (uint32_t)val;436vcmd_sync_write[VCMD_SYNC_WRITE_VALUE_HI] = (uint32_t)(val >> 32);437438vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));439vtest_write(vtest, vcmd_sync_write, sizeof(vcmd_sync_write));440}441442static int443vtest_vcmd_sync_wait(struct vtest *vtest,444uint32_t flags,445int poll_timeout,446struct vn_renderer_sync *const *syncs,447const uint64_t *vals,448uint32_t count)449{450const uint32_t timeout = poll_timeout >= 0 && poll_timeout <= INT32_MAX451? poll_timeout452: UINT32_MAX;453454uint32_t vtest_hdr[VTEST_HDR_SIZE];455vtest_hdr[VTEST_CMD_LEN] = VCMD_SYNC_WAIT_SIZE(count);456vtest_hdr[VTEST_CMD_ID] = VCMD_SYNC_WAIT;457458vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));459vtest_write(vtest, &flags, sizeof(flags));460vtest_write(vtest, &timeout, sizeof(timeout));461for (uint32_t i = 0; i < count; i++) {462const uint64_t val = vals[i];463const uint32_t sync[3] = {464syncs[i]->sync_id,465(uint32_t)val,466(uint32_t)(val >> 32),467};468vtest_write(vtest, sync, sizeof(sync));469}470471vtest_read(vtest, vtest_hdr, sizeof(vtest_hdr));472assert(vtest_hdr[VTEST_CMD_LEN] == 0);473assert(vtest_hdr[VTEST_CMD_ID] == VCMD_SYNC_WAIT);474475return vtest_receive_fd(vtest);476}477478static void479submit_cmd2_sizes(const struct vn_renderer_submit *submit,480size_t *header_size,481size_t *cs_size,482size_t *sync_size)483{484if (!submit->batch_count) {485*header_size = 0;486*cs_size = 0;487*sync_size = 0;488return;489}490491*header_size = sizeof(uint32_t) +492sizeof(struct vcmd_submit_cmd2_batch) * submit->batch_count;493494*cs_size = 0;495*sync_size = 0;496for (uint32_t i = 0; i < submit->batch_count; i++) {497const struct vn_renderer_submit_batch *batch = &submit->batches[i];498assert(batch->cs_size % sizeof(uint32_t) == 0);499*cs_size += batch->cs_size;500*sync_size += (sizeof(uint32_t) + sizeof(uint64_t)) * batch->sync_count;501}502503assert(*header_size % sizeof(uint32_t) == 0);504assert(*cs_size % sizeof(uint32_t) == 0);505assert(*sync_size % sizeof(uint32_t) == 0);506}507508static void509vtest_vcmd_submit_cmd2(struct vtest *vtest,510const struct vn_renderer_submit *submit)511{512size_t header_size;513size_t cs_size;514size_t sync_size;515submit_cmd2_sizes(submit, &header_size, &cs_size, &sync_size);516const size_t total_size = header_size + cs_size + sync_size;517if (!total_size)518return;519520uint32_t vtest_hdr[VTEST_HDR_SIZE];521vtest_hdr[VTEST_CMD_LEN] = total_size / sizeof(uint32_t);522vtest_hdr[VTEST_CMD_ID] = VCMD_SUBMIT_CMD2;523vtest_write(vtest, vtest_hdr, sizeof(vtest_hdr));524525/* write batch count and batch headers */526const uint32_t batch_count = submit->batch_count;527size_t cs_offset = header_size;528size_t sync_offset = cs_offset + cs_size;529vtest_write(vtest, &batch_count, sizeof(batch_count));530for (uint32_t i = 0; i < submit->batch_count; i++) {531const struct vn_renderer_submit_batch *batch = &submit->batches[i];532struct vcmd_submit_cmd2_batch dst = {533.cmd_offset = cs_offset / sizeof(uint32_t),534.cmd_size = batch->cs_size / sizeof(uint32_t),535.sync_offset = sync_offset / sizeof(uint32_t),536.sync_count = batch->sync_count,537};538if (!batch->sync_queue_cpu) {539dst.flags = VCMD_SUBMIT_CMD2_FLAG_SYNC_QUEUE;540dst.sync_queue_index = batch->sync_queue_index;541dst.sync_queue_id = batch->vk_queue_id;542}543vtest_write(vtest, &dst, sizeof(dst));544545cs_offset += batch->cs_size;546sync_offset +=547(sizeof(uint32_t) + sizeof(uint64_t)) * batch->sync_count;548}549550/* write cs */551if (cs_size) {552for (uint32_t i = 0; i < submit->batch_count; i++) {553const struct vn_renderer_submit_batch *batch = &submit->batches[i];554if (batch->cs_size)555vtest_write(vtest, batch->cs_data, batch->cs_size);556}557}558559/* write syncs */560for (uint32_t i = 0; i < submit->batch_count; i++) {561const struct vn_renderer_submit_batch *batch = &submit->batches[i];562563for (uint32_t j = 0; j < batch->sync_count; j++) {564const uint64_t val = batch->sync_values[j];565const uint32_t sync[3] = {566batch->syncs[j]->sync_id,567(uint32_t)val,568(uint32_t)(val >> 32),569};570vtest_write(vtest, sync, sizeof(sync));571}572}573}574575static VkResult576vtest_sync_write(struct vn_renderer *renderer,577struct vn_renderer_sync *_sync,578uint64_t val)579{580struct vtest *vtest = (struct vtest *)renderer;581struct vtest_sync *sync = (struct vtest_sync *)_sync;582583mtx_lock(&vtest->sock_mutex);584vtest_vcmd_sync_write(vtest, sync->base.sync_id, val);585mtx_unlock(&vtest->sock_mutex);586587return VK_SUCCESS;588}589590static VkResult591vtest_sync_read(struct vn_renderer *renderer,592struct vn_renderer_sync *_sync,593uint64_t *val)594{595struct vtest *vtest = (struct vtest *)renderer;596struct vtest_sync *sync = (struct vtest_sync *)_sync;597598mtx_lock(&vtest->sock_mutex);599*val = vtest_vcmd_sync_read(vtest, sync->base.sync_id);600mtx_unlock(&vtest->sock_mutex);601602return VK_SUCCESS;603}604605static VkResult606vtest_sync_reset(struct vn_renderer *renderer,607struct vn_renderer_sync *sync,608uint64_t initial_val)609{610/* same as write */611return vtest_sync_write(renderer, sync, initial_val);612}613614static void615vtest_sync_destroy(struct vn_renderer *renderer,616struct vn_renderer_sync *_sync)617{618struct vtest *vtest = (struct vtest *)renderer;619struct vtest_sync *sync = (struct vtest_sync *)_sync;620621mtx_lock(&vtest->sock_mutex);622vtest_vcmd_sync_unref(vtest, sync->base.sync_id);623mtx_unlock(&vtest->sock_mutex);624625free(sync);626}627628static VkResult629vtest_sync_create(struct vn_renderer *renderer,630uint64_t initial_val,631uint32_t flags,632struct vn_renderer_sync **out_sync)633{634struct vtest *vtest = (struct vtest *)renderer;635636struct vtest_sync *sync = calloc(1, sizeof(*sync));637if (!sync)638return VK_ERROR_OUT_OF_HOST_MEMORY;639640mtx_lock(&vtest->sock_mutex);641sync->base.sync_id = vtest_vcmd_sync_create(vtest, initial_val);642mtx_unlock(&vtest->sock_mutex);643644*out_sync = &sync->base;645return VK_SUCCESS;646}647648static void649vtest_bo_invalidate(struct vn_renderer *renderer,650struct vn_renderer_bo *bo,651VkDeviceSize offset,652VkDeviceSize size)653{654/* nop */655}656657static void658vtest_bo_flush(struct vn_renderer *renderer,659struct vn_renderer_bo *bo,660VkDeviceSize offset,661VkDeviceSize size)662{663/* nop */664}665666static void *667vtest_bo_map(struct vn_renderer *renderer, struct vn_renderer_bo *_bo)668{669struct vtest *vtest = (struct vtest *)renderer;670struct vtest_bo *bo = (struct vtest_bo *)_bo;671const bool mappable = bo->blob_flags & VCMD_BLOB_FLAG_MAPPABLE;672const bool shareable = bo->blob_flags & VCMD_BLOB_FLAG_SHAREABLE;673674/* not thread-safe but is fine */675if (!bo->base.mmap_ptr && mappable) {676/* We wrongly assume that mmap(dma_buf) and vkMapMemory(VkDeviceMemory)677* are equivalent when the blob type is VCMD_BLOB_TYPE_HOST3D. While we678* check for VCMD_PARAM_HOST_COHERENT_DMABUF_BLOB, we know vtest can679* lie.680*/681void *ptr = mmap(NULL, bo->base.mmap_size, PROT_READ | PROT_WRITE,682MAP_SHARED, bo->res_fd, 0);683if (ptr == MAP_FAILED) {684vn_log(vtest->instance, "failed to mmap %d of size %zu rw: %s",685bo->res_fd, bo->base.mmap_size, strerror(errno));686} else {687bo->base.mmap_ptr = ptr;688/* we don't need the fd anymore */689if (!shareable) {690close(bo->res_fd);691bo->res_fd = -1;692}693}694}695696return bo->base.mmap_ptr;697}698699static int700vtest_bo_export_dma_buf(struct vn_renderer *renderer,701struct vn_renderer_bo *_bo)702{703const struct vtest_bo *bo = (struct vtest_bo *)_bo;704const bool shareable = bo->blob_flags & VCMD_BLOB_FLAG_SHAREABLE;705return shareable ? os_dupfd_cloexec(bo->res_fd) : -1;706}707708static bool709vtest_bo_destroy(struct vn_renderer *renderer, struct vn_renderer_bo *_bo)710{711struct vtest *vtest = (struct vtest *)renderer;712struct vtest_bo *bo = (struct vtest_bo *)_bo;713714if (bo->base.mmap_ptr)715munmap(bo->base.mmap_ptr, bo->base.mmap_size);716if (bo->res_fd >= 0)717close(bo->res_fd);718719mtx_lock(&vtest->sock_mutex);720vtest_vcmd_resource_unref(vtest, bo->base.res_id);721mtx_unlock(&vtest->sock_mutex);722723return true;724}725726static uint32_t727vtest_bo_blob_flags(VkMemoryPropertyFlags flags,728VkExternalMemoryHandleTypeFlags external_handles)729{730uint32_t blob_flags = 0;731if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)732blob_flags |= VCMD_BLOB_FLAG_MAPPABLE;733if (external_handles)734blob_flags |= VCMD_BLOB_FLAG_SHAREABLE;735if (external_handles & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)736blob_flags |= VCMD_BLOB_FLAG_CROSS_DEVICE;737738return blob_flags;739}740741static VkResult742vtest_bo_create_from_device_memory(743struct vn_renderer *renderer,744VkDeviceSize size,745vn_object_id mem_id,746VkMemoryPropertyFlags flags,747VkExternalMemoryHandleTypeFlags external_handles,748struct vn_renderer_bo **out_bo)749{750struct vtest *vtest = (struct vtest *)renderer;751const uint32_t blob_flags = vtest_bo_blob_flags(flags, external_handles);752753mtx_lock(&vtest->sock_mutex);754int res_fd;755uint32_t res_id = vtest_vcmd_resource_create_blob(756vtest, VCMD_BLOB_TYPE_HOST3D, blob_flags, size, mem_id, &res_fd);757assert(res_id > 0 && res_fd >= 0);758mtx_unlock(&vtest->sock_mutex);759760struct vtest_bo *bo = util_sparse_array_get(&vtest->bo_array, res_id);761*bo = (struct vtest_bo){762.base = {763.refcount = 1,764.res_id = res_id,765.mmap_size = size,766},767.res_fd = res_fd,768.blob_flags = blob_flags,769};770771*out_bo = &bo->base;772773return VK_SUCCESS;774}775776static void777vtest_shmem_destroy(struct vn_renderer *renderer,778struct vn_renderer_shmem *_shmem)779{780struct vtest *vtest = (struct vtest *)renderer;781struct vtest_shmem *shmem = (struct vtest_shmem *)_shmem;782783munmap(shmem->base.mmap_ptr, shmem->base.mmap_size);784785mtx_lock(&vtest->sock_mutex);786vtest_vcmd_resource_unref(vtest, shmem->base.res_id);787mtx_unlock(&vtest->sock_mutex);788}789790static struct vn_renderer_shmem *791vtest_shmem_create(struct vn_renderer *renderer, size_t size)792{793struct vtest *vtest = (struct vtest *)renderer;794795mtx_lock(&vtest->sock_mutex);796int res_fd;797uint32_t res_id = vtest_vcmd_resource_create_blob(798vtest, VCMD_BLOB_TYPE_GUEST, VCMD_BLOB_FLAG_MAPPABLE, size, 0, &res_fd);799assert(res_id > 0 && res_fd >= 0);800mtx_unlock(&vtest->sock_mutex);801802void *ptr =803mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, res_fd, 0);804close(res_fd);805if (ptr == MAP_FAILED) {806mtx_lock(&vtest->sock_mutex);807vtest_vcmd_resource_unref(vtest, res_id);808mtx_unlock(&vtest->sock_mutex);809return NULL;810}811812struct vtest_shmem *shmem =813util_sparse_array_get(&vtest->shmem_array, res_id);814*shmem = (struct vtest_shmem){815.base = {816.refcount = 1,817.res_id = res_id,818.mmap_size = size,819.mmap_ptr = ptr,820},821};822823return &shmem->base;824}825826static VkResult827sync_wait_poll(int fd, int poll_timeout)828{829struct pollfd pollfd = {830.fd = fd,831.events = POLLIN,832};833int ret;834do {835ret = poll(&pollfd, 1, poll_timeout);836} while (ret == -1 && (errno == EINTR || errno == EAGAIN));837838if (ret < 0 || (ret > 0 && !(pollfd.revents & POLLIN))) {839return (ret < 0 && errno == ENOMEM) ? VK_ERROR_OUT_OF_HOST_MEMORY840: VK_ERROR_DEVICE_LOST;841}842843return ret ? VK_SUCCESS : VK_TIMEOUT;844}845846static int847timeout_to_poll_timeout(uint64_t timeout)848{849const uint64_t ns_per_ms = 1000000;850const uint64_t ms = (timeout + ns_per_ms - 1) / ns_per_ms;851if (!ms && timeout)852return -1;853return ms <= INT_MAX ? ms : -1;854}855856static VkResult857vtest_wait(struct vn_renderer *renderer, const struct vn_renderer_wait *wait)858{859struct vtest *vtest = (struct vtest *)renderer;860const uint32_t flags = wait->wait_any ? VCMD_SYNC_WAIT_FLAG_ANY : 0;861const int poll_timeout = timeout_to_poll_timeout(wait->timeout);862863/*864* vtest_vcmd_sync_wait (and some other sync commands) is executed after865* all prior commands are dispatched. That is far from ideal.866*867* In virtio-gpu, a drm_syncobj wait ioctl is executed immediately. It868* works because it uses virtio-gpu interrupts as a side channel. vtest869* needs a side channel to perform well.870*871* virtio-gpu or vtest, we should also set up a 1-byte coherent memory that872* is set to non-zero by GPU after the syncs signal. That would allow us873* to do a quick check (or spin a bit) before waiting.874*/875mtx_lock(&vtest->sock_mutex);876const int fd =877vtest_vcmd_sync_wait(vtest, flags, poll_timeout, wait->syncs,878wait->sync_values, wait->sync_count);879mtx_unlock(&vtest->sock_mutex);880881VkResult result = sync_wait_poll(fd, poll_timeout);882close(fd);883884return result;885}886887static VkResult888vtest_submit(struct vn_renderer *renderer,889const struct vn_renderer_submit *submit)890{891struct vtest *vtest = (struct vtest *)renderer;892893mtx_lock(&vtest->sock_mutex);894vtest_vcmd_submit_cmd2(vtest, submit);895mtx_unlock(&vtest->sock_mutex);896897return VK_SUCCESS;898}899900static void901vtest_get_info(struct vn_renderer *renderer, struct vn_renderer_info *info)902{903struct vtest *vtest = (struct vtest *)renderer;904905memset(info, 0, sizeof(*info));906907info->pci.vendor_id = VTEST_PCI_VENDOR_ID;908info->pci.device_id = VTEST_PCI_DEVICE_ID;909910info->has_dma_buf_import = false;911info->has_cache_management = false;912info->has_external_sync = false;913info->has_implicit_fencing = false;914915info->max_sync_queue_count = vtest->max_sync_queue_count;916917const struct virgl_renderer_capset_venus *capset = &vtest->capset.data;918info->wire_format_version = capset->wire_format_version;919info->vk_xml_version = capset->vk_xml_version;920info->vk_ext_command_serialization_spec_version =921capset->vk_ext_command_serialization_spec_version;922info->vk_mesa_venus_protocol_spec_version =923capset->vk_mesa_venus_protocol_spec_version;924}925926static void927vtest_destroy(struct vn_renderer *renderer,928const VkAllocationCallbacks *alloc)929{930struct vtest *vtest = (struct vtest *)renderer;931932if (vtest->sock_fd >= 0) {933shutdown(vtest->sock_fd, SHUT_RDWR);934close(vtest->sock_fd);935}936937mtx_destroy(&vtest->sock_mutex);938util_sparse_array_finish(&vtest->shmem_array);939util_sparse_array_finish(&vtest->bo_array);940941vk_free(alloc, vtest);942}943944static VkResult945vtest_init_capset(struct vtest *vtest)946{947vtest->capset.id = VIRGL_RENDERER_CAPSET_VENUS;948vtest->capset.version = 0;949950if (!vtest_vcmd_get_capset(vtest, vtest->capset.id, vtest->capset.version,951&vtest->capset.data,952sizeof(vtest->capset.data))) {953vn_log(vtest->instance, "no venus capset");954return VK_ERROR_INITIALIZATION_FAILED;955}956957return VK_SUCCESS;958}959960static VkResult961vtest_init_params(struct vtest *vtest)962{963uint32_t val =964vtest_vcmd_get_param(vtest, VCMD_PARAM_MAX_SYNC_QUEUE_COUNT);965if (!val) {966vn_log(vtest->instance, "no sync queue support");967return VK_ERROR_INITIALIZATION_FAILED;968}969vtest->max_sync_queue_count = val;970971return VK_SUCCESS;972}973974static VkResult975vtest_init_protocol_version(struct vtest *vtest)976{977const uint32_t min_protocol_version = 3;978979const uint32_t ver = vtest_vcmd_ping_protocol_version(vtest)980? vtest_vcmd_protocol_version(vtest)981: 0;982if (ver < min_protocol_version) {983vn_log(vtest->instance, "vtest protocol version (%d) too old", ver);984return VK_ERROR_INITIALIZATION_FAILED;985}986987vtest->protocol_version = ver;988989return VK_SUCCESS;990}991992static VkResult993vtest_init(struct vtest *vtest)994{995util_sparse_array_init(&vtest->shmem_array, sizeof(struct vtest_shmem),9961024);997util_sparse_array_init(&vtest->bo_array, sizeof(struct vtest_bo), 1024);998999mtx_init(&vtest->sock_mutex, mtx_plain);1000vtest->sock_fd =1001vtest_connect_socket(vtest->instance, VTEST_DEFAULT_SOCKET_NAME);1002if (vtest->sock_fd < 0)1003return VK_ERROR_INITIALIZATION_FAILED;10041005const char *renderer_name = util_get_process_name();1006if (!renderer_name)1007renderer_name = "venus";1008vtest_vcmd_create_renderer(vtest, renderer_name);10091010VkResult result = vtest_init_protocol_version(vtest);1011if (result == VK_SUCCESS)1012result = vtest_init_params(vtest);1013if (result == VK_SUCCESS)1014result = vtest_init_capset(vtest);1015if (result != VK_SUCCESS)1016return result;10171018vtest_vcmd_context_init(vtest, vtest->capset.id);10191020vtest->base.ops.destroy = vtest_destroy;1021vtest->base.ops.get_info = vtest_get_info;1022vtest->base.ops.submit = vtest_submit;1023vtest->base.ops.wait = vtest_wait;10241025vtest->base.shmem_ops.create = vtest_shmem_create;1026vtest->base.shmem_ops.destroy = vtest_shmem_destroy;10271028vtest->base.bo_ops.create_from_device_memory =1029vtest_bo_create_from_device_memory;1030vtest->base.bo_ops.create_from_dma_buf = NULL;1031vtest->base.bo_ops.destroy = vtest_bo_destroy;1032vtest->base.bo_ops.export_dma_buf = vtest_bo_export_dma_buf;1033vtest->base.bo_ops.map = vtest_bo_map;1034vtest->base.bo_ops.flush = vtest_bo_flush;1035vtest->base.bo_ops.invalidate = vtest_bo_invalidate;10361037vtest->base.sync_ops.create = vtest_sync_create;1038vtest->base.sync_ops.create_from_syncobj = NULL;1039vtest->base.sync_ops.destroy = vtest_sync_destroy;1040vtest->base.sync_ops.export_syncobj = NULL;1041vtest->base.sync_ops.reset = vtest_sync_reset;1042vtest->base.sync_ops.read = vtest_sync_read;1043vtest->base.sync_ops.write = vtest_sync_write;10441045return VK_SUCCESS;1046}10471048VkResult1049vn_renderer_create_vtest(struct vn_instance *instance,1050const VkAllocationCallbacks *alloc,1051struct vn_renderer **renderer)1052{1053struct vtest *vtest = vk_zalloc(alloc, sizeof(*vtest), VN_DEFAULT_ALIGN,1054VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);1055if (!vtest)1056return VK_ERROR_OUT_OF_HOST_MEMORY;10571058vtest->instance = instance;1059vtest->sock_fd = -1;10601061VkResult result = vtest_init(vtest);1062if (result != VK_SUCCESS) {1063vtest_destroy(&vtest->base, alloc);1064return result;1065}10661067*renderer = &vtest->base;10681069return VK_SUCCESS;1070}107110721073