blob: 55f7b8873f6143d9722843bdd5504f9f02890de9 [file] [log] [blame]
/*
* Copyright 2021 Google LLC
* SPDX-License-Identifier: MIT
*/
#include "vkr_cs.h"
#include "vkr_context.h"
void
vkr_cs_encoder_set_stream(struct vkr_cs_encoder *enc,
const struct vkr_resource *res,
size_t offset,
size_t size)
{
if (!res) {
memset(&enc->stream, 0, sizeof(enc->stream));
enc->cur = NULL;
enc->end = NULL;
return;
}
if (unlikely(size > res->size || offset > res->size - size)) {
vkr_log(
"failed to set the reply stream: offset(%zu) + size(%zu) exceeds res size(%zu)",
offset, size, res->size);
vkr_cs_encoder_set_fatal(enc);
return;
}
enc->stream.resource = res;
enc->stream.offset = offset;
enc->stream.size = size;
enc->end = res->u.data + res->size;
vkr_cs_encoder_seek_stream(enc, 0);
}
void
vkr_cs_encoder_seek_stream(struct vkr_cs_encoder *enc, size_t pos)
{
if (unlikely(pos > enc->stream.size)) {
vkr_log("failed to seek the reply stream to %zu", pos);
vkr_cs_encoder_set_fatal(enc);
return;
}
enc->cur = enc->stream.resource->u.data + enc->stream.offset + pos;
}
void
vkr_cs_decoder_init(struct vkr_cs_decoder *dec,
bool *fatal_error,
const struct hash_table *object_table)
{
memset(dec, 0, sizeof(*dec));
dec->fatal_error = fatal_error;
dec->object_table = object_table;
}
void
vkr_cs_decoder_fini(struct vkr_cs_decoder *dec)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
for (uint32_t i = 0; i < pool->buffer_count; i++)
free(pool->buffers[i]);
if (pool->buffers)
free(pool->buffers);
}
static void
vkr_cs_decoder_sanity_check(const struct vkr_cs_decoder *dec)
{
const struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
assert(pool->buffer_count <= pool->buffer_max);
if (pool->buffer_count) {
assert(pool->buffers[pool->buffer_count - 1] <= pool->reset_to);
assert(pool->reset_to <= pool->cur);
assert(pool->cur <= pool->end);
}
assert(dec->cur <= dec->end);
}
static void
vkr_cs_decoder_gc_temp_pool(struct vkr_cs_decoder *dec)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
if (!pool->buffer_count)
return;
/* free all but the last buffer */
if (pool->buffer_count > 1) {
for (uint32_t i = 0; i < pool->buffer_count - 1; i++)
free(pool->buffers[i]);
pool->buffers[0] = pool->buffers[pool->buffer_count - 1];
pool->buffer_count = 1;
}
pool->reset_to = pool->buffers[0];
pool->cur = pool->buffers[0];
pool->total_size = pool->end - pool->cur;
vkr_cs_decoder_sanity_check(dec);
}
/**
* Reset a decoder for reuse.
*/
void
vkr_cs_decoder_reset(struct vkr_cs_decoder *dec)
{
/* dec->fatal_error is sticky */
vkr_cs_decoder_gc_temp_pool(dec);
dec->saved_state_count = 0;
dec->cur = NULL;
dec->end = NULL;
}
bool
vkr_cs_decoder_push_state(struct vkr_cs_decoder *dec)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
struct vkr_cs_decoder_saved_state *saved;
if (dec->saved_state_count >= ARRAY_SIZE(dec->saved_states))
return false;
saved = &dec->saved_states[dec->saved_state_count++];
saved->cur = dec->cur;
saved->end = dec->end;
saved->pool_buffer_count = pool->buffer_count;
saved->pool_reset_to = pool->reset_to;
/* avoid temp data corruption */
pool->reset_to = pool->cur;
vkr_cs_decoder_sanity_check(dec);
return true;
}
void
vkr_cs_decoder_pop_state(struct vkr_cs_decoder *dec)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
const struct vkr_cs_decoder_saved_state *saved;
assert(dec->saved_state_count);
saved = &dec->saved_states[--dec->saved_state_count];
dec->cur = saved->cur;
dec->end = saved->end;
/* restore only if pool->reset_to points to the same buffer */
if (pool->buffer_count == saved->pool_buffer_count)
pool->reset_to = saved->pool_reset_to;
vkr_cs_decoder_sanity_check(dec);
}
static uint32_t
next_array_size(uint32_t cur_size, uint32_t min_size)
{
const uint32_t next_size = cur_size ? cur_size * 2 : min_size;
return next_size > cur_size ? next_size : 0;
}
static size_t
next_buffer_size(size_t cur_size, size_t min_size, size_t need)
{
size_t next_size = cur_size ? cur_size * 2 : min_size;
while (next_size < need) {
next_size *= 2;
if (!next_size)
return 0;
}
return next_size;
}
static bool
vkr_cs_decoder_grow_temp_pool(struct vkr_cs_decoder *dec)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
const uint32_t buf_max = next_array_size(pool->buffer_max, 4);
if (!buf_max)
return false;
uint8_t **bufs = realloc(pool->buffers, sizeof(*pool->buffers) * buf_max);
if (!bufs)
return false;
pool->buffers = bufs;
pool->buffer_max = buf_max;
return true;
}
bool
vkr_cs_decoder_alloc_temp_internal(struct vkr_cs_decoder *dec, size_t size)
{
struct vkr_cs_decoder_temp_pool *pool = &dec->temp_pool;
if (pool->buffer_count >= pool->buffer_max) {
if (!vkr_cs_decoder_grow_temp_pool(dec))
return false;
assert(pool->buffer_count < pool->buffer_max);
}
const size_t cur_buf_size =
pool->buffer_count ? pool->end - pool->buffers[pool->buffer_count - 1] : 0;
const size_t buf_size = next_buffer_size(cur_buf_size, 4096, size);
if (!buf_size)
return false;
if (buf_size > VKR_CS_DECODER_TEMP_POOL_MAX_SIZE - pool->total_size)
return false;
uint8_t *buf = malloc(buf_size);
if (!buf)
return false;
pool->total_size += buf_size;
pool->buffers[pool->buffer_count++] = buf;
pool->reset_to = buf;
pool->cur = buf;
pool->end = buf + buf_size;
vkr_cs_decoder_sanity_check(dec);
return true;
}