blob: d0618a2f55b159f9dc3007bbe6e76c4b42bc0e1d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "block_pool.h"
#include <assert.h>
#include <stdlib.h>
#include "common/macros.h"
#include "common/vk/assert.h"
#include "common/vk/barrier.h"
#include "core_c.h"
#include "deps.h"
#include "device.h"
#include "handle_pool.h"
#include "shaders/push.h"
#include "spinel/spinel_assert.h"
//
// FIXME(allanmac): The same routine is found in common/utils
//
static uint32_t
spinel_pow2_ru_u32(uint32_t n)
{
assert(n <= 0x80000000U);
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
//
//
//
void
spinel_device_block_pool_dispose(struct spinel_device * device)
{
struct spinel_block_pool * const block_pool = &device->block_pool;
// All dbi structures share the same VkBuffer
spinel_allocator_free_dbi_dm(&device->allocator.device.perm.drw,
device->vk.d,
device->vk.ac,
&block_pool->vk.dbi_dm.bp);
}
//
// Record the block pool initialization commands.
//
static VkPipelineStageFlags
spinel_block_pool_init_record(VkCommandBuffer cb, void * data0, void * data1)
{
struct spinel_device * const device = data0;
struct spinel_block_pool * block_pool = &device->block_pool;
//
// Record
//
struct spinel_push_block_pool_init const push = {
.devaddr_block_pool_ids = block_pool->vk.dbi_devaddr.ids.devaddr,
.bp_size = block_pool->bp_size
};
vkCmdPushConstants(cb,
device->ti.pipeline_layouts.named.block_pool_init,
VK_SHADER_STAGE_COMPUTE_BIT,
0,
sizeof(push),
&push);
vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_COMPUTE, device->ti.pipelines.named.block_pool_init);
//
// Size the dispatch
//
struct spinel_target_config const * config = &device->ti.config;
// ids per workgroup
uint32_t const bpis_per_wg = config->group_sizes.named.block_pool_init.workgroup * //
config->block_pool.ids_per_invocation;
// round up
uint32_t const bpi_wgs = (block_pool->bp_size + bpis_per_wg - 1) / bpis_per_wg;
vkCmdDispatch(cb, bpi_wgs, 1, 1);
//
// This command buffer ends with a compute shader
//
return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
//
// Initialize the block pool
//
static void
spinel_device_block_pool_init(struct spinel_device * device)
{
struct spinel_deps_immediate_submit_info const disi = {
.record = {
.pfn = spinel_block_pool_init_record,
.data0 = device,
},
//
// The rest of submit_info structure is zeroed -- these are the defaults we
// want for this submission.
//
};
//
// NOTE: We don't need to save the immediate semaphore handle because context
// creation will block and drain all submissions before returning.
//
spinel_deps_immediate_submit(device->deps, &device->vk, &disi, NULL);
}
//
//
//
void
spinel_device_block_pool_create(struct spinel_device * device,
uint64_t block_pool_size,
uint32_t handle_count)
{
struct spinel_target_config const * const config = &device->ti.config;
// How large is this target's block?
uint32_t const block_dwords_log2 = config->block_pool.block_dwords_log2;
uint32_t const block_dwords = 1 << block_dwords_log2;
// How large is the block pool?
uint64_t const block_pool_size_ru = block_pool_size + sizeof(uint32_t) - 1;
uint32_t const block_pool_dwords = (uint32_t)(block_pool_size_ru / sizeof(uint32_t));
uint32_t const block_count = (block_pool_dwords + block_dwords - 1) >> block_dwords_log2;
// The `bp_ids` extent is always a power-of-two.
uint32_t const id_count_pow2 = spinel_pow2_ru_u32(block_count);
struct spinel_block_pool * const block_pool = &device->block_pool;
block_pool->bp_size = block_count;
block_pool->bp_mask = id_count_pow2 - 1; // ids ring is power-of-two
//
// Allocate in one buffer:
//
// [ `bp_blocks` | `bp_ids` | `bp_host_map` ]
//
// Note that `bp_blocks` is first in order to robustify alignment.
//
// Even though we're using device addresses inside of Spinel, we keep the
// intermediate VkDescriptorBufferInfo structures around in case we need to
// interfact with descriptor sets.
//
// clang-format off
uint32_t const bp_dwords = block_count * block_dwords;
VkDeviceSize const bp_blocks_size = bp_dwords * sizeof(uint32_t);
VkDeviceSize const bp_ids_offset_ids = SPN_BUFFER_OFFSETOF(block_pool_ids, ids);
VkDeviceSize const bp_ids_size = bp_ids_offset_ids + id_count_pow2 * sizeof(spinel_block_id_t);
VkDeviceSize const bp_host_map_size = handle_count * sizeof(spinel_handle_t);
VkDeviceSize const bp_size = bp_blocks_size + bp_ids_size + bp_host_map_size;
// clang-format on
spinel_allocator_alloc_dbi_dm(&device->allocator.device.perm.drw,
device->vk.pd,
device->vk.d,
device->vk.ac,
bp_size,
NULL,
&block_pool->vk.dbi_dm.bp);
//
// Init dbi_devaddr structs
//
spinel_dbi_devaddr_from_dbi(device->vk.d,
&block_pool->vk.dbi_devaddr.blocks,
&block_pool->vk.dbi_dm.bp.dbi,
0UL,
bp_blocks_size);
spinel_dbi_devaddr_from_dbi(device->vk.d,
&block_pool->vk.dbi_devaddr.ids,
&block_pool->vk.dbi_dm.bp.dbi,
bp_blocks_size,
bp_ids_size);
spinel_dbi_devaddr_from_dbi(device->vk.d,
&block_pool->vk.dbi_devaddr.host_map,
&block_pool->vk.dbi_dm.bp.dbi,
bp_blocks_size + bp_ids_size,
bp_host_map_size);
//
// Initialize and wait for completion elsewhere before the new context is
// returned.
//
spinel_device_block_pool_init(device);
}
//
//
//