You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
virglrenderer/src/venus/vkr_transport.c

327 lines
9.2 KiB

/*
* Copyright 2020 Google LLC
* SPDX-License-Identifier: MIT
*/
#include "vkr_transport.h"
#include "venus-protocol/vn_protocol_renderer_dispatches.h"
#include "venus-protocol/vn_protocol_renderer_transport.h"
#include "vrend_iov.h"
#include "vkr_context.h"
#include "vkr_ring.h"
static void
vkr_dispatch_vkSetReplyCommandStreamMESA(
struct vn_dispatch_context *dispatch,
struct vn_command_vkSetReplyCommandStreamMESA *args)
{
struct vkr_context *ctx = dispatch->data;
struct vkr_resource_attachment *att;
if (!args->pStream) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
att = util_hash_table_get(ctx->resource_table,
uintptr_to_pointer(args->pStream->resourceId));
if (!att) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
vkr_cs_encoder_set_stream(&ctx->encoder, att->resource->iov, att->resource->iov_count,
args->pStream->offset, args->pStream->size);
}
static void
vkr_dispatch_vkSeekReplyCommandStreamMESA(
struct vn_dispatch_context *dispatch,
struct vn_command_vkSeekReplyCommandStreamMESA *args)
{
struct vkr_context *ctx = dispatch->data;
vkr_cs_encoder_seek_stream(&ctx->encoder, args->position);
}
static void *
copy_command_stream(struct vkr_context *ctx, const VkCommandStreamDescriptionMESA *stream)
{
struct vkr_resource_attachment *att;
struct virgl_resource *res;
att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(stream->resourceId));
if (!att)
return NULL;
res = att->resource;
/* seek to offset */
size_t iov_offset = stream->offset;
const struct iovec *iov = NULL;
for (int i = 0; i < res->iov_count; i++) {
if (iov_offset < res->iov[i].iov_len) {
iov = &res->iov[i];
break;
}
iov_offset -= res->iov[i].iov_len;
}
if (!iov)
return NULL;
/* XXX until the decoder supports scatter-gather and is robust enough,
* always make a copy in case the caller modifies the commands while we
* parse
*/
uint8_t *data = malloc(stream->size);
if (!data)
return NULL;
uint32_t copied = 0;
while (true) {
const size_t s = MIN2(stream->size - copied, iov->iov_len - iov_offset);
memcpy(data + copied, (const uint8_t *)iov->iov_base + iov_offset, s);
copied += s;
if (copied == stream->size) {
break;
} else if (iov == &res->iov[res->iov_count - 1]) {
free(data);
return NULL;
}
iov++;
iov_offset = 0;
}
return data;
}
static void
vkr_dispatch_vkExecuteCommandStreamsMESA(
struct vn_dispatch_context *dispatch,
struct vn_command_vkExecuteCommandStreamsMESA *args)
{
struct vkr_context *ctx = dispatch->data;
if (!args->streamCount || !args->pStreams) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
/* note that nested vkExecuteCommandStreamsMESA is not allowed */
if (!vkr_cs_decoder_push_state(&ctx->decoder)) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
for (uint32_t i = 0; i < args->streamCount; i++) {
const VkCommandStreamDescriptionMESA *stream = &args->pStreams[i];
if (args->pReplyPositions)
vkr_cs_encoder_seek_stream(&ctx->encoder, args->pReplyPositions[i]);
if (!stream->size)
continue;
void *data = copy_command_stream(ctx, stream);
if (!data) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
break;
}
vkr_cs_decoder_set_stream(&ctx->decoder, data, stream->size);
while (vkr_cs_decoder_has_command(&ctx->decoder)) {
vn_dispatch_command(&ctx->dispatch);
if (vkr_cs_decoder_get_fatal(&ctx->decoder))
break;
}
free(data);
if (vkr_cs_decoder_get_fatal(&ctx->decoder))
break;
}
vkr_cs_decoder_pop_state(&ctx->decoder);
}
static struct vkr_ring *
lookup_ring(struct vkr_context *ctx, uint64_t ring_id)
{
struct vkr_ring *ring;
LIST_FOR_EACH_ENTRY (ring, &ctx->rings, head) {
if (ring->id == ring_id)
return ring;
}
return NULL;
}
static void
vkr_dispatch_vkCreateRingMESA(struct vn_dispatch_context *dispatch,
struct vn_command_vkCreateRingMESA *args)
{
struct vkr_context *ctx = dispatch->data;
const VkRingCreateInfoMESA *info = args->pCreateInfo;
const struct vkr_resource_attachment *att;
uint8_t *shared;
size_t size;
struct vkr_ring *ring;
if (!info) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(info->resourceId));
if (!att) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
/* TODO support scatter-gather or require logically contiguous resources */
if (att->resource->iov_count != 1) {
vrend_printf("vkr: no scatter-gather support for ring buffers (TODO)");
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
shared = att->resource->iov[0].iov_base;
size = att->resource->iov[0].iov_len;
if (info->offset > size || info->size > size - info->offset) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
shared += info->offset;
size = info->size;
if (info->headOffset > size || info->tailOffset > size || info->statusOffset > size ||
info->bufferOffset > size || info->extraOffset > size) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
if (sizeof(uint32_t) > size - info->headOffset ||
sizeof(uint32_t) > size - info->tailOffset ||
sizeof(uint32_t) > size - info->statusOffset ||
info->bufferSize > size - info->bufferOffset ||
info->extraSize > size - info->extraOffset) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
if (!info->bufferSize || !util_is_power_of_two(info->bufferSize)) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
const struct vkr_ring_layout layout = {
.head_offset = info->headOffset,
.tail_offset = info->tailOffset,
.status_offset = info->statusOffset,
.buffer_offset = info->bufferOffset,
.buffer_size = info->bufferSize,
.extra_offset = info->extraOffset,
.extra_size = info->extraSize,
};
ring = vkr_ring_create(&layout, shared, &ctx->base, info->idleTimeout);
if (!ring) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
ring->id = args->ring;
list_addtail(&ring->head, &ctx->rings);
vkr_ring_start(ring);
}
static void
vkr_dispatch_vkDestroyRingMESA(struct vn_dispatch_context *dispatch,
struct vn_command_vkDestroyRingMESA *args)
{
struct vkr_context *ctx = dispatch->data;
struct vkr_ring *ring = lookup_ring(ctx, args->ring);
if (!ring || !vkr_ring_stop(ring)) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
list_del(&ring->head);
vkr_ring_destroy(ring);
}
static void
vkr_dispatch_vkNotifyRingMESA(struct vn_dispatch_context *dispatch,
struct vn_command_vkNotifyRingMESA *args)
{
struct vkr_context *ctx = dispatch->data;
struct vkr_ring *ring = lookup_ring(ctx, args->ring);
if (!ring) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
vkr_ring_notify(ring);
}
static void
vkr_dispatch_vkWriteRingExtraMESA(struct vn_dispatch_context *dispatch,
struct vn_command_vkWriteRingExtraMESA *args)
{
struct vkr_context *ctx = dispatch->data;
struct vkr_ring *ring = lookup_ring(ctx, args->ring);
if (!ring) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
if (!vkr_ring_write_extra(ring, args->offset, args->value))
vkr_cs_decoder_set_fatal(&ctx->decoder);
}
static void
vkr_dispatch_vkGetVenusExperimentalFeatureData100000MESA(
struct vn_dispatch_context *dispatch,
struct vn_command_vkGetVenusExperimentalFeatureData100000MESA *args)
{
struct vkr_context *ctx = dispatch->data;
if (!args->pDataSize) {
vkr_cs_decoder_set_fatal(&ctx->decoder);
return;
}
const VkVenusExperimentalFeatures100000MESA features = {
.memoryResourceAllocationSize = VK_TRUE,
};
vn_replace_vkGetVenusExperimentalFeatureData100000MESA_args_handle(args);
if (!args->pData) {
*args->pDataSize = sizeof(features);
return;
}
*args->pDataSize = MIN2(*args->pDataSize, sizeof(features));
memcpy(args->pData, &features, *args->pDataSize);
}
void
vkr_context_init_transport_dispatch(struct vkr_context *ctx)
{
struct vn_dispatch_context *dispatch = &ctx->dispatch;
dispatch->dispatch_vkSetReplyCommandStreamMESA =
vkr_dispatch_vkSetReplyCommandStreamMESA;
dispatch->dispatch_vkSeekReplyCommandStreamMESA =
vkr_dispatch_vkSeekReplyCommandStreamMESA;
dispatch->dispatch_vkExecuteCommandStreamsMESA =
vkr_dispatch_vkExecuteCommandStreamsMESA;
dispatch->dispatch_vkCreateRingMESA = vkr_dispatch_vkCreateRingMESA;
dispatch->dispatch_vkDestroyRingMESA = vkr_dispatch_vkDestroyRingMESA;
dispatch->dispatch_vkNotifyRingMESA = vkr_dispatch_vkNotifyRingMESA;
dispatch->dispatch_vkWriteRingExtraMESA = vkr_dispatch_vkWriteRingExtraMESA;
dispatch->dispatch_vkGetVenusExperimentalFeatureData100000MESA =
vkr_dispatch_vkGetVenusExperimentalFeatureData100000MESA;
}