mesa/src/virtio/vulkan/vn_cs.h

258 lines
7.0 KiB
C

/*
* Copyright 2019 Google LLC
* SPDX-License-Identifier: MIT
*/
#ifndef VN_CS_H
#define VN_CS_H
#include "vn_common.h"
#include "venus-protocol/vn_protocol_driver_info.h"
#define VN_CS_ENCODER_BUFFER_INITIALIZER(storage) \
(struct vn_cs_encoder_buffer) { .base = storage, }
/* note that buffers points to an unamed local variable */
#define VN_CS_ENCODER_INITIALIZER_LOCAL(storage, size) \
(struct vn_cs_encoder) \
{ \
.storage_type = VN_CS_ENCODER_STORAGE_POINTER, \
.buffers = &VN_CS_ENCODER_BUFFER_INITIALIZER(storage), \
.buffer_count = 1, .buffer_max = 1, .current_buffer_size = size, \
.cur = storage, .end = (const void *)(storage) + (size), \
}
#define VN_CS_ENCODER_INITIALIZER(buf, size) \
(struct vn_cs_encoder) \
{ \
.storage_type = VN_CS_ENCODER_STORAGE_POINTER, .buffers = (buf), \
.buffer_count = 1, .buffer_max = 1, .current_buffer_size = size, \
.cur = (buf)->base, .end = (buf)->base + (size), \
}
#define VN_CS_DECODER_INITIALIZER(storage, size) \
(struct vn_cs_decoder) \
{ \
.cur = storage, .end = (const void *)(storage) + (size), \
}
enum vn_cs_encoder_storage_type {
/* a pointer to an externally-managed storage */
VN_CS_ENCODER_STORAGE_POINTER,
/* an array of dynamically allocated shmems */
VN_CS_ENCODER_STORAGE_SHMEM_ARRAY,
/* same as above, but shmems are suballocated from a pool */
VN_CS_ENCODER_STORAGE_SHMEM_POOL,
};
struct vn_cs_encoder_buffer {
struct vn_renderer_shmem *shmem;
size_t offset;
void *base;
size_t committed_size;
};
struct vn_cs_encoder {
struct vn_instance *instance; /* TODO shmem cache */
enum vn_cs_encoder_storage_type storage_type;
size_t min_buffer_size;
bool fatal_error;
struct vn_cs_encoder_buffer *buffers;
uint32_t buffer_count;
uint32_t buffer_max;
size_t total_committed_size;
/* the current buffer is buffers[buffer_count - 1].shmem */
size_t current_buffer_size;
/* TODO remove when blob_id_0 support gets required */
uint32_t current_buffer_roundtrip;
/* cur is the write pointer. When cur passes end, the slow path is
* triggered.
*/
void *cur;
const void *end;
};
struct vn_cs_decoder {
const void *cur;
const void *end;
};
struct vn_cs_renderer_protocol_info {
simple_mtx_t mutex;
bool init_once;
uint32_t api_version;
BITSET_DECLARE(extension_bitset, VN_INFO_EXTENSION_MAX_NUMBER + 1);
};
extern struct vn_cs_renderer_protocol_info _vn_cs_renderer_protocol_info;
static inline bool
vn_cs_renderer_protocol_has_api_version(uint32_t api_version)
{
return _vn_cs_renderer_protocol_info.api_version >= api_version;
}
static inline bool
vn_cs_renderer_protocol_has_extension(uint32_t ext_number)
{
return BITSET_TEST(_vn_cs_renderer_protocol_info.extension_bitset,
ext_number);
}
void
vn_cs_renderer_protocol_info_init(struct vn_instance *instance);
void
vn_cs_encoder_init(struct vn_cs_encoder *enc,
struct vn_instance *instance,
enum vn_cs_encoder_storage_type storage_type,
size_t min_size);
void
vn_cs_encoder_fini(struct vn_cs_encoder *enc);
void
vn_cs_encoder_reset(struct vn_cs_encoder *enc);
static inline void
vn_cs_encoder_set_fatal(const struct vn_cs_encoder *enc)
{
/* This is fatal and should be treated as VK_ERROR_DEVICE_LOST or even
* abort(). Note that vn_cs_encoder_reset does not clear this.
*/
((struct vn_cs_encoder *)enc)->fatal_error = true;
}
static inline bool
vn_cs_encoder_get_fatal(const struct vn_cs_encoder *enc)
{
return enc->fatal_error;
}
static inline bool
vn_cs_encoder_is_empty(const struct vn_cs_encoder *enc)
{
return !enc->buffer_count || enc->cur == enc->buffers[0].base;
}
static inline size_t
vn_cs_encoder_get_len(const struct vn_cs_encoder *enc)
{
if (unlikely(!enc->buffer_count))
return 0;
size_t len = enc->total_committed_size;
const struct vn_cs_encoder_buffer *cur_buf =
&enc->buffers[enc->buffer_count - 1];
if (!cur_buf->committed_size)
len += enc->cur - cur_buf->base;
return len;
}
bool
vn_cs_encoder_reserve_internal(struct vn_cs_encoder *enc, size_t size);
/**
* Reserve space for commands.
*/
static inline bool
vn_cs_encoder_reserve(struct vn_cs_encoder *enc, size_t size)
{
if (unlikely(size > enc->end - enc->cur)) {
if (!vn_cs_encoder_reserve_internal(enc, size)) {
vn_cs_encoder_set_fatal(enc);
return false;
}
assert(size <= enc->end - enc->cur);
}
return true;
}
static inline void
vn_cs_encoder_write(struct vn_cs_encoder *enc,
size_t size,
const void *val,
size_t val_size)
{
assert(val_size <= size);
assert(size <= enc->end - enc->cur);
/* we should not rely on the compiler to optimize away memcpy... */
memcpy(enc->cur, val, val_size);
enc->cur += size;
}
void
vn_cs_encoder_commit(struct vn_cs_encoder *enc);
static inline void
vn_cs_decoder_init(struct vn_cs_decoder *dec, const void *data, size_t size)
{
*dec = VN_CS_DECODER_INITIALIZER(data, size);
}
static inline void
vn_cs_decoder_set_fatal(const struct vn_cs_decoder *dec)
{
abort();
}
static inline bool
vn_cs_decoder_peek_internal(const struct vn_cs_decoder *dec,
size_t size,
void *val,
size_t val_size)
{
assert(val_size <= size);
if (unlikely(size > dec->end - dec->cur)) {
vn_cs_decoder_set_fatal(dec);
memset(val, 0, val_size);
return false;
}
/* we should not rely on the compiler to optimize away memcpy... */
memcpy(val, dec->cur, val_size);
return true;
}
static inline void
vn_cs_decoder_read(struct vn_cs_decoder *dec,
size_t size,
void *val,
size_t val_size)
{
if (vn_cs_decoder_peek_internal(dec, size, val, val_size))
dec->cur += size;
}
static inline void
vn_cs_decoder_peek(const struct vn_cs_decoder *dec,
size_t size,
void *val,
size_t val_size)
{
vn_cs_decoder_peek_internal(dec, size, val, val_size);
}
static inline vn_object_id
vn_cs_handle_load_id(const void **handle, VkObjectType type)
{
return *handle ? vn_object_get_id(*handle, type) : 0;
}
static inline void
vn_cs_handle_store_id(void **handle, vn_object_id id, VkObjectType type)
{
vn_object_set_id(*handle, id, type);
}
#endif /* VN_CS_H */