blob: 47c36742a18b0b78ecbe72dcce6c6fcd2bcb7761 [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.
#ifndef SRC_GRAPHICS_LIB_COMPUTE_SPINEL_PLATFORMS_VK_VK_H_
#define SRC_GRAPHICS_LIB_COMPUTE_SPINEL_PLATFORMS_VK_VK_H_
//
// Each Vulkan shader's descriptor set layout and associated push
// constants are defined in vk_layouts.h
//
// Defining the layouts once ensures *consistency* between the host C
// source, the GLSL shaders, and the Vulkan pipelines and resources.
//
// This file uses the layout file to provide type-safe access to
// all Vulkan resources.
//
// An spn_vk instance does the following:
//
// - Takes a Spinel/VK target and creates device-specific instances
// of all Spinel pipelines.
//
// - Allocates fixed size pools of pipeline descriptor sets.
//
// - Enables performant update of descriptor sets using Vulkan
// update templates.
//
// - Pumps the scheduler when descriptor sets are unavailable.
//
// - Defines typed C bindings for updating descriptor sets.
//
// - Defines typed C bindings for initializing push constants.
//
// - Defines explicity named pipeline binding functions.
//
#include <stdbool.h>
#include <stdint.h>
#include <vulkan/vulkan_core.h>
#include "vk_layouts.h"
//
// No need to know how these are implemented
//
struct spn_device;
struct spn_vk_environment;
struct spn_vk_target;
//
// If you want to see what's happening here with all of the descriptor
// layout expansions, run vk.c through the preprocessor:
//
// clang -I $VULKAN_SDK/include -I ../.. -I ../../.. -I ../../include -E vk.c | clang-format > vk_clang.c
// cl -I %VULKAN_SDK%\include -I ..\.. -I ..\..\.. -I ..\..\include -EP vk.c | clang-format > vk_msvc.c
//
//
// Update the descriptor sets
//
// There are currently 10 descriptor sets:
//
// - block_pool
// - path copy
// - fill_cmds
// - prim_scan
// - rast_cmds
// - ttrks
// - ttcks
// - place_cmds
// - styling
// - surface
//
// Most descriptor sets are ephemeral and sized according to the
// target config.
//
// The following descriptor sets are durable and are either explicitly
// sized or sized using configuration defaults:
//
// - block_pool
// - fill_cmds
// - place_cmds
// - ttcks
// - styling
//
// The surface descriptor set is currently the only descriptor that is
// externally defined/allocated/managed:
//
// - surface
//
//
// Given a target, create an instance of spn_vk
//
struct spn_vk *
spn_vk_create(struct spn_vk_environment * const environment,
struct spn_vk_target const * const target);
//
// Resources will be disposed of with the same device and allocator
// that was used for creation.
//
void
spn_vk_dispose(struct spn_vk * const instance, struct spn_vk_environment * const environment);
//
// Get the target configuration structure
//
struct spn_vk_target_config const *
spn_vk_get_config(struct spn_vk const * const instance);
//
// Get the VkPipelineLayout that HotSort will operate on
//
VkPipelineLayout
spn_vk_pl_hotsort(struct spn_vk const * const instance);
//
// Declare host-side descriptor set buffer/image binding structures:
//
// struct spn_vk_buf_block_pool_bp_ids
// struct spn_vk_buf_block_pool_bp_blocks
// ...
// struct spn_vk_buf_render_surface
//
#define SPN_VK_BUFFER_NAME(ds_id_, name_) struct spn_vk_buf_##ds_id_##_##name_
#define SPN_VK_GLSL_LAYOUT_BUFFER(ds_id_, s_idx_, b_idx_, name_) SPN_VK_BUFFER_NAME(ds_id_, name_)
#define SPN_VK_GLSL_LAYOUT_IMAGE2D(ds_id_, s_idx_, b_idx_, img_type_, name_)
SPN_VK_GLSL_DS_EXPAND()
//
// If the host-side buffer structure is simply:
//
// struct SPN_VK_BUFFER_NAME(foo,bar) {
// <type> bar[0];
// };
//
// it will have a sizeof() equal to type (right?).
//
//
#define SPN_VK_BUFFER_OFFSETOF(ds_id_, name_, member_) \
OFFSETOF_MACRO(SPN_VK_BUFFER_NAME(ds_id_, name_), member_)
#define SPN_VK_BUFFER_MEMBER_SIZE(ds_id_, name_, member_) \
MEMBER_SIZE_MACRO(SPN_VK_BUFFER_NAME(ds_id_, name_), member_)
//
// Define host-side pipeline push constant structures
//
// struct spn_vk_push_block_pool_init
// ...
// struct spn_vk_push_render
//
//
#define SPN_VK_PUSH_NAME(p_id_) struct spn_vk_push_##p_id_
#undef SPN_VK_HOST_DS
#define SPN_VK_HOST_DS(p_id_, ds_idx_, ds_id_)
#undef SPN_VK_HOST_PUSH
#define SPN_VK_HOST_PUSH(p_id_, p_pc_) SPN_VK_PUSH_NAME(p_id_){ p_pc_ };
#undef SPN_VK_P_EXPAND_X
#define SPN_VK_P_EXPAND_X(p_id_x, p_id_, _p_descs) _p_descs
SPN_VK_P_EXPAND()
//
// Declare descriptor acquire/release/update functions
//
#define SPN_VK_DS_TYPE(ds_id_) struct spn_vk_ds_##ds_id_##_t
#define SPN_VK_DS_TYPE_DECLARE(ds_id_) \
SPN_VK_DS_TYPE(ds_id_) \
{ \
uint32_t idx; \
}
#define SPN_VK_DS_ACQUIRE_FUNC(ds_id_) spn_vk_ds_acquire_##ds_id_
#define SPN_VK_DS_UPDATE_FUNC(ds_id_) spn_vk_ds_update_##ds_id_
#define SPN_VK_DS_RELEASE_FUNC(ds_id_) spn_vk_ds_release_##ds_id_
#define SPN_VK_DS_ACQUIRE_PROTO(ds_id_) \
void SPN_VK_DS_ACQUIRE_FUNC(ds_id_)(struct spn_vk * const instance, \
struct spn_device * const device, \
SPN_VK_DS_TYPE(ds_id_) * const ds)
#define SPN_VK_DS_UPDATE_PROTO(ds_id_) \
void SPN_VK_DS_UPDATE_FUNC(ds_id_)(struct spn_vk * const instance, \
struct spn_vk_environment * const environment, \
SPN_VK_DS_TYPE(ds_id_) const ds)
#define SPN_VK_DS_RELEASE_PROTO(ds_id_) \
void SPN_VK_DS_RELEASE_FUNC(ds_id_)(struct spn_vk * const instance, \
SPN_VK_DS_TYPE(ds_id_) const ds)
#undef SPN_VK_DS_EXPAND_X
#define SPN_VK_DS_EXPAND_X(ds_idx_, ds_id_, ds_) \
SPN_VK_DS_TYPE_DECLARE(ds_id_); \
SPN_VK_DS_ACQUIRE_PROTO(ds_id_); \
SPN_VK_DS_UPDATE_PROTO(ds_id_); \
SPN_VK_DS_RELEASE_PROTO(ds_id_);
SPN_VK_DS_EXPAND()
//
// Get references to descriptor set entries
//
#define SPN_VK_DS_GET_FUNC(ds_id_, d_id_) spn_vk_ds_get_##ds_id_##_##d_id_
#define SPN_VK_DS_GET_PROTO_STORAGE_BUFFER(ds_id_, d_id_) \
VkDescriptorBufferInfo * SPN_VK_DS_GET_FUNC(ds_id_, d_id_)(struct spn_vk * const instance, \
SPN_VK_DS_TYPE(ds_id_) const ds)
#define SPN_VK_DS_GET_PROTO_STORAGE_IMAGE(ds_id_, d_id_) \
VkDescriptorImageInfo * SPN_VK_DS_GET_FUNC(ds_id_, d_id_)(struct spn_vk * const instance, \
SPN_VK_DS_TYPE(ds_id_) const ds)
#undef SPN_VK_DESC_TYPE_STORAGE_BUFFER
#define SPN_VK_DESC_TYPE_STORAGE_BUFFER(ds_id_, d_id_x_, d_id_) \
SPN_VK_DS_GET_PROTO_STORAGE_BUFFER(ds_id_, d_id_);
#undef SPN_VK_DESC_TYPE_STORAGE_IMAGE
#define SPN_VK_DESC_TYPE_STORAGE_IMAGE(ds_id_, d_id_x_, d_id_) \
SPN_VK_DS_GET_PROTO_STORAGE_IMAGE(ds_id_, d_id_);
#undef SPN_VK_DS_EXPAND_X
#define SPN_VK_DS_EXPAND_X(ds_idx_, ds_id_, ds_) ds_
SPN_VK_DS_EXPAND()
//
// Bind a pipeline-specific descriptor set to a command buffer
//
#define SPN_VK_DS_BIND_FUNC(p_id_, ds_id_) spn_vk_ds_bind_##p_id_##_##ds_id_
#define SPN_VK_DS_BIND_PROTO(p_id_, ds_id_) \
void SPN_VK_DS_BIND_FUNC(p_id_, ds_id_)(struct spn_vk * const instance, \
VkCommandBuffer cb, \
SPN_VK_DS_TYPE(ds_id_) const ds)
#undef SPN_VK_HOST_DS
#define SPN_VK_HOST_DS(p_id_, ds_idx_, ds_id_) SPN_VK_DS_BIND_PROTO(p_id_, ds_id_);
#undef SPN_VK_HOST_PUSH
#define SPN_VK_HOST_PUSH(p_id_, p_pc_)
#undef SPN_VK_P_EXPAND_X
#define SPN_VK_P_EXPAND_X(p_id_x, p_id_, p_descs_) p_descs_
SPN_VK_P_EXPAND()
//
// Write push constants to command buffer
//
#define SPN_VK_P_PUSH_FUNC(p_id_) spn_vk_p_push_##p_id_
#define SPN_VK_P_PUSH_PROTO(p_id_) \
SPN_VK_PUSH_NAME(p_id_); \
void SPN_VK_P_PUSH_FUNC(p_id_)(struct spn_vk * const instance, \
VkCommandBuffer cb, \
SPN_VK_PUSH_NAME(p_id_) const * const push)
#undef SPN_VK_P_EXPAND_X
#define SPN_VK_P_EXPAND_X(p_id_x, p_id_, p_descs_) SPN_VK_P_PUSH_PROTO(p_id_);
SPN_VK_P_EXPAND()
//
// Bind pipeline to command buffer
//
#define SPN_VK_P_BIND_FUNC(p_id_) spn_vk_p_bind_##p_id_
#define SPN_VK_P_BIND_PROTO(p_id_) \
void SPN_VK_P_BIND_FUNC(p_id_)(struct spn_vk * const instance, VkCommandBuffer cb)
#undef SPN_VK_P_EXPAND_X
#define SPN_VK_P_EXPAND_X(p_id_x, p_id_, p_descs_) SPN_VK_P_BIND_PROTO(p_id_);
SPN_VK_P_EXPAND()
//
//
//
#endif // SRC_GRAPHICS_LIB_COMPUTE_SPINEL_PLATFORMS_VK_VK_H_